Enabling cross-domain calls for Silverlight apps on self-hosted web services


In order for a Silverlight (or Flash) app coming from one domain to be able to consume data from services in a different domain, the service must “allow” the app to do so by providing a policy file which grants access (to prevent all sorts of cross-site scripting attacks). This policy file must be located in the root of the “domain” (hostname + port), so if your service is located at http://my.service.com:8000/Service/CoolService.svc/Endpoint, the policy file must be located at http://my.service.com:8000/ClientAccessPolicy.xml (or http://my.service.com:8000/crossdomain.xml in case of the Flash format). That’s fairly easy to do on a IIS-hosted service (simply put the static policy file in the root of the web), but for self-hosted apps it isn’t as simple (there’s no “root” of the web).

To solve this problem for self-hosted WCF services, you can use the web programming model support fairly easily. Basically, you’d define the base address at the root of the domain, and have a web endpoint at the “” address. All the “real” service endpoints would then be in different addresses. The example below shows it in action:

[update (2010/07/24): if your self-hosted service uses the TCP binding (new in SL4), you can look at the solution at my new post at http://blogs.msdn.com/b/carlosfigueira/archive/2010/07/25/enabling-cross-domain-calls-for-sl-apps-on-self-hosted-tcp-services.aspx]

A complete VS solution with a SL application and the self-hosted service can be found at the MSDN Code Gallery at http://code.msdn.microsoft.com/Accessing-self-hosted-WCF-7872c931. The code for the service itself is listed below.

  1.     public class SelfHostedServiceWithSilverlightPolicy
  2.     {
  3.         [ServiceContract]
  4.         public interface ITest
  5.         {
  6.             [OperationContract]
  7.             string Echo(string text);
  8.         }
  9.         [ServiceContract]
  10.         public interface IPolicyRetriever
  11.         {
  12.             [OperationContract, WebGet(UriTemplate = “/clientaccesspolicy.xml”)]
  13.             Stream GetSilverlightPolicy();
  14.             [OperationContract, WebGet(UriTemplate = “/crossdomain.xml”)]
  15.             Stream GetFlashPolicy();
  16.         }
  17.         public class Service : ITest, IPolicyRetriever
  18.         {
  19.             public string Echo(string text) { return text; }
  20.             Stream StringToStream(string result)
  21.             {
  22.                 WebOperationContext.Current.OutgoingResponse.ContentType = “application/xml”;
  23.                 return new MemoryStream(Encoding.UTF8.GetBytes(result));
  24.             }
  25.             public Stream GetSilverlightPolicy()
  26.             {
  27.                 string result = @”<?xml version=””1.0″” encoding=””utf-8″”?>
  28. <access-policy>
  29.     <cross-domain-access>
  30.         <policy>
  31.             <allow-from http-request-headers=””*””>
  32.                 <domain uri=””*””/>
  33.             </allow-from>
  34.             <grant-to>
  35.                 <resource path=””/”” include-subpaths=””true””/>
  36.             </grant-to>
  37.         </policy>
  38.     </cross-domain-access>
  39. </access-policy>”;
  40.                 return StringToStream(result);
  41.             }
  42.             public Stream GetFlashPolicy()
  43.             {
  44.                 string result = @”<?xml version=””1.0″”?>
  45. <!DOCTYPE cross-domain-policy SYSTEM “”http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd””>
  46. <cross-domain-policy>
  47.     <allow-access-from domain=””*”” />
  48. </cross-domain-policy>”;
  49.                 return StringToStream(result);
  50.             }
  51.         }
  52.         public static void Main()
  53.         {
  54.             string baseAddress = “http://” + Environment.MachineName + “:8000”;
  55.             ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
  56.             host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), “basic”);
  57.             host.AddServiceEndpoint(typeof(IPolicyRetriever), new WebHttpBinding(), “”).Behaviors.Add(new WebHttpBehavior());
  58.             ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
  59.             smb.HttpGetEnabled = true;
  60.             host.Description.Behaviors.Add(smb);
  61.             host.Open();
  62.             Console.WriteLine(“Host opened”);
  63.  
  64.             Console.WriteLine(“Press ENTER to close”);
  65.             Console.ReadLine();
  66.             host.Close();
  67.         }
  68.     }

