Showing posts with label Microsoft Dynamics CRM 2011. Show all posts
Showing posts with label Microsoft Dynamics CRM 2011. Show all posts

Friday, March 23, 2012

Microsoft Dynamics CRM 2011 for Developers | Plug-ins

Contents

  1. Introduction
  2. Common Uses of Plug-ins
  3. Plug-ins Basics
    1. Event Framework
    2. Event Execution Pipeline
    3. Pipeline Stages
    4. Message Processing
    5. Inclusion in Database Transactions 
    6. Plug-in Isolation
    7. Trusts
  4. Develop Plug-ins
  5. Register Plug-ins

Introduction

A plug-in is .Net assembly that can be used to intercept events generated from the CRM system. Plug-ins subscribe to a set of events and run when the events occur regardless of how the event raised (or the method that is used to perform the activity that raised the event).

Any number of plug-ins can be associated with a given entity and event. When multiple plug-ins are registered for the same event on the same entity, they are called in a sequence based on the order specified on the step registration. This value is specified as the Rank and it is supplied when the plug-in is registered. This allows developer control over the sequence.

Common Uses of Plug-ins

Plug-ins have many uses like:

  • Performing complex business logic data validation
  • Performing complex update routines on CRM entities and/or attributes when it is impractical to use JavaScript.
  • Grabbing data from another system and updating CRM when an entity instance is being created or updated.
  • Updating another system programmatically from CRM

Plug-ins Basics

Event Framework Event framework is the term that is used to describe the technology and mechanisms available in Microsoft Dynamics CRM to enable you to extend or customize functionality with custom code. Your custom code will run on top of Dynamics CRM either synchronously as part of the main Microsoft Dynamics CRM execution path, or asynchronously from a managed queue.

Event Execution Pipeline Event framework executes plug-ins based on a message pipeline execution model. A user action in the Microsoft Dynamics CRM Web application or an SDK method call by a plug-in or other application results in a message being sent to the organization Web service. The message contains business entity information and core operation information. The message is passed through the event execution pipeline where it can be read or modified by the platform core operation and any registered plug-ins.

The event execution pipeline processes events either synchronously or asynchronously. The platform core operation and any plug-ins registered for synchronous execution are executed immediately. Synchronous plug-ins that are registered for the event are executed in a well-defined order. Plug-ins registered for asynchronous execution are queued by the Asynchronous Queue Agent and executed at a later time by the asynchronous service.

Pipeline Stages The event execution pipeline is divided into multiple stages, four of them are available to register custom developed plug-ins. Multiple plug-ins that are registered in each stage can be further be ordered (ranked) within that stage during plug-in registration.

Event

Stage name

Stage number

Description

Pre-Event Pre-validation 10
  • For plug-ins that execute before the main system operation.
  • Plug-ins may execute outside the database transaction.
  • For plug-ins run prior to making security checks on the calling user.  
Pre-Event Pre-operation 20
  • For plug-ins that execute before the main system operation.
  • Plug-ins execute within the database transaction.
Platform Core Operation MainOperation 30
  • Dedicated to main system operations.
  • For internal use only, no custom plug-ins can register in this stage.
Post-Event Post-operation 40
  • For plug-ins that execute after the main operation.
  • Plug-ins execute within the database transaction.
Post-Event Post-operation
(Deprecated)
50
  • For Dynamics CRM 4.0 based plug-ins ONLY.

Message Processing as we saw in a previous post, any web service method call is done through OrganizationRequest message. This call raises an event. Information in this message is passed to first plug-in registered for that event. Plug-in receives the message information in the form of context that is passed to its Execute method, where it can be read or modify its contents before passing it to the next registered plug-in for that event and so on. The message then passed to the platform core operation. After the core platform operation has completed, the message is then known as the OrganizationResponse. This response is passed to the registered post-event plug-ins which may modify it before a copy of the response is passed to any registered asynchronous plug-ins. Finally, the response is returned to the application or workflow that initiated the original Web service method call.

Because a single Microsoft Dynamics CRM server can host more than one organization, the execution pipeline is organization specific. Plug-ins registered with the pipeline can only process business data for a single organization.

Inclusion in Database Transactions Plug-ins can execute or not execute within the database transaction of the Dynamics CRM platform. Within the plug-in, you can detect that through the IsInTransaction property in IPluginExecutionContext that is passed to the plug-in. Any registered plug-in that executes during the database transaction and that passes an exception back to the platform cancels the core operation. This results in a rollback of the core operation. In addition, any pre-event or post event registered plug-ins that have not yet executed and any workflow that is triggered by the same event that the plug-in was registered for will not execute.

Plug-in Isolation The execution of plug-ins can be in an isolated environment, known as a sandbox, where a plug-in can access and use the organization Web service only. Plug-ins can’t access system resources but can access to external endpoints (only through HTTP and HTTPS). CRM platform collects run-time statistics and monitors plug-ins that execute in the sandbox, if it exceeded certain thresholds or became unresponsive, it kills the sandbox worker process (this makes all currently executing plug-ins in the current organization fail).

Trusts

  • Full trust Plug-ins run outside the sandbox, available in on-premises and internet facing deployments.
  • Partial trust Plug-ins run inside the sandbox, available in all deployments.

Develop Plug-ins

Simply plug-ins are classes that implement the IPlugin interface. You can write a plug-in in any .NET Framework 4 CLR-compliant language.

Now let’s consider a simple case that plug-ins may be its appropriate solution. Let say that your company wants leads to be numbered automatically when they are created. In order to achieve our goal, we will add a custom field to the Lead entity and add it to the form. We will disable this field on the form. We will create a plug-in and register it for the Pre-event for the Create message on the Lead entity. When a lead is created, it will look for the next available number in the system and assign it to the newly created Lead.

