2015-05-11  861 views 评论

物理三层实现分布式架构及WCF新特性的无SVC文件服务激活

 标签:    

结构如下:

psb (1)

实际结构中应该还应有以下三个项目(逻辑层)

WCFDemo.Repository.Interface

WCFDemo.Repository

WCFDemo.BusinessComponent

通常使用WCF进行服务创建的时候都是一个服务创建对应的一个SVC文件,一个服务对应很多方法。本文主要研究WCF4.0的新特性中无SVC文件服务的激活。实际使用中还会使用到Unity依赖注入,此处不做研究。

 

导读:

Step1: 创建WCF应用

Step2: 通过配置服务端配置文件实现相应的服务方法

Step3: 通过配置服务端配置文件实现无SVC文件服务激活

Step4: 编写代理类

Step5: 通过配置客户端配置文件实现与服务端的mapping

Step6: 通过实现代理类call service中的方法

 

 

1.创建WCF应用

 

在项目中创建一个新的WCF应用。

 

2.创建WCF服务端

 

观察默认生成的IService1可以发现这个接口使用了ServiceContract特性标签,具体方法则使用OperationContract特性标签。OK,接下来要做的就是模仿系统自动生成的接口自己创建一个Sample接口如下:

using System.Collections.Generic;

using System.Linq;

using System.ServiceModel;

using System.Text;

using System.Threading.Tasks;

namespace WCFDemo.Service.Interface

{

    [ServiceContract(Namespace="WCFDemo")]

    public interface IHelloWorldServiceInterface

    {

        [OperationContract]

        string GetStringFormat();

    }

}

再模仿Service1.svc中实现的写法仿写一个Sample类去实现刚才定义的Sample接口,如下所示:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using WCFDemo.Service.Interface;

namespace WCFDemo.Service

{

    public class DemoService : IDemoService

    {

        public string GetString()

        {

            return "Hello world!";

        }

    }

}

WCF应用下的配置文件需要添加以下内容:

  <system.serviceModel>

    <bindings>

      <wsHttpBinding>

        <binding name="NoneSecurity" maxBufferPoolSize="12000000"maxReceivedMessageSize="12000000" useDefaultWebProxy="false">

          <readerQuotas maxStringContentLength="12000000" maxArrayLength="12000000"/>

          <security mode="None"/>

        </binding>

      </wsHttpBinding>

    </bindings>

    <behaviors>

      <serviceBehaviors>

        <behavior name="metadataBehavior">

          <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->

          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>

          <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为false 以避免泄漏异常信息 -->

          <serviceDebug includeExceptionDetailInFaults="false"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

    <protocolMapping>

        <add binding="wsHttpBinding" scheme="http" />

    </protocolMapping>

    <services>

      <service name="WCFDemo.Service.DemoService"behaviorConfiguration="metadataBehavior">

        <endpoint address="" binding="wsHttpBinding"contract="WCFDemo.Service.Interface.IDemoService" bindingConfiguration="NoneSecurity"></endpoint>

        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

      </service>

    </services>

    <!--无svc文件wcf服务激活-->

    <serviceHostingEnvironment>

      <serviceActivations>

        <add relativeAddress="Service.svc" service="WcfService1.Service"/>

        <add relativeAddress="DemoService.svc" service="WCFDemo.Service.DemoService"/>

      </serviceActivations>

    </serviceHostingEnvironment>

  </system.serviceModel>

  <system.webServer>

    <modules runAllManagedModulesForAllRequests="true"/>

    <!--

        若要在调试过程中浏览 Web 应用程序根目录,请将下面的值设置为 True。

        在部署之前将该值设置为 False 可避免泄露 Web 应用程序文件夹信息。

      -->

    <directoryBrowse enabled="true"/>

  </system.webServer>

 

可以发现Services节点下可以配置多个Service即实现多个服务,通常Name命名为多实现的服务的namespace和class name,contract这位说实现接口的namespace和interface name,其他可以保持不变。

 

而实现无SVC文件服务激活最主要的就是在serviceenvironment节点下配置一个名为serviceActivations的节点,并添加对应的relativeAddress以及services,relativeAddress为svc服务文件名 service则为实现的服务。

 

这样WCF的服务端就创建完成了。

 

3.创建客户端

 

客户端需要调用WCF服务需要通过一个代理类来实现,第一步需要创建一个代理类,如下:

using System.Collections.Generic;

using System.Linq;

using System.ServiceModel;

using System.ServiceModel.Channels;

using System.Text;

using System.Threading.Tasks;

using WCFDemo.Service.Interface;

namespace WCFDemo.Proxy

{

    public class DemoProxy : ClientBase<IDemoService>,IDemoService

    {

        public DemoProxy()

        {

        }

