Advertisements

{Knowhow} How to execute Web API calls to Microsoft Dynamics CRM from an external ASP.NET web application

Microsoft Web API has delighted all and specially if you have a penchant towards exploring the API features, then Web API must have thrilled you by this time. Many consultants and experts, including myself, have written blogs on how to leverage the Web API features in Dynamics CRM.

But all these far, all the examples have been written in javascript. To elaborate most of the examples are on

  • Using web API from within Microsoft Dynamics CRM webresources
  • Using web API from an external HTML page using javascript and adal.js

Web API uses OAuth 2.0 protocol for authorization. However when you are making Web API calls from within Dynamics CRM, the entire nuances of OAuth 2.0 authorization is hidden from you. All you need to do is send a well formatted request and get the response back, parse the json response and get the data back in the application to use.

For the second example, although it will expose you greatly to the nuances of OAuth 2.0 protocol  but there is a subtle difference when you execute Web API calls from browser based application (like javascript/ jquery) and from a server based application like ASP.NET web application. The main difference is that in the first case, you would not need the client secret to get the access token. The authentication is implicit and you get the access token in just one call to the authorization endpoint. For the second case you would need to first get the authorization code by asking the end-user to enter his credentials and then once you get the authorization code, you would need to make a second call to the token endpoint to get the access token using authorization code + client_id + client_Secret.

If you are not aware of the OAuth 2.0 mechanisms, I would strongly suggest to first check for the OAuth documentations or you may go through my below blog post.

https://debajmecrm.com/2016/02/23/understanding-in-depth-cross-origin-resource-sharing-cors-in-dynamics-crm-2016/

The above post first gives you an introduction to the OAuth 2.0 protocol and then how to use that to connect to Dynamics CRM Web API endpoint from an external HTML Page. The post also covers on how to register the application in azure AD and get the client id and the client secret. Before you read further I would strongly suggest you go through the above post and understand how OAuth 2.0 works from CRM perspective.

After I wrote the above blog post, I received lot of requests personally if I can provide and code of how to make the same call from ASP.NET web application. Well your wish is granted. Here I will show you end-end on how to fetch data from Dynamics CRM Web API from a ASP.NET web application.

 

  • Create a ASP.NET web application project with a single web page. I named it default.aspx.
  • Go to the design mode and the markup should look like below.

image

The markup should contain

  1. A Login button which when the user clicks will take him/ her to the authentication screen.
  2. The label will display the name of the user once the user is authenticated.
  3. Get Accounts Button will retrieve the list of accounts when clicked.
  4. GridView will show the list of accounts retrieved once the Get Accounts button is clicked.

The above link explains how to add Dynamics CRM AD in Azure and register the application in Dynamics AD and how to get the client id and the client secret. Please make a note of the client id and specially the client secret which is visible immediately after saving. Please note that the client secret is visible only for the first time. If you come back later, you won’t be able to view it.

  • For this demo, I will keep these values in the web.config file. However do not keep the client id and client secret in the web.config specially the client secret. It’s very sensitive information. You should have some better ways of managing the same.

<appSettings>
<add key=”client_id” value=”f8a39dc3-338b-4018-b67e-6dbaa846f469″/>
<add key=”client_secret” value=”<your client secret>”/>
<add key=”tenant” value=”xrmtr14.onmicrosoft.com”/>
<add key=”redirect_url” value=”
http://localhost:52432/default.aspx”/>
<add key=”resource” value=”
https://xrmtr14.crm.dynamics.com”/>
</appSettings>

  • Now add a reference to the Active Directory authentication library and NewtonSoft.json.dll. The best way to do this is using Nuget Packages. For Active Directory Authentication Library type ‘Microsoft IdentityModel’ in the search box.

image

image

  • Now come to code-behind file (default.aspx.cs) and copy the entire code from below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using System.Configuration;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Net;
using System.Web.Script.Serialization;
using Newtonsoft.Json;