Step 1: Create Customizations

Now we will quickly customize the Lead entity and form to accommodate our solution. Navigate to Settings > Customizations > Customize the System. In the left navigation pane, expand Entities, expand Lead, select Fields, and click New.  
In the New for Lead form, set the Display Name to Auto Number, the Type to Whole Number, and then click Save and Close. In the left navigation Pane, select Forms. Click the Main Information form > Drag the field, new_autonumber, to the Name section of the General section. Select the field, click Change Properties, mark the Field is read-only check box, and then click OK. Click Save and Close, and then Publish.

Step 2: Create the Plug-in

1- Open Visual Studio and Create a new project of type Class Library.

2- Add references to Microsoft.Xrm.Client.dll, Microsoft.Xrm.Sdk.dll, and Microsoft.crm.sdk.proxy.dll [located at %SDK%\bin folder].

3- Add references to System.Data.Services, System.Data.Services.Client, System.Runtime.Serialization, and System.ServiceModel.

4- Add reference to Microsoft.IdentityModel.dll from "C:\Program Files\Reference Assemblies\Microsoft\Windows Identity Foundation\v3.5\”. Then go to reference properties and set Copy Local to True for the DLL. The DLL will be included in the package. If you don’t have the dll you need to install Windows Identity Foundation.

5- Make your class implement the IPlugin interface, and implement its member method Execute method. This identifies your class as a plugin to the CRM platform when registering your assembly later. Plug-in code will be placed in the Execute method which takes a parameter of type IServiceProvider. This parameter is a container of many objects that will be utilized by our code.

First get the IPluginExecutionContext. This context object gives you access to all the property values associated with the entity and event context where the method is being executed.

IPluginExecutionContext context = (IPluginExecutionContext) serviceProvider.GetService(typeof(IPluginExecutionContext));


InputParameters property of the context is a collection of the request parameters associated with the event. We use it to check the entity of which the event is fired.



if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName != "lead")
return;


Then we get the OrganizationServiceFactory to use it to create an OrganizationService. We also get the TracingService. Then we edited our auto number field with the next maximum number in the organization. GetMaxLeadNumber is a typical method that passes a QueryExpression to the OrganizationService to get the next max lead number.



IOrganizationServiceFactory orgServiceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
IOrganizationService orgService = orgServiceFactory.CreateOrganizationService(context.UserId);

try
{
entity.Attributes["new_autonumber"] = GetMaxLeadNumber(orgService);
}
catch (Exception ex)
{
tracingService.Trace("xRM_Demo03 | {0}", ex.ToString());
throw;
}
}
}


Now your class should look like:



using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Security;
using System.ServiceModel.Description;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using System.Collections;

namespace xRM_Demo03
{
public class Plugin:IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context =
(IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName != "lead")
return;

IOrganizationServiceFactory orgServiceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService orgService = orgServiceFactory.CreateOrganizationService(context.UserId);
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

try
{
Random rand = new Random();
entity.Attributes["new_autonumber"] = GetMaxLeadNumber(orgService);
}
catch (Exception ex)
{
tracingService.Trace("xRM_Demo03 | {0}", ex.ToString());
throw;
}
}
}

private int GetMaxLeadNumber(IOrganizationService orgService)
{
QueryExpression qe = new QueryExpression("lead");
qe.ColumnSet.AddColumn("new_autonumber");
qe.AddOrder("new_autonumber", OrderType.Descending);
qe.PageInfo.Count = 1;
qe.PageInfo.PageNumber = 1;

Entity entity = (Entity)orgService.RetrieveMultiple(qe)[0];
if (entity.Attributes["new_autonumber"].ToString()!= string.Empty)
return int.Parse(entity.Attributes["new_autonumber"].ToString()) + 1;
else
return 1;
}
}
}


Now the last step is to sign your assembly. Double click Properties under your plugin project.



xRM_Demo03 - Microsoft Visual Studio (Administrator)_2012-03-19_12-33-32



then click Signing from the left tabs



xRM_Demo03 - Microsoft Visual Studio (Administrator)_2012-03-19_12-34-21



select Sign the assembly checkbox, choose New from the dropbox or choose an existing key. Build the project. Now we are ready to register our plugin into Dynamics CRM.



Step 3: Register the Plug-in







The Dynamics CRM SDK have a tool to register plugins located as a source code at %CRMSDK%\tools\pluginregistration. Open the solution, build it, and run it.



1- Click the Create New Connection on the toolbar. Enter a name for the connection, organization URL, and the email you used for creating this organization.Plugin Registration Tool_2012-03-19_12-20-45



Click Connect, it will ask you for the password.



Connect to CRM Web Service_2012-03-19_12-21-24



Enter your password and click Ok to connect to the CRM organization web service.



After getting connected click Register > Register New Assembly



Plugin Registration Tool_2012-03-19_12-27-20



This will open Register New Plugin dialog.



Register New Plugin_2012-03-19_12-27-57



Click the three dots button in the top right of the dialog, browse to your plugin dll. Ensure that your plugin is listed and checked. Also ensure that you selected Sandbox as isolation mode, and to store your assembly in the Database as shown below.



Register New Plugin_2012-03-19_12-29-50



Click Register Selected Plugins. You will see in the log the steps done by the tool and when it is done it will show message box showing how many assemblies and plugins have been registered (you could have multiple plugins in one assembly). Click Ok.



xRM_Demo03 - Microsoft Visual Studio (Administrator)_2012-03-19_12-36-58



Now select your assembly from the list



Plugin Registration Tool_2012-03-19_12-39-46



and click Register > Register New Step. This will open Register New Step dialog. This dialog used to define mainly the message, the entity, and the stage that your plugin will execute within. We will register for Message Create, Entity lead, Pre-operaton stage. Click Register New Step.



Register New Step_2012-03-19_12-42-08



You will see child step added under your assembly.



Plugin Registration Tool_2012-03-19_12-43-20





Now our assembly is registered and our plugin will run for create messages on the lead entity. Go to the CRM web interface and create a new lead, save it, open it again and see the Auto Number populated.



In this post we explored the plug-in basics, and developed a simple plug-in. To complete the picture, you also explored how to register our plug-in into Dynamics CRM and see it in action.

Tuesday, March 13, 2012

Microsoft Dynamics CRM 2011 for Developers | Creating Custom Reports Using Microsoft SQL Server 2008 Reporting Services

Contents

  1. Introduction
  2. Setup the Development Environment
  3. Report Development Process
  4. Create Custom Reports Using Business Intelligence Development Studio
    1. Create a Custom SQL-Based Report
    2. Create a Custom Fetch-Based Report
  5. Import Custom Reports into Dynamics CRM

Introduction

Microsoft Dynamics CRM provides many out-of-box reports for viewing business data. You can view a list of reports you have access to by navigating to Workplace > My Work > Reports. You can also see a list of all reports available by navigating to Settings > Customization > Customizations > Customize the System > Report [left navigation]. In both lists, you can select a report and click Run Report from the ribbon to preview the report in running mode.

You can create custom reports using one of the out-of-box reports as templates, or create a custom report from scratch. There are two types of reports in Microsoft Dynamics CRM:

  • SQL-Based Reports Use SQL queries to retrieve data from filtered views defined by the system. The default out-of-box reports are SQL-based reports. You can’t deploy SQL-based reports for Dynamics CRM online.
  • Fetch-Based Reports Use FetchXML queries to retrieve data. They are introduced in Dynamics CRM 2011 and can be deployed both on on-premise and online. All reports created using the Report Wizard in the web interface, are fetch-based reports.

Setup the Development Environment

To write custom reports for Microsoft Dynamics CRM you need the following:

  • Microsoft SQL Server 2008 Reporting Services (or 2008 R2) in native mode installation.
  • Business Intelligence Development Studio. This is the report authoring environment in Visual Studio that hosts the Report Designer (available on the Microsoft SQL Server setup CD).
  • Microsoft Dynamics CRM Report Authoring Extension. You will need this when creating a custom fetch-based reports. You can install it from http://www.microsoft.com/download/en/details.aspx?id=27823 or from the BIDSExtension folder in the Microsoft Dynamics CRM setup DVD.

Report Development Process

The following lists the steps for developing custom Microsoft Dynamics CRM reports. You may have to repeat some steps while you develop a report:

  1. Develop a report concept or specification based on what business information is to be displayed.
  2. Decide on the type of report you want to create: SQL-based or Fetch-based. Microsoft Dynamics CRM Online users can only create custom Fetch-based reports.
  3. Download an existing Microsoft Dynamics CRM report definition (.rdl), and modify it or create a new report by using Business Intelligence Development Studio.
  4. Create basic report parameters.
  5. Specify datasets and filtering criteria for retrieving data:
    • For SQL-based reports, create datasets that contain Microsoft Dynamics CRM data obtained from the filtered views.
    • Enable pre-filtering on the primary entities.
  6. Define the basic layout of the report, including headers and footers.
  7. Add report items as required based on the report specification.
  8. Preview the report in Microsoft Visual Studio, and resolve any errors.
  9. Deploy the report to the reporting server by using Microsoft Dynamics CRM.
  10. Run the deployed report to verify.

Create Custom Reports Using Business Intelligence Development Studio

Create a Custom SQL-Based Report

To create a custom SQL-based report using Business Intelligence Development Studio:

1- Open Business Intelligence Development Studio, and create a report server project.

xRM_Demo2 - Microsoft Visual Studio_2012-03-12_17-50-44

2- In Solution Explorer, right-click the Reports folder, and then click Add New Report.

xRM_Demo2 - Microsoft Visual Studio_2012-03-12_17-51-26

3- Click Next on the Report Wizard welcome screen.

4- On the Select the Data Source page, click New Data Source, and specify the following details:

  • Name: Type a name for the data source.
  • Type: Select Microsoft SQL Server.

Report Wizard_2012-03-12_17-53-25

  • Connection String: Specify the connection string to connect to the instance of the Microsoft SQL Server database. To build the connection string, click Edit. To supply credentials, click Credentials. Click Next.

Connection Properties_2012-03-12_17-54-53

3- On the Design the Query page, type the SQL query to use in the report. You could also click Query Builder button to open the Query Builder window. Right click in the empty area at the top of the dialog and choose Add Table

xRM_Demo2 - Microsoft Visual Studio_2012-03-12_17-58-43

then click on the Views tab, hold the CTRL key and and select the views that you will use in your report and click Add

Add Table_2012-03-12_17-59-13

select the columns you want, test your query results [We just retrieved the account name, city, country]

Query Designer_2012-03-12_18-02-20

when you satisfied with your query results, click Ok to use the query in the report

Report Wizard_2012-03-12_18-03-19

click Next.

4- On the Select the Report Type page, select a Tabular report or a Matrix report, and click Next. [we used Tabular, which is the most common report format]

Report Wizard_2012-03-12_18-03-24

5- Specify the fields that will be included in the report. You can add fields in three different sections [Page, Group, Details]. Page can be used for granular grouping like Country in our case, it will displayed on the page header only. Group can be used to more specific grouping within the page, like City in our case. Details is the place where individual records will be rendered, like our accounts names. Select each column name from the list on the left and click the designated section button to add the column to it.

Report Wizard_2012-03-12_18-04-41

Then click Next.

6- Select a stepped layout and click Next.

Report Wizard_2012-03-12_18-05-16

7- Select a style to apply to the report, and then click Next.

