Posted on 28. November 2014

Separate Content from Code

Back in the On-Prem CRM 3/4 days I would regularly customise the Dynamics CRM help files to add new topics and amend existing ones to match a company's solution. Context sensitive help was also possible by linking specific entities to specific help topics. With CRM2011 and the advent of the 'getting started pane' help became more of an inline experience with links being displayed above grids of records however customising the online help was no longer supported. CRM2013 removed the 'getting started pane' and so it was much harder to provide a customised help experience. I'm really pleased that the Dynamics CRM team has invested in this area in CRM 2015 in the form of the 'Custom Help URL' feature.

Global Help URL

If you navigate to Settings->Administration->System Settings you'll see the new Custom Help URL options. To use this new feature you must first enable 'Use custom Help for customizable entities'


You then have the option to provide a global help URL that will be used when users click the '?' icon on the top right of any refreshed UI page. It is also used when user click on the 'classic' style help icon on non-refreshed pages.

If the help button is clicked on an entity form then some contextual parameters are passed. For the Case entity the following are added to the Global Help URL:

entrypoint=form&formid=4a63c8d1-6c1e-48ec-9db4-3e6c7155334c&typename=incident&userlcid=1033

Solution Deployment vs. Content Management

You have the option to use either a relative URL that points to a WebResource as shown in the screenshot above but you can also use an absolute URL to content hosted outside of CRM. You can also then create a help URL per entity in the entity customisation properties as shown below.

The disadvantage with this external URL per entity approach is that this URL is likely to be different in your DEV/UAT/PROD environments and since this URL will be transferred with each solution deployment we'll have to update this setting every time we deploy.

I've found that although the software development lifecycle is usually a regulated release process, the help content authoring process tends to be more of an evolving one. With the CRM2011 getting started pane being linked to Web resources I always found it much harder to get this content updated due to the rigor of the deployment process. For this reason I now recommend not coupling your company's help content to your CRM solution's web resources but rather use an external content management system such as SharePoint. This allows you to then regular release updates and new content without having to schedule a new release and the down time associated to this.

But how do we avoid having to update the entity URLs on each DEV/UAT/PROD environment? We use only the Global Help URL in combination with the typename querystring parameter and not use the entity Help URL at all.

To do this in SharePoint:

1. First we must enable embedding of code into SharePoint pages.

2. Edit the SharePoint page that is the default landing page in the Global Help URL (e.g. SitePages/Home.aspx)

3. On the Insert ribbon tab, select 'Embed Code'

And paste the following code:

<script>
function getQueryStringArray(){
    var assoc=[]; 
    var items = window.location.search.substring(1).split('&'); 
    for(var j = 0; j < items.length; j++) { 
       var a = items[j].split('='); assoc[a[0]] = a[1]; 
    }
    return assoc;
}
var qs = getQueryStringArray();

if (qs.typename!=null)
{
  window.location.href = '/SitePages/' + qs.typename + '.aspx';
}
</script>

Now when CRM opens your Global Help URL it will redirect to the specific page for that entity passed on the typename. You can then create pages for each typename in the Site Pages library:

Since the Global Help URL is not solution aware, you can deploy your solution to multiple environments without having to change all those URLS with each deploy.

You can read more about this on Bryce Holmes' post on this feature. Read the Online Help about this feature and read Magnetism's blog on this feature.

Hope this helps!

@ScottDurow

Posted on 9. August 2014

SharePoint Integration Reloaded – Part 2

Part 1 of in this series described how SharePoint Server to Server SharePoint integration (new to CRM2013 SP1) works from the client interface perspective. In this post I'd like to share a bit more how this all works from the server side.

Authentication

When this feature was introduced my first question was about authentication. Having created a fair number of solutions that integrated SharePoint with Dynamics CRM on the server side I knew that this is a tricky area. Since this feature is only available for CRM Online to SharePoint Online where they are in the same tenant it makes authentication slightly simpler because there is already an existing trust in place between the two servers which allows Dynamics CRM to authenticate with SharePoint and act as the calling user. The HTTP request that comes from the client is inspected by the integration component and the UPN is used to authenticate with SharePoint as the same user rather than the service account. This is acting on behalf of the user is critical because when documents are created, checked in/out or queried, it must be performed under the account of the user and not the system account. Perhaps even more important, when CRM queries for documents it will only return those that the user has access to as configured in SharePoint.

