Posted on 27. September 2013

Microsoft.Xrm.Client (Part 3b): Configuration via app/web.config

In this series we have been looking at the Developer Extensions provided by the Microsoft.Xrm.Client assembly:

Part 1 - CrmOrganizationServiceContext and when should I use it?

Part 2 - Simplified Connection Management & Thread Safety

Part 3a – CachedOrganizationService

So far in this series we have learnt how to use the Microsoft.Xrm.Client developer extensions to simplify connecting to Dynamics CRM, handling thread safety and client side caching.

This post shows how the configuration of the Dynamics CRM connection and associated OrganizationService context can be configured using an app.config or web.config file. This is esspecially useful with ASP.NET Portals and Client Applications that don't need the facility to dynamically connect to different Dynamics CRM Servers.

If you only want to configure connection string, then you would add a app.config or web.config with the following entry:

<connectionStrings>
<add name="Xrm" connectionString="Url=http://<server>/<org>"/>
</connectionStrings>

The Connection string can take on the following forms:

On Prem (Windows Auth)

Url=http://<server>/<org>;

On Prem (Windows Auth with specific credentials)

Url=http://<server>/<org>; Domain=<domain>; Username=<username>; Password=<password>;

On Prem (Claims/IFD)

Url=https://<server>; Username=<username>; Password=<password>;

On Line (Windows Live)

Url=https://<org>.crm.dynamics.com; Username=<email>; Password=<password>; DeviceID=<DeviceId>; DevicePassword=<DevicePassword>;

On Line (O365)

Url=https://<org>.crm.dynamics.com; Username=<email>; Password=<password>;"

You can find a full list of connection string parameters in the SDK

You can then easily instantiate an OrganizationService using:

var connection = new CrmConnection("Xrm");
var service = new OrganizationService(connection);

If you want to simplify creation of the ServiceContext, and make it much easier to handle thread safety – you can use a configuration file that looks like:

<configuration>
<configSections>
    <section name="microsoft.xrm.client" type="Microsoft.Xrm.Client.Configuration.CrmSection, Microsoft.Xrm.Client"/>
</configSections>
<microsoft.xrm.client>
    <contexts>
        <add name="Xrm" type="Xrm.XrmServiceContext, Xrm" serviceName="Xrm"/>
    </contexts>
    <services>
        <add name="Xrm" type="Microsoft.Xrm.Client.Services.OrganizationService, Microsoft.Xrm.Client"
        instanceMode="[Static | PerName | PerRequest | PerInstance]"/>
    </services>
</microsoft.xrm.client>
</configuration>

You can then instantiate the default context simply by using:

var context = CrmConfigurationManager.CreateContext("Xrm") as XrmServiceContext;

The most interesting part of this is the instanceMode. It can be Static, PerName, PerRequest, PerInstance. By setting it to PerRequest, you will get a OrganizationService per ASP.NET request in a portal scenario – making your code more efficient and thread safe (provided you are not using asynchronous threads in ASP.NET).

The examples above I find are the most common configurations, although you can also specify multiple contexts with optional caching if required for specific contexts – the SDK has a full set of configuration file examples. Using the configuration file technique can simplify your code and ensure your code is thread safe.

On the topic of thread safety, it was recently brought to my attension that there appears to a bug with the ServiceConfigurationFactory such that if you are instantiating your OrganizationService passing the ServiceManager to the constructor in conjunction with EnableProxyTypes, you can occationally get a threading issue with the error "Collection was modified; enumeration operation may not execute". The work around to this is to ensure that the call to EnableProxyTypes is wrapped in the following:

if (proxy.ServiceConfiguration.CurrentServiceEndpoint.EndpointBehaviors.Count == 0)
{
    proxy.EnableProxyTypes();
}

More information can be found in my forum post.

Next up in this series are the Utility and extension functions in the Microsoft.Xrm.Client developer extensions.

@ScottDurow

 

Posted on 24. September 2013

Asynchronous loading of JavaScript in CRM 2013

When CRM2011 UR 12 (POLARIS) introduced asynchronous loading of web resources, there were some unfortunate side effects caused by the load order in which the scripts were executed not being the same as defined by form customisations. If you had scripts that required a previous scripts to be loaded first before it could be executed, you would experience random script errors due to the unpredictable load order. You can read more about the issue in the MSDN forums thread and the blog post I wrote explaining the behaviour and workaround.

