Create a Custom Service in D365

Share this:

In the last article we looked at how to setup Postman to call D365 services. We called a simple existing service. In this article I will show you how to create a custom service in D365.

Unlike calling a Data Entity which can create or retrieve data from tables, services allow us to run code within Microsoft Dynamics 365. This is very useful if for example you need to retrieve a value that is not stored in a table. Or you would like to run a process, and return whether it was successful or not.

What Are the Steps?

In order to create a custom service in D365, there are several pieces we need.

  1. We need a new class that is our ‘Request‘ object. The data we send in will be mapped to the variables in this class. Then we will use this class to run our operation.
  2. We need a new calls that is our ‘Response‘ object. In our code we will set the variables in this class to contain whatever information we want returned to the calling program. D365 will then convert these values into JSON data.
  3. We need a Service class. This is the class where we will put the code that will: a) read the data in our Request object, b) run some process, and then c) populate the Response object.
  4. We need a Service object, that points to our Service class. This lets Dynamics 365 know that our class can be called by an outside system.
  5. Lastly, we need a Service Group to put our Service object into.

Create the Request Class

When you create a custom service in D365, the Request class needs to have a variable for each piece of data you are sending into the system.

First, create a new class in Visual Studio. I named my ‘rsmTutRequestSimple’.

Next, add the Attribute [DataContractAttribute] just above the class declaration.

Add a variable. I named mine ‘dataAreaId’.

Finally, create a parameter method for that variable, and put the attribute [DataMember(“<The name of your Data>“)] above the method.

Your code should now look like this:

[DataContractAttribute]
class rsmTutRequestSimple
{
    private str dataAreaId;

    [DataMember("DataAreaId")]
    public str parmDataAreaId(str _value = dataAreaId)
    {
        if (!prmIsDefault(_value))
        {
            dataAreaId = _value;
        }

        return dataAreaId;
    }
}

Create the Response Class

The Response class needs to have a variable for each piece of information we would like to send back to the calling program.

First, create a new class in Visual Studio. I named mine ‘rsmTutReponse’.

Add the attribute [DataContractAttribute] just above the class definition.

Add variables that will contain information you want to return to the calling program. I created variables ‘success, ‘errorMessage’, and ‘debugMessage’.

Finally, create a parameter method for each of your variables. Put the attribute [DataMember(“<The name of your data>“)] above each method definition. The value you put as <The name of your data> will be the name of the JSON tag that is generated.

Your code should now look like this:

[DataContractAttribute]
class rsmTutResponse
{
    private boolean     success;
    private str         errorMessage;
    private str         debugMessage;

    [DataMember("ErrorMessage")]
    public str parmErrorMessage(str _value = errorMessage)
    {
        if (!prmIsDefault(_value))
        {
            errorMessage = _value;
        }

        return errorMessage;
    }

    [DataMember("Success")]
    public Boolean parmSuccess(Boolean _value = success)
    {
        if (!prmIsDefault(_value))
        {
            success = _value;
        }

        return success;
    }

    [DataMember("DebugMessage")]
    public str parmDebugMessage(str _value = debugMessage)
    {
        if (!prmIsDefault(_value))
        {
            debugMessage = _value;
        }

        return debugMessage;
    }

}

Create The Service Class

The Service class is the most interesting class when you create a custom service in D365. It is responsible for reading values from the Request object, running some process, then setting values on the Response object.

First, create a new class in Visual Studio. I named mine ‘rsmTutServiceSimple’.

Create a method in the class, named whatever you would like. I named mine ‘create’.

The method needs to take as a parameter which has a type of your Request object. And it needs to return a value which has a type of your Response object. So for example this:

public rsmTutResponse create(rsmTutRequestSimple _request)

Next, you can put whatever code you need to inside the method. In my example, I am reading the dataAreaId from the request object, and then I am storing the text “Hello World” in the response object.

public class rsmTutServiceSimple
{
    public rsmTutResponse create(rsmTutRequestSimple _request)
    {
        var response = new rsmTutResponse();
        changecompany(_request.parmDataAreaId())
        {
            try
            {
                response.parmDebugMessage("Hello World");
                response.parmSuccess(true);
            }
            catch (Exception::CLRError)
            {
                System.Exception interopException = CLRInterop::getLastException();

                response.parmSuccess(false);
                response.parmErrorMessage(interopException.ToString());
            }

            return response;
        }
    }
}

