views:

198

answers:

4

Hi, and sorry for another Cross Domain question.

I have been fighting with this all day now and am at the point of boiling over.

I have a Silverlight Application Project (SLApp1), a Web project for hosting the Silverlight (SLApp1.Web) and the WCF Project (SLWcfService).

Now I am building everything together and all the projects are in one solution. The Web project is hosted by Visual Studio and the WCF Service is hosted by the WcfSvcHost.

The problem that because the web and wcf are hosted separately there is a cross domain issue, so every time my Silverlight application attempts to make a call to the WCF the Cross Domain Exception is thrown.

I have tried:

  1. Adding clientaccesspolicy.xml to C:\inetpud\wwwroot
  2. Using webHttpBinding and having a ReadPolicy method in the service

The problem is I am still developing the solution and so publishing the service and then hosting in IIS is simply not a feasible solution.

Why does this have to be so INCREDIBLY difficult?

Please Help!

Reference Material:

My App.config:

     <system.serviceModel>
    <services>
      <service name="Test.Service1" behaviorConfiguration="Test.Service1Behavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8055" />
          </baseAddresses>
        </host>
        <endpoint address="Service1" binding="basicHttpBinding" contract="Test.IService1"/>
        <endpoint address="" binding="webHttpBinding" behaviorConfiguration="webHttpBehavior" contract="Test.WCFService.IClientAccessPolicy" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="Test.WCFService.Service1Behavior">
          <serviceMetadata httpGetEnabled="True" />
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="webHttpBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
A: 

I was also facing same kind of problem a time ago. What i concluded that time was to reference dll of the WCFService Project in the WebProject(Hosting Silverlight Control) and changed its web.config according to WCFService. Then instead of consuming WcfSvcHost Reference i used Reference from WebProject, That was the workaround i used.

But in short it is a little tricky to apply client-access-policy on a service hosted by WCFSvcHost.

Shoaib Shaikh
I am going to be honest and say that the fact the WcfSvcHost is the default hosting mechanism yet cannot deal with cross domain is pretty stupid.The way my solution is organised logical and well modularized but this problem is hampering my ability to move forward.
Oliver
+1  A: 

Although I am not sure that this will fix your issue, I will show you how I managed to get a similar solution layout fixed and maybe the steps will be of some guidance.

I set up a solution with a silverlight project (domainexception), a web project (domainexception.Web) and a wcf service (WcfServiceLibrary1). I made the Service1 endpoint a basicHttpBinding like it is in your App.config.

I then added a service reference to the silverlight project, and it built it with the following address:

"http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/"

Trying to run it like this I also ran into the cross-domain policy issue.

I then added the webHttpBinding and method to it and still found that it did not work.

So, finally I changed the base address from the one above to

http://localhost:8731

and it worked.

In the end that worked. So this is what it looked like at the end.

App.config

 <system.serviceModel>
<services>
  <service name="WcfServiceLibrary1.Service1" behaviorConfiguration="WcfServiceLibrary1.Service1Behavior">
    <host>
      <baseAddresses>
        <add baseAddress = "http://localhost:8731/" />
      </baseAddresses>
    </host>
    <endpoint address ="Service" binding="basicHttpBinding" contract="WcfServiceLibrary1.IService1">
      <identity>
        <dns value="localhost"/>
      </identity>
    </endpoint>
    <endpoint address="" binding="webHttpBinding" behaviorConfiguration="policyBehavior" contract="WcfServiceLibrary1.IService1"/>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  </service>
</services>
<behaviors>
  <endpointBehaviors>
    <behavior name="policyBehavior">
      <webHttp />
    </behavior>
  </endpointBehaviors>
  <serviceBehaviors>
    <behavior name="WcfServiceLibrary1.Service1Behavior">
      <serviceMetadata httpGetEnabled="True"/>
      <serviceDebug includeExceptionDetailInFaults="False" />
    </behavior>
  </serviceBehaviors>
</behaviors>

ServiceReferences.ClientConfig

<configuration>
<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpBinding_IService1" maxBufferSize="2147483647"
                maxReceivedMessageSize="2147483647">
                <security mode="None" />
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://localhost:8731/Service" binding="basicHttpBinding"
            bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference1.IService1"
            name="BasicHttpBinding_IService1" />
    </client>
</system.serviceModel>

and my web call for the policy:

Interface

[OperationContract, WebGet(UriTemplate="clientaccesspolicy.xml")]
    Stream ReturnPolicy();

Code

public System.IO.Stream ReturnPolicy()
    {
        string file = @"<?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 new MemoryStream(Encoding.UTF8.GetBytes(file));
    }
Johannes
HAHA, I just posted a similar post. Thanks so much!
Oliver
A: 

Ok somehow I got it working using the REST and webHttpBinding trick. I made a change to how I read the clientaccesspolicy from a file read to just using a cons string.

Here is how I resolved the problem:

App.config:

 <system.serviceModel>
<services>
  <service name="Symphony.Server.WCFService.Service1" behaviorConfiguration="Symphony.Server.WCFService.Service1Behavior">
    <host>
      <baseAddresses>
        <add baseAddress="http://localhost:8055" />
      </baseAddresses>
    </host>
    <endpoint address="Service1" binding="basicHttpBinding" contract="Symphony.Server.WCFService.IService1"/>
    <endpoint address="" binding="webHttpBinding" behaviorConfiguration="webHttpBehavior" contract="Symphony.Server.WCFService.IClientAccessPolicy" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="Symphony.Server.WCFService.Service1Behavior">
      <serviceMetadata httpGetEnabled="True" />
      <serviceDebug includeExceptionDetailInFaults="False" />
    </behavior>
  </serviceBehaviors>
  <endpointBehaviors>
    <behavior name="webHttpBehavior">
      <webHttp/>
    </behavior>
  </endpointBehaviors>
</behaviors>

IClientAccessPolicy.cs

[ServiceContract]
public interface IClientAccessPolicy
{
    [OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
    Stream GetPolicy();
}

Service1.cs

public class Service1 : IService1, IClientAccessPolicy
{
    public IList<string> GetData(string value)
    {
        //Some logic
    }

    [OperationBehavior]
    public Stream GetPolicy()
    {
        const 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>";

        if (WebOperationContext.Current != null)
            WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
        return new MemoryStream(Encoding.UTF8.GetBytes(result));
    }

Note: You must include System.ServiceModel.Web as a reference

Thank you

Oliver
A: 

PolicyService(REST) in WCFService Project can solve this probelm. This kind of service allows to send xml(clientAccessPolicy) in Response. eg If your service URL is like: http://localhost:[port]/Design_Time_Addresses/MyService.svc

Then PolicyService URL will be: http://localhost:[port]/clientaccesspolicy.xml (this kind of REST request will send clientaccesspolicy in Response to SilverlightClient).

Here is a link on how to create such PolicyService: http://social.msdn.microsoft.com/Forums/en/wcf/thread/d145a38f-b9bb-4c8e-9eab-b728dacc19df

Shoaib Shaikh
Can you elaborate?It would be great if I could have a PolicyService that stands alone that makes use of the webHttpBinding and has the GetPolicy() to return the clientaccsesspolicy and then have the other service that can be run as normal.No I am getting a little confused as I cannot run more than one server one port? Maybe you can give me an example of the segmented structure?
Oliver