You must be wondering why you would use ‘self-hosted’ WCF services when you can host WCF Service on IIS.
Well, I was lucky enough to access CRM Web APIs using a native client application like a console application. But unfortunately, I was not able to get it working from my web application. A web application requires us to use the client secret and client ID (both can be obtained once you register your application in Azure AD) to retrieve an access token. To achieve this, I could not find an overload method to acquire the token.
The following post lists down the limitations and describes why it is not working for my web application although it works for a console application.
http://www.cloudidentity.com/blog/2014/07/08/using-adal-net-to-authenticate-users-via-usernamepassword/
Hence my solution was to host my WCF code inside a native console application, i.e. a self-hosted WCF Service. I registered the console application which hosts the WCF Services in Azure AD and everything is working fine.
The below code is of my native C# console application.
Note that I used the following NuGet packages.
- Clients.ActiveDirectory: Contains binaries of the Active Directory Authentication Library (ADAL)
- JSON
- using Microsoft.IdentityModel.Clients.ActiveDirectory;
- using Newtonsoft.Json;
- using Newtonsoft.Json.Linq;
- using System;
- using System.Web;
- using System.Collections.Generic;
- using System.Linq;
- using System.Net;
- using System.Net.Http;
- using System.Net.Http.Headers;
- using System.Text;
- using System.Threading.Tasks;
- using System.ServiceModel;
- using System.ServiceModel.Description;
- using System.ServiceModel.Web;
- using System.Runtime.Serialization;
- using System.IO;
- using System.Xml;
- using System.Reflection;
-
- namespace CRMTest
- {
- class Program
- {
- [ServiceContract]
- public interface IDynCRMProxyService
- {
- [OperationContract]
- [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json,
- UriTemplate = "/getAccountInfo")]
- Account LoadAccounts();
- }
-
- public class DynCRMProxyService : IDynCRMProxyService
- {
- public Account LoadAccounts()
- {
- string token = getAccessToken();
-
- var webRequest = (HttpWebRequest)WebRequest.Create(new Uri(
- "https://ur-crm.api.crm5.dynamics.com/api/data/v8.1/accounts?$top=1"));
- webRequest.Method = "GET";
- webRequest.ContentLength = 0;
- webRequest.Headers.Add("Authorization", String.Format("Bearer {0}", token));
- webRequest.Headers.Add("OData-MaxVersion", "4.0");
- webRequest.Headers.Add("OData-Version", "4.0");
- webRequest.ContentType = "application/json; charset=utf-8";
-
- Account account = new Account();
-
- using (var response = webRequest.GetResponse() as System.Net.HttpWebResponse)
- {
- using (var reader = new System.IO.StreamReader(response.GetResponseStream()))
- {
- string responseContent = reader.ReadToEnd();
- dynamic dynamicObj = JsonConvert.DeserializeObject(responseContent);
- foreach (var data in dynamicObj.value)
- {
- account.name = data.name.Value;
- }
- }
- }
-
- return account;
- }
- }
-
- public static string getAccessToken()
- {
- string username = ConfigurationManager.AppSettings["username"];
- string password = ConfigurationManager.AppSettings["password"];
- string authorityUriString = ConfigurationManager.AppSettings["authorityUri"];
- string domain = ConfigurationManager.AppSettings["domain"];
- string clientId = ConfigurationManager.AppSettings["clientId"];
-
- UserCredential userCredential = new UserCredential(username, password);
- string authorityUri = authorityUriString;
- AuthenticationContext context = new AuthenticationContext(authorityUri);
- AuthenticationResult result = context.AcquireToken(domain, clientId, userCredential);
-
- return result.AccessToken;
- }
-
- static void Main(string[] args)
- {
- Uri baseAddress = new Uri("http://localhost:58535/hello");
-
- using (ServiceHost host = new ServiceHost(typeof(DynCRMProxyService), baseAddress))
- {
- host.Open();
-
- Console.WriteLine("Service is up at {0}", baseAddress);
- Console.WriteLine("Press enter to stop service.");
- Console.ReadLine();
-
- host.Close();
- }
- }
- }
- }
Following information has been stored in the config file of the console application.
- <appSettings>
- <add key="username" value="[email protected]"/>
- <add key="password" value="password"/>
- <add key="authorityUri" value="https://login.windows.net/ur-crm.onmicrosoft.com/oauth2/authorize"/>
- <add key="domain" value="https://ur-crm.crm5.dynamics.com"/>
- <add key="clientId" value="clientId"/>
- <add key="apiUrl" value="https://ur-crm.api.crm5.dynamics.com/api/data/v8.1/"/>
- </appSettings>
authorityUri is Azure AD’s OAUTH 2.0 Authorization Endpoint.
clientId is the application ID that you get when you register your application with Azure Active Directory. You need to register this console application in Azure AD to allow access to CRM Web APIs.
Let’s see the steps of registering a console application in Azure AD.
- Login to portal.azure.com.
- Go to App registrations.
- Add the new application as seen below, make sure to select Application Type as ‘Native’.
- In settings, you will be able to retrieve the Application ID. Copy it as this will be used as the clientId in the code.
- Thereafter, we need to give required permissions for our application. Go to settings -> Required Permissions and grant ‘Delegated Permissions’ to CRM online as seen below.
Run your console application and a WCF client will be able to consume WCF services which retrieves the CRM data.