I also added a try catch block. If the process throws an error, I am storing the error message in the response object as well.

Create The Service Object

The Service object, exposes our Service class and allows it to be called by an outside system with the proper authentication. In Visual Studio, right click on your project, and select ‘Add New Item’. Then select ‘Service’.

Give the item a name. I named mine ‘rsmTutServiceSimple’

Open the object. Right click on it and select ‘Properties’

In the Properties window, set the ‘Class’ property with the name of the Service Class you created earlier. Mine is named ‘rsmTutServiceSample’. (The same as the service object). Also, set the ‘External Name’ property to the same value. You can change this to be whatever you want. But it is simpler if you leave it the same.

Now, Right click on the ‘Service Operations’ node, and select ‘New Service Operation’

Select the new node that is created, and in the Properties window set the ‘Method’ property to the name of the method in your Service class. I named mine ‘create’. Also set the ‘Name’ property to be the same. (You could change this to be something different. But it is simpler if you set it to be the same as the method name).

Create The Service Group

The Service Group is an object that can contain one or more services and is a way of organizing similar operations together.

In Visual Studio right click on the project and select Add>New Item. Select the ‘Service Group’ item. Then give your object a name. I named mine ‘rsmTutServiceGroupSimple’.

Open the new Service Group object, and right click on the main node. Select ‘New Service’ from the drop down.

Select the node that is created, and view the properties window. Set the ‘Name’ and the ‘Service’ properties to the name of your Service object. In my case, the name of my Service object is ‘rsmTutServiceSimple’.

Call The Service From Postman

You can view the previous article for detailed steps on how to use Postman to call the service. In this case the URL to call the service will be:

https://<D365 URL>/api/services/rsmTutServiceGroupSimple/rsmTutServiceSimple/create

Let’s break down this URL into it’s parts.

  • https:// – This specifies we are making a secure call.
  • <D365 URL> – This should be replaced by the URL used to access your D365 environment. For example: https://usnconeboxax1aos.cloud.onebox.dynamics.com
  • api/services – This text tells D365 that we are calling a service.
  • rsmTutServiceGroupSimple – This is the name of the service group we are calling.
  • rsmTutServiceSimple – This is the name of the service we are calling.
  • create – This is the name of the method we are calling on the Service class.

In this example the Postman body would look like this:

{
	"_request" :
	{
		"DataAreaId": "USRT"
	}
}

Conclusion

You have now performed the actions to create a custom service in D365 as well as call it! Great job! Now any outside system can call code inside of D365. This can be used by Microsoft Power Apps, Power Automate, Azure Logic Apps, other externals systems, and many more. Enjoy!

Peter Ramer
Peter Ramer is a part of the Managed Application Services team at RSM working on Microsoft Dynamics 365. He focuses on the Retail and Commerce industries. When he is not solving problems and finding ways to accelerate his clients' business, he enjoys time with his three kids and amazing wife.

Share this:

33 thoughts on “Create a Custom Service in D365