If this feature is made available for On Prem customers I would expect that a configuration would have to be made available to provide the user's SharePoint username and password to use when performing server side operations.

Query SharePoint Documents

The new SharePoint sub grid that is rendered by CRM actually uses exactly the same query mechanism as any other entity – but rather than the query being sent to the CRM Database, it is handled by the SharePoint query handler. If you fire up Advanced Find, you'll see a new Entity named 'Documents' but if you query against this entity you will get the error:

The error is given by the SharePoint FetchXml conversion to CAML only works if a specific regarding object is provided – this means that you can only return records for a specific folder, rather than all documents in all document locations. When the refresh button is clicked on the client sub-grid there is FetchXml similar to the following executed:

<fetch distinct="false" no-lock="true" mapping="logical" page="1" count="50" returntotalrecordcount="true" >
    <entity name="sharepointdocument" >
        <attribute name="documentid" />
        <attribute name="fullname" />
        <attribute name="relativelocation" />
        <attribute name="sharepointcreatedon" />
        <attribute name="ischeckedout" />
        <attribute name="filetype" />
        <attribute name="fullname" />
        <attribute name="modified" />
        <attribute name="sharepointmodifiedby" />
        <attribute name="relativelocation" />
        <attribute name="documentid" />
        <attribute name="modified" />
        <attribute name="fullname" />
        <attribute name="title" />
        <attribute name="author" />
        <attribute name="sharepointcreatedon" />
        <attribute name="sharepointmodifiedby" />
        <attribute name="sharepointdocumentid" />
        <attribute name="filetype" />
        <attribute name="readurl" />
        <attribute name="editurl" />
        <attribute name="ischeckedout" />
        <attribute name="absoluteurl" />
        <filter type="and" >
            <condition attribute="regardingobjecttypecode" operator="eq" value="1" />
            <condition attribute="regardingobjectid" operator="eq" value="{1EF22CCD-9F19-E411-811D-6C3BE5A87DF0}" />
        </filter>
        <order attribute="relativelocation" descending="false" />
    </entity>
</fetch>

The interesting part here is that we can add filters not only by regarding object but we could also add our own filters for name or document type. Initially I was confused because running this Fetch query in the Xrm Toolbox FetchXml tester gave no results but as it turns out this uses the ExecuteFetchRequest rather than RetrieveMultiple and this new SharePoint integration is only implemented on the latter.

Internal Execute Messages

This new server to server functionality is exposed by a set of internal messages that are not documented in the SDK but by using Fiddler (the tool that give you super powers!), you can see these messages being called from the client when operation such as Check In/Check Out are called. Here is a list of these internal messages:

Message Name

Description

RetrieveMultipleRequest
(sharepointdocument)

Returns a list of document names from SharePoint for a specific document location. This query is converted into SharePoint CAML on the server and supports basic filter criteria and sorting.

NewDocumentRequest

Creates a new document location and matching SharePoint folder and is called when the documents sub grid is first shown with no document locations configured.

 

FileName – Name of the file to create including extension (e.g. NewDocument.docx)

RegardingObjectId – Guid of the record that the document location belongs to

RegardingObjectTypeCode – Object type code of the record the document location belongs to

LocationId – The ID of the document location to add the new document to (in case there are multiple)

CheckInDocumentRequest

CheckOutDocumentRequest

DisregardDocumentCheckoutRequest

This performs the check in/out operation on a specific document in SharePoint.

Entity – The document to check in/out with the 'documentid' property populated with the List Id in SharePoint.

CheckInComments

RetainCheckOut

CreateFolderRequest

Creates a new documents location in CRM and the corresponding SharePoint folder.

FolderName – the name to give to the SharePoint folder

RegardingObjectId – Guid of the record that the document location belongs to

RegardingObjectTypeCode – Object type code of the record the document location belongs to

 

Now before you get excited you can't use these requests on the server because you will get a 'The request <Request Name> cannot be invoked from the Sandbox.' (Yes, I did try!) This is expected since the sandbox does not have access to the HTTP context that contains the information about the calling user and so the authentication with SharePoint cannot take place.

