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.
- public class SelfHostedServiceWithSilverlightPolicy
- {
- [ServiceContract]
- public interface ITest
- {
- [OperationContract]
- string Echo(string text);
- }
- [ServiceContract]
- public interface IPolicyRetriever
- {
- [OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
- Stream GetSilverlightPolicy();
- [OperationContract, WebGet(UriTemplate = "/crossdomain.xml")]
- Stream GetFlashPolicy();
- }
- public class Service : ITest, IPolicyRetriever
- {
- public string Echo(string text) { return text; }
- Stream StringToStream(string result)
- {
- WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
- return new MemoryStream(Encoding.UTF8.GetBytes(result));
- }
- public Stream GetSilverlightPolicy()
- {
- string result = @"<?xml version=""1.0"" encoding=""utf-8""?>
- <access-policy>
- <cross-domain-access>
- <policy>
- <allow-from http-request-headers=""*"">
- <domain uri=""*""/>
- </allow-from>
- <grant-to>
- <resource path=""/"" include-subpaths=""true""/>
- </grant-to>
- </policy>
- </cross-domain-access>
- </access-policy>";
- return StringToStream(result);
- }
- public Stream GetFlashPolicy()
- {
- string result = @"<?xml version=""1.0""?>
- <!DOCTYPE cross-domain-policy SYSTEM ""https://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"">
- <cross-domain-policy>
- <allow-access-from domain=""*"" />
- </cross-domain-policy>";
- return StringToStream(result);
- }
- }
- public static void Main()
- {
- string baseAddress = "https://" + Environment.MachineName + ":8000";
- ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
- host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "basic");
- host.AddServiceEndpoint(typeof(IPolicyRetriever), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
- ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
- smb.HttpGetEnabled = true;
- host.Description.Behaviors.Add(smb);
- host.Open();
- Console.WriteLine("Host opened");
- Console.WriteLine("Press ENTER to close");
- Console.ReadLine();
- host.Close();
- }
- }
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 LibertyAnonymous
March 17, 2008
Depuis la mise a disponibilité de Silverlight 2 au Mix08 il y a eu beaucoup d'articles, de blogs surAnonymous
April 16, 2008
Silverlight 2 Beta1 makes it easy to use Web Services based on either the WCF technology (Windows CommunicationAnonymous
August 11, 2008
This tip concerns those who wants to use self hosting capabilities of services in WCF or Restlet in cross-domainAnonymous
October 25, 2008
Recently I tried to call a WCF service hosted in a windows service from silverlight. I got an HTTP 404Anonymous
October 27, 2008
See a small correction needed to your clientaccesspolicy.xmlAnonymous
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.aspxAnonymous
December 07, 2008
Read the full details Here . Carlos came up with an elegant way to enable cross domain calls from silverlightAnonymous
January 15, 2009
Read the full details Here . Carlos came up with an elegant way to enable cross domain calls from silverlightAnonymous
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 assistAnonymous
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 IISAnonymous
July 31, 2009
The comment has been removedAnonymous
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.xmlAnonymous
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 removedAnonymous
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 removedAnonymous
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, ThanksAnonymous
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,JimAnonymous
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.thanksAbhishekAnonymous
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 daysAnonymous
April 10, 2012
I got that exception when i use the wcf service and i changed it to wcf service application its goneAnonymous
April 18, 2012
Thanks a lot, it reduced lot of my works. it works really niceAnonymous
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 otherAnonymous
August 22, 2014
Could you please share your web.config file here? thanksAnonymous
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).