Silverlight有限支持WCF的binding问题
这是最近遇到的一个小问题。情况是这样的:
1.我们有一个网站,是用.NET Framework 3.5编写的,里面有一些WCF的服务。作为演示,我下面有一个范例服务
合约
using System.ServiceModel; namespace WebApplication1 { // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together. [ServiceContract] public interface IService1 { [OperationContract] void DoWork(); [OperationContract] string Helloworld(); } }
服务
namespace WebApplication1 { // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together. public class Service1 : IService1 { public void DoWork() { } public string Helloworld() { return "hello,world"; } } }
2.我们需要在一个新的Silverlight应用程序中访问这些WCF服务,但是无论我们选择Silverlight的版本是3.0,还是4.0(注意,这不是.NET Framework的版本),都无法完成服务引用。
具体的症状就是,添加引用之后,Silverlight无法正确生成那个配置文件
会有两个警告
具体的信息是
Warning 2 Custom tool warning: No endpoints compatible with Silverlight 3 were found. The generated client class will not be usable unless endpoint information is provided via the constructor. d:\temp\WebApplication1\SilverlightApplication1\Service References\DataModel\Reference.svcmap 1 1 SilverlightApplication1
然后,我们去看那个生成的配置文件的话,会看到一片空白
这样的问题要怎么解决呢?我们首先要把问题找到,从上面的错误消息,它的意思应该是说,不支持目前提供的EndPoint。
那么,服务端到底使用了什么样的EndPoint呢
我们转到web应用程序中的web.config文件,可以看到如下的设置
<system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="WebApplication1.Service1Behavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> <services> <service behaviorConfiguration="WebApplication1.Service1Behavior" name="WebApplication1.Service1"> <endpoint address="" binding="wsHttpBinding" contract="WebApplication1.IService1"> <identity> <dns value="localhost" /> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> </system.serviceModel>
也就是说,默认情况下,.NET Framework 3.5提供的WCF,是使用wsHttpBinding的。难道是Silverlight不支持这种EndPoint吗?
为了做测验,我们可以将其修改为相对简单的basicHttpBinding
<system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="WebApplication1.Service1Behavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> <services> <service behaviorConfiguration="WebApplication1.Service1Behavior" name="WebApplication1.Service1"> <endpoint address="" binding="basicHttpBinding" contract="WebApplication1.IService1"> <identity> <dns value="localhost" /> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> </system.serviceModel>
然后,我们再去Silverlight中添加引用看看是否能解决问题
我们发现,这次成功了,ClientConfig中也正确生成了WCF的配置,并且通过如下的代码可以完成服务的调用
using System; using System.Windows; using System.Windows.Controls; using System.ServiceModel; namespace SilverlightApplication1 { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { var proxy = new DataModel.Service1Client(); proxy.Endpoint.Address = new EndpointAddress(new Uri(Application.Current.Host.Source, "../Service1.svc")); proxy.HelloworldCompleted += (o, a) => { MessageBox.Show(a.Result); }; proxy.HelloworldAsync(); } } }
好的,看起来问题是解决了,也就是说Silverlight只支持使用basicHttpBinding?如果我们非要改成wsHttpBinding ,行不行呢?
我尝试将clientconfig文件修改为
<configuration> <system.serviceModel> <client> <endpoint address="http://localhost:2514/Service1.svc" binding="wsHttpBinding" contract="DataModel.IService1" name="BasicHttpBinding_IService1" /> </client> </system.serviceModel> </configuration>
并且将服务端的web.config,也修改为
<system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="WebApplication1.Service1Behavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> <services> <service behaviorConfiguration="WebApplication1.Service1Behavior" name="WebApplication1.Service1"> <endpoint address="" binding="wsHttpBinding" contract="WebApplication1.IService1"> <identity> <dns value="localhost" /> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> </system.serviceModel>
运行程序的结果是,会报告如下的错误
也就是说,确实不支持wsHttpBinding
关于这一点,有兴趣的朋友,也可以参考一下微软官方的文档说明
http://msdn.microsoft.com/en-us/library/cc896571(v=VS.95).aspx
【又及】
在Silverlight中,最简单易用的服务是RIA Service,关于这一点,我已经写过很多文章介绍。
那么,RIA Service是使用什么binding呢?
请参考下面这篇文章
http://weblogs.asp.net/fredriknormen/archive/2009/11/27/wcf-ria-services-binding-deep-dive.aspx