6
votes

I have read most of the topics covering cross-domain error and still cannot get it working. Within the website, I load Silverlight module which communicates with WCF Webservice. On localhost, it works fine, no error occurred.

I have Webservice hosted on http://localhost:50283 and in the same folder that port 50283 refers to I have clientaccesspolicy.xml located which looks as follows

<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>

I placed clientaccesspolicy.XML hardly everywhere including \wwwroot but that brought no effect anyway. I can access clientaccesspolicy.xml both on local and on a different computer within the same network (http://computerIP:50283/clientaccesspolicy.xml displays content).
I tried to intercept error in order to find out some more details about error's nature but fiddler does not enlist any error, the only browser does. Literally, I tried everything and still no change. Has anyone faced a similar issue and could provide some hints where I should seek for a solution?

I ran into similar topic with no solution as well, alas
Silverlight-to-WCF cross-domain exception, but clientaccesspolicy.xml is being read successfully

2
Just for troubleshooting change http-request-headers to http-request-headers="*" to make sure that requests can go though is allowed, then work backwards as you add restrictions. If with all headers allowed it still does not go through then the issue is elsewhere. a fire wall setting maybe?Nkosi

2 Answers

3
votes

I remember running into this many years ago and solving it a bit differently, namely with a behavior. Consider the following:

using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.Xml;

internal class CrossDomainServiceBehavior : BehaviorExtensionElement, IEndpointBehavior
{
    private ServiceHost serviceHost;

    public override Type BehaviorType
    {
        get { return typeof(CrossDomainServiceBehavior); }
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        if (serviceHost == null)
        {
            serviceHost = new ServiceHost(typeof(CrossDomainPolicyService));

            string address = new Uri(endpoint.Address.Uri, "/").ToString();
            ServiceEndpoint crossDomainEndpoint = serviceHost.AddServiceEndpoint(typeof(ICrossDomainPolicyService), new WebHttpBinding(), address);
            crossDomainEndpoint.Behaviors.Add(new WebHttpBehavior());

            serviceHost.Open();
        }
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }

    protected override object CreateBehavior()
    {
        return new CrossDomainServiceBehavior();
    }
}

internal class CrossDomainPolicyService : ICrossDomainPolicyService
{
    public Message ProvideClientAccessPolicyFile()
    {
        XmlReader xmlReader = CreateClientAccessXml();
        return Message.CreateMessage(MessageVersion.None, string.Empty, xmlReader);
    }

    public Message ProvideCrossDomainPolicyFile()
    {
        XmlReader xmlReader = CreateCrossDomainXml();
        return Message.CreateMessage(MessageVersion.None, string.Empty, xmlReader);
    }

    private static XmlReader CreateClientAccessXml()
    {
        TextReader reader = new StringReader(@"<?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 XmlReader.Create(reader);
    }

    private static XmlReader CreateCrossDomainXml()
    {
        TextReader reader = new StringReader(@"<?xml version='1.0'?>
                                                  <cross-domain-policy>
                                                  <allow-http-request-headers-from domain='*' headers='*'/>
                                                  </cross-domain-policy>");
        return XmlReader.Create(reader);
    }
}

The CrossDomainServiceBehavior needs to be added to the behaviors on your WCF service and it uses the CrossDomainPolicyService for dynamically adding the cross domain policy. This prevents you from having to add the cross domain file to the website itself.

Adding the behavior from code (for example with self hosted services):

endPoint.Behaviors.Add(new CrossDomainServiceBehavior());

Or in case of WCF definitions in config: For the sake of this example I will assume the CrossDomainServiceBehavior is in the namespace Services.CrossDomainServiceBehavior and the assembly it is located in is version 1.0.0.0 with a neutral culture. It also assumes you have a binding on your service declaration called webHttp.

Registering the behavior:

<system.serviceModel>
  <extensions>
    <behaviorExtensions>
      <add name="CrossDomainServiceBehavior" type="Services.CrossDomainServiceBehavior, CrossDomainServiceBehavior.AssemblyName, Version=1.0.0.0, Culture=neutral" />
    </behaviorExtensions>
  </extensions>

Declare the behavior:

<behaviors>
  <endpointBehaviors>
    <behavior name="CrossDomainServiceBehavior">
      <webHttp/>
      <CrossDomainServiceBehavior/>
    </behavior>
  </endpointBehaviors>
<behaviors>

Add the behavior to the binding (here as example one called webHttp):

<bindings>
    <webHttpBinding>
        <binding name="webHttp"
         maxReceivedMessageSize="20000000" >
            <security mode="None">
                <transport clientCredentialType = "None"/>
            </security>
        </binding>
        <CrossDomainServiceBehavior />
    </webHttpBinding>
</bindings>

Finally, add the behavior to your service endpoint, here in example one that implements ISomeService:

<endpoint address="" binding="webHttpBinding" contract="Services.ISomeService" bindingConfiguration="webHttp" behaviorConfiguration="CrossDomainServiceBehavior "/>
1
votes

Not sure if it has to do anything with it, but I have a similar setup and my clientaccesspolicy.xml looks a bit different.

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

Especially the splitting of http and https adresses is different. Besides that you are trying to do this with a non-default port, have you tried it on the default port 80? oh and on the production environment those *'s are replaced with the actual domain name.