从Silverlight 4访问自托管WCF服务

时间:2011-02-18 18:10:04

标签: wcf silverlight

我有一个自托管的WCF 4服务,通过basicHttpBinding为Silverlight 4客户端提供相同的合同,并为其他客户端提供wsHttpBinding。代码非常简短,在这里提供。

尝试从WCF访问服务方法时出现以下错误:

  

Message =尝试向URI发出请求时发生错误   http://localhost:8008/WCF4Silverlight.MyService/SL。这可能是   由于尝试以跨域方式访问服务而没有   适当的跨域策略或不适合的策略   用于SOAP服务。您可能需要联系服务的所有者   发布跨域策略文件并确保它允许   要发送的与SOAP相关的HTTP标头。此错误也可能是由此引起的   使用Web服务代理中的内部类型而不使用   InternalsVisibleToAttribute属性。请查看内部异常   了解更多详情。

我确实有方法,GetClientAccessPolicy()使用WebGet属性提供跨域策略,我确信它有一个问题,它正确暴露。您对此问题的见解将受到高度赞赏。如果我在浏览器中键入http://localhost:8008/WCF4Silverlight.MyService/clientaccesspolicy.xml,我会得到相同的xml,但Silverlight的调用总是因上述错误而失败。

以下是WCF服务的代码:

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

以下是发布服务的代码:

class Program
{
 static void Main(string[] args)
 {
  ServiceHost myServiceHost = new ServiceHost(typeof(MyService));
  myServiceHost.Open();

  //Wait for client action.

  myServiceHost.Close();
 }
}

以下是WCF服务主机的app.config:

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

以下是Silverlight客户端的ServiceReferences.ClientConfig:

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

4 个答案:

答案 0 :(得分:2)

这就是我为解决这个问题所做的工作:

1)使用Fiddler查看WCF调用的定向位置。 Fiddler告诉说这些调用未能成为HOST - http:/ localhost:8008和URL - /clientaccesspolicy.xml。

2)创建了一个实现IClientAccessPolicy的不同类ClientAccessPolicy(带有/clientaccesspolicy.xml的WebGet)。

3)在主机的app.config中添加了另一个部分,用于托管Clientaccesspolicy类的新服务。这个的基地址为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)在托管代码中,创建了另一个ServiceHost实例并使用Clientaccesspolicy启动了新服务

ServiceHost clientAccessPolicyHost = new ServiceHost(typeof(ClientAccessPolicy)); clientAccessPolicyHost.Open(); 

5)在Silverlight客户端中,删除了对WCF的现有引用,并将其添加到新托管的服务中。

Silverlight的WCF调用正在进行中。

答案 1 :(得分:2)

在没有IIS的计算机上自托管服务,其中clientaccesspolicy 无法从root用户提供服务,而是可以使用此方法在端口80上动态提供策略:

http://blogs.msdn.com/b/carlosfigueira/archive/2010/07/25/enabling-cross-domain-calls-for-sl-apps-on-self-hosted-tcp-services.aspx

答案 2 :(得分:1)

调试此类问题的最简单方法是使用Fiddler(www.fiddler2.com)拦截HTTP流量。您将立即查看是否请求了clientAccessPolicy.xml,它应该在何处,以及结果是什么。

如果你得到一个404(资源未找到),那么该文件不在预期位置(但你的webGet注释对我来说很好),否则问题就在xml本身内。

这是我通常用于开发/测试目的的非常许可的clientAccessPolicy.xml:

<?xml version="1.0" ?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>

答案 3 :(得分:0)

如果您使用的是自托管Web服务,则需要将ClientAccessPolicy.xml放入可在计算机端口80上访问的网站的根目录(例如http://localhost:80/ClientAccessPolicy.xml)。这是Silverlight 4中的新功能,不幸的是,我没有在MS文档中清楚地解释它。 (它已被提及,但它并不十分清楚。)