Saturday 3 February 2018

Sample Code for creating D365 Custom Data Provider

The below code helps in Writing the Retrieve Multiple plugin for a Custom Data Provider that fetches the data from SQL via a Web API


Sample Code :

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Extensions;
using Microsoft.Xrm.Sdk.Query;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;



namespace POC
{

    public class HttpHelper
    {
        public static HttpClient GetHttpClient()
        {
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Add("Connection", "close");

            return client;
        }
    }
 
   //For handling filters
    public class SearchVisitor : IQueryExpressionVisitor
    {
        public string SearchKeyWord { get; private set; }

        public QueryExpression Visit(QueryExpression query)
        {
          
            if (query.Criteria.Conditions.Count == 0)
                return null;

          
            SearchKeyWord = query.Criteria.Conditions[0].Values[0].ToString();

            return query;
        }
    }

   //Definition of the result
    public class SQLResult
    {
        public string application { get; set; }
        public string region { get; set; }
        public string vhdpath { get; set; }
    }

   //Main Plugin Code
    public class RetrieveMultiple : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = factory.CreateOrganizationService(context.UserId);


            try
            {
                QueryExpression query = context.InputParameterOrDefault<QueryExpression>("Query");
                Guid crmId = new Guid();
                var visitor = new SearchVisitor();
                query.Accept(visitor);

                try
                {
                    var retrieverService = serviceProvider.Get<IEntityDataSourceRetrieverService>();
                    var SourceEntity = retrieverService.RetrieveEntityDataSource();

                    var tableName = SourceEntity.GetAttributeValue<string>("poc_collectionname");
                    var connString = SourceEntity.GetAttributeValue<string>("poc_connectionstring");
                    var columns = SourceEntity.GetAttributeValue<string>("poc_columns");

                    tracer.Trace("Conn String  is :" + tableName.ToString());
                    tracer.Trace("TableName is :" + connString.ToString());
                    tracer.Trace("Columnds are :" + columns.ToString());

                }
                catch
                {
                    tracer.Trace("Details could not be retrieved");
                }

                EntityCollection results = new EntityCollection();
                results.EntityName = "poc_d365customdatasource";

                if (string.IsNullOrEmpty(visitor.SearchKeyWord))
                {
                    tracer.Trace("Getting database records");


                    try
                    {
                        tracer.Trace("Retreiving details from API");
                        crmId = Guid.NewGuid();

                        var getAPIdataTask = Task.Run(async () => await GetAPIdata());
                        Task.WaitAll(getAPIdataTask);
                        Console.ReadKey();
                        List<SQLResult> output = new List<SQLResult>();
                        output = getAPIdataTask.Result;
                        int i = 1;

                        foreach (SQLResult r1 in output)
                        {
                            tracer.Trace($"The values in the record are {r1.application} ,  {r1.region}  , {r1.vhdpath}  ");
                            crmId = Guid.NewGuid();
                            Entity e = new Entity("poc_d365customdatasource");
                            e.Attributes.Add("poc_d365customdatasourceid", crmId);
                            e.Attributes.Add("poc_application", r1.application);
                            e.Attributes.Add("poc_region", r1.region);
                            e.Attributes.Add("poc_vhdpath", r1.vhdpath);
                            e.Attributes.Add("poc_name", "D365 Custom Record " + i++.ToString());
                            results.Entities.Add(e);
                        }

                    }
                    catch (System.TimeoutException ex)
                    {
                        tracer.Trace(" Time out exception occurred and sending only hardocded data");
                        crmId = Guid.NewGuid();
                        Entity e = new Entity("poc_d365customdatasource");
                        e.Attributes.Add("poc_d365customdatasourceid", crmId);
                        e.Attributes.Add("poc_application", "Application");
                        e.Attributes.Add("poc_region", "region");
                        e.Attributes.Add("poc_key", "VHD Path");
                        e.Attributes.Add("poc_name", "D365 Custom Record 1");
                        results.Entities.Add(e);

                    }

                }
                else
                {
                    tracer.Trace($"Searching records for: {visitor.SearchKeyWord}");

                    // Write your own custom Logic to get the data based on the search criteria


                }
                tracer.Trace(results.Entities.Count.ToString() + " " + results.TotalRecordCount.ToString() + " Entity Name :" + results.EntityName + " Entity count :" + results.Entities.Count + " :");
              
                context.OutputParameters["BusinessEntityCollection"] = results;
            }
            catch (Exception e)
            {
                tracer.Trace($"{e.Message} {e.StackTrace}");
                if (e.InnerException != null)
                    tracer.Trace($"{e.InnerException.Message} {e.InnerException.StackTrace}");

                throw new InvalidPluginExecutionException(e.Message);
            }
        }


        private static async Task<List<SQLResult>> GetAPIdata()

        {
            using (HttpClient client = HttpHelper.GetHttpClient())
            {

                string url = "http://mypoc.azurewebsites.net/api/values";  // Give the details of your API that returns the data from SQL
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(url));
                HttpResponseMessage response = await client.SendAsync(request);

                if (!response.IsSuccessStatusCode)
                    throw new Exception("My API stopped this from happening");

                string json = response.Content.ReadAsStringAsync().Result;
                List<SQLResult> l1 = new List<SQLResult>();
                l1 = JsonConvert.DeserializeObject<List<SQLResult>>(json);              
                return l1;
            }
        }

    }

}

1 comment:

  1. Does it effect the database server ? If number of users in my organization are more and they are continuously trying to access the external data source by virtual entities. Does it effects my other systems using the same database?

    ReplyDelete