Report Wizard_2012-03-12_18-05-22

8- Verify the fields that will be included in the report, and name the report. Click Finish.

Report Wizard_2012-03-12_18-05-28

This will generate an .rdl file with the specified report name. You can use the .rdl file to publish your custom report in Microsoft Dynamics CRM.

xRM_Demo2 - Microsoft Visual Studio_2012-03-12_18-07-31

Create a Custom Fetch-Based Report

Creating a custom Fetch-based report is similar to creating a custom SQL-based report except for the data source name and the report query specified while creating the report definition.

Since you have the capability to create SQL-based reports for on-premise, most people will not use Fetch-based reports for on-premise. Let’s learn how to get the data source name for our CRM On-Line organization. It consists of:

  • Organization URL something like https://xrmdemo5.crm.dynamics.com
  • Organization unique name you can get it by navigating to Settings > Customization > Customizations > Developer Resources > it will be on this page

Developer res

Put the two parts separated by semi-colon will form your connection string, like https://xrmdemo5.crm.dynamics.com;4c69b8c565264033b4707c804cba7aa2 put that connection string in a text file for later use.

Now, lets learn how to create a query for our Fetch-based report. There are two ways to do that:

  1. Manually type the FetchXML query (which I don’t personally prefer)
  2. Obtain the FetchXML queries from the CRM web client and then modify it.

To obtain FetchXML queries you can navigate to any entity listing in CRM web client, like Accounts. Then click Advanced Find on the ribbon

adv fnd

This will open the Advanced Find dialog

adv fnd 2

Then click New to start creating a new query.

1- You can select the Entity (Table) from the Look For combo-box.

2- You can create your query where conditions. Click Select link to select the desired column

adv fnd 3

You can then click Equals link to specify the operator used in the where condition. You can then click Enter Text link to specify the value used in the condition

adv fnd 4adv fnd 5

when you have multiple conditions, you can select them and use the Group AND and Group OR on the ribbon to build your query logic.

3- You can specify the columns you want retrieve. Click Edit Columns in the ribbon, this will open the Edit Columns dialog

Edit Columns -- Webpage Dialog_2012-03-13_13-07-57

The area on the left shows the query columns and the sequence they appear. You can click Add Columns from the left to add more columns from this entity or any of entities related to it.

Add Columns -- Webpage Dialog_2012-03-13_13-10-04

Select Address 1: City and Address 1: Country and click Ok.

4- You can specify the query sorting. Click Configure Sorting on the left to open the Configure Sort Order dialog

Configure Sort Order

You can specify two columns only for the sorting criteria.

5- You can remove any column by click its name on the right and click Remove from the left.

When you done with editing the query columns click OK to return to the Advanced Find window. Now, click Download Fetch XML on the ribbon to download the Fetch query in a .xml file format to use inside SQL Business Intelligence Development Studio.

Now to add a custom Fetch-based report to our Report project, Right click Reports folder and click Add New Report. Click Next on the Report Wizard welcome screen.

1- On the Select the Data Source page, click New Data Source, and specify the following details:

  • Name: Type a name for the data source.
  • Type: Select Microsoft Dynamics CRM Fetch.
  • Connection String: copy the connection string we prepared earlier and past it here.
  • Click on Credentials and enter your live account and password you used in CRM Online and click Ok. Then click Next

Data Source Credentials_2012-03-13_15-07-56

2- On the Design the Query page, click on Query Builder. On the Query Designer dialog, click Import and browse to the xml file you downloaded earlier.

Query Designer_2012-03-13_15-24-04 

You can click on Run to test the query. Click Ok to close the Query Designer dialog, and Click Next.

Complete the Wizard steps just like the SQL-based report, it is the same.

As you can create queries using Business Intelligence Development Studio, you can also use it to modify complex queries.

Import Custom Reports into Dynamics CRM

To complete the cycle and let the report used by your organization, you need to import it into CRM. Follow the following steps to import our report:

1- Navigate to My Work > Reports > click New on the ribbon. The New Report window will open.

Report New - Windows Internet Explorer_2012-03-13_17-07-32

Click Browse and select your .rdl report file. Enter the report name. Near the bottom of the window there is a Display In field which decides areas where your reports will be displayed. By default new reports will be displayed in Reports area,  You can click the eclipse button if you want to make it displayed in forms or lists of the related entities, then select desired values and move them to Selected Values list.

Select Values -- Webpage Dialog_2012-03-13_17-20-21

In the New Report window, if you want to make the report accessible by the whole organization click the Administration tab and change the Viewable By field from Individual to Organization.

Report New - Windows Internet Explorer_2012-03-13_17-14-18

Click Save and Close. Now our report will be available in the Reports area of configured accessibility level [Organization or Individual].

To copy a report between organizations or deployments, include the report and any custom entities the report uses in a solution. This ensures that the entity types are mapped automatically by the system

In this post we used the Business Intelligence Development Studio to create both SQL-based and Fetch-based custom reports for on-premise and on-line CRM deployments. We also learned how to upload our reports to Dynamics CRM and make them accessible to the whole organization and through many access points.

Friday, March 2, 2012

Microsoft Dynamics CRM 2011 for Developers | Accessing Microsoft Dynamics CRM 2011 using WCF

Contents

  1. Introduction
  2. Creating a client application
  3. Using the Discovery Service
  4. Using the Organization Service
  5. Working with CRM Data
    1. Late Binding Approach
      1. Using RetrieveMultiple method
      2. Using Retrieve method
      3. Using Update method
      4. Using Delete method
      5. Using Create method
    2. Early binding Approach
      1. generating Client Types
      2. Enable ProxyTypeBehavior
      3. Using RetrieveMultiple method
      4. Using Retrieve method
      5. Using Create method

Introduction

