Get Down On It…
Although I have posted several CRM code-samples on my blog, I don’t think of myself as a particularly expressive or creative developer. Sure, I can code a plug-in in VB (and more recently C#), or knock out the occasional JScript library, but I struggle to use design patterns & practices to ensure the clean separation and testability of code required in production environments. Luckily my role is in pre-sales, and it is usually somebody else's responsibility to make sure any code is “Production-Ready”.
One of the biggest gaps in my knowledge is how to build user interface (UI) components that extend the out-of-the-box CRM forms. With CRM 2011 we introduced the concept of web resources, that allow you to integrate Html, JScript and Silverlight components directly into CRM. However, that still leaves me with the big problem of actually writing the UI code.
A couple of weeks ago, I built a Broker Management demo for a prospect in the Insurance industry. They had a simple requirement along the following lines:
- When a business manager (user) books an appointment with a particular broker, they may also want to book other appointments with nearby brokers to maximise their time in the local area.
- For the broker they are visiting, they wanted to open the broker (account) CRM record and see a map showing the other nearest brokers within a pre-defined radius.
- From the map, they wanted to be able to click on a nearby broker, open up the CRM record for that broker and book an appointment.
This scenario is a perfect candidate for using Microsoft Silverlight, and a quick search for “CRM 2011 Silverlight Map” brings up many different examples, including:
- Codeplex: Bing Map Browser for Microsoft Dynamics CRM 2011
- Planet xRM: Maps for CRM
- Mando Group: Silverlight CRM Dashboard
The problem was that none of the examples did "exactly” what I needed, so I took a look at the source code for some of the examples and came up with my own variation on the theme using the Bing Maps Silverlight control.
Using Plug-Ins For Some “Heavy Lifting”
Before I could begin building the Silverlight UI I needed a way to calculate Latitude and Longitude values for an address. Now I could do this within the Silverlight code itself, but the problem comes when trying to calculate the nearest set of accounts when you have thousands of account records. This is not something you really want to do in “real-time” in the UI. Instead, I opted to build a plug-in that would call the Bing Maps Web Services every time I created or updated an account address.
As is my usual “best practice”, I chose to implement an Asynchronous, Post-Event plug-in that would trigger every time an account was created or whenever and account address field was updated. The Geocode Web Service allows you to submit a postal address, and will return Latitude and Longitude values, and my plug-in writes these to the account entity address fields.
Now that I have this geocode information stored in the CRM database, I am able to retrieve and sort quickly and efficiently inside my Silverlight app, without having to make additional, expensive, and (relatively) slow web service calls to Bing Maps every time the app is run.
Initial Silverlight Design
As this was my first attempt as using Silverlight in earnest, I tried to apply my knowledge of developing other types of CRM components (such as plug-ins and custom workflow activities) to this task. However, I quickly hit two problems.
- By default, Silverlight is not able to connect to the CRM SOAP service, but instead has to make use of the CRM REST service. Now this is all well and good, but I haven’t spent much time using REST, so this would be quite a steep learning curve. Luckily, the CRM 2011 SDK team has published an article on how to enable SOAP support: Walkthrough: Use the SOAP Endpoint for Web Resources with Silverlight.
- Silverlight only supports asynchronous web service calls. Now this one really does confuse me, as I have only really built synchronous, sequential code before. Now I have to write a method that calls a CRM web service, then write another “callback” method to handle the response on another thread. What happens when I need to make a web-service request, that depend on the results of a previous request on a different thread, and then update the UI which is running on yet another thread? Well, you quickly end up with “spaghetti” code, chaining together multiple methods and callbacks, and making life very difficult if you want to make minor changes, or if you need to have conditional branching.
MVVM Comes To The Rescue
Although my code was working, I knew there had to be a better way to build Silverlight applications. After a few Bing searches, the term MVVM kept cropping up. MVVM (short for Model-View-ViewModel) is a design pattern, specifically developed to solve this class of problem.
Now, I won’t go into detail here, but there is a great series of articles that helped me understand MVVM, which I encourage you to read - How To Refactor And Build Better Microsoft Silverlight Applications. Using this approach, I refactored my original design into different layers, one each for Views, Models and ViewModels, as shown in my Visual Studio project solution explorer
In addition, I also started to make use of a couple of other design patterns, such as the Service Agent pattern for to handle instantiating the CRM WCF proxy object and calling the appropriate CRM operations. It’s still very much “work-in-progress”, but I definitely think I am on the right track, and I now have the confidence to start building even more Silverlight UI components for other scenarios.
Bringing It All Together
Just like in my previous postings, I have packaged up the solution components ready for you to try out. The solution package includes the following components:
- A Silverlight control that will work when placed on any account entity form.
- A plug-in to handle the Create and Update events for the account entity, and obtain latitude and longitude values for an address.
- A modified account entity containing a new form to contain the Silverlight control. I have not updated any of the out-of-the-box forms or views, so this won’t overwrite any other customisations.
In order for the solution to work correctly, you will need to sign-up to obtain a unique Bing Maps Developer Key here - http://www.bingmapsportal.com. This key is passed as a parameter to both the plug-in (using the plug-in registration tool in the CRM SDK), and the Silverlight control.
In addition, the Silverlight control takes an additional parameter; the search radius (in miles) to use when locating nearby accounts.
You can download my solutions package (both managed and unmanaged), the source code for the plug-in and Silverlight control, as well as sample data with real UK addresses here.
This posting is provided "AS IS" with no warranties, and confers no rights.