Posted on 30. December 2010

Automatically Generate CRM2011 Entity Data Model Documentation

I am a firm believer in using a tool to generate documentation; it makes it more accurate and ultimately more useful. With CRM 4.0 we used a tool that parsed the Customizations.xml to produce the documentation. A significant difference between CRM2011 and CRM4.0 is the managed solutions approach to customisations, making it much easier to move customisations between environments. However as a result of this change, the way that entity metadata is imported/exported has changed so that managed (out of the box) attributes are no longer included in the customizations.xml. This means that it is no longer possible to generate documentation from the customizations.xml and so any such tool must call the Organizations.svc web service to retrieve the metadata.

With this in mind, I spent some time this Christmas (in between eating turkey left overs) writing a Microsoft Word 2010 Add-In to aid the documentation process.

Download CRM2011WordDocumentor.zip (29.45 kb)

Merry Christmas and a Happy New Year!

Posted on 17. December 2010

Speed up JavaScript Web Resource development time

Don't waste time re-publishing JavaScript web resources during development

The new solution framework in Dynamics CRM 2011 is a fantastic addition to the Xrm platform – especially with the new Web Resources functionality. The ability to include JavaScript files rather than including the script in the form customisations makes the management of source code much easier.

This post shows a method that allows rapid changes to be made to the JavaScript code without the lengthy process of uploading the updated file and then re-publishing it. The key here is that whilst we are developing, we are going to use a 'stub' JavaScript web resource that simply bootstraps the actual JavaScript that we are working on from the file system.

When you are ready to publish your solution, you will replace the 'Stub' with the actual JavaScript file you have developed.

In this example we are creating JavaScript for the Contact Form.

1) Create 'ContactForm.js' file

///
if (typeof (Develop1) == "undefined")
{ Develop1= {}; }
Develop1.EntityForm = {
    onLoad: function () {
        var attribute = Xrm.Page.data.entity.attributes.get('salutation');
        var delegate = function () {
            Develop1.EntityForm.salutation_onchange(attribute);
        };
        attribute.addOnChange(delegate);

    },

    salutation_onchange: function(sender) {
        alert(sender.getName());
    }
}


 

This script simply provides an onload function that will be called from the form, and 'wires up' an event handler to the salutation onchange event. Notice that we don't need to add any messy script to the form event handlers in the CRM form designer anymore, we can do this programmatically.

I am going to store my script in the Dynamics CRM ISV folder whilst I work on it – however you can use any location accessible via a URL. The ISV folder is now deprecated and will be removed in future versions, but it is convenient since we can use relative paths to access it. Correspondingly save this file in a folder with the same name as your organisation underneath the ISV folder. E.g. ISV\<YourOrgName>\ContactForm.js.

To ease development, you can add this to a Visual Studio project using a File Link.

2) Create the 'ContactForm_stub.js'

var scriptHtml = '<script language="javascript" src="\/ISV\/' + Xrm.Page.context.getOrgUniqueName() + '\/contactForm.js"><\/script>';
var scriptElement = document.createElement(scriptHtml);
document.documentElement.appendChild(scriptElement);

 

3) Upload the 'ContactForm_stub.js' as a web resource

Inside your solution, upload the ContactForm_stub.js.

Important: Name it as though you are uploading the actual JavaScript file since you will replace it before you export your solution.

4) Add reference to the contact form

Within the CRM Contact form designer, add a reference to the ContactForm.js web resource and add an onload event handler that calls the function:

Develop1.EntityForm.onLoad

 

5) Publish once, then test, edit, test, edit…

Publish your web resource and form customisations, and you'll find that you can edit the ContactForm.js file in the ISV folder with the effects happening immediately you refresh your contact form.

6) When you're done, before you export your solution

Now that you've got your JavaScript working, before you export your solution, you want to remove the dependency on that external file, so you can simply edit your ContactForm web resource and upload the external file, thus replacing the stub.

You will find that this greatly reduces the time it takes to author and debug your form JavaScript.

Posted on 15. December 2010

Things Dynamics CRM 4.0 Developers must know about CRM 2011 #1:

Nulls are handled differently by the SDK Web services:

Using the CRM 4.0 SDK webservice and pipeline context, you could always exclude an attribute from an update by setting it to null. This has now changed:

CRM 4.0:

entity.attributename = null;

CRM 2011:

entity.Remove("attributename");

 

Data loss when using the RESTfull endpoint

When using the CRM 4.0 SDK  Webservices, you could choose to only return certain attribute values and then when updating only update those values provided whilst leaving the rest the same as they were on the server. This is very desirable to facilitate concurrency (we don't want to send any update to an attribute if we are not actually updating it) and to minimise the traffic between the client and server (don't send/return every attribute with each call).

In CRM2011 however using the OData endpoint this is no longer possible. All values must be retrieved and re-set when updating.

For example, we can use projection onto an Entity to manipulate the $select on the OrganisationData.svc:

 var queryVar = from c in _context.ContactSet
                  where c.FullName.Contains(criteria)
                  select new Contact {
                    FullName = c.FullName,
                    Telephone1 = c.Telephone1,
                    EMailAddress1 = c.EMailAddress1,
                    FirstName = c.FirstName,
                    LastName = c.LastName,
                    Address1_Line1 = c.Address1_Line1,
                    Address1_City = c.Address1_City,
                    Address1_StateOrProvince = c.Address1_StateOrProvince,
                    Address1_PostalCode = c.Address1_PostalCode
                };

This code uses the following GET:

http://{server}:5555/{orgname}/xrmservices/2011/organizationdata.svc/ContactSet()?$filter=FullName%20eq%20'{crtieria}'&$select=FullName,Telephone1,EMailAddress1,etc...

This will only pull down the attributes we need to display.

All good so far.

However, when using the DataContext to update the record on the server using:

_context.BeginSaveChanges(OnSaveContactsComplete, TheMainViewModel.Contacts);
...

We find that all the data that we didn't include in the $select is now nulled out.

This is a common problem with ADO.Net data services and is indeed detailed as "Data loss might occur in the data service when you save updates that were made to projected types." in http://msdn.microsoft.com/en-us/library/ee473425.aspx

This seems like a big flaw to the OData endpoint - in that it forces us to retrieve all values if we want to make any updates at all via the Client OData API. This might be a good reason to avoid the RESTful endpoint unless you know up front that you will never be updating data. The overhead having to retrieving *all* values before performing an update is not something that you want.

 

There is always an exception...

Since JScript RESTful operations use the JSON notation to send data to the server rather than the OData framework, we can perform partial updates as shown by this JScript in the SDK example 'JScriptRestDataOperations:

function updateAccountRecord(Id) {

 var updateAccountReq = new XMLHttpRequest();
 var changes = new Object();
 changes.Name = "Updated Sample";
 changes.Telephone1 = "555-0123";
 changes.AccountNumber = "ABCDEFGHIJ";
 changes.EMailAddress1 = "someone1@example.com";

 updateAccountReq.open("POST", ODataPath + "/AccountSet(guid'" + Id + "')", true);
 updateAccountReq.setRequestHeader("Accept", "application/json");
 updateAccountReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
 updateAccountReq.setRequestHeader("X-HTTP-Method", "MERGE");
 updateAccountReq.onreadystatechange = function () {
  updateAccountReqCallBack(this, Id);
 };
 updateAccountReq.send(JSON.stringify(changes));
}

This code will only update the Name, Telephone1, AccountNumber and EmailAddress1 attributes, and leave the rest unchanged. Note that the attribute names are Case Sensitive.

Posted on 15. December 2010

Microsoft Dynamics CRM 2011 Release Candidate is available for download

The next major milestone in the release schedule for Dynamics CRM 2011 has been reached with the Release Candidate being available for download:

Download Dynamics CRM 2011 Release Candidate

This is said to be the last externally available release before RTM.
It seems that although the Team blog states that "On-premises Beta databases can be upgraded to this new RC release which can then be upgraded to the upcoming RTM release.", what that actually means is that you must un-install your Beta 1, install RC1, and then import the organisation database using the deployment manager.
Read more on the Dynamics Team Blog

Posted on 7. December 2010

Cloud CRM for Less: $200 Cash back per seat

Microsoft have announced a new promotion called 'Cloud CRM for Less' that targets Oracle and Salesforce.com customers offering USD200 per seat cash back:

http://www.microsoft.com/Presspass/press/2010/dec10/12-06OpenLetterPR.mspx

http://www.cloudCRMforLess.com

Posted on 2. December 2010

Unit Testing Dynamics CRM 2011 Pipeline Plugins using Rhino Mocks

It’s been a while since Dynamics CRM 2011 Beta 1 was released (surely we are due Beta 2 soon!) so I thought it was about time I set up a Unit Test framework for PlugIns. I’ve been using Rhino Mocks for a while to great effect, so here we go!

This example aims to unit test the SDK sample Plugins, and demonstrates the following:

    • Mocking the pipeline context, target and output property bags.
    • Mocking the Organisation Service.
    • How to assert that exceptions are raised by a plugin
    • How to assert that the correct Organisation Service method was called with the desired values.

To build the examples, you’ll need the CRM2011 SDK example plugins and Rhino Mocks 3.6 (http://ayende.com/Blog/archive/2009/09/01/rhino-mocks-3.6.aspx). 

The key principle of mocking is that we can exercise and examine the code that we need to test without executing the bits that are not being tested. By mocking we are fixing behaviour and return values of the dependant code so that we can assert if the results are what we expect.  This approach supports Test Driven Development (TDD), where the test is written first and then the desired functionality is added in order that the test passes. We can then say we are ‘Done’ when all tests pass. 

So in our example, the Followup Plugin should create a task with the regarding id set to the id of the account. So by mocking the pipeline context, we can specify the account id, and check that the resulting task that is created is regarding the same account. Using Rhino Mocks allows us to create a mock Organisation Service and assert that the Create method was called passing a task with the desired attributes set.

 

[TestMethod]
public void FollowupPlugin_CheckFollowupCreated()
{
    RhinoMocks.Logger = new TextWriterExpectationLogger(Console.Out);

    // Setup Pipeline Execution Context Stub
    var serviceProvider = MockRepository.GenerateStub();
    var pipelineContext = MockRepository.GenerateStub();
    Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
        serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
    serviceProvider.Stub(x => x.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext))).Return(pipelineContext);

    // Add the target entity
    ParameterCollection inputParameters = new ParameterCollection();
    inputParameters.Add("Target", new Entity("account"));
    pipelineContext.Stub(x => x.InputParameters).Return(inputParameters);

    // Add the output parameters
    ParameterCollection outputParameters = new ParameterCollection();
    Guid entityId= Guid.NewGuid();

    outputParameters.Add("id", entityId);
    pipelineContext.Stub(x => x.OutputParameters).Return(outputParameters);

    // Create mock OrganisationService
    var organizationServiceFactory = MockRepository.GenerateStub();
    serviceProvider.Stub(x => x.GetService(typeof(Microsoft.Xrm.Sdk.IOrganizationServiceFactory))).Return(organizationServiceFactory);
    var organizationService = MockRepository.GenerateMock();
    organizationServiceFactory.Stub(x => x.CreateOrganizationService(Guid.Empty)).Return(organizationService);

            
    // Execute Plugin
    FollowupPlugin plugin = new FollowupPlugin();
    plugin.Execute(serviceProvider);

    // Assert the task was created
    organizationService.AssertWasCalled(x => x.Create(Arg.Is.NotNull));

    organizationService.AssertWasCalled(x => x.Create(Arg.Matches(s => 
            ((EntityReference)s.Attributes["regardingobjectid"]).Id.ToString() == entityId.ToString()
            &&
            s.Attributes["subject"].ToString() == "Send e-mail to the new customer."
            )));
          
}

The key thing to notice is that the only mock object here is the OrganisationService - all others are stubs. The difference between a stub and a mock is that the mock records the calls that are made so that they can be verified after the test has been run. In this case we are verifying that the Create method was called with the correct properties set on the task entity.

It’s worth noting the RhinoMocks.Logger assignment. This gives the Rhino logging output in the VS2010 test results; most helpful during debugging asserts that don’t do as you expect.

Looking at the sample Account Plugin, it throws an exception when the account number is already set - so what testing that plugin’s throw exceptions under some conditions. Unfortunately, the standard VS2011 ExpectedExceptionAttribute doesn’t provide the functionality we need here since we can’t check exception attributes, nor can we run the tests in Debug without the Debugger breaking into the code even though the exception is marked as being expected. In order to get around this this I use a class written by Keith E. Burnell:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Kb.Research.RhinoMocks.UnitTests.CusomAssertions
{
    /// 
    /// Custom assertion class for unit testing expected exceptions.  
    /// A replacement for the ExpectedException attribute in MSTest
    /// 
    public static class AssertException
    {
        #region Methods

        /// 
        /// Validates that the supplied delegate throws an exception of the supplied type
        /// 
        /// Type of exception that is expected to be thrown
        /// Delegate that is expected to throw an exception of type 
        public static void Throws<TExpectedExceptionType>(Action actionThatThrows) where TExpectedExceptionType : Exception
        {
            try
            {
                actionThatThrows();
            }
            catch (Exception ex)
            {
                Assert.IsInstanceOfType(ex, typeof(TExpectedExceptionType), String.Format("Expected exception of type {0} but exception of type {1} was thrown.", typeof(TExpectedExceptionType), ex.GetType()));
                return;
            }
            Assert.Fail(String.Format("Expected exception of type {0} but no exception was thrown.", typeof(TExpectedExceptionType)));
        }

        /// 
        /// Validates that the supplied delegate throws an exception of the supplied type
        /// 
        /// Type of exception that is expected to be thrown
        /// Expected message that will be included in the thrown exception
        /// Delegate that is expected to throw an exception of type 
        public static void Throws<TExpectedExceptionType>(string expectedMessage, Action actionThatThrows) where TExpectedExceptionType : Exception
        {
            try
            {
                actionThatThrows();
            }
            catch (Exception ex)
            {
                Assert.IsInstanceOfType(ex, typeof(TExpectedExceptionType), String.Format("Expected exception of type {0} but exception of type {1} was thrown.", typeof(TExpectedExceptionType), ex.GetType()));
                Assert.AreEqual(expectedMessage, ex.Message, String.Format("Expected exception with message '{0}' but exception with message '{1}' was thrown.", ex.Message, expectedMessage));
                return;
            }
            Assert.Fail(String.Format("Expected exception of type {0} but no exception was thrown.", typeof(TExpectedExceptionType)));
        }

        #endregion

    }
}

So, we want to test that if the account number is already set on execution of the AccountNumberPlugin, then an exception is raised:

[TestMethod]
public void AccountNumberPlugin_CheckExceptionIfAccountNumberSetAllready()
{
    // Setup Pipeline Execution Context Stub
    var serviceProvider = MockRepository.GenerateStub();
    var pipelineContext = MockRepository.GenerateStub();
    Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
        serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
    serviceProvider.Stub(x => x.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext))).Return(pipelineContext);

    // Add the target entity
    ParameterCollection inputParameters = new ParameterCollection();
    inputParameters.Add("Target",new Entity("account") { Attributes = new AttributeCollection  { 
            new KeyValuePair("accountnumber", "123")
        }});

    pipelineContext.Stub(x => x.InputParameters).Return(inputParameters);

    // Test that an exception is thrown if the account number already exists
    AccountNumberPlugin plugin = new AccountNumberPlugin();
    AssertException.Throws < InvalidPluginExecutionException> ("The account number can only be set by the system.",(Action) delegate {
            plugin.Execute(serviceProvider);
            });

}

The examples above show how to test plugins that don’t call any external services or code - where all dependencies are discovered via the execution context. Next time I’ll provide an example of how to mock an external service using inversion of control.