none
Self hosted WCF service and enabling cross domain calls RRS feed

  • Question

  • Hi,

     

    With the new Silverlight 2 beta 1 (and the old Flash/Flex), cross domain access to services are possible, as long as the service it self permitts the SL/Flash/Flex to access the service. This is done by adding a clientaccesspolicy.xml or crossdomain.xml file to the root of the domain where the service is hosted. (See http://msdn2.microsoft.com/en-us/library/cc197955(VS.95).aspx for details.)

     

    The question though, is how to do this when using a self hosted WCF service? Since the ServiceHost has ownership of the port that it is bound to, no one else can serv any additional webpages/xml files on the same port. And since the port number counts towards cross domain, serving the xml permission files on the same domain name but on a different port, isn't possible.

     

    Is there any configuration of the ServiceHost that would allow it to send the crossdomain.xml/clientaccesspolicy.xml to regular http requests? Can it be done using custom bindings or behaviours?

     

    (I allready posted this question on the silverlight forum, http://silverlight.net/forums/t/10513.aspx, but this might be more of a WCF question really, sorry for the duplication.)

     

    Cheers,

    RedZ

    Friday, March 7, 2008 7:48 AM

Answers

  • If I'm not mistaken, the clientaccesspolicy/crossdomain.xml file needs to be in the root of the "host" (service + port). So as long as the base address for the host doesn't contain any path after the port, you can add a webHttpBinding-based endpoint at the root address, and have it return the policy file. The "real" endpoints would need to be based on some other address. The code below shows how to do that:

     

    public class Post2965772

    {

        [ServiceContract]

        public interface ITest

        {

            [OperationContract]

            string Echo(string text);

        }

        [ServiceContract]

        public interface IPolicyRetriever

        {

            [OperationContract, WebGet(UriTemplate = "/crossdomain.xml")]

            Stream GetPolicy();

        }

        public class Service : ITest, IPolicyRetriever

        {

            public string Echo(string text) { return text; }

            public Stream GetPolicy()

            {

                string result = @"<?xml version=""1.0""?>

    <!DOCTYPE cross-domain-policy SYSTEM ""http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"">

    <cross-domain-policy>

        <allow-access-from domain=""*"" />

    </cross-domain-policy>";

                WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";

                return new MemoryStream(Encoding.UTF8.GetBytes(result));

            }

        }

        public static void Test()

        {

            string baseAddress = "http://" + 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("Endpoints:");

            foreach (ServiceEndpoint endpoint in host.Description.Endpoints)

            {

                Console.WriteLine("Binding: {0}, address: {1}", endpoint.Binding.GetType().Name, endpoint.Address.Uri);

            }

     

            Console.Write("Press ENTER to close");

            Console.ReadLine();

            host.Close();

        }

    }

    Friday, March 7, 2008 8:25 AM

All replies

  • If I'm not mistaken, the clientaccesspolicy/crossdomain.xml file needs to be in the root of the "host" (service + port). So as long as the base address for the host doesn't contain any path after the port, you can add a webHttpBinding-based endpoint at the root address, and have it return the policy file. The "real" endpoints would need to be based on some other address. The code below shows how to do that:

     

    public class Post2965772

    {

        [ServiceContract]

        public interface ITest

        {

            [OperationContract]

            string Echo(string text);

        }

        [ServiceContract]

        public interface IPolicyRetriever

        {

            [OperationContract, WebGet(UriTemplate = "/crossdomain.xml")]

            Stream GetPolicy();

        }

        public class Service : ITest, IPolicyRetriever

        {

            public string Echo(string text) { return text; }

            public Stream GetPolicy()

            {

                string result = @"<?xml version=""1.0""?>

    <!DOCTYPE cross-domain-policy SYSTEM ""http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"">

    <cross-domain-policy>

        <allow-access-from domain=""*"" />

    </cross-domain-policy>";

                WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";

                return new MemoryStream(Encoding.UTF8.GetBytes(result));

            }

        }

        public static void Test()

        {

            string baseAddress = "http://" + 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("Endpoints:");

            foreach (ServiceEndpoint endpoint in host.Description.Endpoints)

            {

                Console.WriteLine("Binding: {0}, address: {1}", endpoint.Binding.GetType().Name, endpoint.Address.Uri);

            }

     

            Console.Write("Press ENTER to close");

            Console.ReadLine();

            host.Close();

        }

    }

    Friday, March 7, 2008 8:25 AM
  • Thank you, I'll try it later today, but I think this will do the trick. There's without a doubt a lot of cool stuff that can be done with WCF and to learn.

    Friday, March 7, 2008 8:56 AM
  • i've tried exactly your sample and when i try to reach url http://localhost:8000/basic, i have the following error :

     

    - <s:Envelope xmlnsTongue Tied="http://schemas.xmlsoap.org/soap/envelope/">
    - <s:Body>
    - <s:Fault>
      <faultcode xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:ActionNotSupported</faultcode>
      <faultstring xml:lang="fr-FR">The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).</faultstring>
      </s:Fault>
      </s:Body>
      </s:Envelope>
     
    i'm totally disappointed, thx for your help
    Friday, April 4, 2008 2:23 PM
  • This worked fine with Silverlight Beta 1, but it doesn't seem to work with Beta 2.   In the ServiceReferences.clientconfig file that gets generated it's complaining about the CustomBinding.....

     

    <customBinding>

    <binding name="PolicyResponder">

    <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"

    messageVersion="Soap12" writeEncoding="utf-8">

    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"

    maxBytesPerRead="4096" maxNameTableCharCount="16384" />

    </textMessageEncoding>

    </binding>

    </customBinding>

     

     

     

     

    Can someone post a solution for what we need to change to call a self-hosted WCF service from Silverlight Beta 2?

     

    Thanks!

    Tuesday, June 10, 2008 2:54 PM
  •  

    I have the same problem. Would like a solution too, since this was a very neat solution, only 1 service and easy to deploy and maintain.
    Monday, June 16, 2008 8:41 AM
  •  

    I know this is an older thread,  but i have a related issue and am desperatly seeking help.

    I have a simple self hosted wcf service which runs via console. (BasicHttpBinding, win7,). 

    I want to consume this service from a asp.net page which runs on a differnt machine,

    different domain. 

    When under debug(i.e. the asp page and the service are on same machine/domain), 

    everything works just fine.  When I publish the page to my host service (diff domain), 

    it no longer works.  (no response for the service/server).

    I have opended the port on my router to fwd to my dev machine, and win firewall is OFF. 

    One other key requirment: 

    The wcf service will eventually be part of a application that will be 

    distributed to multiple locations , each with there own domain.  The client (asp.net page). will at runtime determine the users "site", and resolve the domain,

    and then connect to the wcf service being hosted at the users site. 

    This means the I must set the wcf service address at runtime, which 

    is how i have it coded up right now. 

    Questions:

    Should I be using a differnt binding?,  can I do what I want with basicHttpbinding?

    Is there someother network configuration thing that i am missing,  like port sharing..??,

    Do I need to add a clientaccesspolicy.xml...etc to allow for cross domain access?, 

    and if so,   where to place it, since self hosted, I don't have a "web root", ..?

    Any help/ideas would be much appreciated. 

    Sunday, May 16, 2010 8:33 PM