Accessing Cross-Domain ADO.NET Data Services from the Silverlight Client Library

When we built the client library for Silverlight in Silverlight 2.0 , the underlying Network Stack provided by Silverlight core libraries
was very limited in terms of the Status Codes and Request Verbs that it supported.Our options were :
a) Use the System.Net libraries provided by the agClr and give a limited subset of the functionality available on the desktop.
b) Cook up our own Network stack and provide all the functionality provided on the desktop , in Silverlight.

We went with Option (b) and built a network stack that uses the browser’s underlying XmlHttpRequest object.
This means that the cross domain access available in Silverlight networking stack is not available in our networking stack.

Forums user Ben Hayat asked a question about the guidelines for Cross-Domain access using our Silverlight Client Library .

Now , this is not supported out of the box . But ,you can use the same solution as you would for an Ajax application ,
which is building  a server-side proxy that talks to the remote service and is completely transparent to the client library.

Below is a sample Server-Side proxy that would help one talk to Data Services hosted on a different domain than the Silverlight application.

There are a couple of issues that a Server-Side proxy needs to solve for an ADO.NET Data Service ,
  a) Appear totally transparent
  b) Resolve Identities of resources to appear as they would from the Proxy service and not the original Data Service.

Issue a) is easy , Issue b) is a little more involved.

When the client library receives a Payload back as part of a query ,we construct the entity’s identity based on the following rules,
ex: If you browse to https://ServiceEndpoint /Northwind.svc/Customers('ALFKI') , the response looks like this :

  <entry 
xml:base="https://ServiceEndpointNorthwind.svc/"         xmlns:d="https://schemas.microsoft.com/ado/2007/08/dataservices" 
       xmlns:m="https://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
       xmlns="https://www.w3.org/2005/Atom">

 <link rel="edit" title="Customers" href="Customers('ALFKI')" /> <id>https://ServiceEndpointNorthwind.svc/Customers('ALFKI')</id>  
    <content type="application/xml">
    <m:properties>
     Properties go here 
    </m:properties>
    </content>
</entry>

 

When we get the above payload back as a response , we  create  a Customer object and its identity is the value of the <id> field in the payload.

When you make any edits to this Customer object, the edits are sent to the URI specified in the <link rel=”edit”> value of the payload.

Which means that the proxy server has to modify the payload it recieves from the real Data Service to make sure that all links , Id and Edit

point to the proxy Data Service and not the real Data Service. The easiest way to do this is to do a String.Replace replacing all occurrences of the

the original Service end point with the Proxy Service end point in the payload.

Without further stalling  , here is the  Proxy Handler.

A couple of words of caution so that I can keep my job,
  1. This is only a sample implementation of what a proxy could look like.

  2. Do NOT use this in your production applications.

  3. This is NOT an official solution provided by the ADO.NET Data Services team ,

    this is just me illustrating how to write a proxy.

  4. If you download this sample , it means that you understand these rules .

  5. For any problems with this sample , leave a comment on my blog ,

    the ADO.NET Data Services Forums is NOT the right place for any issues with this proxy.

Running the sample 
  1. Download the sources from the link above.

  2. Open the solution in Visual Studio 2008 and hit F5.

  3. You should see the Silverlight application come up and

    get the data from the Data Service hosted in a different application.

The Cross Domain Proxy is a generic AShx handler which receives the requests from the Client library and forwards them onto the

original Data Service , gets the response , changes the ID and Edit Links and returns the response to the Silverlight Client .

  1. Client Sends request to Proxy Handler

  2. Proxy Handler sends the request data to the Original Data Service

  3. Data Service responds with response

  4. Proxy handler reads response and changes the ID and EDIT links in the payload

  5. In case of POST , the Proxy Handler changes the response “Location” Header

    so that the identity points to the Proxy Handler and not the Data Service.

  6. Proxy handler returns the response data to the client .

How do I use this in my application ?

The source available for download contains “CrossDomainHandlerBase” which is the class that contains the functionality required

for recieving requests from clients and forwarding the requests onto the Data Service.

Setting up the Server-Side Proxy
  1. Add a Generic ASHX Handler to the application that contains the Web page hosting the Silverlight application ,
    1. Right-Click on Project

    2. Add –> New Item –> Generic Handler

       image

    2. This will create a Generic Handler which implements IHttpHandler.

    3. Remove the code stubs for IHttpHandler methods and properties .

    4. Replace IHttpHandler with “CrossDomainHandlerBase”. 
 

     [WebService(Namespace = "https://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class CrossDomainHandler : CrossDomainHandlerBase
    {
        public CrossDomainHandler()
            : base()
        {
            this.DataServiceURI = "URI FOR THE DATA SERVICE";
            this.ProxyServiceURI = "URI FOR THE PROXY SERVICE";
        }
     }

    4.From this point on , for all purposes , the Proxy Handler service IS the Data Service

Setting up the Silverlight application for Cross-Domain access
  1. Right-Click on “References” in the Project

  2. Select "Add Service Reference"

  3. In the “Address” field , enter the URI for the proxy service ,

  4. image

  5. In case of the sample solution provided, the Provider is called “DataProvider”, hence

    the code-gen produces the code with a type “DataProvider” derived from DataServiceContext.

  6. When you instantiate the Context in the Silverlight application , always specify the Base URI

    as the Proxy Handler’s URI,

     DataProvider dataProvider = new DataProvider(
                    new Uri("RELATIVE URI FOR THE PROXY SERVICE", 
                                UriKind.RelativeOrAbsolute)
                      );
    
  7. This is the most important step of all , Party on !!

To do in the near future :

  1. Convert the Handler to be an IHttpAsyncHandler so that we dont block on waiting for the response from the Data Service
  2. Provide better mechanisms for Identity Resolution other than String.Replace .
  3. Write a better demo app than something which binds all the parts of my name to a Grid.
  4. Your suggestion goes here .

slCrossDomain.zip