Microsoft Dynamics CRM is a Customer Relationship Management software package developed to focus mainly on Sales, Marketing, and Service (help desk) sectors. The Microsoft Dynamics family of business applications includes other related products such as Microsoft Dynamics AX, Microsoft Dynamics GP, Microsoft Dynamics NAV, and Microsoft Dynamics SL.

Basically, Dynamics CRM is a client-server web application that supports extensive web services interfaces. Dynamics CRM 2011 introduces a new WCF interface for working with data, services and metadata.

Microsoft Dynamics CRM supports two kinds of deployments: Online, on-premises. You can signup for 30 days free trial at http://crm.dynamics.com/en-us/trial-overview. This will provide you with 30 days full functioning online version of Dynamics CRM. We will you this version in this post and the upcoming posts.

There is a lot of situations where organizations want to gain more benefit of its Dynamics CRM deployment than what Dynamics CRM can offer through its built-in customization tools. Based on the situation, you as a developer may be required to develop applications that interact with Dynamics CRM through its web services interfaces or develop applications that run within Dynamics CRM itself.

In this post we will explore one of the techniques of interacting with Dynamics CRM through its web services interfaces. We will build a windows forms application that connects to the online version of Dynamics CRM 2011, retrieve data from it, and manipulate its data. To continue with this post you need to signup for an online trial version and to install Microsoft Dynamics CRM 2011 Software Development Kit (SDK) ( download from http://www.microsoft.com/download/en/details.aspx?id=24004 )

Step 1: Create a client application

Simply create a new windows forms application. Right click your project in the solution explorer and select properties, locate the Target Framework drop down and change it from .Net Framework 4 Client Profile to .Net Framework 4. Add references to System.Runtime.Serialization.dll and System.ServiceModel.dll and System.Security. Add references to Microsoft.Xrm.Sdk.dll and Microsoft.Crm.Sdk.Proxy.dll (both files located in the Bin folder in your CRM SDK installation directory). Right click on the project in the solution explorer and click Add existing, browse to %CRMSDK%\samplecode\cs\helpercode\deviceidmanager.cs

The DeviceIdManager class is included in the Dynamics CRM SDK to register a computing device with Windows Live ID through the generation of a Device ID and password. Then it optionally stores that information in an encrypted format on the local disk for later use. This functionality is required when authenticating with Microsoft Dynamics CRM online. The device registration is stored in %USERPROFILE%\LiveDeviceID\LiveDevice.xml. It looks like:

<?xml version="1.0"?>


AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAooZFtct7dEyyPUNu1eZujgAAAAACAAAAAAADZgAAqAAAABAAAAD0860vIxbs57z9CgRRPAtTAAAAAASAAACgAAAAEAAAAFL9eqV3G5WLFhHYAkX1/z8gAAAAZjBYCltk8cNwuydeQK70t9/txdmoJhIGeN2StJbyx9EUAAAAY10YU7QprX0EO5Fq43A/S2Wer2I=



The CRM SDK team is separating the more CRM specific types from the xRM Application Framework related types.  The Microsoft.Xrm.Sdk assembly will provide all the low-level types necessary for basic operation against the xRM Application Framework. The Microsoft.Crm.Sdk.Proxy.dll  assembly will abstract away much of the complexity of dealing with the WCF services directly.



Now, try to make your application interface like the one in the image below.



app



Now we created the application interface, added the required references, and ready for the real thing :)



Step 2: Using the Discovery Service



The discovery service allows you to explore and enumerate the organizations on a certain CRM server and the web services endpoint URL needed to access the Organization Services web service for each of these organizations (The CRM server can contain multiple organizations). We will use this information later to configure the organization web service proxy and call web service methods to access the organization’s data and metadata. The service respects security such that it will only return those organizations to which a user has access. The discovery service is accessed using methods on the IDiscoveryService interface. The DiscoveryServiceProxy class is a helper class to make it easier to get instances of IDiscoveryService without having to deal with all the WCF low-level details.



Now on the forms designer surface double click on the Discover button to add event handler and open the MainWindow.xaml.cs code behind file. In the code behind, add the following using statements:



using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Discovery;
using System.ServiceModel.Description;
using Microsoft.Crm.Services.Utility;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;


Inside the frmMain class, add the following private properties to hold references to the organization details (the Discovery service and the Organization service).



private OrganizationDetail CurrentOrganizationDetail { get; set; }
private IDiscoveryService DiscoveryService { get; set; }
private OrganizationServiceProxy OrgService { get; set; }
private ClientCredentials _ClientCreds { get; set; }
private ClientCredentials _DeviceCreds { get; set; }
private bool IsLiveID { get; set; }


Now, let's add to frmMain class a helper method to builds the full Uri of the discovery service.



        public Uri GetDiscoveryServiceUri(string serverName)
{
string discoSuffix = @"/XRMServices/2011/Discovery.svc";

return new Uri(string.Format("{0}{1}", serverName, discoSuffix));
}


Next, In the event handler for the Discover button, add the following code to use the ServiceConfigurationFactory helper class to get an instance of the Discovery service configuration. This returned as an IServiceConfiguration<IDiscoveryService> type that hides and simplifies some of the lower level WCF configuration.



var discoUri = GetDiscoveryServiceUri(ServerURL.Text);
IServiceConfiguration dinfo = ServiceConfigurationFactory.CreateConfiguration(discoUri);


Different credentials are needed for CRM online vs. on premises. To differentiate between them we will add the following GetServerType helper method.



public AuthenticationProviderType GetServerType(Uri uri)
{
return ServiceConfigurationFactory.CreateConfiguration(uri).AuthenticationType;
}