Add yours

  1. Any business or organization is successful by the virtue of its customers. If you are not able to satisfy your customers, it is most likely that you will fail to reach your financial goals. It is also important to understand that customer satisfaction cannot be achieved merely through quality products and consistent services. So in above blogs a custom service will always help to increase and deliever better customer service.

  2. It’s a shame you don’t have a donate button! I’d definitely donate to this superb blog! I guess for now i’ll settle for book-marking and adding your RSS feed to my Google account. I look forward to fresh updates and will share this site with my Facebook group. Talk soon!

  3. After I initially commented I clicked the -Notify me when new comments are added- checkbox and now every time a comment is added I get four emails with the same comment. Is there any means you’ll be able to remove me from that service? Thanks!

  4. Hey very cool website!! Man .. Excellent .. Amazing .. I’ll bookmark your I’m happy to find a lot of useful info here in the post, we need develop more techniques in this regard, thanks for sharing. . . . . .

  5. My spouse and I stumbled over here different web address and thought I may
    as well check things out. I like what I see so now i’m following you.
    Look forward to going over your web page again.

  6. Hey, you used to write great, but the last few posts have been kinda boring?I miss your super writings. Past few posts are just a little bit out of track! come on!

  7. Attractive component of content. I simply stumbled upon your website and in accession capital to claim that I acquire actually loved account your weblog posts. Any way I will be subscribing in your feeds and even I fulfillment you get entry to persistently quickly.

  8. Hey there! This is my first visit to your blog! We are a collection of volunteers and starting a new initiative in a community in the same niche. Your blog provided us valuable information to work on. You have done a extraordinary job!

  9. Pingback: My Homepage
  10. Thanks for the blog!! Really helpful.
    How to handle the security for the custom service call?
    In my case, User is receiving error “”An exception occured when authorizing – Entry point security access denied to current user for operation ‘submit’ on service ‘XXXXService’.
    I have already created Maintain and view privileges and added ‘Service’ in the EntryPoint. Call is working fine with Admin rights.

  11. Thank you for this wonderful blog series that demystifies the easy to miss parts of creating and calling a custom service. I would have struggled a good bit with the app registration and postman headers needed to make the custom service call without this great documentation.

    I have a question about user context when calling the custom service. Is there any guidance or documentation on how to provide different user context for the service calls? If I have a microservice running as a service account and I want to grab data from a 3rd party API and pass it to D365 as the user who created the data, is there a good way to handle that so that data looks like it was created by the user who created it in the 3rd party system instead of all data showing it’s been modified by the service account user?

    1. Thank you for your kind words. I really appreciate it.
      There isn’t a way to spoof the createdBy field. As you can imagine that would somewhat defeat the purpose. That said, you can created your own field and pass in the user if from the outside system and store it in your custom field. Then show that field on a form so that people can see who created that record in the 3rd party system. I hope that helps some.

      1. Thanks for the quick response! I think I made a mistake in my question because I stated that it will use the service account of my microservice. I believe it would actually user the user that is linked to the Azure AD client application that microservice used when getting the authentication token. Nevertheless, I’m investigating using the RunAs runtime method to try to run the operations as the user from the 3rd party system so that both security and audit are handled as if the user themselves invoked the functionality. If this doesn’t work, then we’ll look at creating a custom audit field as a work around.

        Thanks again, love the blog!

  12. Hello, I get error 404 which indicates the endpoint does not exist but my authentication seems to be valid since if I change the token with something random I get forbiden error.
    Could there be some step I have misseed? Ive built my project, triple checked the names of the classes and objects.

      1. I am able to call the SysTestService endpoint but when calling the one I created I still get 404. I double checked the names of the service and group.

  13. Hi Peter!
    I created a Contract class. but the requirement is to hide the attributes when they have a Null value. How can I achieve it? I tried using Newtonsoft.Json.JsonPropertyAttribute(NullValueHandling = Newtonsoft.Json.NullValueHandling::Ignore) attribute in the parm method but it gives an error.

    1. Hi Sohan. I don’t think I understand. When you send in a json message from outside D365 to inside of D365 the contract class just lists all of the json name/value pairs you might get sent in so that the system can take that json and populate the contract class object for you.
      I think that if you have some extra properties in your contract class but the json data doesn’t pass name/values for those, then they just won’t be set. And you can check if the values are blank or null in your x++ code. But perhaps I am misunderstanding your scenario. I don’t insert why you would need to hide properties on your contract class as these aren’t visible to the end user. It is just used by the back end system to convert the json string you are passing in to a x++ class object.

  14. Hi Peter,

    I’m getting the value below in my Body, I thought it will return the actual text. Do you know what’s the problem?

    {
    “Parameters”: [
    {
    “Name”: “_request”,
    “Type”: “MySampleRequest”
    }
    ],
    “Return”: {
    “Name”: “return”,
    “Type”: “String”
    }
    }

    1. I’ve seen this before. I’m trying to remember. It is something small. It may have to do with the url in your post. Can you share that piece? You can leave out the first environment piece. But the second half may be relevant. I will try to remember.

Leave a Reply

Your email address will not be published. Required fields are marked *

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