Sample: Windows 8 desktop modern OData app

 

Applies To: Dynamics CRM 2013

This sample code is for Microsoft Dynamics CRM 2013 and Microsoft Dynamics CRM Online.  This code can be found in the following location in the download package:

SampleCode\CS\ModernAndMobileApps\ModernOdataApp

Download the Microsoft Dynamics CRM SDK package.

Requirements

This sample requires the Microsoft.Preview.WindowsAzure.ActiveDirectory.Authentication NuGet package. This package is automatically downloaded and installed when you load the project’s solution.

For more information about the requirements for running the sample code provided in this SDK, see Use the sample and helper code.

Demonstrates

This sample shows how to write a Windows 8 desktop modern application that can send requests to the organization web service without linking to the SDK assemblies. This sample uses the Microsoft Azure Active Directory Authentication Library (ADAL) and the OData protocol.

While there are seven tiles displayed on the main app page, only the Accounts and Tasks tiles are connected to event handler code. The other tiles are just placeholders.

The example code is configured for the Internet-facing deployment (IFD) server and a fictitious organization. See the SOAP version of this sample for an Microsoft Dynamics CRM Online configuration.

Code snippets showing just the key sections of the full sample are shown later in this topic.

Windows 8 sample app main screen

Tiled user interface of the sample app

Example

The following code snippet shows how to authenticate the user with the organization web service.

Note

This sample code uses the legacy method of hardcoding the OAuth endpoint URL and using “Microsoft.CRM” as the realm. The preferred method is to use the OAuth discovery feature to determine the OAuth endpoint URL at run-time and the root organization web address as the realm. More information: Authenticate the user with the web services. This sample will be updated in a future SDK release.


using Microsoft.Preview.WindowsAzure.ActiveDirectory.Authentication;
using System;
using System.Threading.Tasks;
using Windows.UI.Popups;
using Windows.Security.Authentication.Web;

namespace ModernOdataApp
{
    /// <summary>
    /// Manages authentication with the organization web service.
    /// </summary>
    public static class CurrentEnvironment
    {
        # region Class Level Members

        private static AuthenticationContext _authenticationContext;

        // TODO Set these string values as approppriate for your app registration and server.
        // For more information, see the SDK topic "Walkthrough: Register an app with Active Directory".
        private const string _clientID = "7e506c6a-b941-47f2-87d5-10aad78f9ad6"; 
        public const string CrmServiceUrl   = "https://my-org.contoso.com";

        // Dyamics CRM IFD OAuth URL.
        // TODO Change contoso.com to your IFD server's address.
        private const string _oauthUrl = "https://sts2.contoso.com/adfs/ls/XRMServices/2011/Organization.svc/web"; 

        # endregion

        // <summary>
        /// Perform any required app initialization.
        /// This is where authentication with Active Directory is performed.        
        /// </summary>
        public static async Task<string> Initialize()
        {
            // Obtain the redirect URI for the app programmatically.
            string redirectUrl = WebAuthenticationBroker.GetCurrentApplicationCallbackUri().ToString();

            // Obtain an authentication token to access the web service. 
            _authenticationContext = new AuthenticationContext(_oauthUrl, false);
            AuthenticationResult result = await _authenticationContext.AcquireTokenAsync(CrmServiceUrl, _clientID);

            // Verify that an access token was successfully acquired.
            if (AuthenticationStatus.Succeeded != result.Status)
            {
                if (result.Error == "authentication_failed")
                {
                    // Clear the token cache and try again.
                    (AuthenticationContext.TokenCache as DefaultTokenCache).Clear();
                    _authenticationContext = new AuthenticationContext(_oauthUrl, false);
                    result = await _authenticationContext.AcquireTokenAsync(CrmServiceUrl, _clientID);
                }
                else
                {
                    DisplayErrorWhenAcquireTokenFails(result);
                }
            }
            return result.AccessToken;
        }

        /// <summary>
        /// Display an error message to the user.
        /// </summary>
        /// <param name="result">The authentication result returned from AcquireTokenAsync().</param>
        private static async void DisplayErrorWhenAcquireTokenFails(AuthenticationResult result)
        {
            MessageDialog dialog;

            switch (result.Error)
            {
                case "authentication_canceled":
                    // User cancelled, so no need to display a message.
                    break;
                case "temporarily_unavailable":
                case "server_error":
                    dialog = new MessageDialog("Please retry the operation. If the error continues, please contact your administrator.", "Sorry, an error has occurred.");
                    await dialog.ShowAsync();
                    break;
                default:
                    // An error occurred when acquiring a token. Show the error description in a MessageDialog. 
                    dialog = new MessageDialog(string.Format("If the error continues, please contact your administrator.\n\nError: {0}\n\nError Description:\n\n{1}", result.Error, result.ErrorDescription), "Sorry, an error has occurred.");
                    await dialog.ShowAsync();
                    break;
            }
        }
    }
}

For this code to work, you must first register your app with a supported identity provider (AD FS or Microsoft Azure Active Directory). Next, you must set the variable values for _clientID, _oauthUrl, and CrmServiceUrl in the code. The value for client ID was defined during app registration. More information: Walkthrough: Register a CRM app with Active Directory

Example

The following code snippet shows how to retrieve entity records from the organization web service using OData protocol code in an HTTP request. The authentication access token is placed in the authorization header.


using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace ModernOdataApp
{
    public static class HttpRequestBuilder
    {
        /// <summary>
        /// Retrieve entity record data from the organization web service. 
        /// </summary>
        /// <param name="accessToken">The web service authentication access token.</param>
        /// <param name="Columns">The entity attributes to retrieve.</param>
        /// <param name="entity">The target entity for which the data should be retreived.</param>
        /// <returns>Response from the web service.</returns>
        /// <remarks>Builds an OData HTTP request using passed parameters and sends the request to the server.</remarks>
        public static async Task<string> Retrieve(string accessToken, string[] Columns, string entity)
        {
            // Build a list of entity attributes to retrieve as a string.
            string columnsSet = "";
            foreach (string Column in Columns)
            {
                columnsSet += "," + Column;
            }

            // The URL for the OData organization web service.
            string url = CurrentEnvironment.CrmServiceUrl + "/XRMServices/2011/OrganizationData.svc/" + entity + "?$select=" + columnsSet.Remove(0, 1) + "";

            // Build and send the HTTP request.
            HttpClient httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
            HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, url);
            req.Method = HttpMethod.Get;

            // Wait for the web service response.
            HttpResponseMessage response;
            response = await httpClient.SendAsync(req);
            var responseBodyAsText = await response.Content.ReadAsStringAsync();

            return responseBodyAsText;
        }
    }
}

See Also

Write mobile and modern apps
Azure Authentication Library (AAL) for Windows Store: a Deep Dive
Securing a Windows Store Application and REST Web Service Using Azure AD
OData.org