WCF之各种WCF引用方式

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

写在开头:本文内容来自 WCF全面解析中的一个经典例子,如果你已经看过了,那么可以忽略本文,本文旨在和大家分享不一样的WCF使用方法。

 

准备工作:

 

1.创建解决方案WCFService(当然名字可以任意哦)

 

 

依次添加四个项目,如上图,Client和Hosting为控制台应用程序,Service和Service.Interface均为类库。

 

2.引用关系

 

Service.Interface:定义服务契约(Service Contract)接口,引用WCF核心库System.ServiceModel.dll;

 

Service:定义服务的项目,由于需要实现具体的服务,而服务契约在Service.Interface中,所以要引用Service.Interface项目;

 

Hosting:服务宿主的控制台程序,需要引用Service.Interface和Service项目,同时还要引用System.ServiceModel.dll类库:

 

Client:一个控制台应用程序的客户端,需要引用Service.ServiceModel类库。

 

Service.Interface:

 

服务契约抽象了服务的所有操作,一般契约为接口形式存在。

 
  
    [ServiceContract(Name = "CalculatorService", Namespace = "Listen.Fly")]    public interface ICalculator    {        [OperationContract]        double Add(double x, double y);        [OperationContract]        double Subtract(double x, double y);        [OperationContract]        double Multiply(double x, double y);        [OperationContract]        double Divide(double x, double y);    }
 
 

通过使用System.ServiceModel.ContractAttribute特性来标识接口为服务契约,同时可以在特性中指定契约的Name和Namespace。通过ContractAttribute特性标识为契约后的接口的方法并不能自动成为服务操作,WCF采用的是显示选择策略,所以我们要在对应的服务操作上添加OperationContractAttribute特性。

 

Service:

 

在Service项目中添加类CalculatorService类,并实现自ICalculator接口,并将服务操作(加减乘除四个方法)代码补全。

 
  
   public class CalculatorService : ICalculator    {        public double Add(double x, double y)        {            return x + y;        }        public double Subtract(double x, double y)        {            return x - y;        }        public double Multiply(double x, double y)        {            return x * y;        }        public double Divide(double x, double y)        {            return x / y;        }    }
 
 

 Hosting:

 

WCF服务需要一个运行着的宿主进程,服务寄宿就是给服务指定一个宿主的过程。WCF采用基于终结点(EndPoint)的通信手段。终结点有地址(Address),绑定(Binding)和契约(Contract)三部分组成,三要素也可以记作:EndPoint=ABC。

 

一个终结点包含了通信所必须的所有信息,具体如下:
Address:地址决定了服务的位置,解决了寻址的问题;
Binding:绑定实现了通信的所有细节,包括网络传输,消息编码,以及其他为实现某种功能(比如传输安全,可靠消息传输,事务等)对消息进行的相应处理。WCF中具有一系列的系统定义绑定,比如BasicHttpBinding,WSHttpBinding和NetTcpBinding等;
Contract:契约是对服务操作的抽象,也是对消息交换模式以及消息结构的定义。

 

服务寄宿的目的是开启一个进程,为WCF服务提供一个运行环境,并为服务添加一个或者多个终结点,然后暴漏给服务消费者。

 

Hosting的代码如下:

 
  
            using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))            {                host.AddServiceEndpoint(                    typeof(ICalculator),                    new WSHttpBinding(),                    "http://127.0.0.1:1111/CalculatorService");                if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)                {                    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();                    behavior.HttpGetEnabled = true;                    behavior.HttpGetUrl = new Uri("http://127.0.0.1:1111/CalculatorService/metadata");                    host.Description.Behaviors.Add(behavior);                }                host.Opened += delegate                    {                        Console.Write("CalculatorService已经启动,按任意键终止服务");                    };                host.Open();                Console.Read();            }
 
 

  WCF的寄宿通过System.ServiceModel.ServiceHost对象来完成,我们代码中基于服务类型(typeof(CalculatorService))创建了ServiceHost对象。添加了基于WSHttpBinding绑定的终结点,服务契约类型为typeof(ICalculator),地址为"http://127.0.0.1:1111/CalculatorService"(此处的地址可以随意指定)。
  WCF中客户端和服务端是松耦合的,客户端只需要知道WCF服务的基本描述,而不需知道服务的具体实现,就可以完成调用。WCF服务的描述通过元数据(Metadata)的形式发布出来,WCF中的元数据通过一个特殊的服务行为ServiceMetadataBehavior来实现。
  在上述代码中我们为ServiceHost添加了ServiceMetadataBehavior这样一个服务行为,并采用基于HTTP-GET的元数据获取方式,并且通过ServiceMetadataBehavior的HttpGetUrl属性指定元数据的发布地址(当前地址为http://127.0.0.1:1111/CalculatorService/metadata)。在服务启动之后,访问该地址可以看到元数据,即为XML返回数据的页面。(也就是和我们通常点击svc文件中的链接看到的结果是一样的)

 

上面的代码实在是不太好记住,不过通常我们也不会这么做,可以将这些配置的过程放在config文件中去:

 
  
<configuration>  <startup>    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />  </startup>  <system.serviceModel>    <behaviors>      <serviceBehaviors>        <behavior name="metadataBehavior">          <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:1111/CalculatorService/metadata"/>        </behavior>      </serviceBehaviors>    </behaviors>    <services>      <service name="Service.CalculatorService" behaviorConfiguration="metadataBehavior">        <endpoint address="http://127.0.0.1:1111/CalculatorService" binding="wsHttpBinding"                             contract="Service.Interface.ICalculator"></endpoint>      </service>    </services>  </system.serviceModel></configuration>
 
 

打开Hosting项目中的app.config,添加上述代码即可。xml中的标签的意思和我们创建ServiceHost过程基本是一致的。

 

如果使用了配置文件的方式,我们的代码可以更简单,Hosting代码修改如下:

 
  
            using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))            {                host.Opened += delegate            {              Console.Write("CalculatorService已经启动,按任意键终止服务");            };                host.Open();                Console.Read();            }
 
 

Client:

 

契约也定义了,服务也实现了,宿主也写好了,还剩下最后一步调用服务,运行Hosting.exe(debug目录下的哦,如果运行失败,那么请用管理员身份运行),然后看到如下界面:

 

 

然后在Client中添加对服务的引用:

 

 

在地址中输入我们配置的url,单击Go即可找到发布的WCF(必须要一直运行着Hosting.exe),可以在Namespace修改为自定义的命名空间,点击OK即可成功添加WCF。添加成功之后,被客户端调用的契约接口CalculatorService会被生成出来。客户端之所以会被命名为CalculatorService,是因为我们在ICalculator接口的特性中设置Name为CalculatorService。CalculatorService是与定义在Service.Interface项目中ICalculator接口等效的契约接口。但是我们在客户端使用则是一个CalculatorServiceClient(当然不同的WCF名称不一样,但是都是以Client结尾),CalculatorServiceClient的基类为System.ServiceModel.ClientBase<CalculatorService>。CalculatorServiceClient同样实现了契约接口CalculatorService,并通过从基类继承的Channel属性调用相对应的方法。

 

使用如下:

 
  
            using (CalculatorServiceClient proxy = new CalculatorServiceClient())            {                Console.WriteLine("x+y={2} when x={0} and y={1}", 1, 2, proxy.Add(1, 2));                Console.WriteLine("x-y={2} when x={0} and y={1}", 10, 2, proxy.Subtract(10, 2));                Console.WriteLine("x*y={2} when x={0} and y={1}", 10, 2, proxy.Multiply(10, 2));                Console.WriteLine("x/y={2} when x={0} and y={1}", 10, 2, proxy.Divide(10, 2));                Console.Read();            }
 
 

很简单吧,只需定义一个xxClient对象,然后调用其对应的方法即可,当然我们现在使用的是同步的,每个方法都有对应的异步方法。比如Add对应的异步方法就是AddAsync,如果使用异步方法则要给xxClient添加对应的回调函数。
      户端通过服务代理对象进行服务调用,上述代码中的通过添加服务引用自动创建生成的、继承自ClientBase<TChannel>的类型对象进行服务调用。实际上还有另外一种实现方法,通过System.ServiceModel.ChannelFactory<TChannel>直接创建服务代理对象。WCF采用基于契约的服务调用方法,从上述代码中可以看到,VS在添加服务引用的过程中,会在客户端创建一个与服务等效的服务契约接口。由于服务端和客户端都在同一个解决方案,因此可以让服务端和客户端引用相同的契约。

 

客户端使用第二种方法也就是ChannelFactory<T>形式创建代理对象,删除掉之前添加的WCF的引用,然后添加对Service.Interface项目的引用(注:如果客户端是Silverlight应用程序可能会提示无法添加,因为Silverlight应用程序只能添加Silverlight应用程序或者Silverlight类库),然后修改代码如下:

 
  
            using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>(                new WSHttpBinding(),                "http://127.0.0.1:1111/CalculatorService"))            {                ICalculator proxy = channelFactory.CreateChannel();                Console.WriteLine("x+y={2} when x={0} and y={1}", 1, 2, proxy.Add(1, 2));                Console.WriteLine("x-y={2} when x={0} and y={1}", 10, 2, proxy.Subtract(10, 2));                Console.WriteLine("x*y={2} when x={0} and y={1}", 10, 2, proxy.Multiply(10, 2));                Console.WriteLine("x/y={2} when x={0} and y={1}", 10, 2, proxy.Divide(10, 2));            }
 
 

 终结点是WCF进行通信的唯一方式,ChannelFactory<TChannel>本质上是通过指定的终结点创建用于进行服务调用的服务代理。上述嗲吗中,在创建ChannelFactory<TChannel>的时候在构造函数中指定了终结点的ABC三要素,其中地址和绑定则通过参数指定,契约提现在ChannelFactory<TChannel>的泛型参数上。不过一般我们也不会这么做,聪明的你猜到了,还是通过配置文件来进行,没错,配置如下:

 
  
<configuration>  <system.serviceModel>    <client>      <endpoint        name="CalculatorService"        address="http://127.0.0.1:1111/CalculatorService"        binding="wsHttpBinding"        contract="Service.Interface.ICalculator"  />    </client>  </system.serviceModel></configuration>
 
 

在配置文件中添加了endpoint,同样还是指定了address地址、binding绑定、以及契约constract和代码创建的过程一致哦。

 

代码修改如下:

 
  
            using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("CalculatorService"))            {                ICalculator proxy = channelFactory.CreateChannel();                Console.WriteLine("x+y={2} when x={0} and y={1}", 1, 2, proxy.Add(1, 2));                Console.WriteLine("x-y={2} when x={0} and y={1}", 10, 2, proxy.Subtract(10, 2));                Console.WriteLine("x*y={2} when x={0} and y={1}", 10, 2, proxy.Multiply(10, 2));                Console.WriteLine("x/y={2} when x={0} and y={1}", 10, 2, proxy.Divide(10, 2));            }
 
 

可以看到,唯一的区别就是在对ChannelFactory<TChannel>实例化的时候,使用配置文件中endpoint的name属性替代了之前的Binding和地址。

 

 注:上述代码中如果是非添加服务引用的方式进行创建Client,那么在运行Client的时候,请确保Hosting.exe已经正常启动。

 

通过IIS方式寄宿服务

 

