2
votes

My issue is accessing the Dynamics CRM 365 data in RESTful service.

I want to use Dynamics CRM data in a RESTful service. This RESTful service will be used in an WCF services to connect a mobile application to CRM data access.

I have gone through below reference but does not looks like any of them will work for me. Here, I want to try to avoid the use of Azure.

For above requirement, I tried with CODE provided in below reference: Ref 1: Microsoft CRM Web API Query Data Sample (CS), but that is also giving the error as attached screenshot

Error ScreenShot

Error zone: In Program.cs file - when it tries to get the result throws error on below line of code:

HttpResponseMessage response = SendAsJsonAsync(httpClient, HttpMethod.Post,
            "accounts", account1).Result;

If link shared above as Ref 1 is the correct way than how am I supposed to get ClientId and RedirectUrl?

1

1 Answers

0
votes

This is the code using the Microsoft example to authenticate against CRM:

public class CrmConnector
{
    private const string ApiVersion = "v8.2";

    public static HttpClient Client { get; set; }

    public CrmConnector(FileConfiguration config)
    {
        if (Client == null)
        {
            Task.WaitAll(Task.Run(async () => await ConnectToCRM(config)));
        }
    }

    /// <summary>
    /// Obtains the connection information from the application's configuration file, then 
    /// uses this info to connect to the specified CRM service.
    /// </summary>
    protected virtual async Task ConnectToCRM(Configuration config)
    {
        Authentication auth = new Authentication(config);
        Client = new HttpClient(auth.ClientHandler, true);
        Client.BaseAddress = new Uri($"{config.ServiceUrl}api/data/{ApiVersion}/");
        Client.Timeout = new TimeSpan(0, 2, 0);
        Client.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
        Client.DefaultRequestHeaders.Add("OData-Version", "4.0");
        Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }
}

To pass the config file, will look like this:

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>

  <connectionStrings>
    <clear />

    <!-- When providing a password, make sure to set the app.config file's security so that only you can read it. -->
    <add name="default"   connectionString="Url=ORG; Username=USER; Password=PASS; Domain=DOMAIN" />
    <add name="CrmOnline" connectionString="Url=https://mydomain.crm.dynamics.com/; [email protected]; Password=password" />
  </connectionStrings>

  <appSettings>
    <!--For information on how to register an app and obtain the ClientId and RedirectUrl
        values see https://msdn.microsoft.com/dynamics/crm/mt149065 -->

    <!--Active Directory application registration. -->
    <!--These are dummy values and should be replaced with your actual app registration values.-->
    <add key="ClientId" value="CLIENTID" />
    <!--<add key="RedirectUrl" value="http://localhost/SdkSample" />-->

    <!-- Use an alternate configuration file for connection string and setting values. This optional setting
    enables use of an app.config file shared among multiple applications. If the specified file does
    not exist, this setting is ignored.-->
    <add key="AlternateConfig" value="C:\Temp\crmsample.exe.config"/>
  </appSettings>

</configuration>

You can get your clientId from the developer resources in your organization, redirectUrl is optional and you can use the object like this:

CrmConnector CrmConnector = new CrmConnector(new FileConfiguration(null));

And to make the request:

public const string OdataAnnotationAll = "odata.include-annotations=*";

protected virtual async Task<HttpResponseMessage> RequestCRMAsync(HttpMethod method, string query, string pag, bool annotations)
{
    HttpRequestMessage request = new HttpRequestMessage(method, query);
    request.Headers.Add("Prefer", "odata.maxpagesize=" + pag);

    if (annotations)
    {
        request.Headers.Add("Prefer", OdataAnnotationAll);
    }

    return await CrmConnector.Client.SendAsync(request);
}

To read the response:

using Newtonsoft.Json;

public virtual async Task<JObject> RequestCRM(HttpMethod method, string query, string pag, bool annotations)
{
    JObject responseObject = new JObject();
    HttpResponseMessage response = await RequestCRMAsync(method, query, pag, annotations);

    if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.NoContent)
    {
        responseObject = JsonConvert.DeserializeObject<JObject>(response.Content.ReadAsStringAsync().Result);
    }
    else
    {
        throw new CrmHttpResponseException(response.Content);
    }

    return responseObject;
}

If you are making a create or update you have to send the params in the body:

JObject data = new JObject();
data.Add("firstname", "Sxntk");
data.Add("lastname", "IG");
data.Add("annualincome", "1000000000");
request.Content = new StringContent(data.ToString(), Encoding.UTF8, "application/json");

And if it is a create or update, the guid will come in this header:

protected virtual string GetGuidFromResponse(HttpResponseMessage response)
{
    string RegexGuid = @"(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}";

    // Get the url -> http://~/entity(guid)
    var urlHeader = response.Headers.FirstOrDefault(x => x.Key == "OData-EntityId");

    //Type of this is KeyPairValue
    if (urlHeader.Value == null)
    {
        return null;
    }

    // Get the guid form url
    return Regex.Matches(urlHeader.Value.FirstOrDefault(), RegexGuid)?[0].Value;
}

Update http method is PATCH not POST.

The clases from microsoft helpers are Authentication, Configuration, Exceptions and CrmConnector modified.