A powerful point of extensibility in Dynamics CRM 2011, is the ability to build a library of re-usable Web Resources of varying content type and declaratively introduce those resources in various parts of the native interface to extend the presentation layer. The web resource approach to extending the UI offers a compelling alternative to integrating separately-hosted ASP.NET Web Forms/MVC apps that minimizes complications arising in areas such as security/identity impersonation, deployment, and solution distribution (For more details on CRM 2011 Web Resources in CRM SDK on MSDN: http://msdn.microsoft.com/en-us/library/gg309473.aspx). In addition to these benefits, CRM 2011 supports Silverlight (.XAP) as a web resource content type for creating rich interactive user experiences. I’m pleased to see more Partners and Customers transitioning to leverage this technology to solve sophisticated presentation challenges.
A Trend Identified in CRM 2011 Silverlight Web Resources Development
Nevertheless, while observing this transition, I’ve noticed a trend in development approach where a separate Silverlight Web Resource is created to address each area of the UI needing to be extended within a common CRM solution, even when extending the same general area such as an entity form. This approach may work for meeting a small set of functional needs, but quickly presents scalability concerns in the form of CRM solution export file size bloat and initial page-load performance. Underlying contributors to unnecessary solution export file size bloat often include shared dependencies or code such as:
- Client data services generated classes
- Shared internal libraries/class files/resources
- Third-party libraries
Generating the OrganizationData.svc client data service classes for alone can contribute approx. 500kb - 1mb to the overall physical file size of your .XAP output. This can grow significantly beyond that if your solution contains many custom entities. Add in a shared internal library and a third-party controls library to each of your Silverlight applications and you could easily be contributing 2 – 3mb to each .XAP from these application dependencies. If creating one or two Silverlight Web Resources, this may not present too much of a concern. But, what if you were to introduce 5, 10, or 20 unique extensions? Your solution file size could easily contain 15mb – 60mb of duplicate dependencies in the .XAP Web Resources!
Applying Silverlight Navigation to CRM 2011 Web Resources
A simple approach that I’d advocate for avoiding the situation described above is to consolidate your extensions into fewer Silverlight application projects and employ a navigation pattern to the application. This approach will essentially allow a single Silverlight application to present and navigate between multiple views similar to pages in a website. Putting this approach into context with CRM 2011, we would have a single Silverlight web resource, reference it multiple times throughout the UI of our solution, and in doing so specify which view should be presented for each instance. For our application to determine which view to present, we would register the view name in the InitParams, read this value out when the application is loaded, and navigate to that view.
For smaller solutions or single developers, a single Silverlight application project may suffice. For larger, more sophisticated solution or collaborative development teams, you may choose to consolidate extensions by functional area or entity. Seek to strike a balance between effective consolidation without adversely impacting team collaboration during development/testing.
So, how do we implement this approach? Here’s a quick overview (we’ll assume you’re familiar with building Silverlight applications and adding CRM 2011 Web Resources) applied to a basic scenario.
How To Implement the Approach
The scenario is a need to extend the Opportunity form to display customer information, provide an editable products grid, and invoke a custom dialog via Ribbon button command. We’ll build a single Silverlight application that contains separate views for each of the three extensions. The MainPage.xaml will essentially be the host container for each of the views and will handle navigating to each (For more details on building navigation applications in Silverlight on MSDN: http://msdn.microsoft.com/en-us/library/cc838245(v=VS.95).aspx). To begin, the MainPage.xaml UserControl will need to reference the Navigation namespace.
The navigation Frame control will then be placed in our MainPage.xaml layout root. An event handler for the Loaded event will parse the InitParams values and perform the navigation. The UriMapper will convert the value passed in the InitParams to the source Uri for navigation.
The UriMapper can either be defined inline or within a resource dictionary. Above I referenced a static resource and below is the associated XAML from that resource dictionary (For more details on Silverlight resource dictionaries on MSDN: http://msdn.microsoft.com/en-us/library/cc903952(v=VS.95).aspx). Note that multiple UriMappings can be defined. Below is a simple example of accepting a user friendly relative path and redirecting that to the intended folder structure for our pages (views).
The Loaded event needs to be handled in the code-behind for the MainPage.xaml. Here is a very basic illustration of reading the ‘data’ parameter supplied in the InitParams by an instance of CRM 2011 Silverlight web resource.
When creating views for the application, we’ll need to use a Silverlight Page control. Below is the XAML and namespaces included for this item type.
From this point, you would implement the XAML for your view within this Page control and bind your ViewModel to the layout root. Your Silverlight application project may resemble something similar to below after adding the views, view models, and a reference to the OrganizationData.svc endpoint.
After building your Silverlight project, the .XAP will be available in the /ClientBin folder of your target web application project. The size of this file is ~1mb without any additional shared/third-party libraries or additional code to flesh out the view models, commands, etc.
We’ll instantiate this Web Resource directly on the Opportunity form for each of the two embedded extension scenarios, customer details and editable grid. For the dialog scenario, add an HTML page to host the Silverlight Web Resource since it will be opened via a Ribbon Button command. The easiest approach to create the host page is to utilize the contents of the HTML test page generated when creating your Silverlight application project. Within the Silverlight plugin object reference, we’ll need to specify our data parameter in the InitParams collection (For more details on setting InitParams for the Siliverlight Plugin Object on MSDN: http://msdn.microsoft.com/en-us/library/cc838255%28v=VS.95%29.aspx). Notice also that the ‘source’ value can be a functioning relative path assuming it matches the name for the Silverlight Web Resource.
We’re now ready to define and upload our Web Resources to CRM. For the stated scenario, we’ll create three new Web Resources:
- Silverlight XAP: /ClientBin/Microsoft.Pfe.Xrm.SilverlightNavSample.xap
- Web Page HTML: /Pages/OpportunityDialog.htm
- Script Library: /Scripts/Silverlight.js (this is the Silverlight library created by default in the target web site project)
Note that in the naming of these Web Resources we’ll want to maintain the relative path structure of our web resources project. This naming convention allows us to easily create references between multiple Web Resources such as an HTML web page embedding a Silverlight application.
On the Opportunity form, we’ll create two instances of the same Silverlight Web Resource and configure the data parameter to specify the appropriate view to navigate to. Below is an example of a Web Resource instance’s properties as defined on an entity form.
To enable a custom Ribbon button to invoke our host dialog page in a modal dialog window, we can add the following Action to the Button’s CommandDefinition. Since we have an HTML page to host our Silverlight application, we can use the Url action type and specify the relative path to the HTML Web Resource. Notice we’ve added the $webresource: directive which creates a dependency between the Ribbon definition and our HTML Web Resource.
After publishing all customizations, here is what the extended Opportunity form would look like with three individual Web Resource extensions all being presented by a single Silverlight Web Resource! Our solution size remains tidy and there is no additional download when opening the modal dialog since the application is already cached client-side.
Let me know your thoughts on the above approach. How do you see this benefiting your CRM 2011 solution? What challenges/issues do you foresee? Please provide a comment to discuss.
P.S. Stay tuned for a future blog post where I explore a more sophisticated approach using Prism patterns to create modularized CRM 2011 Silverlight web resources!