Since then, the behaviour has been reverted back to the pre-UR12 loading technique as of Dynamics CRM2011 UR15 but this post describes what you can expect from Dynamics CRM 2013's script loading mechanism.

Why Asynchronous?

One of the reasons for moving to an Asynchronous loading model for JavaScripts was to make the form feel more responsive. Rather than having to load all scripts first before code can start and the form can be rendered, the scripts are loaded in parallel (as far as the browser will let them) resulting in a faster load time compared to a sequential load. Code that has all of its dependencies loaded can also start running before all of the unrequired scripts have completed being downloaded. Libraries such as RequireJs handle the complexities that can result from interdependent scripts all loading in parallel and your code needing to know when its dependencies are loaded before executing.

CRM2013 scripts do not load in order

With Dynamics CRM 2013, scripts are now loaded asynchronously and although the onload event will be executed after all scripts are loaded, the loading of the individual scripts will happen in the order that they are received from the server and not the order that they are specified in the form properties. Of course how you load JavaScript in Html Web Resources is still up to you!

Debugging Scripts

One by-product of this dynamic loading of scripts is that you won't see your web resources in the list of scripts using the F12 debugger since the browser has no <SCRIPT> tag to get the URL from. The script will still be available for debugging; however it will appear as an anonymous script block rather than in the list of script sources against its web resource URL. The technique I describe in the 'New Project' SparkleXrm tutorial of using www.fiddler2.com to create a re-direct to a script on the disk will still work because the browser request the web resource by its URL, allowing fiddler to intercept and redirect. Caching behaviour is unchanged with the web resources being cached by the client until customisations are published and the cache version is changed. You can read more about this mechanism in my web resource caching blog post on the subject.

Fast and Responsive

The good news is that as a result of the changes – forms are noticeable faster to load.

@ScottDurow

Posted on 20. September 2013

4 things you need to know about the Command Bar

This post provides the important information you need to know in order to transition to customising the Command Bar in Dynamics CRM 2013.

1. The Command Bar is a Ribbon in disguise!

The Ribbon Bar in Dynamics CRM 2013 to a certain degree has been replaced by the Command Bar but it still exists on non 'refreshed' entity Forms such as Connection Form and Price List Form, and is still present on all home list view grids in Microsoft Outlook.

The Command Bar is actually the same Ribbon structure but rendered differently in the User Interface. Although the Command Bar has no visual concept of Tabs, Groups or Layouts and there is no dynamic resizing and scaling, it still requires the Ribbon Diff Xml with these constructs to function. Using the Ribbon Workbench for CRM2013 will allow you to still edit these structures, but view in both the Command Bar and Ribbon display format.

2. Disabled Buttons are hidden

The Command Bar will only show 5 controls at any one time before they are added to the 'overflow' section. This deliberate constraint means that you will need to think carefully about what the user really needs on their command bar. Initially this may sound like a tricky problem but the Command Bar will not display a disabled button – it will always hide it – which means that the 5 buttons being shown will dynamically change depending on what buttons are available to the user. This is a significant improvement over the Ribbon that would always look cluttered even if there were very few buttons enabled for use.

To work with the 5 control constraint you can use fly out and split buttons to group commands together and not be moved to the overflow. The Overflow menu can also have fly out controls that open to the right rather than pulled down.

3. No contextual Sub Grid Controls

CRM2011 form Sub Grids used to dynamically swap in the Sub Grid Ribbon at the top of a form when a sub grid was selected. This allowed access to the sub grid entity commands directly from the parent entity form but often left a user confused. This functionality has been removed in CRM 2013 and the primary entity Command Bar now always is shown at the top of the form. A new 'mini' Command Bar is shown above each form Sub Grid showing only the 'Add' and 'Open Associated Sub Grid' buttons with the Delete button shown next to each record. If you want to access all of the sub grid buttons you must use the 'Open Associated Sub Grid' button that opens the entire page into the Sub Grid list view. To return to the form you must click on the name of the record in the Nav Bar. You cannot customise this mini Sub Grid at this time other than overriding the 'Add' and 'Delete' command - you cannot add buttons or change the icons of buttons on the mini Sub Grid, but full customisation is supported on the full Sub Grid Command Bar.

4. Controlling Visibility of Controls on the Command Bar

The visibility of a control on the command bar is defined using a new Display Rule named 'CommandClientTypeRule'. Controls will only show on the Command Bar if their associated Command has no CommandClientTypeRule Display Rules or it has a CommandClientTypeRule is added with Type=Refresh.

The Types property can have the following values:

Modern

The control is visible in the Tablet client

Refresh

The control is visible in the Command Bar

Legacy

The control is visible on ribbons of non-refresh entities or in list views presented in Microsoft Outlook.


There is a built in Display Rule that is used to hide system buttons from the Command Bar named 'Mscrm.HideOnCommandBar' that has a 'CommandClientTypeRule' with Type=Legacy. Commands with this Display Rule will not be visible on the Command Bar. You can remove this display rule from command to bring back buttons that were hidden by default. I have created instruction on how to do this.

Clean and Responsive

These 4 points will make planning & designing your CRM2013 solution easier and I'm sure you'll soon be loving the clean and responsive user experience that the new Command Bar gives.

@ScottDurow

Posted on 20. September 2013

How to change process and stage programmatically

Scenario

UPDATE: With CRM2015 - the new client side process API should be used to set the current step. The following approach should be only used for setting the process to the first step.

If you have more than one Dynamics CRM 2013 Business Process Flow for a given entity users can easily change the current process by using the 'Switch Process' Command Bar button:

Once changed, you can identify which process is running by hovering over the 'I' on the bottom right of the process flow:

If your users would like to change the Business Process Flow stage dynamically based on a given set of attribute values then it is not immediately obvious how this can be achieved. This post provides one solution using a custom workflow activity in combination with the new Synchronous Workflow feature of Dynamics CRM 2013.

Solution

The currently selected process stage on a given entity record is stored in CRM using the following attributes:

  • processid – GUID of the selected Business Process (workflow)
  • stageid – GUID of the selected Process Stage (processstage)

Initially I thought that these attributes might be able to be updated using a workflow directly, but it turns out you can only update them via code.

You will need to know how to write Custom Workflow Activities and add JavaScript Web Resources to follow these steps:

1. Using the Visual Studio Developer Tookit found in the SDK, create a new Custom Workflow Activity that accepts the following input arguments:

[RequiredArgument]
[Input("Process Name")]
public InArgument Process { get; set; }

[RequiredArgument]
[Input("Process Stage Name")]
public InArgument ProcessStage { get; set; }

These parameters need to be strings since you cannot pass in EntityReferences to the Workflow and ProcessStage entities.

2. Add to the Execute code the following:

using (var ctx = new OrganizationServiceContext(service))
{	
    // Get the processid using the name provided
    var process = (from p in ctx.CreateQuery()
                   where
                   p.Name == Process.Get(executionContext)
                   &&
                   p.StateCode == WorkflowState.Activated
                   select new Workflow
                   {
                       WorkflowId = p.WorkflowId

                   }).FirstOrDefault();
    if (process==null)
        throw new InvalidPluginExecutionException(String.Format("Process '{0}' not found",Process.Get(executionContext)));

    // Get the stage id using the name provided
    var stage = (from s in ctx.CreateQuery()
                 where
                 s.StageName == ProcessStage.Get(executionContext)
                 &&
                 s.ProcessId.Id == process.WorkflowId
                 select new ProcessStage
                 {
                     ProcessStageId = s.ProcessStageId

                 }).FirstOrDefault();
    if (stage == null)
        throw new InvalidPluginExecutionException(String.Format("Stage '{0}' not found", Process.Get(executionContext)));

    // Change the stage
    Entity updatedStage = new Entity(context.PrimaryEntityName);
    updatedStage.Id = context.PrimaryEntityId;
    updatedStage["stageid"] = stage.ProcessStageId;
    updatedStage["processid"] = process.WorkflowId;
    service.Update(updatedStage);
}

3. Deploy your custom workflow activity.

4. Create a New Workflow that is defined with the following parameters:

  • Activate As: Process
  • Run this workflow in the background : NO
  • Scope: Organization (if you want it to run for all users)
  • Start when: Before – Record fields change. Select the attributes that the process stage is dependant on so that it does not run on every change.

4. Add a set of conditions to determine if the stage should be changed and call your custom workflow activity providing the Process Name and Process Stage to change to.

5. Since the Process and Stage will not automatically change on the form, you need to add some JavaScript to refresh the form by saving it when the dependant fields are changed. You can do this by adding an onChange event to the dependant fields that calls:

Xrm.Page.data.entity.save()

UPDATE: Rob Boyers pointed out that this doesn't reliably refresh the process, however there isn't currently a supported way of doing it.
You could use the following unsupported method call to reload the whole form:

Mscrm.ReadFormUtilities.openInSameFrame(window._etc, Xrm.Page.data.entity.getId())


Notes:

  1. This technique could also be written using a plugin - but the advantage of using a Synchronous workflow is that the logic that determines the stage can be easily changed without re-compiling code.
  2. You can use the same technique to read the process and stage name so that you can make a decision using the current position in the process. I've included a sample of this too in the download
  3. You can download the sample code from here - http://code.msdn.microsoft.com/Change-Dynamics-CRM-2013-a6beb85e
Posted on 9. September 2013

Do you understand MergeOptions?

If you use LINQ queries with the OrganizationServiceContext then understanding MergeOptions is vital. At the end of this post I describe the most common 'gotcha' that comes from not fully understanding this setting.

The OrganizationServiceContext implements a version of the 'Unit of Work' pattern (http://martinfowler.com/eaaCatalog/unitOfWork.html ) that allows us to make multiple changes on the client and then submit with a single call to 'SaveChanges'. The MergeOption property alters the way that the OrganizationServiceContext handles the automatic tracking of objects when returned from queries. It is important to understand what's going on since by default LINQ queries may not return you the most recent version of the records from the server, but rather a 'stale' versions that is currently being tracked.

What is this 'Merge' they speak of?!

The SDK entry on MergeOptions talks about 'Client side changes being lost' during merges.

The term 'merge' is nothing to do with merging of contacts/leads/accounts – but describes what happens when the server is re-queried within an existing context and results from a previous query are returned rather than new copies of each record. It is a record ID based combination, not an attribute merge – so a record is either re-used from the current context, or a new instance is returned that represents the version on the server.

In order to describe the different options, consider the following code:

// Query 1
var contacts = (from c in context.ContactSet
                select new Contact
                {
                    ContactId = c.ContactId,
                    FirstName = c.FirstName,
                    LastName = c.LastName,
                    Address1_City = c.Address1_City

                }).Take(1).ToArray();

// Update 1
Contact contact1 = contacts[0];
contact1.Address1_City = DateTime.Now.ToLongTimeString();
context.UpdateObject(contact1);

// Query 2
var contacts2 = (from c in context.ContactSet
                 select c
          ).Take(2).ToArray();

// Update 2
var contact2 = contacts2[0];
contact2.Address1_City = DateTime.Now.ToLongTimeString();
context.UpdateObject(contact2);

// Save Changes
context.SaveChanges();

MergeOption.NoTracking

Perhaps the best place to start is the behaviour with no tracking at all.

  • Query 1 – Will return all matching contacts but not add them to the tracking list
  • Update 2 – Will throw and exception because the contact is not being tracked. You would need to use context.Attach(contact) to allow this update to happen
  • Query 2 – This query will pull down new copies of all contacts from the server include a new version of contact 1
  • Update 2 – We now have two version of the same contact with different city attribute value. The UpdateObject will fail without Attach first being called. If you attempt to attach contact2 after attaching contact1 you will receive the error 'The context is already tracking a different 'contact' entity with the same identity' because contact1 is already tracked and has the same ID.

MergeOption.AppendOnly (Default Setting)

When using the OrganizationServiceContext, by default it will track all objects that are returned from LINQ queries. This means that the second query will return the instance of the contacts that have already been returned from query 1. Critically this means that any changes made on the server between query 1 and query 2 (or any additional attributes queried using projection) will not be returned.

  • Query 1 – Will return all matching contacts and add them to the tracking list
  • Update 2 – Will succeed because the contact is being tracked
  • Query 2 – Will return the same instances that are already being tracked. The only records that will be returned from the server will be those that are not already being tracked. This is the meaning of 'AppendOnly'. The query still returns the data from the server, but the OrganizationServiceContext redirects the results to the instances already in the tracking list meaning that any changes made on the server since Query 1 will not be reflected in the results.
  • Update 2 – Will succeed since contact1 and contact2 are the same object. Calling UpdateObject on the same instance more than once is acceptable.

MergeOption.PreserveChanges

PreserveChanges is essentially the same as AppendOnly except:

  • Query 2 – Will return the same instances that are already being tracked provided they have an EntityState not equal to Unchanged. This means that contact2 will be the same instance as contac1 because it has been updated, but other instances in the contacts1 and contacts2 results will be new instances.

The result of this is that queries will not pick up the most recent changes on the server if a tracked version of that record has been edited in the current context.

MergeOption.OverwriteChanges

With a MergeOption of OverwriteChanges, the query behaviour will effectively be as per NoTracking however the tracking behaviour is like AppendOnly and PreserverChanges:

  • Query 1 – Will return all matching contacts and add each on to the tracking list (as per AppendOnly and PreserveChanges)
  • Update 2 – Will succeed because the contact is being tracked (as per AppendOnly and PreserveChanges)
  • Query 2 – This query will pull down new copies of all contacts from the server include a new version of contact 1 (as per NoTracking). Previously tracked contact1 will no longer be tracked, but the new version (contact2) will be.
  • Update 2 – Will succeed and the values on contact1 will be lost.

The MergeOption has a subtle but important effect on the OrganizationServiceContext, and without truly understanding each setting you might see unexpected results if you stick with the default 'AppendOnly'. For instance, you might update the value on the server between queries, but because a record is already tracked, re-querying will not bring down the latest values. Remember that all of this behaviour only is true for the same context – so if you are creating a new context then any previously tracked/modified records will no longer be tracked.

LINQ Projection 'Gotcha'

The most common issue I see from not fully understanding MergeOptions (and yes I made this mistake too! Smile) is the use of the default AppendOnly setting in conjunction with LINQ projection. In our code example Query 1 returns a projected version of the contact that only contains 4 attributes. When we re-query in Query 2 we might expect to see all attribute values but because we are already tracking the contacts our query will only return the previously queried 4 attributes! This can hide data from your code and cause some very unexpected results!

In these circumstances, unless you really need tracking and fully understand MergeOptions, I recommend changing the MergeOptions to 'NoTracking'.

@ScottDurow

Posted on 6. September 2013

How to restore a hidden button on the CRM 2013 Command Bar

The new Dynamics CRM 2013’s command bar has deliberatly limited space for buttons due to the ‘intentionally constrained’ user interface design. The idea being that if you limit the space for buttons, then designers will be forced to only show those that are absolutely necessary and the user experience will be improved. As result, many of the buttons from the CRM 2011 Ribbon Bar have been removed from the CRM 2013 Command Bar.

The CRM2011 Ribbon Buttons are still there, but hidden using a new RibbonXml Display Rule named 'Mscrm.HideOnCommandBar'. This article shows you how to restore those buttons to the Command Bar that your users absolutely must have using the Ribbon Workbench for CRM2013.

1. Create a solution containing the entities that you wish to restore buttons for. This example uses the ‘Case’ entity, and we are restoring the ‘Connect’ button on the ‘Form’ command bar.
Before customising, the Form Command Bar looks like the following:

You’ll notice that only 5 buttons are shown until buttons are added to the ‘overflow’ menu. The ‘Connect’ button is not here since it was deemed unessential.

2. Open the solution containing the Case entity in the Ribbon Workbench for CRM 2013 and select the ‘incident’ entity if not already selected. You will see by default the Command Bar is selected.
 

3. In order to locate the button we want to restore, click on the ‘Ribbon’ selector to show the Ribbon. This will show the Ribbon Design surface.

4. Select the ‘Form’ ribbon using the dropdown on the top right of the design surface, then select the ‘Connect’ button and Right-Click ‘Customize Command’

5. Locate the Customised Command in the ‘Solution Elements’ tab under ‘Commands’

6.  In the Edit Display Rules dialog, select the ‘Mscrm.HideOnCommandBar’ rule and click the ‘<Remove’ button.

7.  Important: Locate the following Display Rules, and set the ‘IsCore’ property to ‘True’ – this will prevent them from being customised as well:

a.      Mscrm.HideOnCommandBar

b.      Mscrm.CreateConnection

c.      Mscrm.IsConnectionsEnabledPrimary

d.      Mscrm.HideOnModern

8. Important: Locate the ‘Mscrm.FormStateExistingOrReadOnlyOrDisabled’ Enable Rule, and set the ‘IsCore’ property to ‘True’

9. Click ‘Publish’

10 Now when you refresh the Case Form, you will see the Connect button again.

11  You’ll notice that only the default button is shown – so if you use the drop down, you’ll only get the ‘Connect to Another’ option. To enable the ‘To Me’ button repeat the process for the ‘To Me’ button:

Remember to make sure that only the buttons that are really needed are included - the Command Bar has been constrained intentially to give your users the best experience.

@ScottDurow