Now, we will return to the Discover button handler. The follwoing code will create a DiscoveryServiceProxy instance based on the server type we connecting to (on-line or on-premises). Note that DeviceIdManager class have been used only in the on-line scenario. Then we use this instance (DiscoveryServiceProxy) to connect to the server, authenticate, and execute our RetrieveOrganizationsRequest to get RetrieveOrganizationResponse. This response has a property OrganizationDetails that is an array of OrganizationDetail objects which we will use to fill the oragnizations combo box. Add the following code to the couple of lines that you are added to btnDiscover_click handler.



_ClientCreds = new ClientCredentials();
DiscoveryServiceProxy dsp;

if (GetServerType(discoUri) == AuthenticationProviderType.LiveId)
{
_ClientCreds.UserName.UserName = username.Text;
_ClientCreds.UserName.Password = password.Text;

_DeviceCreds = DeviceIdManager.LoadOrRegisterDevice();

dsp = new DiscoveryServiceProxy(discoUri, null, _ClientCreds, _DeviceCreds);
IsLiveID = true;
}
else
{
_ClientCreds.Windows.ClientCredential.UserName = username.Text;
_ClientCreds.Windows.ClientCredential.Password = password.Text;
_ClientCreds.Windows.ClientCredential.Domain = domain.Text;

dsp = new DiscoveryServiceProxy(dinfo, _ClientCreds);
IsLiveID = false;
}

dsp.Authenticate();
var orgRequest = new RetrieveOrganizationsRequest();
var orgResponse = dsp.Execute(orgRequest) as RetrieveOrganizationsResponse;
comboOrgs.ItemsSource = orgResponse.Details;


You can now check your frmMain.cs aginst the below code. If everything is Ok, hit F5, enter the user name/password you used in your 30-days free trial signup (or your active directory credentials, if you test against your on-premises deployment), click Discover button. You will see the organizations combo box filled with the available organizations on this server that you have access to.



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Discovery;
using System.ServiceModel.Description;
using Microsoft.Crm.Services.Utility;

using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;

namespace xRM_Demo01
{
public partial class frmMain : Form
{
private OrganizationDetail CurrentOrganizationDetail { get; set; }
private IDiscoveryService DiscoveryService { get; set; }
private IOrganizationService OrgService { get; set; }
private ClientCredentials _ClientCreds { get; set; }
private ClientCredentials _DeviceCreds { get; set; }
private bool IsLiveID { get; set; }
public frmMain()
{
InitializeComponent();
}

private void btnDiscover_Click(object sender, EventArgs e)
{
var discoUri = GetDiscoveryServiceUri(txtServer.Text);

IServiceConfiguration dinfo =
ServiceConfigurationFactory.CreateConfiguration(discoUri);
_ClientCreds = new ClientCredentials();
DiscoveryServiceProxy dsp;

if (GetServerType(discoUri) == AuthenticationProviderType.LiveId)
{
_ClientCreds.UserName.UserName = txtUserName.Text;
_ClientCreds.UserName.Password = txtPassword.Text;

_DeviceCreds = DeviceIdManager.LoadOrRegisterDevice();

dsp = new DiscoveryServiceProxy(discoUri, null, _ClientCreds, _DeviceCreds);
IsLiveID = true;
}
else
{
MessageBox.Show("This is not a valid Microsoft Dynamics CRM online URL");
return;
}

dsp.Authenticate();
var orgRequest = new RetrieveOrganizationsRequest();
var orgResponse = dsp.Execute(orgRequest) as RetrieveOrganizationsResponse;
comboOrgs.DataSource = orgResponse.Details;
comboOrgs.DisplayMember = "FriendlyName";
comboOrgs.ValueMember = "UrlName";
}
public Uri GetDiscoveryServiceUri(string serverName)
{
string discoSuffix = @"/XRMServices/2011/Discovery.svc";

return new Uri(string.Format("{0}{1}", serverName, discoSuffix));
}
public AuthenticationProviderType GetServerType(Uri uri)
{
return ServiceConfigurationFactory.CreateConfiguration(uri).AuthenticationType;
}


Step 3: Using the Organization Service



The organization service is the endpoint that you will use to interact with an individual organization's data and metadata services. It accessed using the methods on the IOrganizationService interface. The OrganizationServiceProxy helper class is used to make it easier to get instance of IOrganizationService without dealing with the WCF low-level details. Double click on the Connect button to add an event handler for it and add the following code.



            if (comboOrgs.SelectedItem == null)
{
MessageBox.Show("You must select an organization before connecting");
return;
}
this.CurrentOrganizationDetail = comboOrgs.SelectedItem as OrganizationDetail;
Uri orgServiceUri = new Uri(CurrentOrganizationDetail.Endpoints[EndpointType.OrganizationService]);
if (IsLiveID)
{
OrgService = new OrganizationServiceProxy(orgServiceUri, null, _ClientCreds, _DeviceCreds);
}
else
{
IServiceConfiguration orgConfigInfo =
ServiceConfigurationFactory.CreateConfiguration(orgServiceUri);
OrgService = new OrganizationServiceProxy(orgConfigInfo, _ClientCreds);
}


The added code checks that you selected an organization, get the select organization as an OrganizationDetail object, use the EndPoints of this object to get the Uri of the Organization Service. Then use this information and the client credentials and the device credentials to create an object of OrganizationServiceProxy.



Now we are ready to start interacting with the organization service through this proxy (which will be the next step). If you want to ensure that you did everything right, you can try send a simple request to the organization service and see the result. To do so, we can send the WhoAmI message to the service and receive the response (the ID of the logged in used). Add a using statement for Microsoft.Crm.Sdk.Messages. Add the following code to the end of btnConnect_click to test your connectivity.



WhoAmIRequest req = new WhoAmIRequest();
var response = OrgService.Execute(req) as WhoAmIResponse;
MessageBox.Show("You are connected as userid " + response.UserId.ToString());


Run, put your credentials an server, click Discover, choose your organization from the combo box and click connect. You will get something like the below image.



msg



Step 4: Working with the CRM data



Early versus Late-Bounding In Microsoft Dynamics CRM 2011, you can choose from several programming styles to find the model that best fits your situation.




In Early-Bound style, you create a class for each business entity in your CRM deployment. You will use these classes to access business data in your CRM deployment. There is a code generation tool included in the %CRMSDK%\bin called crmsvcutil.exe that will generate early-bound entity classes for you. It works with on-premises and online deployments. Every time you make customizations to your entities, you have to run this tool to regenerate these classes again. The advantages of using early-bound entity classes is that all type references are checked at compile time. You will also enjoy the intellisense support.



In Late-Bound style, you can work with the data in CRM without having classes representing each data entity in the organization. Most Probably, you will use this style when working with entities (or customizations) that you can’t anticipate at the development time.




In this step we will work with the CRM data using late-bound style to retrieve all accounts data in our CRM, update it, save it, and add new records also.



Method : RetrieveMultiple



To retrieve multiple records from Dynamics CRM, we use the RetrieveMultiple of the organization service and pass a QueryExpression object to it. QueryExpression holds all the information required to get the desired data from Dynamics CRM. To construct the Query expression you need:




  • ColumnSet object to specify the columns we need to retrieve.


  • ConditionExpression object to hold any conditions we will use to filter the returned rows.


  • FilterExpression object to hold all the ConditionExpression objects we use in our query. This enables us to make complex queries.


  • EntityName a string property used to specify the entity the query runs against.


  • You can also order the returned data through method AddOrder(“columnName”, OrderType). OrderType is an enumeration have the values Ascending and Descending.



For Simplicity we will retrieve columns name and accountid of all account type records in CRM. Because we using late-bound style, we get the results into EntityCollection collection. We enumerate through the returned collection, and put the entities into a list of custom objects of type Item. Then we bind our accounts combobox to this list.



            ColumnSet cs = new ColumnSet();
cs.AddColumns("name", "accountid");

QueryExpression qe = new QueryExpression();
qe.ColumnSet = cs;
qe.EntityName = "account";

EntityCollection accountList = OrgService.RetrieveMultiple(qe);
List accounts = new List();
comboAccounts.ValueMember = "Value";
comboAccounts.DisplayMember = "Name";
for (int i = 0; i < accountList.Entities.Count; i++ )
{
accounts.Add(new Item(accountList[i].Attributes["name"].ToString(),
accountList[i].Attributes["accountid"].ToString()));
}
comboAccounts.DataSource = accounts;
}


Also add the following class into your solution namespace, which holds the acounts name and accountid to bind it to the combobox.



    class Item
{
private string _name;
private string _value;
public string Name
{
get { return _name; }
set { _name = value; }
}
public string Value
{
get { return _value; }
set { _value = value; }
}
public Item(string p_name, string p_value)
{
Name = p_name;
Value = p_value;
}
}


Now you can run the application, connect to your organization, and check that the combobox is filled of your accounts data.



Method : Retrieve



Now we will use the accountid of the selected account in the combobox to get the rest of the account data. In this case we will use the Retrieve method of the organization service. This method retrieves just one record of the type specified in the first argument, designated by the key passed in the second argument. Double click on the accounts combobox to add an event handler for the SelectedIndexChanged event. Add the following code to this event handler to fill the form with the account data.



            ColumnSet cs2 = new ColumnSet(new string[] {"address1_city","address1_line1","address1_stateorprovince",
"name","industrycode"});
try
{
var account = OrgService.Retrieve("account", new Guid(comboAccounts.SelectedValue.ToString()), cs2);
txtName.Text = account.Attributes["name"].ToString();
txtCity.Text = account.Attributes["address1_city"].ToString();
txtAddress.Text = account.Attributes["address1_line1"].ToString();
txtState.Text = account.Attributes["address1_stateorprovince"].ToString();
}
catch (Exception ex)
{
MessageBox.Show("An error happened: " + ex.Message);
}


Method : Update



Now we can go farther and modify the current displayed account data and try to save it. To save any entity data into CRM, create an Entity object and pass the entity type into the constructor (it will be "account" in our case). Then set the attribute values you want and pass the updated entity to the organization service Update method. Add the following code the save button click event handler to realize the update operation.



 
try
{
Entity account = new Entity("account");
account.Attributes["accountid"] = new Guid(comboAccounts.SelectedValue.ToString());
account.Attributes["name"] = txtName.Text;
account.Attributes["address1_line1"] = txtAddress.Text;
account.Attributes["address1_city"] = txtCity.Text;
account.Attributes["address1_stateorprovince"] = txtState.Text;
OrgService.Update(account);
MessageBox.Show("Account updated successfully");
// TODO: reload the accounts combobox.
}
catch (Exception ex)
{
MessageBox.Show("An error occurred : " + ex.Message);
}


Method : Delete



To delete a record you use the Delete method of the organization service, pass the entity type name and its key like the following.



try
{
OrgService.Delete("account", new Guid(comboAccounts.SelectedValue.ToString()));
MessageBox.Show("Account deleted successfully");
// TODO: reload the accounts combobox
}
catch (Exception ex)
{
MessageBox.Show("An error occurred : " + ex.Message);
}


Now let's add code to clear the form in the clear button click event handler.



