Use the REST Endpoint with Silverlight Web Resources

[Applies to: Microsoft Dynamics CRM 2011]

When you work with the REST endpoint for Microsoft Dynamics CRM 2011 by using Microsoft Silverlight, you will use the WCF Data Services Client Library for Silverlight. This library uses the same HTTP protocol requests to work with data, but it returns data by using the ATOM format and transforms the data into objects on the client.

In This Topic

Preliminary Steps

Writing Code

Preliminary Steps

Before you start writing code for a Silverlight Web resource that uses the REST endpoint, there are some planning and preparatory steps that you must perform.

Generating WCF Data Services Client Data Service Classes

The first thing that you must do is generate the Windows Communication Foundation (WCF) Data Services Client Data Service classes in your Silverlight application project in Visual Studio 2010. The procedure that is used to generate these classes for Microsoft Dynamics CRM differs from what you may see in other documentation. This is because the objective is to create a Silverlight Web resource that can be included in a Microsoft Dynamics CRM solution and installed in any organization and any kind of deployment. Authentication is not an issue because the Silverlight Web resource will be included in the application.

Note

The classes are generated based a conceptual schema definition language (CDSL) that the REST endpoint generates based on the entities available to your development organization. Only those entities that are present when you generate the classes will be available for the Silverlight application.

You will need to re-generate your WCF Data Services Client Data Service classes if you add or edit entities and attributes while developing your application.

Generate the WCF Data Services Client Data Service Class

  1. In Microsoft Dynamics CRM 2011 navigate to Settings. Choose Customizations and then Developer Resources.

  2. Under Service Endpoints, click the Download CSDL link and save the OrganizationData.csdl file to your computer.

  3. In your Visual Studio 2010 Silverlight application project, right-click References, and then click Add Service Reference.

  4. Type the path of the location where you saved the OrganizationData.csdl file in step 2, and then click Go.

  5. Enter an appropriate Namespace and then click OK.

You should now see a service reference in your project with the namespace name that you entered.

Tip

By default, the name of the DataServiceContext object created in Visual Studio 2010 for your project is [Your development environment organization name]Context. For example, using an organization named ContosoDevOrg03 creates a DataServiceContext object named ContosoDevOrg03Context.

The name of your context class will not affect the behavior of your code on other organizations that include the same customizations. However, you can re-name this class to remove the reference to a specific organization by using the following procedure.

Change the Name of the Generated DataServiceContext

  1. In Visual Studio 2010, click the icon with the tooltip Show All Files at the top of the Solution Explorer window.

  2. In Solution Explorer, expand the service reference you created and the Reference.datasvcmap file to view the Reference.cs file.

  3. Open the Reference.cs file, and then locate the class definition.

  4. Right-click the class and select Refactor. Then select Rename.

  5. Build your project.

Note

If you refresh your service reference, you must repeat this procedure.

Implement Data Service Context Extensions

Important

The WCF data services client data service classes can cause some undesirable behavior when records are updated. All properties of the record are updated regardless of whether they are changed or not. Furthermore, if an entity is instantiated rather than being retrieved, any properties not set in code will be null. These null values overwrite any existing values for the record. To avoid these issues, do the following steps:

Add Data Service Context Extensions

  1. Add a reference to System.Xml.Linq to your Microsoft Silverlight project.

  2. Create a new class file in your project as follows:

    using System;
    using System.Linq;
    using System.Data.Services.Client;
    using System.Reflection;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Collections.ObjectModel;
    using System.Xml.Linq;
    
    namespace Microsoft.Crm.Sdk.Samples.CrmODataService
    {
     partial class AdventureWorksCycleContext
        {
            #region Methods
            partial void OnContextCreated()
            {
                this.ReadingEntity += this.OnReadingEntity;
                this.WritingEntity += this.OnWritingEntity;
            }
            #endregion
    
            #region Event Handlers
            private void OnReadingEntity(object sender, ReadingWritingEntityEventArgs e)
            {
                ODataEntity entity = e.Entity as ODataEntity;
                if (null == entity)
                {
                    return;
                }
    
                entity.ClearChangedProperties();
            }
    
            private void OnWritingEntity(object sender, ReadingWritingEntityEventArgs e)
            {
                ODataEntity entity = e.Entity as ODataEntity;
                if (null == entity)
                {
                    return;
                }
    
                entity.RemoveUnchangedProperties(e.Data);
       entity.ClearChangedProperties();
            }
            #endregion
        }
    
        public abstract class ODataEntity
        {
            private readonly Collection<string> ChangedProperties = new Collection<string>();
    
            public ODataEntity()
            {
                EventInfo info = this.GetType().GetEvent("PropertyChanged");
                if (null != info)
                {
                    PropertyChangedEventHandler method = new PropertyChangedEventHandler(this.OnEntityPropertyChanged);
    
                    //Ensure that the method is not attached and reattach it
                    info.RemoveEventHandler(this, method);
                    info.AddEventHandler(this, method);
                }
            }
    
            #region Methods
            public void ClearChangedProperties()
            {
                this.ChangedProperties.Clear();
            }
    
            internal void RemoveUnchangedProperties(XElement element)
            {
                const string AtomNamespace = "http://www.w3.org/2005/Atom";
                const string DataServicesNamespace = "https://schemas.microsoft.com/ado/2007/08/dataservices";
                const string DataServicesMetadataNamespace = DataServicesNamespace + "/metadata";
    
                if (null == element)
                {
                    throw new ArgumentNullException("element");
                }
    
                List<XElement> properties = (from c in element.Elements(XName.Get("content", AtomNamespace)
                                                       ).Elements(XName.Get("properties", DataServicesMetadataNamespace)).Elements()
                                             select c).ToList();
    
                foreach (XElement property in properties)
                {
                    if (!this.ChangedProperties.Contains(property.Name.LocalName))
                    {
                        property.Remove();
                    }
                }
            }
    
            private void OnEntityPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
            {
                if (!this.ChangedProperties.Contains(e.PropertyName))
                {
                    this.ChangedProperties.Add(e.PropertyName);
                }
            }
            #endregion
        }
    }
    
  3. Change the ”Microsoft.Crm.Sdk.Samples.CrmODataService” namespace to the namespace used for your service reference namespace in your project.

  4. Change the Data Service Context class from “AdventureWorksCycleContext” to the one used in your project.

  5. In the service reference, edit the Reference.cs file. Replace each instance of “: global::System.ComponentModel.INotifyPropertyChanged” with “: ODataEntity, global::System.ComponentModel.INotifyPropertyChanged”. You will find this text for every entity in your organization.

    Note

    If you cannot locate the Reference.cs file, see the instructions in the procedure to Change the Name of the Generated DataServiceContext previously in this topic.

Use ODataEntity.ClearChangedProperties Method

When you instantiate an entity without retrieving it you should use the ClearChangedProperties method to initialize tracking of changed properties. For example, if you have property values for an existing record, you can instantiate an entity instance and then set the values. Before you change properties on the entity instance you should call ClearChangedProperties to ensure that only changes made from that point will be sent back to the server when the record is updated.

Get the Server URL

To instantiate a DataServiceContext class by using the service reference you created, you must set the URL to the REST endpoint for the organization. For your initial testing, you may want to temporarily use a static URL, but for any Silverlight Web resource to be installed on different organizations, or work when a Microsoft Dynamics CRM for Microsoft Office Outlook with Offline Access user is working offline, you must retrieve the server URL from the organization context by using the Xrm.Page.context.getServerUrl function or by using the GetGlobalContext Function.

For more information, see Accessing Context data and Query Microsoft Dynamics CRM Data Using the REST Endpoint.

Create and Test Silverlight Web Resources for Use with the REST Endpoint

To authenticate with the REST endpoint, your Silverlight application must be hosted in a page in the Microsoft Dynamics CRM application. You cannot test your code without first creating a Silverlight Web resource.

For more information, see Creating Silverlight Web Resources and the application help.

We recommend that you create an HTML Web resource by using the HTML page generated with a Silverlight application project in Microsoft Visual Studio 2010. By using this HTML Web resource, you have the option to preview the Silverlight application outside the context of a Microsoft Dynamics CRM form. For more information, see the sample_/SilverlightDataOperations.htm page in Sample: Create, Retrieve, Update and Delete Using the REST Endpoint with Silverlight for an example of minimal edits that are required to make this HTML page work as a host page for your Silverlight Web resource.

Names of Web Resources and Relative Paths

