Silverlight 2 and CRM

Q: Is there a way to directly call CRM 4 from Silverlight 2 managed code using the auto-generated proxy?

A: Yes :) with a small workaround that will be available with SL2 RTM.

I finally had a bit of time to spend on a matter that personally bothered me. During TechEd 2008 I demonstrated how managed code could talk to CRM using an intermediary WCF proxy… why did I have to use the WCF proxy? Because the CRM Web Service didn’t seem to play well with the proxy that SL2 auto-generates. Things worked but having that piece of code in the middle (the proxy) didn’t seem quite right (although I can tell you that there are very valid scenarios in which you would definitively like to have a proxy, for example if you are aggregating data from different sources). Of course you could talk to CRM directly if you build your own proxy (basically handcrafting the SOAP requests using POX) or use an existing one (This book actually has nice sample code that you can reuse). Anyway, I didn’t post the TechEd sample because I didn’t feel comfortable with the proxy pattern, especially because the sample didn’t use the proxy other than to talk to CRM.

Sniffing the HTTP communication between the auto-generated SL2 proxy and CRM it seemed that the problem was the CRM authentication token wasn’t being passed from SL2 to CRM.... but how to test my theory? Turns out that on the Beta 2 bits of SL2 injecting a SOAP header into the outgoing request was not a trivial task (you had to extend the channel and do a bunch of code to merely inject a couple of lines into the outgoing request). I contacted the Silverlight team and they informed me that injecting SOAP headers was going to get a lot easier with post beta 2 (closer to RTM) bits of SL2…a couple of weeks back I got an email with sample code that demonstrated how to inject the SOAP headers and guess what?

Yes!... it worked J. My theory was correct and after injecting the authentication header I was able to use the auto-generated proxies in SL2 and talk directly to CRM.

It was a bit tricky at first because I had to properly encode the authentication token but I was finally able to directly call CRM from SL2 managed code; I was really happy to see the “Test Account” text appearing on the screen (yes, I was retrieving the name of an account).

So great you say; now give me the code, right? Well, unfortunately I can’t do that since I’m using a set of SL2 bits that hasn’t been released yet but I have the sense that SL2 will RTM pretty soon and when that happens I’ll validate once again that the code works and post it on the web (the actual VS project). Please don’t ask me about SL2 RTM date or anything like that because honestly I don’t know.

However I see no harm in posting the key piece of the puzzle … and if for some reason you do have access to SL2 latest bits you will be able to try this out (it may be challenging since you do have to figure out some missing instructions in order for this to work but hey!, you are smart right J ). When I post the complete project it will have all the code and all the detailed instructions.

******UPDATE******* : See this post, there is a link there to the code.

void Page_Loaded(object sender, RoutedEventArgs e)

        {

            CrmServiceSoapClient crmService = new CrmServiceSoapClient();

            crmService.RetrieveCompleted += new EventHandler<CRMSilverlightDirect.CrmSdk.RetrieveCompletedEventArgs>(crmService_RetrieveCompleted);

            // Create the column set object that indicates the fields to be retrieved.

            ColumnSet cols = new ColumnSet();

            // Set the properties of the column set.

         cols.Attributes = new string[] { "name" };

            using (new OperationContextScope((IContextChannel)crmService.InnerChannel))

            {

                //This is the KEY part... we inject the CRM Authentication header

                //The Xml formater is just to prevent some characters from being encoded (otherwise CRM can't parse the authentication token properly)

                MessageHeader header = MessageHeader.CreateHeader("CrmAuthenticationToken", "https://schemas.microsoft.com/crm/2007/WebServices", "", new MyCrmAuthenticationTokenSerializer(0, "crm5Org", null));

                // Insert SOAP header

                OperationContext.Current.OutgoingMessageHeaders.Add(header);

                crmService.RetrieveAsync("account", new Guid("1EB30C87-EA80-DD11-AE35-00155DA20A01"), cols);

            }

        }