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.
- 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.
- 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.
- 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.
- 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.
- 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!
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.
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!
It is not my first time to go to see this website,
i am visiting thiis web page dailly and take good information frim here
all thhe time.
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!
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. . . . . .
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.
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!
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.
Very nice post. I just stumbled upon your weblog and wanted to say that I have really enjoyed surfing around your blog posts. After all I will be subscribing to your feed and I hope you write again soon!
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!
Your mode of describing all in this piece of writing is in fact pleasant, all be capable of simply be aware of it, Thanks a lot.
Hello! Do you use Twitter? I’d like to follow you if that would be okay.
I’m definifely enjoying your blog and look forward too new articles.
I enjoy reading through your website. Thanks!
It is not my first time to ggo to see this website, i am visiting thius web page dailly and take good information from
here all the time.
Pretty! Thhis has been an extremely wonderful post.Thank you for supplhing this info.
Thanks for the blog.Really looking forward to read more. Really Great
Thanks for the blog.Really looking forward to read more. Really Great
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.
ARe you able to resolve this issue?
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?
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.
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!
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.
Are you able to call the SysTestService? See this article. https://dynamics365musings.com/setup-postman-to-call-d365-services/
This serves as a good test to ensure your authentication is right. If that that works then double check the external name on your Service object in the Application Explorer.
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.
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.
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.
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”
}
}
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.
That looks like you’re doing a “GET”. Is that your intention, or did you mean to do “POST”?
Yes, I think this should be a Post. I need to correct this. Thanks.
Hi Peter Ramer,
We are using API integration in our current D365 F&O project. I am getting 500 internal server error on failure of outbound integration i.e. F&O to third party application. Is there any way we can get specific error message instead 500 internal server error. Please let me know if any.
Thanks in advance…..
A 500 error is a generic server error. You can see if there is a more detailed error message in the response body. Otherwise, you should attach a debugger to your x++ code and then call the custom service. If it doesn’t get into your method at all, then it is a problem with the format of your request. If it does, and you can debug you can see if there is a place in code that the system is throwing an error. If so, you can use try catch statements to catch an error, and then return a response object that includes a status and error message that you set, if you want more visibility on what went wrong sent back to the calling program. https://en.m.wikipedia.org/wiki/List_of_HTTP_status_codes
Hi Pater Ramer, excellent blogs. nicely explained
I have few queries…
1. can I share the API to the 3rd party application?
2. if yes, then what are the approaches to send the API to 3rd party application.
3. how they (3rd party application) will consume the API from D365FO.
4. from the 3rd party application, if they do CRUD operation on the shared API (which we shared to 3rd party),
is, it will impact on D365FO as well?
Kindly share me some link for point no 3 & 4 please.
Kindly elaborate please
thanks in advance!
1) yes you can
2) you need to share the clientID client secret, and url path to your api. Then they will be able to call it.
3)the third party will may an http web call to consume the service.
4) yes. Whatever your api does: read, write, when the third party calls it, it will affect your system. So make sure it is someone you trust.
Thank you, Peter for the quick response.
Point no 2 : As you said “you need to share the clientID client secret, and url path to your api. Then they will be able to call it.”
You mean to say the Azure > App registration the Client Id etc.. which we also stored in D365FO > System Administration > Microsoft Entra Id. The same client Id etc. we need to share with the 3rd party application. correct?
Now the question is, where they will use that client Id, Secret key etc. to call to consume the API.
Kindly elaborate please.
Thanks!
Hi Arpan. See this article: https://dynamics365musings.com/setup-postman-to-call-d365-services/
It shows you how to use Postman to make an http call. Postman is a test tool for making http web requests. But the third party would write code on their end to make the http web request.
Then look at this article that shows how to setup the azure client id and secret. And then use postman to make an http call to get an auth token. Once you have the auth token, then you can call the custom service, passing in the auth token in the second web request.
https://dynamics365musings.com/use-postman-to-call-d365-data-entities/
So any third party would make two calls. One, using the client Id and secret to get an auth token that expires in a few hours. Then, a second call to run the custom service you wrote.
Hi Peter Ramer,
I have go through the links which you advised:
the first link https://dynamics365musings.com/setup-postman-to-call-d365-services/
I have found that:
here we first successfully setup the postman to call D365 services. and
second, here we called the existing custom service and method as well.
the second link https://dynamics365musings.com/use-postman-to-call-d365-data-entities/
I have found that:
here in Azure > App registration – we generate Client id (application id) and
secret key.
Once we got Client id and Secret Id form Azure then we need to Register the external application in D365FO.
So, In System administration > Setup > Microsoft Entra Id > here we need to fill the
“Client Id”.
“Name”,
“User Id” – It should be admin privileges. then save it.
So, finally it makes the connection between Azure & D365FO.
Is my assumption being correct?
As you said “So any third party would make two calls. One, using the client Id and secret to get an auth token that expires in a few hours. Then, a second call to run the custom service you wrote.”
My question is
1. The Client id and secret Id which we shared with the 3rd party, where they will use those to get the auth token?
Is it in postman tool? Is they need to install postman in their end also?
2. Once they got the auth token from postman, the next step is to call the custom service.
for example – this is my custom service API
https://URL/api/services/service_group_name/service_name/operation_name
https://DEV.axcloud.dynamics.com/api/services/TestServiceGroup/TestService/create
Is the above API will use in 3rd party directly in postman tool to get the data from D365FO?
Or is there any other options.
3.To get the auth token with using application id and secret id by 3rd party application, is postman tool is only option or is there any other tool to get it.
4. Is they (3rd party) required to write any code to access our API to get the data from D365FO
or simply they can use our API in postman tool to get the data from D365FO.
Kindly elaborate please. Thanks!
Hi Arpan. You need to look at this link: https://dynamics365musings.com/setup-postman-to-call-d365-data-entities/
In it, it shows you need to make an http web request to this url, passing it the clientid, secret, and environment to get the auth token.
https://login.microsoftonline.com//oauth2/v2.0/token
Postman is just a tool to test out making http web requests. Your third party can use whatever method they want to make an http web request. This be done by writing c# code. Or with another integration tool.
Hopefully that helps.
Thank you so much Peter for the clarity. I will go through and let you know.
Hi Peter Ramer,
I have go through the links which you advised:
the first link https://dynamics365musings.com/setup-postman-to-call-d365-services/
I have found that:
here we first successfully setup the postman to call D365 services. and second, it is called existing custom service and method.
the second link https://dynamics365musings.com/use-postman-to-call-d365-data-entities/
I have found that:
here in Azure > App registration – we generate
Client id (application id) and
secret Id.
Once we got Client id and Secret Id form Azure then we need to Register the external application in D365FO.
So, In System administration > Setup > Microsoft Entra Id >
here we need to fill the
“Client Id”,
“Name”,
“User Id” – It should be admin privileges. then save it.
So, finally it makes the connection between Azure & D365FO.
Is my assumption being correct?
As you said “So any third party would make two calls. One, using the client Id and secret to get an auth token that expires in a few hours. Then, a second call to run the custom service you wrote.”
My question is:
1. The Client id and secret Id which I shared with the 3rd party, where they will use those Ids to get the auth token?
Is it in postman tool ? Is they need to install postman in their end also ?
2. Once they got the auth token, the next step is to call the custom service.
for example – this is my custom service API
https://URL/api/services/service_group_name/service_name/operation_name
https://DEV.axcloud.dynamics.com/api/services/TestServiceGroup/TestService/create
Is the above API will use directly in 3rd party in postman tool to get the data from D365FO.
is my assumption being correct?
Kindly elaborate please.
Thanks!
Hi Arpan. You need to look at this link: https://dynamics365musings.com/setup-postman-to-call-d365-data-entities/
In it, it shows you need to make an http web request to this url, passing it the clientid, secret, and environment to get the auth token.
https://login.microsoftonline.com//oauth2/v2.0/token
Postman is just a tool to test out making http web requests. Your third party can use whatever method they want to make an http web request. This be done by writing c# code. Or with another integration tool.
Hopefully that helps.
Thanks Peter,
What I understood…
Whatever API I have, we need to do two things like:
First – Https web request to this API ( URL)
Second – I need to be passing clientid, secret, and environment to get the auth token.
So, this is done from our end (D365FO).
Now the next part is to consume the API from the 3rd party application
So, they can use C# or any other integration tools to consume this API from their end.
Only we need to send this API (URL) to 3rd party application. They will do the code to consume this API to get data from D365FO.
Is my assumption is correct?
Thanks!
Yes
Thanks Peter, for the response.
Hi Arpan, Let me jump in to answer your query.
When you create a new web service in D365 FO and you want a third party to access it, you need to share the below details with them:
1. You web service endpoint(s) which would be in the format https://URL/api/services/service_group_name/service_name/operation_name
2. In order for the third party to access the APIs, they need to authenticate using the Client id, Client secret, Grant type and Scope. Similar to what you need when authenticating via Postman.
Additionally, for enhanced security and monitoring, you can use Azure API management tools to expose your D365 FO web service endpoints.
I hope this answers your query.
Thanks Sohan, for the response.
Only one query for point no 2
As you said “In order for the third party to access the APIs, they need to authenticate using the Client id, Client secret, Grant type and Scope. Similar to what you need when authenticating via Postman”.
Suppose I have shared “Client id, Client secret, Grant type and Scope” to the 3rd party.
My question is where they will use those values for the authentication. I mean in which tool?
Kindly elaborate please.
It depends on the third party Arpan, they might create something in c# or they might already have an application in which they can configure all of the setups and it can then send requests to D365FO along with the authentication token.
Thanks Sohan,for the response.
Hi Peter/Sohan,
when we decide to go for create a custom service.
Is any specific business scenario?
Kindly elaborate please.
Thanks!
You should use a custom service when you need a third party to run code and return a response all in real time. If you just need to insert, update, or get data you should use a data entity. If you don’t need to return data, but still need to run code to insert it, you can use a data entity to stage in in a table then use a batch job to process it.
Thanks Peter, for the update.
Hi Peter, Thanks for your response and well understood about Custom service. Really appreciate.
Here we discussed about custom service and shared the API to third party to access the data from D365FO.
I have a question:
1. can we use custom service API with Logic Apps?
2. Any specific business scenario, where we need to configure custom service with Logic apps.
kindly elaborate please.
Thanks!
Logic apps are just code running in azure. You can have an azure app call a D365 custom service if you want to.
Thanks Peter for the response.
Kindly explain about azure app pls. how we can access custom service with using azure app.
kindly elaborate please.
Thanks in advance!