Create CRM records using REST endpoint with Silverlight


The sample will explain …

1. how to perform basic operation Create CRM records using REST endpoint
2. Display the result( created record ) by adding Silverlight web resource(.XAP file) on entity form.

Step 1: Create Silverlight Application project in Visual Studio 2010

Create a Silverlight project in Visual Studio 2010. Follow the following steps to create Silverlight Application

1. Start -> Visual Studio 2010 -> New -> Project ->Silverlight Template -> Silverlight Application
2. Enter name of the Solution as “SilverlightWithCRM2011” and click “OK”.
3.  Select the option selected in below image.
SilverlightApplication_Host

Keep the option checked  “Host the Silverlight application in a new Web site”

4. Click on “Ok” to create the Silverlight Application Project which will be similar to below.
SilverlightApplication

Step 2: 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.

Enter an appropriate CrmODataService and then click OK. Below is the sample image.
AddServiceReference

Step 3: Modify the SilverlightWithCRM2011TestPage.html

Modify three lines of auto generated SilverlightWithCRM2011TestPage.html page

1.            The #silverlightControlHost style width is set to 100%.
2.            The script reference to the Silverlight.js file is commented out (or removed). This will be             provided by Microsoft Dynamics CRM.
3.            A script reference to ../ClientGlobalContext.js.aspx was added. This provides access to a                                              context object that is accessed from the code within MainPage.xaml.cs.

Step 4: Add ServiceUtility.cs file into Silverlight application

This static class will provides the functions to retrieve the Server URL. Below is the sample code of ServiceUtility.cs file
using System;
using System.Windows.Browser;
namespace SilverlightWithCRM2011
{
public static class ServerUtility
{
/// <summary>
/// Returns the ServerUrl from Microsoft Dynamics CRM
/// </summary>
/// <returns>String representing the ServerUrl or String.Empty if not found.</returns>
public static String GetServerUrl()
{
String serverUrl = String.Empty;
//Try to get the ServerUrl from the Xrm.Page object
serverUrl = GetServerUrlFromContext();
return serverUrl;
}
/// <summary>
/// Attempts to retrieve the ServerUrl from the Xrm.Page object
/// </summary>
/// <returns></returns>
private static String GetServerUrlFromContext()
{
try
{
// If the Silverlight is in a form, this will get the server url
ScriptObject xrm = (ScriptObject)HtmlPage.Window.GetProperty(“Xrm”);
ScriptObject page = (ScriptObject)xrm.GetProperty(“Page”);
ScriptObject pageContext = (ScriptObject)page.GetProperty(“context”);
String serverUrl = (String)pageContext.Invoke(“getServerUrl”);

//The trailing forward slash character from CRM Online needs to be removed.
if (serverUrl.EndsWith(“/”))
{
serverUrl = serverUrl.Substring(0, serverUrl.Length – 1);
}

return serverUrl;
}
catch
{
return String.Empty;
}
}
}
}

Step 5: Implement DataServiceContextExtension.cs file

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

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;
using SilverlightWithCRM2011.CrmODataService;
namespace SilverlightWithCRM2011.CrmODataService
{
partial class ContosoContext
{
#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&#8221;;
const string DataServicesNamespace =
http://schemas.microsoft.com/ado/2007/08/dataservices&#8221;;
const string DataServicesMetadataNamespace = DataServicesNamespace + “/metadata”;
if (null == element)
{
throw new ArgumentNullException(“element”);
}

List<XElement> properties = (from c in element.Elements(XName.Get(“content”,
tomNamespace)
).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,
ystem.ComponentModel.PropertyChangedEventArgs e)
{
if (!this.ChangedProperties.Contains(e.PropertyName))
{
this.ChangedProperties.Add(e.PropertyName);
}
}
#endregion
}
}
For reference, please visit the below URL
http://msdn.microsoft.com/en-in/library/7a31d077-2f18-47d7-8631-
a711717d02a#BKMK_GenerateWCFDataServicesClientClasses

Step 6: Edit the MainPage.xaml file as below

Just added two TextBox and a button to default MainPage.xaml
<UserControl x:Class=”SilverlightWithCRM2011.MainPage”
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml    xmlns:d=http://schemas.microsoft.com/expression/blend/2008    xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006&#8243;
mc:Ignorable=”d”
d:DesignHeight=”300″ d:DesignWidth=”400″>
<Grid x:Name=”LayoutRoot” Background=”White”>
<StackPanel x:Name =”MessagePanel” VerticalAlignment=”Top”/>
<TextBox Name=”lblAccountName” Height=”30″ Width=”130″ Background=”White”
lowDirection=”LeftToRight” TextAlignment=”Left” Margin=”47,110,212,160″ Text=”Account Name”></TextBox>
<TextBox Name=”txtAccountName” Height=”30″ Width=”150″ Background=”LightGray”   FlowDirection=”LeftToRight” TextAlignment=”Left” Margin=”214,110,36,160″></TextBox>

        <Button Name=”btnSubmit” Click=”btnSubmit_Click” Background=”Brown” Height=”30″ Width=”60″ DataContext=”{Binding}” Content=”Submit” Margin=”153,176,187,94″></Button>
