Building Silverlight Apps For CRM
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 - https://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.
Laughing Boy Chestnuts Pre-School Chain Gang
Comments
Anonymous
October 20, 2011
Best post i ever read about CRM 2011 with silverlight including MVVM. Good on you.Anonymous
October 22, 2011
The comment has been removedAnonymous
October 25, 2011
I just downloaded the "Bing Maps Browser.zip" file, extracted the file "bingmapsbrowser_1_0_0_0_managed.zip", then imported to CRM Online with no issues. What steps are you going through?Anonymous
January 16, 2012
Imported the managed solution, changed the key to mine with the registration tool and geocoding is not working. Also it is not obvious where you add the key for the silverlight. Since it is a managed resource then I would assume you create a new resource, but we cannot see the name from the above image. I also tried to register the plugins through the tool and they would not geocode either. Thanks, SteveAnonymous
January 17, 2012
Steve, that's odd. I downloaded the .zip file just yesterday, extracted the managed package and installed it on a brand new CRM 2011 tenant with no issues. One little trick you might find useful is to locate the customizations.xml file within bingmapsbrowser_1_0_0_0_managed.zip. Create a copy of this file, edit it using notepad, search for the three occurances of the text string "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" and replace all three with your Bing Maps key. Save the .xml file, and copy if back into the .zip file. You no longer need to use the plug-in registration tool or modify the Silverlight Web Resource, as your key will be part of the solution package. If you are still having problems, you might want to use the plug-in registration tool to run the plug-in in "Non Sandbox" so that any errors will get written to the Windows Application Event Log. Failing that, I have also included the source code to the plug-in, so you can attach the Visual Studio 2010 debugger to the CRM Async Service and see what is going on in the code,Anonymous
December 12, 2012
Hi Steve. Great post, I've followed it and got it working with CRM Online. I'm hoping to adapt it to work with custom entities. I have added 2 fields 'exp_lat' and 'exp_lon' which I have another plugin updating. I have adapted the MapViewModel.cs in the Silverlight part with the following: Columns = new ObservableCollection<string>(new String[] { "exp_lat", "exp_lon", "name", _crmTypeName + "id" }) and replaced other remarks for the custom fields and to hopefully account for the custom entity name. This works for account still but not for the custom entity. Am I missing another reference on a different form somewhere? I can't see it.Anonymous
February 01, 2015
From where can I get entity model.cs? I have CRM 2011 entity model.cs added to my project which is not working for 2015 SOAP URL?Anonymous
May 05, 2015
Good Work.