Introduction
In the last blog, we saw how we could execute all available data types in Custom API. In this blog, we will be creating Custom Function using Custom API.
Let’s create a custom API similarly to retrieve multiple as we have in Dynamics 365. However, we will extend the limit of 5000 records per request to 20000 per request.
We will be passing a table name and columns as parameters to Custom API and our Custom API should send back the response with the data based on the same.
Let us go with the code first approach for this Custom API.
We have written an Assembly shown below that has three input parameters and two Output Parameters.
Input Parameters:
• Table Name (Entity)
• Columns Name (Field)
• Cookie (This is the paging cooking, in case there are more than 20000 records and the Custom API needs to be called a second time to get the other 20000 records).
Output Parameters:
• Values
• Cookie (Paging Cooking that needs to be passed to the next request)
Create Assembly:
public void Execute(IServiceProvider serviceProvider)
{
try
{ // tracing object
ITracingService tracing = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
// ExecutionContext object
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// object Organization service factory object
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
// object organization object
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
string cookie = context.InputParameters.Contains(“cookie”) ? Convert.ToString(context.InputParameters[“cookie”]) : string.Empty;
bool moreRecords = false;
int pageNumber = !string.IsNullOrEmpty(cookie) ? Convert.ToInt32(cookie.Substring(cookie.IndexOf(“page=”) + 6, 1)) : 1;
if (pageNumber > 1)
moreRecords = true;
EntityCollection eCollection = new EntityCollection();
tracing.Trace($”Before Request”);
//check the key is present
if (context.InputParameters.Contains(“table”))
{
/*We get the 5000 max record per request using OOB way,
* For making to 20000 records max we will be executing OOB request to max for time */
for (int i = 0; i < 4; i++)
{
tracing.Trace($”Loop number {i}”);
//Create queryexpression query
var query = new QueryExpression(Convert.ToString(context.InputParameters[“table”]));
//define dynamic variable for storing the columns
dynamic columns = context.InputParameters.Contains(“columns”) ? Convert.ToString(context.InputParameters[“columns”]) : string.Empty;
if (string.IsNullOrEmpty(columns))
columns = true;
else
columns = columns.Split(‘,’);
query.ColumnSet = new ColumnSet(columns);
//If more records are there
if (moreRecords)
{
query.PageInfo.PagingCookie = cookie;
query.PageInfo.PageNumber = pageNumber;
}
var result = service.RetrieveMultiple(query);
//Add the all records in the collection variable
eCollection.Entities.AddRange(result.Entities.AsEnumerable());
tracing.Trace($”data Count {eCollection.Entities.Count}”);
cookie = result.PagingCookie;
moreRecords = result.MoreRecords;
pageNumber = pageNumber + 1;
if (!moreRecords)
break;
}
context.OutputParameters[“values”] = eCollection;
context.OutputParameters[“cookie”] = cookie;
tracing.Trace($”Cookie {cookie}”);
tracing.Trace($”After OutPut Parameter set”);
}
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.InnerException != null && ex.InnerException.Message != null ? ex.InnerException.Message : ex.Message);
}
}
Now create the Custom API record as below:
As mentioned above, create three Input parameters:
1) Table Name: A required parameter to be passed to Custom API for retrieving entity-specific data.
2) Columns: An optional parameter, which will define the columns to be retrieved by our request.
3) Cookie: Paging Cookie, in case we have more than 20000 and for getting data in a sequence after every request.
Output Parameters:
1) Values: Since this Custom API can be used to retrieve data of any table, we have deliberately left the Logical Entity Name blank, which means that Entity Collection can be of any table.
2) Cookie: Paging Cookie that needs to be passed along the next request for the same table.
We have completed with the configuration part. Now we can execute our Custom API.
Move to a browser and execute the custom function as shown below.
custom_retrievetabledata is our Custom API table, columns and cookie are our parameters, amongst them table is our required parameters.
For passing parameters as QueryString, you can create aliases for the parameters and then execute it as below.
First, we need to create parameter aliases, which shall reference the parameter, and using that aliases we can pass the parameters as QueryString. Please note for creating parameter aliases we need to use the ‘@’ keyword else, it will give us an error. You can read more about it from here.
Execute it using Fetch API.
await (await fetch(“/api/data/v9.2/custom_retrievetabledata(table=’account’,columns=’name,telephone1′)”)).json()
Execute using Xrm.WebApi.online.execute function.
var getTableData= async function(tableName){
var Request = {};
/**
* Request to Get All Relationship Count
* @param {String} EntityName – Entity Logical Name.
*/
Request = function(table) {
this.table = table;
};
// NOTE: The getMetadata property should be attached to the function prototype instead of the
// function object itself.
Request.prototype.getMetadata = function () {
return {
boundParameter: null,
parameterTypes: {
“table”: {
“typeName”: “Edm.String”,
“structuralProperty”: 1 // Primitive Type
}
},
operationType: 1, // This is an action. Use ‘1’ for functions and ‘2’ for CRUD
operationName: “custom_retrievetabledata”,
};
};
// Construct a request object from the metadata
var req = new Request(tableName);
result = await Xrm.WebApi.online.execute(req);
return await result.json();
}
Conclusion
This way we can create and execute the function type Custom API.
I followed all steps expecting to see how should I connect the assembly part with the Custom API. After doing everything, I get a response from the API but all values are empty. I’m guessing I need to do something else with the assembly but I have no idea. Could you give me any advice or point me in the right direction?
Thanks in Advance,
Well there are two ways to associate a plugin on Custom API:
1) On Code first approach while creating Custom API record you can bind the Plugin.
2) Using Plugin Registration tool register a plugin step on the Custom API Action message.
And for information on passing parameters to plugin you can check this blog.
Hope this helps.
Thanks!
Thanks my bad. Missed the image where you selected the registered plugin.
Keep up the good work!