namespace DynamicsCRMWebApiConnector
{
public partial class _default : System.Web.UI.Page
{
const string AuthorityUri = “
https://login.windows.net/{0}/oauth2/authorize”;
        const string CompleteAuthUri = “https://login.windows.net/{0}/oauth2/authorize?response_type=code&client_id={1}&resource={2}&redirect_uri={3}”;
        Configurations _configuration;

        protected void Page_Init(object sender, EventArgs e)
{
this.PopulateConfigurations();
}

        protected void Page_Load(object sender, EventArgs e)
{
var queryString = Request.QueryString;

            // means authorization code has been received
if(queryString != null && queryString[“code”] != null)
{
var authCode = queryString[“code”];

                // get the access token using the authorization code
TokenCache tokenCache = new TokenCache();
AuthenticationContext authContext = new AuthenticationContext(string.Format(AuthorityUri, _configuration.ADTenant), tokenCache);
ClientCredential clientCredentials = new ClientCredential(_configuration.ClientId, _configuration.ClientSecret);

                AuthenticationResult authResult = authContext.AcquireTokenByAuthorizationCode(authCode, new Uri(_configuration.RedirectUri), clientCredentials);

                if(authResult.UserInfo != null)
{
this.UserInfoLabel.Text = string.Format(“Welcome: {0} {1}”, authResult.UserInfo.GivenName, authResult.UserInfo.FamilyName);
Session[“AuthResult”] = authResult;
}
}
}

        protected void Login_Click(object sender, EventArgs e)
{
var authorityUri = this.GetAuthorizationUrl();

            Response.Redirect(authorityUri);
}

        protected void GetAccountsButton_Click(object sender, EventArgs e)
{
if (Session[“AuthResult”] != null)
{
var authResult = (AuthenticationResult)Session[“AuthResult”];
var webRequest = (HttpWebRequest)WebRequest.Create(new Uri(“
https://xrmtr14.crm.dynamics.com/api/data/v8.0/accounts?$select=name,address1_city&$top=10″));
webRequest.Method = “GET”;
webRequest.ContentLength = 0;
webRequest.Headers.Add(“Authorization”, String.Format(“Bearer {0}”, authResult.AccessToken));
webRequest.Headers.Add(“OData-MaxVersion”, “4.0”);
webRequest.Headers.Add(“OData-Version”, “4.0”);
webRequest.ContentType = “application/json; charset=utf-8”;

                using (var response = webRequest.GetResponse() as System.Net.HttpWebResponse)
{
//Get reader from response stream
using (var reader = new System.IO.StreamReader(response.GetResponseStream()))
{
var accounts = new List<Account>();
string responseContent = reader.ReadToEnd();

                        dynamic dynamicObj = JsonConvert.DeserializeObject(responseContent);

                        foreach(var data in dynamicObj.value)
{
var account = new Account
{
AccountName = data.name.Value,
City = data.address1_city != null ? data.address1_city.Value : string.Empty
};

                            accounts.Add(account);
}

                        AccountsGridView.DataSource = accounts;
AccountsGridView.DataBind();
}
}
}
}

        #region Methods

        private void PopulateConfigurations()
{
_configuration = new Configurations
{
ADTenant = ConfigurationManager.AppSettings[“tenant”],
ClientId = ConfigurationManager.AppSettings[“client_id”],
ClientSecret = ConfigurationManager.AppSettings[“client_secret”],
RedirectUri = ConfigurationManager.AppSettings[“redirect_url”],
Resource = ConfigurationManager.AppSettings[“resource”]
};
}

        private string GetAuthorizationUrl()
{
return string.Format(CompleteAuthUri, _configuration.ADTenant, _configuration.ClientId, _configuration.Resource, Server.UrlEncode(_configuration.RedirectUri));
}

        #endregion
}
}

public class Account
{
public string AccountName { get; set; }

        public string City { get; set; }
}

 

public class Configurations
{
public string ClientId { get; set; }

        public string ClientSecret { get; set; }

        public string ADTenant { get; set; }

        public string Resource { get; set; }

        public string RedirectUri { get; set; }

    }

  • I have created two classes ‘Account’ and ‘Configurations’ in the above the code. Check for the class definitions just above this line.
  • So let me explain the code a bit here. In the Page_Init method, I retrieve all the values from the web.config file and populate the Configurations class’s object with those values.
  • Next look for the code in the Login Button Click handler Login_Click. First we get the URI where the user would be redirected to authorize himself. In that URI we pass the redirect url as well so that when the authentication completes, the control comes back to this page only.
  • Once the user authenticates, the control will come back to this page and the Page_Load event would fire. The AuthorizationCode would be present in the querystring of the url with the key=code.
  • the Page_Load checks for the authorization code in the query string and then it send another request for the access token. This time it sends the authorization code + client id + client secret. The code makes use of the Microsoft Active Directory Authentication library to get the access token.
  • Finally when the ‘Get Accounts’ button is clicked, a HttpWebRequest is made with the token specified in the header of the request and we get the list of accounts. If everything works fine, your final thing would look something like below.

image

Hope this helps!

Advertisements

About Debajit
I am a Dynamics CRM Most Valuable Professional (MVP) with 10 years of experience in Microsoft .NET Technologies and 7 years of dedicated experience in Microsoft Dynamics CRM. I have worked with companies like Microsoft, SanDisk, PwC, TMF Group and have extensive experience of implementing complex CRM solutions from both offshore and client side. Currently the face of XrmForYou.com with significant experience in delivering corporate training on Dynamics CRM and have already delivered multiple projects to client through XrmForYou.com Author of multiple tools on codeplex including the 'Role Based Views' and 'CRM-Sharepoint Metadata manager & Attachment Extractor' which are available for commercial use under XrmForYou.com For consulting/ training, drop me a note at info@xrmforyou.com or visit our website www.xrmforyou.com

15 Responses to {Knowhow} How to execute Web API calls to Microsoft Dynamics CRM from an external ASP.NET web application

  1. GURMAT S BHATIA says:

    Hi Debajit,
    Your post is very informative. Can you provide more details on how authentication is handled while executing services that are hosted on our network from CRM Cloud from single page HTML applications?

  2. udayan says:

    Hi, can you provide me more details for on-premise implementation using web-api and asp.net

  3. vin garcia says:

    hi,

    having trouble with AcquireTokenByAuthorizationCodeAsync

    Cannot implicitly convert type ‘System.Threading.Tasks.Task’ to ‘Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult’

  4. Kundan says:

    Hi Debjit,
    As I am trying to execute web Api calls to CRM, it is showing the error on authContext.AcquireTokenByAuthorizationCode,
    Can you please suggest me any idea what is the actual reason behind this error.

    I have added the using Microsoft.IdentityModel.Clients.ActiveDirectory package.

    Error 2 ‘Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext’ does not contain a definition for ‘AcquireTokenByAuthorizationCode’ and no extension method ‘AcquireTokenByAuthorizationCode’ accepting a first argument of type ‘Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext’ could be found (are you missing a using directive or an assembly reference?) C:\Users\kundan.a\Documents\Visual Studio 2012\WebSites\WebSite6\Default.aspx.cs 39 59 WebSite6

  5. Diaz Wicaksono says:

    Hi Debajit,
    What if the crm is on-premises and not configured using ifd? Can web api still be called using this method?

    • Debajit says:

      Hi Diaz,
      Without IFD and with on-premises actually there is no need. You can just query your webapi from any external application using network credentials. Sample code:

      WebRequest webRequest = WebRequest.Create(“”);
      webRequest.Credentials = new System.Net.NetworkCredential(“”, “”, “”);

      WebResponse response = webRequest.GetResponse();

      Stream dataStream = response.GetResponseStream();

      StreamReader sr = new StreamReader(dataStream);
      var streamText = sr.ReadToEnd();

  6. ayan Deb says:

    Hi Debjit,

    it gives me Unauthorize error (401)

    every thing i follow as suggested

  7. ayan Deb says:

    Hi Debajit,

    I am waiting for your reply……………
    Thanks in advance

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: