I have a self hosted WCF 4 service, catering the same contract via basicHttpBinding for Silverlight 4 clients and wsHttpBinding for the others. The code is very short and simple and provided here.
I get the following error when trying to access the a service method from WCF:
Message=An error occurred while trying to make a request to URI
http://localhost:8008/WCF4Silverlight.MyService/SL
. 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.
I do have the method, GetClientAccessPolicy() serving the cross-domain policy using WebGet attribute, and I am kind of sure that there is a problem with it getting exposed properly. Your insight into the problem will be highly appreciated. If I type http://localhost:8008/WCF4Silverlight.MyService/clientaccesspolicy.xml
in the browser, I do get the xml for the same, but the call from Silverlight always fails with the above error.
Here is the code for the WCF service:
namespace WCF4Silverlight
{
[ServiceContract(SessionMode = SessionMode.NotAllowed)]
public interface IClientAccessPolicy
{
[OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
Stream GetClientAccessPolicy();
}
}
namespace WCF4Silverlight
{
public class MyService: IMyService, IClientAccessPolicy
{
public Stream GetClientAccessPolicy()
{
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));
}
}
//Other service methods....
}
Here is code that publishes the service:
class Program
{
static v开发者_开发问答oid Main(string[] args)
{
ServiceHost myServiceHost = new ServiceHost(typeof(MyService));
myServiceHost.Open();
//Wait for client action.
myServiceHost.Close();
}
}
Here is the app.config for the WCF service host:
<service name="WCF4Silverlight.MyService" behaviorConfiguration="MyServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8008/MyService/"/>
</baseAddresses>
</host>
<endpoint address="general" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IMyService" contract="WCF4Silverlight.IMyService"/>
<endpoint address="SL" binding="basicHttpBinding" bindingConfiguration="basicHttpBinding_IMyService" contract="WCF4Silverlight.IMyService"/>
<endpoint address="" binding="webHttpBinding" bindingConfiguration="webHttpBinding_IMyService" behaviorConfiguration="webHttpBehavior" contract="WCF4Silverlight.IClientAccessPolicy" />
</service>
And here is the ServiceReferences.ClientConfig for the Silverlight client:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMyService" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
<customBinding>
<binding name="WSHttpBinding_IMyService">
<textMessageEncoding messageVersion="Default" writeEncoding="utf-8" />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:8008/MyService/SL"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyService"
contract="myWCFService.IMyService" name="BasicHttpBinding_IMyService" />
</client>
</system.serviceModel>
This is what I did to resolve the issue:
1) Used Fiddler to see where the WCF calls were directed. Fiddler told that the calls were failing to HOST - http:/localhost:8008 and URL - /clientaccesspolicy.xml.
2) Created a different class ClientAccessPolicy implementing IClientAccessPolicy (with WebGet for /clientaccesspolicy.xml).
3) Added another section in app.config of the host for a new service hosting the Clientaccesspolicy class. This one had its base address as http:/localhost:8008/
<service name="WCF4Silverlight.ClientAccessPolicy" behaviorConfiguration="ClientAccessPolicyBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8008/"/>
</baseAddresses>
</host>
<endpoint address="" binding="webHttpBinding" bindingConfiguration="webHttpBinding_IMyService" behaviorConfiguration="webHttpBehavior" contract="WCF4Silverlight.IClientAccessPolicy" />
</service>
4) In the hosting code, created another instance of ServiceHost and launched the new service with Clientaccesspolicy
ServiceHost clientAccessPolicyHost = new ServiceHost(typeof(ClientAccessPolicy)); clientAccessPolicyHost.Open();
5) In the Silverlight client, deleted the existing reference to the WCF and added the one to the newly hosted service.
The WCF calls from Silverlight are now going through.
Self hosted services on machines without IIS where the clientaccesspolicy can't be served up from the root, can instead use this method to dynamically serve up the policy on Port 80:
http://blogs.msdn.com/b/carlosfigueira/archive/2010/07/25/enabling-cross-domain-calls-for-sl-apps-on-self-hosted-tcp-services.aspx
The easiest way to debug this kind of issues is by using Fiddler (www.fiddler2.com) to intercept the HTTP traffic. You'll immediately see if clientAccessPolicy.xml is requested, where it is expected to be, and what is the result.
If you get a 404 (resource not found) the file is not at the expected location (but your webGet annotation looks good to me), otherwise the issue is within the xml itself.
This is a very permissive clientAccessPolicy.xml that I usually use for development/testing purposes:
<?xml version="1.0" ?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
If you're using a self-hosted web service, you need to throw your ClientAccessPolicy.xml into the root of a website that can be reached on port 80 of your machine (e.g., http://localhost:80/ClientAccessPolicy.xml). This was new in Silverlight 4, and unfortunately, I haven't found it clearly explained in the MS docs. (It's mentioned, but it's not terribly clear.)
精彩评论