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无法正确生成那个配置文件

image

会有两个警告

image

具体的信息是

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

 

然后,我们去看那个生成的配置文件的话,会看到一片空白

image

 

这样的问题要怎么解决呢?我们首先要把问题找到,从上面的错误消息,它的意思应该是说,不支持目前提供的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中添加引用看看是否能解决问题

image

我们发现,这次成功了,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>

运行程序的结果是,会报告如下的错误

image

也就是说,确实不支持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

posted @ 2011-06-19 09:06  陈希章  阅读(2534)  评论(9编辑  收藏  举报