I proved this using a Custom Workflow Activity that tried to call 'CreateFolder' and you see the following error.

These requests can however be called easily from JavaScript which opens up some interesting possibilities (if a little unsupported because these messages are not actually documented the SDK at the moment):

  1. Automatically create a document location using a different naming convention to the standard one via JavaScript onload of a record if there isn't one already.
  2. Provide a custom view of SharePoint documents using fetchxml – this could even be filtered to just show a particular file type by adding a condition similar to <condition attribute="filetype" operator="eq" value="jpeg"/>
  3. Provide custom buttons to create documents in SharePoint.

I hope you've found this interesting - Next time I'll show you how to get around the sandbox limitation to perform server side operation on SharePoint from a CRM Plugin or Workflow Activity.

@ScottDurow

Posted on 9. August 2014

Early Binding vs Late Binding Performance (Revisited)

After having an interesting debate on the CRM Community forums about the performance of Early verses Late Bound entities my friend Guido Preite pointed me at a good blog post on this subject by James Wood named 'CRM 2011 Early Binding vs Late Binding Performance'. I have always been an advocate of Early Bound types but it is true that the SDK still states in the 'Best Practices for Developing with Microsoft Dynamics CRM'

"…use of the Entity class results in slightly better performance than the early-bound entity types"

However it also states that that the disadvantages of using the late-bound Entity types is:

"…you cannot verify entity and attribute names at compile time"

I've seen many bugs introduced into code from the use of late bound types because typos can easily be introduced into the strings that are used to determine the entity and attribute logical names. Due to the productivity gains that come with Early Bound types I always recommend their use if the schema of your entities is known at compile time. There are times when this is not true or you are creating code that must run in a configurable way on many different entities or attributes in which case the late bound entity type is the only choice.

So what about performance?

  1. The SDK state that Late Bound types give 'slightly' better performance and states 'Serialization costs' as the reason.
  2. James' post states a 30% increase in speed for 200 Create operations, and <5% increased for 1500 operations.

So addressing each of these points in turn:

Although before CRM2011 there were serialization costs in using early bound types because they were serialised as part of the web service call, with CRM2011/2013 the early bound types just inherit from the Entity class and the early bound attribute properties simple set/get values from the underlying Attribute collection. The serialization when making SDK calls is effectively the same for both early and late. The main difference is due to the extra work that the OrganizationService Proxy has to do when converting the Early Bound type to the Entity type and then back against when it's received from the server. This is done using Reflection to first search for the Early bound classes and then by searching the classes for the one that matches the logical name received. This obviously will have a cost but it seems to be work that is done once per Service Channel and then cached to avoid any further cost.

James' tests are interesting but perhaps a bit misleading because the initial cost of this additional work is included in his overall speed calculations. This is probably why the overall percentage cost of early binding goes down as the number of records increases.

To remove this initial cost from the equation I adapted his code to introduce a warmup time. In tests I couldn't categorically show that either Late Bound or Early Bound had any performance difference once the OrganizationService was 'warmed up' with all reflection done and cached. In fact sometimes the test showed that early bound was quicker which leads me to believe that the main influencing factor is somewhere else like Database or Server performance. To make the results easier to interpret I have simply shown the average operation time after the warmup period. I also separated out the tests so that the Early Bound types were not compiled and picked in the Late Bound tests.

Each test was a warm up of creating 400 records and a run of creating 500 records.

Conclusions

Whilst it is true that using Early Bound classes incurs some cost of additional 'plumbing' – assuming that you are caching the WCF Service Channels (which the Microsoft.Xrm.Client.Services.OrganizationService does for you) because the difference in speed is so small (< there really is no reason not to use the Early Bound classes unless you have performance related issues and want to eliminate this as the cause.

If you are interesting, here is the code I used (based on James' code)

static void Main(string[] args)
{       
    int warmupCount = 400;
    int runCount = 500;
 
    CrmConnection connection = new CrmConnection("Xrm");
    var service = new OrganizationService(connection);
    
    CreateAccounts("Early Bound Test", warmupCount, runCount, () =>
    {
        Account a = new Account();
        a.Name = "Test Early Vs Late";
        service.Create(a);
    });


    CreateAccounts("Late Bound Test", warmupCount, runCount, () =>
    {
        Entity e = new Entity("account");
        e["name"] = "Test Early Vs Late";
        service.Create(e);
    });

    TidyUp();

    Console.WriteLine("Finished");
    Console.ReadKey();
}

static void CreateAccounts(String name, int warmup, int runs, Action action)
{
    Console.WriteLine("\n" + name);
    // Warm Up
    for (int i = 1; i <= warmup; i++)
    {
        if (i % 10 == 0)
            Console.Write("\r{0:P0}     Warmup   ", (((decimal)i / warmup) ));
        action();
    }

    // Run Test
    double runningTotal = 0;
    Stopwatch stopwatch = new Stopwatch();
    for (int i = 1; i <= runs; i++)
    {
        stopwatch.Reset();
        stopwatch.Start();
        action();
        stopwatch.Stop();
        runningTotal += stopwatch.ElapsedMilliseconds;
      
        double runningAverage = runningTotal / i;
        if (i % 10 == 0)
            Console.Write("\r{0:P0}     {1:N1}ms   ", (((decimal)i / runs)), runningAverage);
    }
}
Posted on 4. August 2014

SharePoint Integration Reloaded – Part 1

Back in the day when CRM2011 was first in beta I blogged about the exciting SharePoint integration and how it works. This post is about the exciting new server side SharePoint integration that is now available as part of CRM2013 SP1 Online.

There has already been some good posts on how to set up SharePoint sever-side Sync but in this series I'm going to explain how the server to server integration works in more detail and run through some scenarios of how it can be used for custom solutions.

CRM List Component Integration

Before CRM2013 SP1 was released the only option for SharePoint Integration was to use the CRM List Component. Each document location was surfaced on a record form record via an IFRAME that placed a SharePoint page inside the CRM page via the list component aspx page. This SharePoint page rendering the document library's default view with a CRM theme and provided the upload/download commands.

  1. The CRM form page is displayed in the browser and including an IFRAME that requested the configured document library page from SharePoint.
  2. The IFRAME shows the SharePoint document library styled to look like CRM. This required the user to be independently authenticated with SharePoint.
  3. Using any of the actions in the page (New/Upload etc.) sends requests directly to SharePoint.

Changing Landscape

This approach worked well but since the user was accessing SharePoint directly within the IFRAME they'd sometimes encounter authentication issues where they must be authenticated with SharePoint first and sometimes SharePoint needed to be configured to allow inclusion of content in IFRAMES. In addition to this the list component required a sandbox host to run but this feature is being phased out in SharePoint Online.

Server to Server SharePoint Integration (S2S)

With the introduction of CRM2013 SP1 a new type of integration has been developed that provides direct server to server integration between SharePoint and CRM thus removing the need for the user to be pre-authenticated with SharePoint on the client.

  1. The Record page includes a standard sub grid that is populated using the CRM entity query object model. CRM converts a RetrieveMultiple request on the SharePoint Document entity into SharePoint CAML (Collaborative Application Markup Language) query and sends it to the SharePoint Web Services. The important part here is that this query is run in the context of the currently logged on user and so they only see the document that they have access to in SharePoint (more on how this works in part 2 of this series).
  2. Documents are rendered inside the CRM Form HTML as a standard sub grid in the same way that any other record might be displayed.
  3. Using the New/Upload command bar buttons sends a request to CRM by way of an Execute Request in the same way that any other command bar buttons might do.
  4. CRM uses the SharePoint Web Service API to execute the requests and refreshes the sub grid.

This server to server integration only works for CRM Online/SharePoint Online combinations that are in the same tenant due to the nature of the server to server authentication and can be turned on in the Document Management Settings using the 'Enable server-based SharePoint integration'. There is a note that states that sandboxed solutions will not be supported in the future for SharePoint online.

Differences between List Component and Server-to-Server

Once S2S integration is enabled you'll see a similar view to the list component but it looks far more CRM2013 like. Apart from a slicker interface there are a few other differences:

Folder Support

The S2S sub grid doesn't support folders within the document library and so all documents are flattened down underneath the document location folder. The Location column does give you folder name which you can sort by to allow grouping by folder.

Custom Views

The great thing about having the documents queried by CRM is that you can create custom views of documents in the same way you would with any other entity in CRM. When using the list component the default view in SharePoint was rendered in the IFRAME meaning that to get new columns you had to have list customisation privileges on SharePoint such that all users would see the changes. With the new server to server integration you can select SharePoint columns to include in your own views and even add in your own filters using the CRM advance find interface. If you think about it – this is very cool!

Item Actions

The List Component was by nature very similar to the SharePoint list user interface and so it had more or less full support of actions that can be performed from SharePoint (with the exception of workflow operations). The server to server sub-grid provides all the main functions but with some options such as Alert Me, Send Short Cut, View History and Download a Copy being unavailable.

The S2S integration gives the following command bar actions:

This is in comparison to the List Component actions that are as shown below.

Inline Dialogs

With CRM2013's single page user experience any pop-out windows are supposed to be kept to a minimum. When using the list component operations (such as check-in/out) a new window would always pop out but with S2S integration an inline dialog shown instead. This really make it feel tightly integrated and slick.

Out of these differences, the lack of folder support is the only one that has had any significant effect on my solutions but actually can be seen as an advantage if using sub-folders to hold child entity documents. In this scenario all documents will be visible from the parent record's document view rather than rely on the user drilling down into each folder to see content.

That's all for now but in the next article in this series I'll show you more of how this functionality works under the covers.

Read Part 2

@ScottDurow

Posted on 2. August 2014

Polymorphic Workflow Activity Input Arguments

I often find myself creating 'utility' custom workflow activities that can be used on many different types of entity. One of the challenges with writing this kind of workflow activity is that InArguments can only accept a single type of entity (unlike activity regarding object fields).

The following code works well for accepting a reference to an account but if you want to accept account, contact or lead you'd need to create 3 input arguments. If you wanted to make the parameter accept a custom entity type that you don't know about when writing the workflow activity then you're stuck!

[Output("Document Location")]
[ReferenceTarget("account")]
public InArgument<EntityReference> EntityReference { get; set; }

There are a number of workarounds to this that I've tried over the years such as starting a child work flow and using the workflow activity context or creating an activity and using it's regarding object field – but I'd like to share with you the best approach I've found.

Dynamics CRM workflows and dialogs have a neat feature of being about to add Hyperlinks to records into emails/dialog responses etc. which is driven by a special attribute called 'Record Url(Dynamic)'

This field can be used also to provide all the information we need to pass an Entity Reference.

The sample I've provide is a simple Workflow Activity that accepts the Record Url and returns the Guid of the record as a string and the Entity Logical Name – this isn't much use on its own, but you'll be able to use the DynamicUrlParser.cs class in your own Workflow Activities.

[Input("Record Dynamic Url")]
[RequiredArgument]
public InArgument<string> RecordUrl { get; set; }
The DynamicUrlParser class can then be used as follows:

var entityReference = new DynamicUrlParser(RecordUrl.Get<string>(executionContext));
RecordGuid.Set(executionContext, entityReference.Id.ToString());
EntityLogicalName.Set(executionContext, entityReference.GetEntityLogicalName(service));

 

The full sample can be found in my MSDN Code Gallery.

@ScottDurow

Posted on 26. July 2014

'Error while copying content to a stream' when pushing to Git

Whilst pushing a recent commit on SparkleXRM I recieved the following error:

An error was raised by libgit2. Category = Net (Error). Error while copying content to a stream.

I turned it off again (rebooted), and used fiddler to trace what was going with no luck. In a last ditch attempt I changed the networking on my virtual machine from NAT to Bridged and hey presto it worked agiain.

So it seems that Git doesn't like NATed connections from Virtual Machines.

Hope this helps someone else!

 

Posted on 26. July 2014

Creating a Contact Card List Web Resource with Images

Sparkle XRM provides a great way of creating grids and forms that look and work similar to Dynamics CRM but sometimes you need to create a responsive user interface that is a little different. Luckily there is a wealth of jQuery plugins out there that provide a great starting point. For this post I'm going to show you how to use FreeWall to create a dynamic grid layout of contact cards but the same approach would apply for any other plugin that isn't included in the core Sparkle XRM dependencies library. This sample creates an HTML web resource that lays out your contacts in a responsive grid that resizes depending on the size available.

Create the Script# Import

Whenever we need to use an external library from Sparkle XRM, the external API must be defined as imported classes. For FreeWall we must import the jQuery plugin and the configuration options class. Notice that the [ScriptName("Object")] is used on the configuration options so that although our Script# class uses a strongly typed class, the JavaScript compiled uses an anonymous type so as not to create unnecessary class prototypes.

Create the View Model

It is a good idea to start with the View Model since this defines all the functionality that the View must expose as well as communicating with the server. For this sample we have a simple view model that simply loads a list of contacts into a list so that FreeWall can be bound to it to display our contact cards. It also provides a function to get the Image Url of the contact and return a placeholder image if no image is defined. The contact image can be found by returning the attribute with logical name 'entityimage_url'

Include the library JS

Once you've selected the library you want to use, you'll need to include it in your Crm Solution project under the js folder, and give it a UniqueName and Display Name similar to dev1_/js/freewall.js

Create the HTML View

The HTML View should be added to the html folder and must contain the scaffolding to hook the jQuery library into and initialise the View code. The data binding is done using Knockout's built in templating engine using the 'template' binding.

Create the View Class

The view class's job is to instantiate the View Model and initialise the binding.

Notice the OnAfterRender call back – this is called every time a new contact card is rendered because of the binding afterRender: Client.InlineSubGrids.Views.ContactCardView.onAfterRender in the HTML. If this is not done then the freewall grid will not layout until the window is resized.

The result is a nice and responsive layout that optimises the fill the available space and has variable height blocks.

@ScottDurow

Posted on 9. June 2014

Multi Entity Search for CRM2013

I've just published an update to my Multi-Entity Search Solution (after being encouraged by my friend and fellow Dynamics CRM MVP Gus Gonzalez!).

Features:

  1. Search across multiple entities at once.
  2. Uses the same configuration as the mobile client 'Quick Find' (Settings->General ->Set Up Quick Find). This allows you to select which entities you would like to search across.
  3. Virtual Scrolling with new records loaded as you scroll rather than all loaded at once.
  4. Shows the primary entity image of returned records (if there is one) in the search results.

 

In the new version you'll find:

  1. A search button added to the top navigation bar* rather than using a Command Bar button.
  2. Auto searching as you type the search term
  3. Mouse Wheel horizontal scrolling support

*Since there is no supported way of doing this, I've had to do a little DOM shenanigans to get this to work the way Gus wanted!

To try it out you'll need to install the following 2 managed solutions:

If you like this, you might also like to check out my Start Menu Navigation for CRM2013!

@ScottDurow

Posted on 6. June 2014

Monitor, Monitor, Monitor

I once heard someone say that "the great thing about Dynamics CRM is that it just looks after itself" Whilst CRM2013 is certainly very good at performing maintenance tasks automatically, if you have a customised system it is important to Monitor, Monitor, Monitor! There are some advanced ways of setting up monitoring using tools such as System Center but just some regular simple monitoring tasks will go a long way for very little investment on your part:

1) Plugin Execution Monitoring

There is a super little entity called 'Plugin-in Type Statistics' that often seems to be overlooked in the long list of advanced find entities. This entity is invaluable for tracing down issues before they cause problems for your users and as defined by the SDK it is "used by the Microsoft Dynamics CRM 2011 and Microsoft Dynamics CRM Online platforms to record execution statistics for plug-ins registered in the sandbox (isolation mode)."

The key here is that it only records statistics for your sandboxed plugins. Unless there is a good reason not to (security access etc.) I would recommend that all of your plugins be registered in sandbox isolation. Of course Dynamics CRM online only allows sandboxed plugins anyway so you don't want to put up barriers not to move to the cloud.

To monitor this you can use advanced to show a sorted list by execution time or failure count descending:

If you spot any issues you can then proactively investigate them before they become a problem. In the screen shot above there are a few plugins that are taking more than 1000ms (1 second) to execute, but their execution count is low. I look for plugins that have a high execution count and high execution time, or those that have a high failure percent.

2) Workflow & Asynchronous Job Execution Monitoring

We all know workflows often can start failing for various reasons. Because of their asynchronous nature these failures can go unnoticed by users until it's too late and you have thousands of issues to correct. To proactively monitor this you can create a view (and even add to a dashboard) of System Jobs filtered by Status = Failed or Waiting and where the Message contains data. The Message attribute contains the full error description and stack trace, but the Friendly message just contains the information that is displayed at the top of the workflow form in the notification box.

3) Client Latency & Bandwidth Monitoring

Now that you've got the server-side under control you should also look at the client connectivity of your users. There is a special diagnostics hidden page that can be accessed by using a URL of the format:

http://<YourCRMServerURL>/tools/diagnostics/diag.aspx

As described by the implementation guide topic, "Microsoft Dynamics CRM is designed to work best over networks that have the following elements:

  • Bandwidth greater than 50 KB/sec
  • Latency under 150 ms"

After you click 'Run' on this test page you will get results similar to that shown below. You can see that this user is just above these requirements!

You can read more about the Diagnostic Page in Dynamics CRM. You can also monitor the client side using the techniques I describe in my series on Fiddler:

If you take these simple steps to proactively monitor your Dynamics CRM solution then you are much less likely to have a problem that goes un-noticed until you get 'that call'!

@ScottDurow

Posted on 1. June 2014

My top 3 fixes in CRM2013 SP1

There are great many new features shipped in CRM2013 SP1 but let's not forget there are some eagerly awaited fixes as well (as described by http://support.microsoft.com/default.aspx?kbid=2941390) Since there has already been plenty of coverage of the new features, I thought I would pick out my top 3 fixes that I've been particularly waiting for…Queue up the charts count-down soundtrack!

In at Number 3: Matching Connection Roles

Connections are a great way of providing users with an overview of a contact's involvement with all areas of your business. Right from within a contact record users can see the roles that the contact has across different record types such as accounts, cases, and opportunities. Roles are specified on each side of the connection and in many cases you need to have the same role on both sides. In CRM2011 this was possible but strangely with CRM2013 the same role could not be specified as the matching role with the issue being described by the KB article as "In Microsoft Dynamics CRM 2013, users are unable to set a Matching Connection Role to the same Connection Role." Up until now the work around was to create a different role but with the same name but I've tested this in SP1 and I'm pleased to report that it now works the same as it did in CRM2011.

New at Number 2: Importing solution fails when plugins attached to custom actions

The addition of custom actions to CRM2013 was fantastic for creating custom server logic that is called from JavaScript. Unfortunately when you attached a plugin to a custom action message and imported a solution containing that plugin it would fail (See the Microsoft Connect article for this issue). I have held back from using this feature up until now due to the pain it created during deployments but now that it is fixed in SP1 I'm going to be making a lot more use of Custom Action plugins!

UPDATE: Actually, the connect item for this issue is not entirely correct - this will be fixed in one of the next Update Rollups of CRM 2013 SP1

…and this Service Pack's Number 1 Fix is: "Found more than one RibbonDiff entity"

This message is likely a very familiar message to anyone who has made customisations to the Ribbon with CRM2011 (as described by http://support.microsoft.com/kb/2503029). The message was shown when importing customisations and was usually down to there being more than one element in the ribbon xml that had been given the same ID. When CRM2013 was released the message started popping up far more frequently. Initially I was worried it was due to an issue with Ribbon Workbench but eventually I tracked it down to the fact that elements were being duplicated when a solution was exported from CRM2013. The Ribbon Workbench resolves duplicate IDs automatically so the issue only caused problems when transferring a solution between environments through an export/import but what was more confusing is that the issue would only happen on the second import. There is a line in the KB article for SP1 that describes the issue as:

"When we import, the import logic creates two values for each entry within the RibbonDifBase. But When we export the application ribbon we do not have any check for this and we export 2 values directly from the DB to the XML. This if imported to a new org will create 4 values in the table RibbonDiffBase. If the solution is imported again to the same org causes an error"

The Microsoft Connect item for this issue is still marked as active but I've tried to reproduce the issue in SP1 and so far so good! Well done Dynamics CRM Product team!

Poptastic!

@ScottDurow