Partager via


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 https://my.service.com:8000/Service/CoolService.svc/Endpoint, the policy file must be located at https://my.service.com:8000/ClientAccessPolicy.xml (or https://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 https://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 https://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 ""https://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 = "https://" + 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

  • Anonymous
    March 07, 2008
    One interesting question from the WCF forums: how to enable the cross-domain calls to self-hosted services,

  • Anonymous
    March 15, 2008
    Karen Corby provides us 3 SL2 controls, Carlos Figueira details the cross-domain policy file, Jesse Liberty

  • Anonymous
    March 17, 2008
    Depuis la mise a disponibilité de Silverlight 2 au Mix08 il y a eu beaucoup d'articles, de blogs sur

  • Anonymous
    April 16, 2008
    Silverlight 2 Beta1 makes it easy to use Web Services based on either the WCF technology (Windows Communication

  • Anonymous
    August 11, 2008
    This tip concerns those who wants to use self hosting capabilities of services in WCF or Restlet in cross-domain

  • Anonymous
    October 25, 2008
    Recently I tried to call a WCF service hosted in a windows service from silverlight. I got an HTTP 404

  • Anonymous
    October 27, 2008
    See a small correction needed to your clientaccesspolicy.xml

  • Anonymous
    October 27, 2008
    I mean see it here:http://blogs.microsoft.co.il/blogs/shaharron/archive/2008/10/25/silverlight-and-wcf-cross-site-scripting-issue.aspx

  • Anonymous
    December 07, 2008
    Read the full details Here . Carlos came up with an elegant way to enable cross domain calls from silverlight

  • Anonymous
    January 15, 2009
    Read the full details Here . Carlos came up with an elegant way to enable cross domain calls from silverlight

  • Anonymous
    March 05, 2009
    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

  • Anonymous
    March 16, 2009
    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.

  • Anonymous
    May 15, 2009
    ClientAccessPolicy.xml sem IIS

  • Anonymous
    July 31, 2009
    The comment has been removed

  • Anonymous
    November 12, 2009
    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.

  • Anonymous
    December 07, 2009
    When is the "Test" Method run? I don't quite understand how this works.

  • Anonymous
    December 07, 2009
    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 roothttp://localhost:8731/clientaccesspolicy.xmlthis must be the link to your clientaccesspolicy.xml

  • Anonymous
    January 22, 2010
    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>>:<<port>>/test.htmlMy 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.

  • Anonymous
    January 22, 2010
    The comment has been removed

  • Anonymous
    January 27, 2010
    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?

  • Anonymous
    January 29, 2010
    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 Silverlighthttp://msdn.microsoft.com/en-us/library/cc645032(VS.95).aspxURL Access Restrictions in Silverlighthttp://msdn.microsoft.com/en-us/library/cc189008(VS.95).aspxYou are served.Carlos.P.D. Probably this could help you Propagandalf.

  • Anonymous
    January 31, 2010
    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.

  • Anonymous
    April 22, 2010
    Thanks for this, this information should come in handy!

  • Anonymous
    July 20, 2010
    The comment has been removed

  • Anonymous
    December 12, 2010
    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..

  • Anonymous
    December 19, 2010
    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!

  • Anonymous
    February 22, 2011
    spot on dude , It saved my lots of time, Thanks

  • Anonymous
    March 01, 2011
    Cross Domain calls are not allowed in HTTPS.

  • Anonymous
    March 15, 2011
    Oliver, I've been able to get cross-domain calls to work on HTTPS as well; are you hitting any specific issue?

  • Anonymous
    August 23, 2011
    Many Thanks this was extremely helpful!

  • Anonymous
    September 05, 2011
    Where should I put this file if I receive such exception during debugging in VS 2010 a sample WCF service call from silverlight ?

  • Anonymous
    September 06, 2011
    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.

  • Anonymous
    October 09, 2011
    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

  • Anonymous
    October 10, 2011
    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.

  • Anonymous
    December 11, 2011
    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.thanksAbhishek

  • Anonymous
    December 11, 2011
    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.

  • Anonymous
    April 10, 2012
    Thanx alottttttttttttttttttttttttttt ... I was stuck on that exception more than 3 days

  • Anonymous
    April 10, 2012
    I got that exception when i use the wcf service and i changed it to wcf service application its gone

  • Anonymous
    April 18, 2012
    Thanks a lot, it reduced lot of my works. it works really nice

  • Anonymous
    August 13, 2014
    silverlight doesn't have WebHttpBinding, how this work? your code is not from silverlight?

  • Anonymous
    August 13, 2014
    @greg, the WebHttpBinding is for the server side (WCF service), not for Silverlight.

  • Anonymous
    August 14, 2014
    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"/>         </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>

  • Anonymous
    August 14, 2014
    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

  • Anonymous
    August 22, 2014
    Could you please share your web.config file here? thanks

  • Anonymous
    August 22, 2014
    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.

  • Anonymous
    September 12, 2014
    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.

  • Anonymous
    September 12, 2014
    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).

  • Anonymous
    September 14, 2014
    thanks, by using similar your code.string baseAddress = "http://172.16.11.78";           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.

  • Anonymous
    September 15, 2014
    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).