Friday 2 March 2012

Using the CRM web service with Silverlight and Rx - The CRM Methods


Recently, I've been developing a complex Quote tool for our client. This tool allows the user to create sophisticated Quotes with minimal effort and includes all sorts of things like preconfigured kits, automated discounts and translations into different languages. This tool had to work offline within the Outlook client, so there was only one way forward, Silverlight. And with that, a steep learning curve on how to get the most out of Silverlight within CRM 2011.

The first port of call was the MSDN walkthrough needed to connect a Silverlight app to CRM 2011 (available here: http://msdn.microsoft.com/en-us/library/gg594452.aspx). This creates your reference to the CRM SOAP web service and a new SilverlightUtility class with some of the helper messages needed.

But, one thing that really stumped me, was how to get the webservice calls to CRM to execute sequential code easily without having events and handlers everywhere, and without destroying the asynchronous nature of Silverlight.

The answer to this was Rx, which allows the developer to create simple (ish) nested code which is then executed on the completion of the asynchronous web service call, and this first blog post sets the foundations of how I used this to communicate with CRM.

I must give credit to David Yack (http://blog.davidyack.com/) who's advice online steered me towards Rx and onto develop this helper class.

First off, you need to follow the MSDN walkthrough to get the Silverlight utility and set up the webservice.

Secondly, you'll need the Rx Extensions for C# (available here: http://msdn.microsoft.com/en-us/data/gg577609) referenced in your project.

Next, we'll need to create our helper class. This class will create the simple methods required to talk to CRM using Rx, through which all calls to CRM will be made:



using System.Reactive;
using System.Reactive.Linq;


public static class RXCRMMethods
{

        public static IObservable<Guid> Create(this IOrganizationService service, Entity entity)
        {
            var orgServiceObservable = Observable.FromAsyncPattern<Entity, Guid>(service.BeginCreate, service.EndCreate);
            var res = orgServiceObservable(entity);           
            return Observable.Create<Guid>(observer =>
            {
                res.Subscribe(result =>
                    {
                        observer.OnNext(result);
                    },
                    exception =>
                        {
                            observer.OnError(exception);
                        });
                return () => { };
            });
        }


        public static IObservable<Entity> Retrieve(this IOrganizationService service, string entityName, Guid id, ColumnSet cols)
        {
            var orgServiceObservable = Observable.FromAsyncPattern<string, Guid, ColumnSet, Entity>(service.BeginRetrieve, service.EndRetrieve);
            var res = orgServiceObservable(entityName, id, cols);
            return Observable.Create<Entity>(observer =>
            {
                res.Subscribe(result =>
                {
                    observer.OnNext(result);
                },
                    exception =>
                    {
                            observer.OnError(exception);
                    });
                return () => { };
            });
        }


        public static IObservable<EntityCollection> RetrieveMultiple(this IOrganizationService service, QueryExpression query)
        {
            var orgServiceObservable = Observable.FromAsyncPattern<QueryBase, EntityCollection>(service.BeginRetrieveMultiple, service.EndRetrieveMultiple);
            var res = orgServiceObservable(query);


            return Observable.Create<EntityCollection>(observer =>
            {
                res.Subscribe(result =>
                {
                    observer.OnNext(result);
                },
                    exception =>
                    {
                            observer.OnError(exception);
                    });
                return () => { };
            });
        }


        public static IObservable<bool> Update(this IOrganizationService service, Entity entity)
        {
            var orgServiceObserveable = Observable.FromAsyncPattern<Entity>(service.BeginUpdate, service.EndUpdate);
            var res = orgServiceObserveable(entity);
            return Observable.Create<bool>(observer =>
            {
                res.Subscribe(result =>
                {
                    observer.OnNext(true);
                },
                    exception =>
                    {
                            observer.OnError(exception);
                    });
                return () => { };
            });
        }


        public static IObservable<bool> Delete(this IOrganizationService service, string entityName, Guid entityId)
        {
            var orgServiceObserveable = Observable.FromAsyncPattern<string, Guid>(service.BeginDelete, service.EndDelete);
            var res = orgServiceObserveable(entityName, entityId);


            return Observable.Create<bool>(observer =>
            {
                res.Subscribe(result =>
                {
                    observer.OnNext(true);
                },
                    exception =>
                    {
                            observer.OnError(exception);
                    });
                return () => { };
            });
        }
}




Finally, we'll need to call our new method and subscribe to the result, this could be anywhere in our application..

RXCRMMethods.Create(service, entity).Subscribe(Id=>
                        {
                            Customer.Id = Id;
                        });

And there you have it, a simple example of Rx and CRM 2011. Obviously this could have been done with an asyncCallback, but in the next couple of posts I'll elaborate on how to extend this further and some of the tips I've picked up during this new development.

Hope you find it useful.

No comments:

Post a Comment