Your reference to the ClientGlobalContext.js.aspx page in your HTML Web resource depends on the name of the Web resource. If you include backslash characters in the name of the Web resource, the reference on the HTML page must reflect the simulated folders that these characters create, for example, contoso_/Pages/SilverlightHost/hostpage.htm. The reference to the ClientGlobalContext.js.aspx page must be../../../ClientGlobalContext.js.aspx.

The same is true for the source param reference in the Silverlight host object on your HTML page. If your HTML Web resource name is contoso_/Pages/SilverlightHost/hostpage.htm, and the source param value is ClientBin/MysilverlightApp.xap, the name of your Silverlight Web resource must be contoso_/Pages/SilverlightHost/ClientBin/MysilverlightApp.xap.

If you only want to view the Silverlight Web resource in the context of an entity form, you can use any name.

Testing Silverlight Web Resources

See Writing and Testing Silverlight Web Resources and Debugging Silverlight Web Resources for information about how to write, test and debug Silverlight Web resources.

Writing Code

After you complete the preliminary planning and preparatory steps, you can start to use the DataServiceContext to interact with the REST endpoint.

Using the WCF Data Services Client Library for Silverlight

The following sample shows how to instantiate DataServiceContext in the MainPage.xaml.cs file in your Silverlight application project. For this sample, the project variables are shown in the following table.

Project Variable Value Description

Silverlight Application Namespace

DataServiceContextSample

Defaults to the name of the Visual Studio project.

Service Reference Namespace

CrmODataService

Entered when you create the service reference.

Generated DataServiceContext

crmContext

Defaults to the name of the CRM organization used to generate the context, in this case, ”crmContext".

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using DataServiceContextSample.CrmODataService;
using System.Data.Services.Client;
using System.Windows.Browser;


namespace DataServiceContextSample
{
 public partial class MainPage : UserControl
 {
  private crmContext context;
  private System.String serverUrl;

  public MainPage()
  {
   InitializeComponent();
   serverUrl = (String)GetContext().Invoke("getServerUrl");
   //Remove the trailing forward slash returned by CRM Online
   //So that it is always consistent with CRM On Premises
   if (serverUrl.EndsWith("/"))
    serverUrl = serverUrl.Substring(0, serverUrl.Length - 1);

   Uri ODataUri = new Uri(serverUrl + "/xrmservices/2011/organizationdata.svc/", UriKind.Absolute);
   context = new crmContext(ODataUri) { IgnoreMissingProperties = true };

  }
  /// <summary>
  /// Returns the application context object from the Xrm.Page if it is available 
  /// and by invoking the GetGlobalContext method if it is not.
  /// </summary>
  /// <returns></returns>
  private static ScriptObject GetContext()
  {
   ScriptObject xrmProperty = (ScriptObject)HtmlPage.Window.GetProperty("Xrm");
   if (null == xrmProperty)
   {
    //It may be that the global context should be used
    try
    {

     ScriptObject globalContext = (ScriptObject)HtmlPage.Window.Invoke("GetGlobalContext");

     return globalContext;
    }
    catch (System.InvalidOperationException)
    {
     throw new InvalidOperationException("Property \"Xrm\" is null and the Global Context is not available.");
    }

   }

   ScriptObject pageProperty = (ScriptObject)xrmProperty.GetProperty("Page");
   if (null == pageProperty)
   {
    throw new InvalidOperationException("Property \"Xrm.Page\" is null");
   }

   ScriptObject contextProperty = (ScriptObject)pageProperty.GetProperty("context");
   if (null == contextProperty)
   {
    throw new InvalidOperationException("Property \"Xrm.Page.context\" is null");
   }

   return contextProperty;
  }
 }
}

For more information, see the MSDN documentation WCF Data Services Client Library for Silverlight.

Important

You must set the DataServiceContext.IgnoreMissingProperties property to true after you instantiate your DataServiceContext.

Without this property set, an error occurs if new entities or attributes are created in Microsoft Dynamics CRM after you generate your service reference.

See Also

Concepts

Use the REST Endpoint for Web Resources

Other Resources

WCF Data Services (Silverlight)

Microsoft Dynamics CRM 2011
Send comments about this topic to Microsoft.
© 2013 Microsoft Corporation. All rights reserved.