If you have an on-premise CRM server you can get around the cross-domain restrictions by putting a ClientAccessPolicy.xml file in the root of the CRM web application (See Markus Konrad's post on creating the policy file), but CRM online won't let you upload a ClientAccessPolicy, so you have to be a little more clever. One method is to just create a proxy to pass all the requests to the CRM server.
Creating a proxy for CRM SOAP requests
A quick note: This works for the SOAP Organization service and the example at the end of this post only uses the SOAP service. I'm not sure if a similar proxy would work for the REST endpoint (Given the REST endpoint's limitation I rarely use it anyway).
To get web-service requests to go from a Silverlight application w just need a few things:
1. Create an aspx page in the web project that's hosting the Silverlight app that will act as our proxy.
2. Program the proxy page to forward all posted requests to the CRM Online web-service endpoint.
3. Authenticate against CRM Online and attach the LiveId security token to each request.
4. Configure the Silverlight app to point to the proxy page.
Steps 1 and 2 are actually pretty straightforward once you pull out fiddler and figure out what the soap requests work like. Step 3 is the complicated bit but the sample code in the CRM SDK provides an example of authenticating against CRM Online (see sdk\samplecode\cs\wsdlbasedproxies\online). Once you've authenticated and have the security token you can just inject the token right into the header of the SOAP request.
I've built an example application which you can download here. It's just a simple Silverlight application that makes create, retrieve, update, delete, and execute request to CRM Online using the proxy described above.
To try it out just update the constants defined at the top of Proxy.aspx.cs:
//Update these constants to match your CRM Online accountconst string host = "orgName.api.crm.dynamics.com";const string userName = "erik.pool@example.com";const string password = "Password";
Also note the GetOrganizationService method in the Silverlight app. If the current page is running on "localhost" it assumes you're debugging and points the org service url at the proxy.aspx page. This way the same silverlight app works on my dev machine and when it's deployed to CRM Online.
if (href.Contains("localhost")){Uri baseUrl = new Uri(href, UriKind.Absolute);orgServiceUrl = new Uri(baseUrl, "SoapProxy/Proxy.aspx");}else{orgServiceUrl = new Uri(location.GetProperty("protocol") + "//" + location.GetProperty("host") + "/xrmservices/2011/organization.svc/web");}
Download the source code here.
-Erik

This is very cool! Thanks for putting this together!
ReplyDeleteHi,
ReplyDeleteThis is great, and saves me so much time deploying to crm online.
I had an error 'server not found', and this was because I was in asia pacific region and had to change the URN to be crm5. For europe it is crm4.
I added the following code to the proxy ExecuteProxyRequest function.
private void ExecuteProxyRequest( XmlNode body )
{
string appliesTo = "urn:crm:dynamics.com";
if (host.IndexOf("crm4.dynamics.com") != -1)
appliesTo = "urn:crm4:dynamics.com";
if (host.IndexOf("crm5.dynamics.com") != -1)
appliesTo = "urn:crm5:dynamics.com";
This is really very cool and time saving.
ReplyDeleteCan you please walk me through the generation of Reference.cs
Thanks
varun
I generated the reference.cs class using the method described in this post: http://erikpool.blogspot.com/2010/12/how-to-use-crm-2011-organization-soap.html, but that's a little out of date now, since the CRM SDK now has a full walkthrough for using the SOAP service in silverlight: http://msdn.microsoft.com/en-us/library/gg594452.aspx
ReplyDeleteI cannot make this work. I keep getting the exception message (trying the Create method) "The remote server returned an error: NotFound.".
ReplyDeleteI have added the code that Johan suggested but it doesn't fix the problem.
Any known issues that could be causing this?
/Aidal
Is it now working any more i used in few months back but its not working now. Do we need to do any changes to make it work.
ReplyDeleteThanks
Varun
I actually made it work (well semi work) because I could make it create an account but somewhere after execution but before callback, something goes wrong somehow.
ReplyDeleteI could see with Fiddler, that the reply does contain what I was expecting, but the callback method has an exception in e.Error, indicating that the operation failed, even though it didn't.
I dunno why this is, but I need to check for errors in my callback methods, so from my code the execution will look like it failed every time it seems.
Varun, it looks like Microsoft made a change (related to how CRM handles gzip compression) that breaks the code I posted before. The code can be made to work again by removing line 56 from Proxy.aspx.cs. Remove this line => req.Headers.Add("Accept-Encoding", "gzip, deflate");
ReplyDeleteAidal, I can't repro your scenario exactly but I think it's probably the same issue with the gzip compression.
Hi Erik,
ReplyDeleteIs it possible to do this without the aspx page? I want to connect to the CRM 2011 Online soap service from an out of browser silverlight application...
Thanks