Clean Coding with CRM Late Bound Entities

This week I was speaking with Daryl LaBar regarding the respective merits of CRM Early and Late Bound Entities. I prefer Late Bound, to me it provides an easier, streamlined development experience. Daryl asked me to provide some example code to demonstrate my approach, so I’ve built a simple app to do so. I’ll accompany the app with some reasoning for a Late Bound preference.

console

In no particular order I prefer Late Bound for the following reasons, it’s worth nothing that this applies to all CRM development (not just the console app I demonstrate here).

I tend to abstract my application logic away from any CRM Entity objects, Late Bound or otherwise. This means I don’t especially benefit from Early Bound entity objects.

Early Bound brings a bit of bulk with it, and it requires an extra few steps to setup. Whilst this isn’t an overly onerous process, it’s something I don’t have to worry about with Late Bound. With Late Bound you can be up and running quickly after a couple of Nuget installs, it just feels easier and quicker.

Early Bound provides compile time checking against the CRM entity schema, and helps to highlight breaking changes in the schema. This is nice, however breaking changes don’t happen that often, and regardless of if you are using Early or Late Bound additional work is required to resolve the issue.

I tend to achieve around 90%+ code coverage using Visual Studio Coded Unit Tests. This means my work is almost fully tested before deployment (even with plugins or custom workflow activities). This significantly mitigates the lack of compile time checking offered by Early Bound.

A final reason, and a far less important one is that Late Bound is faster, a subject I wrote about some time ago. It’s worth noting, the performance difference is slight, and I’m not suggesting Early Bound is in anyway especially slow. If you are about to choose between Early and Late Bound I would not base the decision on the performance, I would base it on the development experience you want to enjoy.

In my development approach I strive to achieve an abstraction of the application logic away from any CRM Entity objects, Service calls, or other CRM constructs, e.g. CodeActivity. I normally create new classes to represent my application data and perform application logic. In this I hope to achieve a relatively clean and flexible class model. I find this makes it easier to write coded unit tests. You can reduce the CRM service baggage that comes with a plugin (or custom workflow activity) into a small area of the code. There is more flexibility to test business logic without requiring a live CRM connection.

I usually structure my applications in the following manner (though my approach tends to change and evolve on a regular basis).

Application structure.png

  • The application logic sits in a single class, and uses the other classes to perform work. (In this particular example I’ve left the application logic within the console app Main function. Normally I would place the logic in its own class. For example; if this was a plugin I would separate the application logic from within the confines of the Execute function).
  • Factory classes, these read CRM and create data objects.
  • Commander classes, these consume data objects and make changes to CRM.
  • Data object classes, these represent the data from CRM I actually want to work with along with any relevant application logic specific to the data objects.

This breaks the application down into easily maintainable and testable chunks. The application logic is totally abstracted from CRM. I could create a MockFactory to test variations of data objects. I can test my logic without being connected to CRM. I have tightly defined data objects which only feature properties for the information I’m actually going to use. Ultimately when using your own classes you have far more control over your app.

Finally it’s worth nothing that nothing in this approach actually requires the use of the Late or Early Bound entities. This approach would work equally well with Early Bound. I just find this approach negates the major benefits of Early Bound, so I use Late Bound for its ease and simplicity.

On to the example app then! This is somewhat contrived but is fairly representative of my development style. The application features the following:

  • It’s a console application using the IOrganizationService to connect to CRM. The connection string is stored in the app.config.
  • The application initially connects to CRM and prints the user name and Id.
  • The user is then prompted for a task description, and priority value expressed as a single letter value.
  • The app then creates a task in CRM with the given description and priority.

console

Within this example code in an attempt to remain concise I’ve left out a number of bits I would normally add, e.g. null checks, method comments, full unit testing, etc, etc.

Data Objects

I have two data objects in my example console application Task and User.

User represents a CRM user record. I only need the Idand FullName so that’s all it’s got. Additionally I’ve added a custom ToString function to enable easy Console writing – a simple example of application logic within a data object.

public class User
{
    public Guid Id { get; private set; }

    public string FullName { get; private set; }

    public User(Guid id, string fullName)
    {
        Id = id;
        FullName = fullName;
    }

    public override string ToString()
    {
        return $"Hello: {FullName} ({Id})";
    }
}

Task represents a CRM task record. As well as a few standard CRM data fields, it also holds application specific data – PriorityValue. This is a value captured from user input, which we will use the to calculate the Priority value we send to CRM later. Application logic within the Priority switch coverts the user inputted character into an enum. The Priority enum matches the priority field in CRM, the numeric values of the enum match those on the option set in CRM, this will be handy later on.

public enum Priority
{
    Low = 0,
    Normal = 1,
    High = 2
}

public class Task
{
    public string Subject { get; private set; }

    public string Description { get; private set; }

    public string PriorityValue { get; private set; }

    public Priority Priority
    {
        get
        {
            switch (PriorityValue)
            {
                case "L":
                    return Priority.Low;
                case "N":
                    return Priority.Normal;
                case "H":
                    return Priority.High;
                default:
                    return Priority.Low;
            }
        }
    }            

    public Task(string subject, string description, string priorityValue)
    {
        Subject = subject;
        Description = description;
        PriorityValue = priorityValue;
    }
}

Factories

I have a single factory in this example, UserFactory. This creates User objects by querying CRM for data.

public class UserFactory
{
    IOrganizationService Service { get; set; }

    public UserFactory(IOrganizationService service)
    {
        Service = service;
    }

    public User Build()
    {
        Guid userId = ((WhoAmIResponse)Service.Execute(new WhoAmIRequest())).UserId;

        Entity e = Service.Retrieve("systemuser", userId, new ColumnSet("fullname"));

        return new User(userId, e.GetAttributeValue<string>("fullname"));
    }
}

Commanders

I have a single commander, TaskCommander. This consumes a User and Task, and then creates a task record in CRM. Note how the OptionSetValue is set. I just cast the enum to an int. This works because enum numeric values match the numeric option set values in CRM.

public class TaskCommander
{
    IOrganizationService Service { get; set; }

    public TaskCommander(IOrganizationService service)
    {
        Service = service;
    }

    public Guid Create(User user, Task task)
    {
        Entity e = new Entity("task");
        e["subject"] = task.Subject;
        e["description"] = task.Description;
        e["prioritycode"] = new OptionSetValue((int)task.Priority);
        e["ownerid"] = new EntityReference("systemuser", user.Id);
        return Service.Create(e);
    }
}

Application Code

The beating heart of the console application. The Main function creates a connection to CRM (if I was being a bit more thorough I would make a ServiceFactory to produce the IOrganizationService). It then users the UserFactory to create a User object which is printed to screen. The app then captures a bit of user input. Then the app creates a Task object with those user inputs, and saves it into CRM using the TaskCommander. Finally the details are printed to screen.

class Program
{
    static void Main(string[] args)
    {
        //Build CRM connection
        CrmServiceClient serviceClient = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Xrm"].ConnectionString);
        IOrganizationService service = serviceClient.OrganizationServiceProxy;

        //Get the current user details and print
        UserFactory userFactory = new UserFactory(service);                    

        User user = userFactory.Build();

        Console.WriteLine(user);

        //Capture task inputs
        Console.WriteLine("Please enter your description:");
        string description = Console.ReadLine();

        Console.WriteLine("Please enter your priority (L, N, H):");
        string priority = Console.ReadLine();

        //Create the task
        Task task = new Task(DateTime.Now.ToShortTimeString(), description, priority);

        TaskCommander taskCommander = new TaskCommander(service);            

        taskCommander.Create(user, task);

        //End
        Console.WriteLine($"Task created as {task.Priority}.");
        Console.ReadKey();
    }
}

Testing

If you read this far, well done, you get some bonus testing code! I normally use the [TestClass] provided within Visual Studio for my testing. I also use FluentAssertions to make the testing a little easier. Normally I would have separate test classes but I have combined them for this demonstration.

UserFactory() performs a simple test to create a User and check its properties are as expected.

PriorityNormal() goes a little further. First it creates a Task and checks the application logic is working correctly – "H" gets converted to Priority.High. It then pushes the Task into CRM using the TaskCommander. I perform a Service.Retrieve to check the "prioritycode" is set as expected.

This isn’t full and thorough testing, but should hopefully give you a flavour of my approach.

public class DemoTests
{
    static IOrganizationService Service;

    [ClassInitialize]
    public static void ClassInit(TestContext context)
    {
        CrmServiceClient serviceClient = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Xrm"].ConnectionString);
        Service = serviceClient.OrganizationServiceProxy;
    }

    [TestMethod]
    public void UserFactory()
    {
        User user = new UserFactory(Service).Build();

        user.FullName.Should().Be("# Gap Consulting");
    }

    [TestMethod]
    public void PriorityNormal()
    {
        Task task = new Task("Test", "Test", "H");

        task.Priority.Should().Be(Priority.High);

        Guid taskId = new TaskCommander(Service).Create(new UserFactory(Service).Build(), task);

        Entity e = Service.Retrieve("task", taskId, new ColumnSet("prioritycode"));

        e.GetAttributeValue<OptionSetValue>("prioritycode").Value.Should().Be((int)Priority.High);
    }
}

In Summary

I don’t dislike Early Binding, I don’t think Early Binding is in anyway a bad choice. I just think Late Binding is better and easier to work with, though in many ways that’s because of my coding and development style.

Hopefully you found this interesting, cheers.

Advertisements

4 thoughts on “Clean Coding with CRM Late Bound Entities

  1. Hi James, very interesting post :).

    I’ve recently started to work in a similar way: decoupling completely the business logic from CRM plugins/custom workflow activities, separating also the data access (implementing a repository pattern), trying to maintain a high code coverage of unit test, which basically ends up in all the advantages that you already mentioned. A difference though, is that we’re not using domain objects (or data object as you call them) but early bound entities. I believe that it would be great to use your approach, but I also consider that there’s some extra work that has to be done and that’s exactly what I want to ask you about:

    1) Do you have an automated or a simple process to keep up to date your domain objects? You mentioned the overhead of generating the early bound classes but this approach seems to have the same “problem” plus maintaining also the mappings with the CRM entity.
    2) Do you have a some O/R mapping structure? In the example looks that the command is responsibly for it.
    3) Non-related-ish-question, do you use any Dependency Injection Container in your CRM development?

    Thanks!

    • Hey,

      1) It’s a manual process, because the classes I create differ depending on scenario. You’re correct of course, I’m swapping the overhead of generating early bound entities for the effort of writing my own classes. In both scenarios (early bound entities, or custom classes) whenever the metadata model changes some manual effort is required to resolve any issues. (Not that a change of metadata is something that happens very often). I suspect in both scenarios the effort required is roughly the same (though I believe late bound is possibly less prone to breaking changes(?)). I have to spend the time somewhere, I would rather have ‘clean’ classes I designed under my control (i.e. I can add my own methods, store data as I please), than the somewhat cumbersome early bound classes (i.e. with properities I never use).

      2) Nothing fancy, it’s just the code you see in the example.

      3) Not regularly.

      Cheers,

      James

  2. Hi James,

    Thank for your answers. I’d rather to have these “clean” domain classes too, but I’m also a little bit concern about the overhead that this could take and I still can’t figure out a nice way of mapping the domain classes with CRM entities (the mappings would have to be duplicated in the Factory and Commander object in this approach unless I’m missing something).

    Thanks again for answering and sharing this in the first place!

  3. Pingback: Using the 365 entity class in a late bound fashion | WOODSWORKBLOG

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s