之前的例子是将控制台作为WCF的寄宿方式或者是直接添加契约项目的引用,然后通过配置或者是ChannelFactory的形式进行创建服务对象,其实在大多的开发中以IIS的形式创建WCF也是比较常见的。
每一个Webservice都是具有一个asmx文本文件,客户端通过访问.asmx文件即可实现Webservice的调用。当然WCF和Webservice类似,每一个WCF服务都有一个对应的.svc文本文件。基于IIS服务寄宿要求的WCF服务都具有相应的.svc文件,.svc文件部署于IIS站点中,对WCF服务的调用提现在对.svc文件的访问上。.svc文件仅仅包含一个%@ ServiceHost这样的指令,该指令具有一个必须的Service属性和一些可选的属性,如下代码所示就是一个简单的.svc文本的内容

 

 

 
  
<%@ ServiceHost Language="C#" Debug="true" Service="Service.CalculatorService" %>
 
 

 

 

其中指定了Service属性为一个完整名称的WCF服务类。

 

寄宿在IIS下的WCF服务实际上就是一个WEB应用,所以通常会把.svc文件放在Web下,并且通过web.config文件进行配置WCF的终结点和用于发布元数据的ServiceMetadataBehavior服务行为。由于服务调用是通过访问服务对应的.svc文件来实现的,这个.svc文件所在的地址对于客户端来说就是服务(终结点)的地址,因此是不需要配置终结点的adder的,配置代码如下:

 
  
<configuration>  <system.serviceModel>    <behaviors>  <serviceBehaviors>        <behavior name="serviceBehavior">          <serviceMetadata httpGetEnabled="true" />          <serviceDebug includeExceptionDetailInFaults="true" />        </behavior>      </serviceBehaviors> </behaviors>    <services>      <service name="Service.CalculatorService" behaviorConfiguration="serviceBehavior" >        <endpoint  binding="basicHttpBinding" contract="Service.Interface.ICalculator"/>      </service>  </services>  </system.serviceModel></configuration>
 
 

 除了终结点没有指定address之外,服务行为ServiceMetadataBehavior用于元数据发布时也没有指定元素的发布地址。在这种情况下,.svc文件的地址加上?wsdl查询字符串就是元数据发布地址。对于当前例子来说,当服务被成功寄宿到本地的Web应用之后,就可以通过http://127.0.0.1:1111/网站名称/CalculatorService.svc?wdsl得到表示服务元数据的WSDL文件,这也就是为什么我们右键浏览.svc文件的时候返回的是很长的xml内容。

 

再次修改客户端:

 
  
<configuration>  <system.serviceModel>    <client>      <endpoint        name="CalculatorService"        address="http://127.0.0.1:1111/MyWeb/CalculatorService.svc"        binding="wsHttpBinding"        contract="Service.Interface.ICalculator"  />    </client>  </system.serviceModel></configuration>
 
 

仅仅修改了address属性,当前假设我们的Web应用程序叫做MyWeb,这也我们的address就可以找到发布后的.svc文件了。

 

 至此,我们一共介绍了两大类的WCF的方法:
一种是将WCF服务寄宿在控制台程序:

 

  1.通过添加服务引用(根据元数据的地址添加),然后创建了一个Client对象,然后就可以操作了;
  2.通过添加对契约项目的引用,然后通过ChannelFactory<TChannel>创建了一个Channel对象(通过契约类型,Binding,以及一个地址);
  3.通过添加对契约项目的引用,然后通过ChannelFactory<TChannel>创建了一个Channel对象(首先会在config中配置endpoint信息,然后通过endpoint的name作为   ChannelFactory的参数进行创建)。  

 

一种是依靠IIS作为寄宿:

 

  1.添加对契约项目的引用,然后通过修改配置文件的endpoint的address为.svc的地址,这样同样还是通过ChannelFactory<TChannel>方式进行创建代理对象;
  2.添加契约项目的引用,然后通过ChannelFactory<TChannel>创建了一个Channel对象(通过契约类型,Binding,以及一个地址,这时候的地址应该是.svc)。

 

 

 

好了,到这里我们的整个对WCF的引用方式(以及发布WCF服务)已经介绍完毕,希望大家多提意见和建议。


<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值