Comments (49)

  1. One interesting question from the WCF forums: how to enable the cross-domain calls to self-hosted services,

  2. Karen Corby provides us 3 SL2 controls, Carlos Figueira details the cross-domain policy file, Jesse Liberty

  3. Depuis la mise a disponibilité de Silverlight 2 au Mix08 il y a eu beaucoup d’articles, de blogs sur

  4. Silverlight 2 Beta1 makes it easy to use Web Services based on either the WCF technology (Windows Communication

  5. This tip concerns those who wants to use self hosting capabilities of services in WCF or Restlet in cross-domain

  6. Shahar Ron says:

    Recently I tried to call a WCF service hosted in a windows service from silverlight. I got an HTTP 404

  7. ShaharRon says:

    See a small correction needed to your clientaccesspolicy.xml

  8. Read the full details Here . Carlos came up with an elegant way to enable cross domain calls from silverlight

  9. Read the full details Here . Carlos came up with an elegant way to enable cross domain calls from silverlight

  10. Masande says:

    Hi Carlos I was able to implement and run the sample code you posted successfuly but get the error

    "This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. Please see the inner exception for more details" when running that very same code in the Web Service Software Factory. Please assist

  11. xmhai says:

    Hi, Carlos,

    It only works fine for the first 5 requests, i.e. click the "refresh" button in IE. After that, "The remote server returned an error: NotFound" exception will raise for subsequent requests. Then I have to shutdown the Service. Do you have any idea? it looks like buffer overflown.

  12. Israel Aece says:

    ClientAccessPolicy.xml sem IIS

  13. mdmSoftware says:

    This works great for me provided the WCF service is up and running on my local box prior to launching my Silverlight application.  I have a self hosted WCF Windows service and I am hitting it from a Silverlight page using the localhost cross domain access trick above.  If I do not launch my WCF service until after hitting my Silverlight page but rather launch it after, my Silverlight application can never recover.  Looks like the clientaccess and crossdomain negotiation for the host domain are done somewhere behind the scenes in the client factory and I can’t seem to find a way to re-initiate the check for security access.  What am I missing?

  14. si says:

    How can this example ever work inside Silverlight when ITest.Echo is a synchronous operation?

    Aside from that, even using asynchronous methods I still get a the same problem as Masande, I can browse to http://localhost:8731/Design_Time_Addresses/MyService/clientaccesspolicy.xml and see that it is being generated, however my Silverlight still throws the cross-domain exception.

  15. Michael says:

    When is the "Test" Method run? I don’t quite understand how this works.

  16. AlWiNu says:

    Hi [si]…

    http://localhost:8731/Design_Time_Addresses/MyService/”>http://localhost:8731/Design_Time_Addresses/MyService/

    is not the root!

    http://localhost:8731/

    this is your root

    http://localhost:8731/clientaccesspolicy.xml

    this must be the link to your clientaccesspolicy.xml

  17. Carlos says:

    Hi,

    I did your example in the same way you showed it, but I still the same problem like I haven’t implemented it. (I already updated the .xml file)

    My environnement is :

    • Silverlight app. in another domain (IIS). I’m accessing in this way http://<<IP>&gt;:<<port>>/test.html
    • My local app. as a server WCF with service address http://localhost:8999/service

    • I’m using CustomBinding with PollingDuplexBindingElement to create a bidirectionnal communication.

    When I call the WCF server, I have the error like I haven’t the clientaccesspolicy.xml set. If I test the clientaccesspolicy.xml using the address http://localhost:8999/clientaccesspolicy.xml, the explorer show it. So, it’s well implemented.

    But, when I have my silverlight app hosted in the same machine and I launch my silverlight app. like this http://localhost:8999/test.html, everything works OK!.

    I see that my silverlight app. is getting the clientaccesspolicy.xml.

    If I use the machine’s IP to launch my silverlight app., even if this app. is hosted in the same machine, I have the same error.

    What am i doing wrong???

    Thanks in advance.

    Carlos.

    Error:

    An error occurred while trying to make a request to URI ‘http://localhost:8999/service‘. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute. Please see the inner exception for more details.

  18. Carlos says:

    Update..

    I make a mistake in this line:

    But, when I have my silverlight app hosted in the same machine and I launch my silverlight app. like this http://localhost:8999/test.html, everything works OK!.

    I would say

    But, when I have my silverlight app hosted in the same machine and I launch my silverlight app. like this http://localhost/test.html, everything works OK!.

    Another thing, when the SL app. is hosted in another PC. With the Nikhil’s Web Development Helper, i didn’t see the SL app. requesting the clientaccespolicy.xml, instead of that, I see the java script error. But when the SL app. is in the same machine and I call it like this "http://localhost/test.html", I see the app. is requesting the .xml file.  

    I’m using Silverlight 3, Visula Studio 8, Net 3.5, Internet Explorer 8.

    Help me!!!

  19. Propagandalf says:

    This works great when using HTTP but what if the service is hosted at https://localhost:9000/MyService ? Won’t Silverlight try to locate the policy file at https://localhost:9000/clientaccesspolicy.xml ?

    When running this on HTTP a breakpoint in the IPolicyRetriever implementation shows me that the policy file contents are returned when the Silverlight client accesses the WCF service.

    When hosting the WCF service on HTTPS the breakpoint is never hit and the Silverlight client gets an exception indicating a cross domain error (because the policy file was not found). I have tried "everything" regarding the webHttpBinding endpoint, but can’t seem to make this work on HTTPS.

    Any tips?

  20. Carlos says:

    After searching a lot about my problem, finally I found the answer which is Cross-Zone restrictions.

    I invite everyone to check those addresses which could save you a lot of hours of searching for an answer, because almost always the examples of this nature don’t mention security restrictions in Silverlight.

    Network Security Access Restrictions in Silverlight

    http://msdn.microsoft.com/en-us/library/cc645032(VS.95).aspx

    URL Access Restrictions in Silverlight

    http://msdn.microsoft.com/en-us/library/cc189008(VS.95).aspx

    You are served.

    Carlos.

    P.D. Probably this could help you Propagandalf.

  21. Propagandalf says:

    Thanks for the links, Carlos.

    However, they "only" describe how to enable/disable access using the clientaccesspolicy.xml file. My problem seems to be that the file isn’t even downloaded from the server on HTTPS; so it doesn’t really matter what’s in the file. Since it’s never downloaded its contents are never evaluated.

    Or is the file evaluated by the server hosting the WCF service before it’s downloaded thus denying access? I’m unsure how this actually works.

  22. Dave says:

    Thanks for this, this information should come in handy!

  23. atconway says:

    @Propagandalf – if you want to use HTTPS you will probably either need to change this line of code:

    smb.HttpGetEnabled = true;

    to

    smb.HttpsGetEnabled = true;

    or change your service configuration to have the following:

         <serviceBehaviors>

           <behavior name="ServiceBehavior">

             <serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />

           </behavior>

         </serviceBehaviors>

       </behaviors>

  24. ken says:

    forgive me for being so stupid,  i am new to silverlight.  I have used your code example above to create a Wcf Self-hosted service.  It runs fine with a non-silverlight client.

    when i create a Silverlight application and create a service reference to this, then add the handler for the 'GetHelloAsychResult' etc etc, i still get this error  …"This could be due to attempting to access a service in a cross-domain way without a prop…"   Am i missing something?   Do I need to explicitly call the 'GetSilverlightPolicy' in the silverlight code??

    thanks for your help..

  25. Ken, you don't need to explictly call GetSilverlightPolicy – it should be done by the SL runtime to verify whether you're allowed to call the GetHelloAsync method.

    There is a video on blogs.msdn.com/…/debugging-wcf-services-in-silverlight.aspx which shows many steps you can take to debug failures on service calls. Take a look at it and see if it gives you any clue to solve your problem.

    Good luck!

  26. Priyang Patel says:

    spot on dude , It saved my lots of time, Thanks

  27. Oliver says:

    Cross Domain calls are not allowed in HTTPS.

  28. Oliver, I've been able to get cross-domain calls to work on HTTPS as well; are you hitting any specific issue?

  29. Nancy Healy says:

    Many Thanks this was extremely helpful!

  30. wqeq says:

    Where should I put this file if I receive such exception during debugging in VS 2010 a sample WCF service call from silverlight ?

  31. If your service is hosted in IIS, then the cross-domain file must be on the root of the site (usually c:inetpubwwwroot). If your service is self-hosted (i.e., you use ServiceHost to host your service), then there's no concrete "file" per se, but the service needs to serve it as well, as I showed in this post.

  32. Jim says:

    HI Carlos,

    Thank you for the post.  It has helped me to understand a lot more about this problem.  After attempting a lot of your suggestions here, I still encounter problems of this nature.

    I am hosting wcf services in a windows service on port 8119.  I have a site that uses a SL app that attempts to access these service.  No go – Cross domaing policy errors.

    I have built a sort of proxy service hosted within a web site (asp.net).  This site accesses the service, and i am trying to call into this site with the SL app.  I have placed a policy file in the site root.  This site is listening on port 8098 – no outside access.  All of these sites are located on the same system.

    No matter what I try, i get domain policy errors.

    Does the SL app run on the client?  Do I need to open the ports to the services?  Doesn't the silverlight app do all of the access to the services on the server?

    I would appreciate any help.

    Thanks,

    Jim

  33. Hi Jim,

    "Does the SL app run on the client" – yes, the SL application runs under the browser.

    "Do I need to open the ports to the services" – it depends; if you can use something like telnet from the client to the server on the port of the service, then you have access; otherwise you should try to use some network tracing tool (such as the Microsoft Network Monitor for Windows, or the Cocoa packet analyzer for Mac) to see if the connection is actually being established.

    "Doesn't the silverlight app do all of the access to the services on the server" – it depends on how the service and the app is implemented. Check either the file ServiceReferences.ClientConfig on SL or any code in which you pass the service address to see which port the service is actually using.

    Hope this helps.

  34. Abhishek says:

    I downloaded this code from Code.msdn link, made the changes as the three steps specified to make both the project as start up , then click F5,

    but i got this error :HTTP could not register URL http://+:80HTTP could not register URL http://+:8000/. Your process does not have access rights to this namespace (see go.microsoft.com/fwlink for details)

    access denied.

    I new to this ,kindly let me know what is the resolution for this.

    thanks

    Abhishek

  35. Hi Abhishek,

    By default, only applications running as administrator can open listen sockets in HTTP. You can either run Visual Studio in Administrator mode (right click the VS icon, select "Run as Administrator"), or you can follow the instructions in the link mentioned in the exception (msdn.microsoft.com/…/ms733768.aspx) to open up the port for your user.

    Hope this helps.

  36. Padma says:

    Thanx alottttttttttttttttttttttttttt … I was stuck on that exception more than 3 days

  37. Padma says:

    I got that exception when i use the wcf service and i changed it to wcf service application its gone

  38. Anbu says:

    Thanks a lot, it reduced lot of my works. it works really nice

  39. greg says:

    silverlight doesn't have WebHttpBinding, how this work? your code is not from silverlight?

  40. @greg, the WebHttpBinding is for the server side (WCF service), not for Silverlight.

  41. greg says:

    ok, do I have to use a port in baseAddress ?

    if I add  the following new end point to the config I got 404 error for the service. it's working fine if remove this part.

    <endpoint address="" binding="webHttpBinding" contract="ClientListenerService.IPolicyRetriever" behaviorConfiguration="webHttpEnablingBehavior">

    /endpoint>

    the app.config like this

    <?xml version="1.0"?>

    <configuration>

     <system.web>

       <compilation debug="true"/>

     </system.web>

     <!– When deploying the service library project, the content of the config file must be added to the host's

     app.config file. System.Configuration does not support config files for libraries. –>

     <system.serviceModel>

       <services>

         <service name="ClientListenerService.ListenerService">

           <endpoint address="" binding="basicHttpBinding" contract="ClientListenerService.IListenerService">        

           </endpoint>

           <endpoint address="" binding="webHttpBinding" contract="ClientListenerService.IPolicyRetriever" behaviorConfiguration="webHttpEnablingBehavior">

           </endpoint>

           <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

           <host>

             <baseAddresses>

               <add baseAddress="http://localhost/CounselingClient"/&gt;

             </baseAddresses>

           </host>

         </service>

       </services>

       <behaviors>

         <serviceBehaviors>

           <behavior>

             <!– To avoid disclosing metadata information,

             set the value below to false and remove the metadata endpoint above before deployment –>

             <serviceMetadata httpGetEnabled="True"/>

             <!– To receive exception details in faults for debugging purposes,

             set the value below to true.  Set to false before deployment

             to avoid disclosing exception information –>

             <serviceDebug includeExceptionDetailInFaults="False"/>

           </behavior>

         </serviceBehaviors>

       </behaviors>

     </system.serviceModel>

     <startup>

       <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>

     </startup>

    </configuration>

  42. Your basic and web http bindings share the same address; try using a relative address for your basicHttpBinding endpoint, as this should solve any conflicts you may have for one endpoint going over the other

  43. Greg says:

    Could you please share your web.config file here? thanks

  44. The project I have here is a self-hosted project, not a webhosted one – as such, there's no web.config. If your WCF service is webhosted, then you don't need to do that – just drop a clientaccesspolicy.xml file in the root of your web service.

  45. Greg says:

    I created a console app using your code and changed the baseAddress = "172.16.11.78/client" after running I am able to get the WCF at http://172.16.11.78/client  but can't find the file 172.16.11.78/crossdomian.xml  and 172.16.11.78/clientaccesspolicy.xml.   still not able to access this wcf from another silverlight app.

  46. The base address must be at the root of the domain (in your case, no /client path). If you want to add an endpoint at 172.16.11.78/client you can do that (by using the relative address "client" when adding your endpoint).

  47. Greg says:

    thanks, by using similar your code.

    string baseAddress = "http://172.16.11.78&quot;;

               ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));

               host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "Client");

               host.AddServiceEndpoint(typeof(IPolicyRetriever), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());

    172.16.11.78/crodomain.xml is working, http://172.16.11.78/Client is return nothing.

    however http://172.16.11.78   returns everything.

  48. What do you mean by "returns nothing" and "returns everything"? By the way, this conversation is better continued in a forum-like setting (better formatting) such as MSDN Forums (social.msdn.microsoft.com/Forums/azure/en-US/home?forum=wcf) or Stack Overflow (stackoverflow.com/questions/tagged/wcf).

Skip to main content