</Grid>
</UserControl>

Step 7: Edit the MainPage.xaml .cs file as below

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 SilverlightWithCRM2011.CrmODataService;
using System.Threading;

namespace SilverlightWithCRM2011
{
public partial class MainPage : UserControl
{
private SynchronizationContext _syncContext;
private ContosoContext _context;
private String _serverUrl;

public MainPage()
{
InitializeComponent();

}

/// <summary>
/// Creates an Account record in CRM.
/// </summary>
private void BeginCreateAccount()
{
Account newAccount = new Account();
newAccount.Name = txtAccountName.Text;
_context.AddToAccountSet(newAccount);
_context.BeginSaveChanges(OnCreateAccountComplete, newAccount);
}

/// <summary>
/// Callback method invoked when Account is done being created.
/// </summary>
/// <param name=”result”></param>
private void OnCreateAccountComplete(IAsyncResult result)
{
try
{
_context.EndSaveChanges(result);
Account createdAccount = result.AsyncState as Account;
MessagePanel.Children.Add(new TextBlock()
{
Text = String.Format(“Created a new account named \”{0}\”\n\twith AccountId = \”{1}\”.”,
createdAccount.Name, createdAccount.AccountId)
});

//Retrieve the Account just created.
// BeginRetrieveAccount(createdAccount.AccountId);
}
catch (SystemException se)
{
_syncContext.Send(new SendOrPostCallback(showErrorDetails), se);
}
}

/// <summary>
/// Will display exception details if an exception is caught.
/// </summary>
/// <param name=”ex”>An System.Exception object</param>
private void showErrorDetails(object ex)
{
//Assure the control is visible
MessagePanel.Visibility = System.Windows.Visibility.Visible;

Exception exception = (Exception)ex;
String type = exception.GetType().ToString();

MessagePanel.Children.Add(new TextBlock()
{
Text =
String.Format(“{0} Message: {1}”, type, exception.Message)
});

MessagePanel.Children.Add(new TextBlock()
{
Text =
String.Format(“Stack: {0}”, exception.StackTrace)
});

if (exception.InnerException != null)
{
String exceptType = exception.InnerException.GetType().ToString();
MessagePanel.Children.Add(new TextBlock()
{
Text =
String.Format(“InnerException: {0} : {1}”, exceptType,
exception.InnerException.Message)
});
}
}

private void btnSubmit_Click(object sender, RoutedEventArgs e)
{
//Keeps a reference to the UI thread
_syncContext = SynchronizationContext.Current;

//Get the ServerUrl (ServerUrl is formatted differently OnPremise than OnLine)
_serverUrl = ServerUtility.GetServerUrl();

if (!String.IsNullOrEmpty(_serverUrl))
{

//Setup Context
_context = new ContosoContext(
new Uri(String.Format(“{0}/xrmservices/2011/organizationdata.svc/”,

_serverUrl), UriKind.Absolute));

//This is important because if the entity has new
//attributes added the code will fail.
_context.IgnoreMissingProperties = true;

MessagePanel.Children.Add(new TextBlock()
{
Text = “Starting Create Operation.”
});

//Begin the Create, Retrieve, Update, and Delete operations. The operations are chained together
//as each of them is completed.
BeginCreateAccount();
}
else
{
//No ServerUrl was found. Display message.
MessagePanel.Children.Add(new TextBlock()
{
Text =
“Unable to access server url. Launch this Silverlight ” +
“Web Resource from a CRM Form OR host it in a valid ” +
“HTML Web Resource with a ” +
“<script src=’../ClientGlobalContext.js.aspx’ ” +
“type=’text/javascript’></script>”
});
}

}

}
}

Step 8: Now Compile the SilverLight Application Solution

Both project in solution should be build successfully. Now take SilverlightWithCRM2011.xap and SilverlightWithCRM2011TestPage.html and create two Web Resource of type XAP and HTML respectively.

Give the proper name of the Web Resource as below.

1. avs_/SilverlightWithCrm2011TestPage.html

An HTML page can be used to view the Silverlight control outside a form. The only purpose of this web resource is to provide the URL of the server when the Microsoft Silverlight control cannot access it itself through the Xrm.Page.context.getServerUrl when the Silverlight web resource is added in an entity form.

2. avs_/ClientBin/SilverlightWithCRM2011.xap

The name of this web resource just reflects the relative output location of the .xap file in the Microsoft Visual Studio 2010 Silverlight application (version 4) project.

Now publish the both Web Resource

Note: avs_ is the publisher customization prefix

Step 9: Add SilverlightWithCRM2011 web Resource on any entity Form

The Silverlight Application UI looks like below.

SilverlightUI

Step 10: Enter the Account Name and Click on Submit

It will give the output similar to below.

FinalOutput

I hope this will help you 🙂

Interacting Silverlight with CRM Forms


Silverlight application can get a reference to the Xrm.Page Object instance using either of following approaches.

1. Using HTML bridge feature of Silverlight

ScriptObject  xrm = (ScriptObject)HtmlPage.Window.GetProperty(“Xrm”);

ScriptObject  page= (ScriptObject)xrm.GetProperty(“Page”);

2. Using Dynamic Language Runtime

Using DLR you can utilize the dynamic language keywords which allow resolving method calls at runtime.

dynamic  xrm = (ScriptObject)HtmlPage.Window.GetProperty(“Xrm”);

 

Below is some important methods/property which is useful for Silverlight Application.

1. Getting the current Theme: This is useful if you are trying to style your Silverlight content in a similar way the user will see the web client. Valid Values are Default, Office12Blue, and Office14Silver.

var theme= xrm.Page.context.getCurrentTheme();

2.      Getting Org Name:

var orgName= xrm.Page.context.getOrgUniqueName();

3.      Getting the Server URL:

var serverUrl = xrm.Page.context.getServerUrl();

4.      Getting the User ID:

Knowing the user id that is working with the current page can be helpful when you need to do things like retrieve all the records that are owned by that person to present on the page.

 

var  userID = xrm.Page.context.getUserId();

5.      Getting the user’s Role:

var roles = xrm.Page.context.getUserRoles();

6.      Getting the entity logical Name:

String entityname =xrm.Page.data.entity.getEntityName();

7.      Getting the Entity Id:
Guid entityID = xrm.Page.data.entity.getId();

8.      Checking if Entity is Dirty:

By checking the dirty flag at the entity level you can quickly determine if there have been any changes to any of the fields. This doesn’t give you field level granularity you have to check each attribute if you need that.

bool isDirty = xrm.Page.data.entity.getIsDirty();

9.      Getting the Data as XML:

Using this feature you can get a string that represents the XML that would be sent to the server when the record is saved. The XML contains only the fields which have been modified.

String dataXml = xrm.Page.data.entity.getDataXml();

10.  Saving Data to the Server:

The save function allows you to simulate saving data to the CRM server just like if the user hit the save button in the ribbon.

Xrm.Page.data.entity.save()
or
Xrm.Page.data.entity.save(“saveandclose”)
or
Xrm.Page.data.entity.save(“saveandnew”)

11.  Working with the Entity Attributes

You can get to the attributes on an entity via the Attributes collection. The different attribute types can have special methods that are only for their specific type.The following shows which methods each type of attribute currently has.

All Attribute have these methods:

addOnChange,fireOnChange, getAttributeType,getFormat,getInitialValue, getIsDirty, getName, getParent,getRequiredLevel, getSubmitMode, getUserPrivelege, getValue, removeOnChange, setRequiredLevel, setSubmitMode, and setValue

Money,decimal,integer and double have these methods too:

getMax, getMin, and getPrecision

Boolean and Optioset attributes have these methods:

getInitalValue

Optionset attributes have these methods:

getOption, getOptions, getSelectedOption, and getText

 

12.  UI Methods:

The UI methods are high level methods located at Xrm.page.ui and are the starting point for working with the UI controls. This is also the starting point for looking for Controls and Tabs.

Refreshing the Ribbon:

This method is beyond helpful if you are doing any enable/display rules that depends on values on the form. After the value is changed on the form you can use this method to force the ribbon to re-evaluate the data in the form so the ribbon is updated.

refreshRibbon();

13.  Working with Form Controls:

The following methods are on all controls:

getControlType, getDisabled, getLabel, getName, getParent, setDisabled(all except web resources), setFocus, setLabel, and setVisible

The following methods are specific to Lookups;

addCustomeView, getDefaultView, and setDefaultView

The following methods are specific to Option Sets

adoption,clearOptions, and removeOption

The following methods are specific to Web Resources:

getData, getObject, setData, keep in mind the get/setData can only be used with Silverlight Web resources

The Following methods are specific to IFrames:

getSrc, setSrc, and getInitalUrl

The following methods are specific to Subgrids:

refresh

%d bloggers like this: