Since its introduction in 2008, Microsoft Dynamics CRM 4.0 has been touted as a platform for rapid application development.

We’ve always been hard core C# and ASP.NET snobs, but we were intrigued by the value that Dynamics CRM promised. We set out to build our next generation software product on that platform, and learned a lot about what’s real and what’s not so real. In this article, we will share the rollercoaster ride of our experience developing our software product on this new CRM “platform.”

When we were first introduced to Dynamics CRM 4.0, we were not looking for a software package to manage our customer relationships. We were looking for a new platform to build our next generation suite of applications. Most of the developers on our side scoffed at the thought of using someone else’s platform; they all wanted to build it from scratch. But the more we learned about Dynamics CRM, the more we liked it. The value of having much of the infrastructure already built was very attractive, but there were constant hints of missing elements here and there that we were just not sure about.

We started with a small “proof of concept” task that gave us a good initial feel for how Dynamics CRM 4 works, and how to leverage it. We then turned our attention to the much larger project that we were tasked with. Everyone on the team was excited to work on this new platform and learn its nuances. The project was fairly sizeable, and we had to push Dynamics CRM to its limits, and at times step a little outside of its intended use. Our project was to develop a software package that was to be installed and customized by our own enterprise clients. It was not to be used by our own organization. The difference between developing an application for in-house consumption and one that can be packaged and sold to your clients makes a huge difference in whether Dynamics CRM is a good fit for your goals or not.

The next few months were very interesting, and we certainly learned a lot about Dynamics CRM 4 along the way. In this article, we will share our discoveries about the platform and explain how we solved some of the problems we ran into.

Dynamics CRM Development Fundamentals

Dynamics CRM is often marketed as an “xRM” development platform where the “x” can be substituted with anything. The idea is that while you can configure out of the box to handle general customer relationship management, you can extend the platform to manage a wide variety of business domains. To accomplish this, Dynamics CRM provides several different methods of customizing and developing on the platform.

The most basic means of customizing Dynamics CRM is through the entity data model. The platform itself uses SQL Server as its backend database. However, you will typically never access the database directly except in a limited manner when creating custom reports. Instead, you will work with a layer on top of the database that Dynamics CRM provides in the form of “entities.” We will expand on the data modeling process later, but for now you can think of an entity as a database table on steroids. In addition to the table schema and relationships, the metadata for an entity defines multi-lingual names for field labels, column sets for views of entity records, and the contents and layout of the entity’s data entry form. Data modeling is done through the Dynamics CRM client, but the data model can also be manipulated programmatically.

The programming API for Dynamics CRM consists primarily of two Web service endpoints: the “CrmService” which is used to interact with entity data, and the “MetadataService” which is used to read and manipulate the entity data model. Microsoft provides an SDK containing assemblies that can be referenced to access the services as an alternative to referencing the service endpoints directly. We will dive deeper into the Web services as we expand more on the different aspects of CRM development.

You can use the service API to access CRM from an external application but there are also several ways to host your custom code inside the Dynamics CRM application itself. These can be generally broken down into client extensions and server extensions. The Dynamics CRM client is an ASP.NET-based Web application that runs only in Internet Explorer (an Outlook plug-in is also available). You can add your own ASP.NET pages to be hosted directly inside the Dynamics CRM Web application, or you can point to pages hosted externally on any platform. You can also use JavaScript to add custom logic to respond to various events that occur when users interact with the client.

On the server side, your options consist of plug-ins and workflow activities. A plug-in is conceptually similar to a SQL trigger: you are writing code that will be fired automatically in response to some change occurring in the database. However the plug-in model is more robust since it allows you to respond to a wider range of events and you can execute your logic in a synchronous or asynchronous manner. For workflow, Dynamics CRM uses .NET Workflow Foundation as the base platform and provides a powerful and user-friendly editor in the CRM native client for creating workflows. You can create your own custom workflow activities that can be registered with the server and then used in any CRM workflow.

CRM Entities in C#

Dynamics CRM, when dissected to its simplest level, is essentially a data store mechanism. Obviously it can do a lot more than just store data, but everything you do in CRM is related to the Entity Model. Essentially, an entity is CRM’s abstracted version of a SQL Data Table. But rather than expose the massive amount of features that SQL allows for, Microsoft has limited their entity model to a specific subset of features that are easier for the layperson to manage.

One of the great strengths of CRM is that it isn’t necessarily just for developers. A lot of back office applications require data model changes and not every organization is going to want to have a professional developer on hand to make data model changes. In this respect, CRM excels, because it allows anyone (anyone who has permission, that is) to modify the data model and create new entities as they are needed, without needing to know the specifics of database programming.

Within the first ten minutes of playing around with CRM I was able to create a new entity and populate it with attributes (CRM’s term for columns). It’s incredibly simple and user-friendly.

The user-friendliness ultimately comes with a cost, however. Some of the more advanced SQL features aren’t really possible with CRM. For example, every entity must have a GUID primary key. You’re not even allowed to name the primary key column. You cannot have composite keys either, or unique columns. Your data type choice is limited to the types that CRM exposes (which means you won’t have access to any of the neat new types that SQL Server 2008 introduced).

All of the limitations and standard attributes are designed to streamline the CRM API. Since CRM puts these limitations in place, you can make certain assumptions, which allows the system to act in a very uniform manner and allows software built on top of CRM to be simplified by making those very same assumptions.

In addition to the limitations, CRM also adds a host of standard attributes to every entity. There’s a Name attribute, which holds the name of the record (as identifying records by GUIDs is not something humans are apt to do), the owner of the record (a CRM user), whom the record was created by, the last user who modified the record, the date of the change, and a state code that tracks whether the record is currently active or inactive.

The entity system in CRM provides more than what SQL does at a base level. Because of the unified entity system, CRM enables the use of file attachments on every single Entity as well as a comprehensive security system that allows administrators to choose who has access to which entity types and how much control each user has over that entity.

As a CRM developer, you will want to interact with entities using C# code. There are two primary methods of doing so. The first method is to interact with an entity within a CRM plug-in or workflow. Plug-ins and workflows are attached to a single entity type and executed when certain events happen (for example, creation or modification of an entity record). The entity that the event is being executed on will be attached to the plug-in or workflow context objects in the form of a DynamicEntity, which is CRM’s method of working with an entity without worrying about having a specific type representing the entity. These objects expose a collection of property objects which you are free to modify, where each property represents an attribute on the entity.

The other method of interacting with entities is to use the CRM Web Services, which allows generic access to entities using the DynamicEntity class, but also introduces typed entities. One of the neat things about CRM is that when the data model is updated, the CRM system actually generates a brand new WSDL definition, defining all of the entities and attributes in the system as datatypes that can be consumed by Web service clients. If you’ve ever used .NET’s svcutil.exe tool to generate a client wrapper, this is good news, because it means you’ll be able to interact with all of the entities on a CRM installation automatically in a fully typed manner.

Unfortunately the data definitions that CRM’s WSDL generates leaves a lot to be desired. Rather than generating types that contain attributes of int’s, bools, strings, and so on, CRM actually uses their own wrapper classes to wrap all of the basic datatypes. For example, the CrmNumber class represents a 32-bit integer and exposes a property named Value that allows you to retrieve the true value. Unfortunately this made working with entities somewhat unnatural and cumbersome because we couldn’t just pass the attributes around. Most code has no idea what a CrmNumber is, but most code does understand what an Int32 is. Instead we had to extract the .NET base types first and then we were able to use them.

An additional problem was that we had code we wanted to work on both the internal plug-in/workflow side and the external Web service client side. On the internal side, we could access and use the DynamicEntity object, which was a type defined in the CRM DLLs. On the external side, all of these classes are replicated via the svcutil.exe code generator and put into our own namespaces. So while we could access an external DynamicEntity, it was a brand new class that looked identical to the internal DynamicEntity.

In order to solve these problems we used custom code generation to build a strongly typed Object Relational Mapping (ORM) layer that would allow code written from any context to talk to CRM entities without caring where it’s being executed from.

There are several commercial products out there which will generate an ORM layer. Most products will do what most people need them to do and are pretty good solutions. Ultimately we decided to roll our own code generator so we could tailor it to our unique requirements. If you decide that your CRM project requires entity code generation to streamline the development process, I would definitely recommend looking at the commercial products out there first.

Development Environment

Dynamics CRM presents unique challenges to overcome in order to support a team of developers working concurrently on the same application. For one thing, it quickly became obvious to us that each developer needed their own CRM environment. CRM supports the concept of “multi-tenancy” in a general sense, which means that you can have multiple databases (CRM calls them “organizations”) hosted on the same CRM server. However, as we began to implement more advanced scenarios it became clear that the multi-tenancy support did not easily apply to all the different ways we needed to extend the platform. For example, if you are adding your own ASP.NET pages to the CRM client, there is no multi-tenancy support built-in for those extensions. Developers working on the same pages will step on each other’s toes. Furthermore, it was not uncommon during the course of development to find ourselves needing to recycle the CRM Web application pool or to stop and restart the Windows service that supports asynchronous operations in CRM. As you can imagine, that creates chaos when multiple developers are working in the same environment.

We also discovered early on that it was far easier to develop when Visual Studio was installed directly on the same machine as CRM. Remote debugging can certainly be a lifesaver when that is your only option, but in general it can be difficult to configure properly and the performance can be quite slow. Developing in Visual Studio on the same machine as CRM allows you to attach to the different CRM processes directly for debugging. It was also easier to automate the deployment of our build output to the CRM server when we were building the application on the same machine. We leveraged MSBuild extensively to automate deployment as part of our development build process. We also created several utilities that we plugged into Visual Studio to help automate some of the more tedious tasks. This included tools for registering our plug-ins and workflows as well as importing data into CRM, which are actions you will find yourself doing frequently during the course of development.

Another aspect of Dynamics CRM that added to the complexity is its requirement to be installed on a server OS (Windows Server 2003 or Windows Server 2008). Our developers were running desktop operating systems locally and it was not practical to have them switch to Windows Server. We used virtualization to overcome this issue, and each developer worked in their own virtual environment running Windows Server 2008. We sometimes struggled to keep adequate resources available to support this, even with server-based virtualization and reasonably powerful hardware. Each development environment needed enough resources to at least run CRM and Visual Studio, and we also virtualized the necessary SQL Server instances.

You can deploy Dynamics CRM in many different configurations with various components of the platform optionally installed on separate machines. For development, however, we found it simpler to install all components of CRM on a single server. We configured CRM and Windows consistently across our different environments. This greatly simplified the deployment of our application during the development cycle because we could engineer our build and deployment process for a consistent target environment. However, it was still necessary during the QA cycle to test thoroughly on every configuration of CRM and Windows Server that we planned to support in order to expose any unanticipated issues caused by different configurations.

The final piece of the puzzle for us was source control. In general, source control for a CRM application is no different than any typical .NET application. Tracking our changes to the data model, on the other hand, was a different story. CRM allows exporting the data model to an XML file, and this file is the most practical way to store model changes in source control. Here is a small snippet of the XML produced by CRM when customizations are exported:

<ImportExportXml version="4.0.0.0"
languagecode="1033"
generatedBy="OnPremise">
  <Entities>
    <Entity>
      <Name LocalizedName="Account"
      OriginalName="Account">Account</Name>
      <ObjectTypeCode>1</ObjectTypeCode>
      <EntityInfo>
        <entity Name="Account">
        <HasRelatedNotes>True</HasRelatedNotes>
        <ObjectTypeCode>1</ObjectTypeCode>
        <CollectionName>Accounts</CollectionName>
        <BaseTableName>AccountBase</BaseTableName>
        <WorkflowEventMask>-1</WorkflowEventMask>

This XML file can quickly become very complex and extremely large, and it is not practical to modify or even read manually as may be the case with a SQL script. Furthermore, the order of the contents in the file can easily become scrambled as it is imported and exported from different CRM environments. This made it very difficult to determine what changes were made to the file and by whom. It was also very easy for one developer to accidently overwrite or remove changes made to the model by others. We did our best to address these problems by documenting and adhering to a strict process for making model changes that required coordination across the team. We used utility programs to assist with comparisons with previous versions of the file, and to automate the export process to avoid human error. Finally, we split the components of our data model into several logical groupings and exported and maintained those groupings with separate XML files. This made the data modeling process manageable and allowed us to have some level of traceability, but it was still not ideal.

Data Modeling - CRM Style

Earlier we talked about CRM’s entity model and how it abstracts the details of database design so that you don’t need a database administrator to modify your data model. However, CRM offers enough flexibility in its modeling capabilities that you still need to have an overarching plan when designing your data model. You must decide how to optimize and normalize your data model to fit your needs, whether it should be optimized for fast data access or optimized for reporting.

Things got even more complex, since we were designing software that would be sold to customers, who in turn would change the base data model we shipped. This introduced a lot of interesting issues that CRM had not initially been designed to handle.

Like SQL tables, CRM entities can be linked together via parent/child relationships. CRM doesn’t call them foreign keys, but has three names for the various relationships: One-to-Many, Many-to-One, and Many-to-Many. The first two are really equivalent, and CRM just switches between the two names depending on which entity you are currently looking at. So if you are looking at a parent record, a relationship with a child record will be called “One-to-Many” and vice-versa on the child record. (See the CRM Entity Creation dialogue in Figure 1)

Figure 1: This is the entity creation screen in the CRM web client. It is simple enough to be understood by many people.

One of the very first limitations we ran into was the lack of a One-to-One relationship. More specifically, CRM lacks the ability to create entities which inherit from other entities. This is a pattern that many people end up needing when designing database models. For example, you may have many different types of people stored in your CRM database: customers, contacts, users, accounts, and leads. Most of these entities will share common fields, such as name, address, email, and so on. You could just store all people in a “Person” entity if you wished, but that would end up taking too much space, because there are fields on one entity that have no meaning on another. Furthermore, it reduces the referential integrity of your system because you might have a related table that should only be related to customers, but not contacts. However the relationship would have no way of automatically determining that the person it is linked to is actually a customer.

Enter the conceptual one-to-one relationship which can solve the problem for you if you have a base table containing common fields and then child tables linking to the base table. This is great from a normalization point of view because a given piece of data only exists in one place and you never have to worry about synchronization issues. However, we ultimately rejected this approach due to several usability concerns, the most grievous of which was record editing. If a user of the system wanted to modify a customer’s address, they would need to open up the customer entity, then navigate to the related base contact entity to change the address, which is a process that the users will find cumbersome and ultimately unacceptable.

In the end, our solution to this problem involved replicating fields across multiple entities. When the replicated fields needed to be synchronized, we ended up using plug-ins to automatically transfer the values from one to another. One of the huge disadvantages of this solution is the fact that the names, types, and sizes of the fields across all entities must remain synchronized at all times or else the synchronization process will fail. This means that if a field on one entity is changed, related fields on the other synchronized entities will also have to be modified accordingly. We found during our development process that this wasn’t a big deal for every field except picklist fields.

Picklist fields are like enumerated types; they hold a given domain of values. We found that the domain of values in any given picklist is going to vary far more often than any other attribute type in a data model. This is mostly because picklists are a lightweight method of introducing a data relationship without creating a new table in the database. Ultimately the solution was to just bite the bullet and create new tables for fields that were previously picklists in our model. Since CRM 4’s picklists are not shared, you must manually define the domain for each and every time you use one. Using a lookup field into another table, however, is reusable on any entity in the system, so this method allowed us to maintain more data synchronization. CRM 5 will have global picklists which will also help to alleviate this problem.

This didn’t completely solve the problem of replicated fields being unsynchronized. The problem seems even worse when you realize that once we ship the product, the customers are free to make changes to the data model however they want, so it’s a very real possibility that they may change the model in ways that will break your underlying software, which can lead to customer service calls. The solution we chose to go with was to document our data model in such a way so that it is understood that these types of fields are “owned” by the base solution and that they should not be changed. The customers are free to add new fields and change other fields, but the fields that the system assumes will be there must not be changed or they risk system failure.

When we first started using CRM we were impressed with all of the base services it provided us, so we could immediately focus on the meat of our business logic rather than waste time designing an infrastructure. Once we decided upon using CRM, we realized it would be very useful to use in other products we want to make in the future. Since our line of business has certain aspects that all of our products share, we decided to make a 2-tiered data model. The first tier we call the “Core,” which has all of the entities that all of our products will share. The second tier, called the “Product” tier, is built on top of the first tier, and it introduces entities that are used only by that specific product. The goal with this design is that when our next product begins development, we will not only have the entire CRM platform to build off of, but we will also have half of the data model and its associated utilities completed as well.

Web Services in CRM

In the previous sections we discussed the CRM Web services. The Web services are the primary method for an external application to access CRM data.

The metadata service is very useful for writing tools to help the development process. For example, above we mentioned that we recommend using Entity Code Generation tools to generate an ORM layer for manipulating CRM entities. All of the tools that generate the ORM layers directly interface with this Web service.

This Web service is also very useful if you want to write some tools to automatically document your data model. CRM lets you put in description properties for each of the entities and attributes you create, so it’s a relatively simple task to write a program which retrieves all of the entity metadata and creates a document using the descriptions that exist within the CRM server.

The Metadata service allows more than just retrieving metadata, however. It allows you to modify an existing data model in place as well. The standard CRM model deployment method is to import an XML file containing the data model using the Web client. However, there is one limitation of this method which might convince people to use the metadata service to upload their model changes instead. If you deploy an entity using a customizations XML file, and then delete attributes from that entity in the XML file, and then finally re-upload the new customization file, the entity will still contain the attribute that you deleted. It is understandable why Microsoft decided to make it operate in this manner since you don’t want to just delete an entire column of data by uploading new customizations. In CRM, when you delete an attribute, all data in that column on every existing entity of that type is irretrievably lost. But in general, if your automated model update utility needs to delete an attribute from an entity, you’ve probably already taken into account what you want to do with the data that is being removed. So an alternative to the customization upload method is to upload your data model changes using a custom application that talks to the metadata service.

The other major service in CRM is the CRM Service. This service exposes a CRUD (Create Retrieve Update Delete) data access model which allows you to interact with the data that is actually stored within the CRM entities on the server. The vast majority of your service interactions will probably be with this service.

In addition to that, the CRM Service exposes three methods of retrieving entities as well. You may retrieve an individual entity using its GUID, or you may retrieve a collection of entities using a query object, which allows you to query fields on an entity or related entities as in the following example:

// Create a CrmService object
CrmService crmService = new CrmService();
// (Code to configure service omitted)
    
// Retrieve IDs of contacts with last name = Smith
QueryExpression query = new QueryExpression();
query.EntityName = "contact";
query.Criteria.AddCondition(
    new ConditionExpression(
        "lastname",
        ConditionOperator.Equal,
        new string[] { "Smith" }));
    
BusinessEntityCollection contacts =
     crmService.RetrieveMultiple(query);

The third retrieval method is the FetchXML method, which is the most complex. FetchXML is a special dialect of XML which allows you to define a complex query which can return a particular view of data within the system. The Retrieve and RetrieveMultiple methods are limited in that you can only retrieve data from a single entity type, but FetchXML may retrieve data from multiple entities and place it on the same record, much like a SQL Join clause can accomplish.

One significant drawback of the FetchXML method is that its power to manipulate a query comes at a significant price. Not only is the XML dialect difficult to piece together by hand, but the searches take noticeably longer and the results are entirely in XML as well, which you then have to parse manually into a format of your choice. But in the event that you need a complex view of data involving a few table joins, FetchXML may offer you a performance advantage in the end, especially if you want to perform any aggregation functions on child data (FetchXML supports counting, averaging, summation, and the standard deviation).

As we mentioned before, the CRM service’s WSDL is dynamic, and will be updated any time the data model of the server is updated. This is to facilitate the strong-typing of the CRM entities, which is useful in the event that you do not elect to use a custom ORM. This can also lead to trouble, however, if you used a program to generate a client wrapper such as svcutil.exe. Since the data model of a CRM installation may be updated at any time, any applications that depend on a specific data model may cease to operate properly when the new WSDL is generated. This is mainly because the client wrapper will be generating SOAP messages in an outdated format and could potentially cause service faults. Therefore, in any CRM installation it is good practice to put a process in place so that the maintainers of applications that talk to the CRM service are notified whenever the data model is updated, so they can modify the application if needed.

Furthermore, CRUD operations in the CRM Web service are not atomic. Since the execution of concurrent Web service requests is up to the scheduling mechanism of the ASP.NET worker process, you cannot guarantee that a service operation will be complete before a subsequent one is started, unless the client application specifically executes them in order and waits for each service call to return a result.

If a service operation results in an unrecoverable failure on the server side, CRM throws a SOAP fault which you can catch on the client side by catching exceptions of type SoapException. The outer detail of these exceptions will not give you details of the problem, so you must inspect the detail properties of the exception to figure out what the actual problem is. CRM in this respect is pretty good and will usually tell you exactly what happened to cause the error (such as trying to set an entity’s GUID when creating a new one, or using invalid data for a particular attribute).

The services that CRM provides are pretty comprehensive and you can usually retrieve anything you want with them. The only piece of data that we were unable to retrieve with them in our endeavors was information on whether a specific entity was updated. CRM only lets you know if anything in the data model was changed, but neglects to tell you what actually changed. This played havoc in our caching infrastructure efforts, but other than that the services are very useful and will not leave you wanting.

Custom ASP.NET Pages

One of the limitations when dealing with a third-party client application platform is that you typically do not have much control over the user interface that comes native with the platform. CRM is no exception to this rule, but they have at least allowed a certain amount of customization that allows developers to expand on the internal client greatly.

CRM mainly allows extending the internal client UI by allowing developers to insert iframes into various parts of the UI. The great thing about this method is that it allows you to extend the interface using any Web technology you want, not just ASP.NET. However, since the other extensibility points of CRM (mainly plug-ins and workflows) use .NET, using ASP.NET usually makes the most sense, so you can unify your framework on one platform.

CRM allows you to insert iframes in two locations. The first is within the Site Navigation area in the main page. This allows you to create “landing pages” which usually contain links leading to specific pages within the application and maybe even some at-a-glance data relevant to that particular page.

The other main location is on the Entity Forms. This allows you to place custom logic on an entity form and extend the native form layout for displaying custom data, rather than limiting you to CRM’s fairly strict form layout mechanism.

CRM exposes a robust JavaScript API for working with forms, so you can hook into form events such as “form loaded” “form saving” and “field changed”. Using these events, it is possible to make your iframes react to various actions the user is taking, such as performing special validation on a field without waiting for a plug-in on the server side to validate an entity attribute. This allows your CRM extensions to give better feedback to the user while they’re filling out the form. It is even possible for your iframe to modify the contents of the form by using the CRM JavaScript API.

One pattern we found useful was to expose a custom page which allowed users to enter information in a way that CRM forms did not natively support, and once the user is done entering the information, it would translate that data and store it into hidden fields on the CRM form, which would then be saved to the database. Using this method we were able to extend the CRM form UI to show our custom controls, but also leverage the CRM form object to perform the database communication for us.

In addition to being able to access form contents via the JavaScript API, the pages in a CRM iframe also have the ability to communicate directly with the CRM Web services to retrieve additional data you might like to display. This ties in with the ORM framework we talked about earlier; our iframe pages were able to use the ORM framework to easily talk to CRM and retrieve information which can be displayed on any CRM form. So you can see how choosing to use ASP.NET can prove to be beneficial since you can utilize the same base code in many different parts of the application.

Since CRM’s client application is a Web application, it only allows direct code injection using JavaScript, as that’s the only truly universal Web client tier language. Unfortunately JavaScript can prove to be a problem in certain scenarios. Specifically when dealing with things like unit testing and strong typing, which are weak points of the JavaScript language. Due to these concerns we often found it useful to forego using an ASP.NET page which communicated with CRM using JavaScript, and use a Silverlight plug-in instead. When we switched over to using Silverlight for our client extensions we were able to more rapidly develop strongly engineered solutions than with JavaScript, as we now had access to the majority of the .NET Framework on the client side. This allowed us to show more advanced user interfaces, which also ran faster and took less developer time to create. From our experiences, we definitely recommend looking into using Silverlight to extend the client UI.

One other place for using CRM as a Web platform would be if you want to expose a site that interacts with CRM, but did not want to incur the costs of licenses for every user. For example, if you had a Web site that needed to be accessed by thousands of people, but only wanted to have a dozen or so actual licensed users connect to the CRM Web client itself, you would be allowed to create an external Web site if you purchased an “External Connector” license for CRM. In this model, the external site would use a single service account to communicate with the CRM Web services to retrieve and modify data on the CRM server. CRM’s security model is comprehensive enough so that you can set the service accounts’ permissions to disable retrieval of any sensitive entities so that only internal users would be able to access them. In this type of scenario, CRM becomes a true business server, allowing entire applications to be built on top of the server, with the people using the external site never even knowing what is running the engine underneath.

Packaging Your Solution and Upgrading Your Clients

This article is primarily focused on describing our experiences using Dynamics CRM as a platform for building “packaged” software. Packaged software means that all parts of the application are delivered as a single unit or package. This package will consist of an installation program that deploys and configures each component of the application without requiring manual steps. Ideally an upgrade process is also supported for future updates to the software.

Unfortunately, Dynamics CRM provides very little support for the development of packaged software. There is no built-in way to package and deploy a collection of server and client extensions and data model customizations. Rather, these different components all require manual steps to deploy, and those steps can involve complex configuration or API calls to perform. We knew that a complex manual process would not be acceptable to our end users, so we decided to take on the challenging task of developing our own installation program to automate the deployment process.

To deploy client extensions like ASP.NET pages and Silverlight components you need to copy the necessary files to the CRM application server. These files typically need to be included in the CRM Web application under a special “ISV” folder either directly or via virtual directory. Depending on the needs of the client extensions it may be required to create a new Web application for them. The installer we built automated the deployment of the client extension files and properly configured IIS to serve them as part of the CRM client. CRM created a few hurdles to clear in order for us to flow authentication properly from the native client to our extensions, but in general client extension deployment was straightforward to automate and not all that different from any typical ASP.NET application.

Server extensions, such as plug-ins and workflow activities, were a different story. The assemblies that implement these extensions must be registered with CRM so that their types and configuration are recorded in the CRM database. The base CRM product provides no direct way to do this. You need to either write code to register them via the service API, or use utility programs that are included with the CRM SDK. We chose to use the API so that we could include the code in our installer program and have complete control over the registration process. CRM supports three deployment options when registering server extension assemblies: the file system, the GAC, and the CRM database. Only the database option supports multi-tenancy so we chose that. However, our server extension assemblies referenced other libraries as would be the case with any large application that was designed with code re-use in mind. These referenced assemblies cannot be deployed to the database and needed to be deployed to the GAC. We therefore needed to worry about assembly versioning to support updates to a multi-tenant environment. Another option for referenced assemblies is to use a tool like ILMerge to merge the server extension assembly and any referenced assemblies into a single assembly. This works for most basic cases but you need to watch out for naming conflicts that will arise if the same namespaces are loaded by multiple assemblies. We had a common core library that was used by client extensions and multiple server extensions so we ran into naming conflict problems and had to stick with the GAC for deploying our referenced assemblies.

Finally, we tackled the deployment of the data model. As mentioned previously, data model customizations can be exported from CRM into an XML file. The import of these customizations to another instance of CRM is relatively straightforward and can be done directly through the CRM client, or via the service API. However, the deployment of entity schema is an additive-only process. If you remove fields or entities from the existing model, there is no way to deploy those changes with the customization import process. We needed to use the metadata service to automate those types of changes

The additive-only approach can actually be helpful if you need to preserve any custom fields the client added to their existing model, which is especially important in an upgrade scenario. Unfortunately that approach does not apply to all aspects of the data model. For example, our data model customizations included changes to the client navigation and various data entry forms. When deployed, those types of changes will overwrite any existing customizations. The only way to get around this was to programmatically merge our navigation and form changes with the existing model. Because the customizations are XML-based it is possible to do this, but it is not a trivial task.

All in all, the automated installation process turned out be one of the most complex pieces of our application infrastructure. If you are looking to develop packaged software on Dynamics CRM 4, be prepared to invest heavily in this area. Fortunately, some of the features in CRM 5 demonstrated by Microsoft at PDC look to address this deficiency. A new solution infrastructure was shown that allows you to package different components together and deploy them in a versioned manner.

Conclusion

Microsoft Dynamics CRM 4.0 has introduced many advantages over its predecessor, version 3.0. If you need to build applications centered around a “customer” of some sort (patients in hospitals, students at schools, or employees in a company), then you would be hard pressed to overlook CRM 4.0 and all its advantages. If, on the other hand, you are building applications that you will be selling to your clients, who will in turn customize the software, then be prepared to develop your own infrastructure to support packaged software. If you are not ready to make that kind of investment, then perhaps waiting for CRM 5.0 might be prudent.