            txtName.Text = "";
txtCity.Text = "";
txtAddress.Text = "";
txtState.Text = "";


Method : Create



To insert a new record to CRM, we create an Entity object passing the entity name to its constructor, set its attributes, and pass it to the organization service Create method. Add the following code to the save new button click event handler.



try
{
Entity account = new Entity("account");
account.Attributes["name"] = txtName.Text;
account.Attributes["address1_line1"] = txtAddress.Text;
account.Attributes["address1_city"] = txtCity.Text;
account.Attributes["address1_stateorprovince"] = txtState.Text;
OrgService.Create(account);
MessageBox.Show("Account created successfully");
}
catch (Exception ex)
{
MessageBox.Show("An error occurred : " + ex.Message);
}


No we have examined almost all basic data operations on the CRM data using late-bounding style: RetrieveMultiple, Retrieve, Update, Delete, and Create new record.



Generating Client Types for Early Binding



Now we will use a different style than the one we used above. We will use the SDK tool crmsvcutil.exe to generate the typed classes for our CRM entities bsed on the metadata service of our CRM organization. These generated typed classes will inherit from the Entity class we worked with earlier in this post. Now follow the following steps to generate your typed classes:




  1. Open the project included in the SDK at %SDK%\tools\deviceregistration folder and build it.


  2. Open the command prompt cmd.exe and change directories to %SDK%\tools\deviceregistration\bin\Debug and run the command DeviceRegistration.exe /operation:Register This will generate a Device ID and Device Password for you (similar to the ones created by deviceidmanager.cs class).


  3. Copy the Deviceid and Device Password to a notepad. (if you are not familiar with cmd, right click the inside the window and click highlight, then highlight the desired text, then right click the cmd window title bar and click Edit>> copy.)


  4. In the command window, change the directories to %SDK%\bin and create a command like the following:



crmsvcutil.exe /url:<CRM Online Organization service URL> /out:<Output file name> /servicecontextName:<Organization name> /username:<LiveID> /password:<LiveIDPassword>


/deviceid:<Deviceid> /devicepassword:<DevicePassword> /namespace:<Namespace>



<CRM Online Organization service URL> will be like https://xrmdemo5.api.crm.dynamics.com/XRMServices/2011/Organization.svc? . You can find your URL by going to Settings >> Customizations >> Developer Resources, your URL will be there.



<Output file name> is the file name of the generated code (like GeneratedEntities.cs)



<Organization name> is your organization name.



<LiveID>, <LiveIDPassword> are your live credentials used for this organization.



<Deviceid>, <DevicePassword> are provided from step 3.



<Namespace> is the name space of the generated classes (may be YourCompanyname.YourOrganizationName)



the complete command may look like



crmsvcutil.exe /url:https://xrmdemo5.api.crm.dynamics.com/XRMServices/2011/Organization.svc /out:GeneratedEntities.cs /servicecontextName:xrmdemo5 /username:ebeid_soliman@hotmail.com /password:mypassword

/deviceid:11denl276oo3fgxbakccnnq2x4 /devicepassword:bH.iaG?c3rRi-`L,nKC0S4^^ /namespace:xRMDemo.Entities



Now we created our early bound entity classes. Let’s modify our application to use the early-bound entity classes that we generated.



Step 1: Add the generated types to the project



Right click on the project in the solution explorer and click Add existing, browse to %CRMSDK%\bin and add your generated file (its GeneratedEntities.cs in my above command).



Step 2: Enable proxy types



In order to use the generated types when dealing with the organization service, you have to add the ProxyTypesBehavior to the endpoint Behaviors collection. This instructs the OrganizationServiceProxy to look in the assembly for classes with certain attributes to use. The generated classes are already attributed with these attributes. Simply, this makes all interactions with the organization service to be done using the generated typed classes for each entity instead of the generic Entity class we used earlier.



Open the frmMain.cs, locate btnConnect_Click event handler and add the following line of code after the last section line that creates the new instance of our OrganizationServiceProxy.



OrgService.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());


Method : RetrieveMultiple



It’s the same before. Now, let's modify the accounts combobox filling section to use the generated Account class instead of the Item class (you can get ride of it) that we created earlier. Modify the last section in btnConnect_Click event handler to look like the following.



List accounts = new List();
comboAccounts.ValueMember = "accountid";
comboAccounts.DisplayMember = "name";
for (int i = 0; i < accountList.Entities.Count; i++)
{
accounts.Add((Account)accountList[i]);
}
comboAccounts.DataSource = accounts;


Method : Retrieve



It almost the same, except we will use Account class and its properties instead of the Entity class and its attributes. Modify the comboAccounts_SelectedIndexChanged event handler to look like:



ColumnSet cs2 = new ColumnSet(new string[] {"address1_city","address1_line1","address1_stateorprovince",
"name","industrycode"});
try
{
Account account = (Account)OrgService.Retrieve("account", new Guid(comboAccounts.SelectedValue.ToString()), cs2);
txtName.Text = account.Name;
txtCity.Text = account.Address1_City;
txtAddress.Text = account.Address1_Line1;
txtState.Text = account.Address1_StateOrProvince;
}
catch (Exception ex)
{
MessageBox.Show("An error happened: " + ex.Message);
}


Delete method is solely done by the organization service, so it didn't change due the style we use.



Method : Create



It almost the same, except we will use Account class and its properties instead of the Entity class and its attributes. Modify the btnSaveNew_Click event handler to look like:



try
{
Account account = new Account();
account.Name = txtName.Text;
account.Address1_Line1 = txtAddress.Text;
account.Address1_City = txtCity.Text;
account.Address1_StateOrProvince = txtState.Text;
OrgService.Create(account);
MessageBox.Show("Account created successfully");
}
catch (Exception ex)
{
MessageBox.Show("An error occurred : " + ex.Message);
}


This post is one of multiple posts to come under the same topic, Microsoft Dynamics CRM 2011 for Developers. Basicly we will deal with Dynamics CRM from the developer point of view. In this post we have tried to cover the basics of accessing Microsoft Dynamics CRM data using WCF. We tried the basic data operations: retrieve multiple records, retrieve one record, update, delete, and insert. We tried to cover both early-bounding and late-bounding approaches in our implementations.