Allowing cross-domain access from Silverlight to a standalone WCF-Service

Introduction

Silverlight by default only let’s you access services which come from the same domain as the domain that served the Silverlight control. This guards against some types of security vulnerabilities.

A service can however opt-in to allow calls from Silverlight controls hosted on other domains. To do this a service has to provide a clientaccesspolicy.xml or crossdomain.xml file, which specifies the access policy for this service.

Silverlight, when asked to do a cross-domain call, will look for this file at the root of the domain where the target service is hosted.

The following is a sample clientaccesspolicy.xml file:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

You can also use a crossdomain.xml file, which is used by Adobe Flash, but is also recognized by Silverlight.

Standalone WCF-Services

It’s easy to provide the required file for a service hosted on web server like IIS. For a standalone WCF service however, there is no built-in functionality to achieve this.

You can however create a separate service which is responsible only for serving the required policy file and make it available at the services domain root.

The idea is copied from this forum entry (thanks Yi-Lun Luo): http://forums.silverlight.net/forums/p/21678/77494.aspx

Creating the web service class

[ServiceContract]
public class CrossDomainPolicyRetrieverService
{
    [OperationContract, WebGet(UriTemplate = "crossdomain.xml")]
    public Stream GetFlashPolicy()
    {
        return getPolicy("crossdomain.xml");
    }

    [OperationContract, WebGet(UriTemplate = "clientaccesspolicy.xml")]
    public Stream GetSilverlightPolicy()
    {
        return getPolicy("clientaccesspolicy.xml");
    }

    private static Stream getPolicy(string file)
    {
        if (!File.Exists(file))
        {
            WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
            return null;
        }

        WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
        return File.OpenRead(file);
    }
}

This simple web service has 2 methods corresponding to the two files mentioned above. It will search for the file in the application directory and return them as the response for the file.

Configuring the service

To configure the service add the following lines to your app.config file:

<?xml version="1.0"?>
<configuration>  
  <system.serviceModel>
    <services>
      <!-- snip... regular services -->

      <service name="MyNamespace.CrossDomainPolicyRetrieverService">
        <endpoint address="" binding="webHttpBinding"
                  contract="MyNamespace.CrossDomainPolicyRetrieverService" 
                  behaviorConfiguration="policyBehavior">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        
        <host>
          <baseAddresses>
             <!-- Root Domain where the other services are hosted -->
            <add baseAddress="http://localhost:8732/"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="policyBehavior">
          <webHttp  />  
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
  </system.serviceModel>
  <!-- snip... -->
</configuration>

Testing the service

To should now be able to access the policy files using any web browser and pointing it at /clientaccesspolicy.xml (e.g. http://localhost:8732/clientaccesspolicy.xml)

By setting a breakpoint inside the service methods, you can easily watch Silverlight accessing the corresponding resource files.

Leave a comment