        public DemoProxy(Binding binding, EndpointAddress edpAddress)

            :base(binding,edpAddress)

        {

        }

        public string GetString()

        {

            return base.Channel.GetString();

        }

    }

}

客户端中可以通过使用代理类的第二个实例方法去实现代理类的实例化并调用,具体实现如下所示:

static EndpointAddress edpHttpDemo = newEndpointAddress("http://localhost:40008/DemoService.svc");

DemoProxy  client = new DemoProxy(new WSHttpBinding(SecurityMode.None), edpHttp);

Console.WriteLine(client.GetString());

输出结果为:

Hello world!

 

实际使用中如果将endpoint address写死在程序中并不是明智的选择,故此处选择使用配置来实现,需要在配置中添加如下节点:

<system.serviceModel><bindings>

<basicHttpBinding>

<binding name="BasicHttpBinding_IDemoService" />

</basicHttpBinding>

</bindings>

<client>

<endpoint name="WCFDemo.Service.DemoService" address="http://localhost:40008/DemoService.svc" binding="basicHttpBinding"

bindingConfiguration="BasicHttpBinding_IService1"contract="WCFDemo.Service.Interface.IDemoService"/>

</client>

</system.serviceModel>

 

客户端实现则改为如下代码:

Console.WriteLine(new DemoProxy.GetString());

 

运行后发现会报异常,InnerMessage为:

不支持内容类型 text/xml; charset=utf-8。客户端和服务绑定可能不匹配

 

通过查找后可以发现服务端的配置文件中默认binding为wsHttpBinding,而客户端中我们自己编写的为basicHttpBinding。

BasicHttpBinding发送的是明文数据,而WsHttpBinding发送的是加密和更加安全的数据。

所以只要将客户端中的binding与服务端中的类型改为一致即可。

 

再次运行程序会发现又报错异常,InnerMessage为:

无法打开安全通道,因为与远程终结点的安全协商已失败。这可能是由于用于创建通道的 EndpointAddress 中不存在EndpointIdentity 或错误指定了 EndpointIdentit

 

这问题一定是出现在配置上,才仔细查看服务端的配置后发现默认状态下wsHttpbinding中的安全模式设置为none,而我们调用默认无参代理类对象中并未对其声明。 <wsHttpBinding>

        <binding name="NoneSecurity"

         <security mode="None"/>

       </binding>

</wsHttpBinding>

 所以在客户端配置文件中需要添加安全模式为none的属性。最后运行结果为Hello world! 4.完整的客户端与服务端配置 最终正确的完整配置如下:服务端:

  <system.serviceModel>

    <bindings>

      <wsHttpBinding>

        <binding name="NoneSecurity" maxBufferPoolSize="12000000"maxReceivedMessageSize="12000000" useDefaultWebProxy="false">

          <readerQuotas maxStringContentLength="12000000" maxArrayLength="12000000"/>

          <security mode="None"/>

        </binding>

      </wsHttpBinding>

    </bindings>

    <behaviors>

      <serviceBehaviors>

        <behavior name="metadataBehavior">

          <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->

          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>

          <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为false 以避免泄漏异常信息 -->

          <serviceDebug includeExceptionDetailInFaults="false"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

    <protocolMapping>

        <add binding="wsHttpBinding" scheme="http" />

    </protocolMapping>

    <services>

      <service name="WcfService1.Service" behaviorConfiguration="metadataBehavior">

        <endpoint address="" binding="wsHttpBinding" contract="WcfService1.IService"bindingConfiguration="NoneSecurity"></endpoint>

        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

      </service>

      <service name="WCFDemo.Service.DemoService"behaviorConfiguration="metadataBehavior">

        <endpoint address="" binding="wsHttpBinding"contract="WCFDemo.Service.Interface.IDemoService" bindingConfiguration="NoneSecurity"></endpoint>

        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

      </service>

    </services>

    <!--无svc文件wcf服务激活-->

    <serviceHostingEnvironment>

      <serviceActivations>

        <add relativeAddress="Service.svc" service="WcfService1.Service"/>

        <add relativeAddress="DemoService.svc" service="WCFDemo.Service.DemoService"/>

      </serviceActivations>

    </serviceHostingEnvironment>

  </system.serviceModel>

<system.webServer>

客户端:

<system.serviceModel>

    <bindings>

      <wsHttpBinding>

        <binding name="DemoService">

          <security mode="None"/>

        </binding>

      </wsHttpBinding>

    </bindings>

    <client>

      <endpoint address="http://localhost:40008/DemoService.svc" binding="wsHttpBinding"

        bindingConfiguration="DemoService"contract="WCFDemo.Service.Interface.IDemoService"

        name="WCFDemo.Service.DemoService" />

    </client>

</system.serviceModel>

给我留言

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: