Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口,它是.NET框架的一部分。由 .NET Framework 3.0 开始引入
WCF合并了Web服务、.net Remoting、消息队列和Enterprise Services的功能并集成在Visual Studio中。
WCF 部署到IIS中 自动生成的配置文件如下:
客户端Web.config:
<?xml version="1.0" encoding="utf-8"?>
<!--
有关如何配置 ASP.NET 应用程序的详细消息,请访问
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IUser" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/User.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IUser" contract="WCFService.IUser"
name="BasicHttpBinding_IUser" />
</client>
</system.serviceModel>
</configuration>
服务端Web.config代码:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->
<serviceMetadata httpGetEnabled="true"/>
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
由上面的两个配置文件我们发现,客户端system.serviceMode节点有我们刚才讲的endpoint,而服务端为什么没有?这不是和我们刚才讲的有违背吗?那么我们看下面手工修改后[把对看起来很复杂并且对当前的学习无用的配置节删掉]的配置文件的代码(我将服务端和客户端放在一块了):
那么第一次的配置文件为什么能执行呢?答案是我们把WCF寄宿在IIS上,而IIS默认监听的就是Http协议[B确定了]并且地址也是相对于IIS上的文件地址[A确定了],合同更不用说了,找到User.svc什么都有了[C确定了],所以在服务端就没有必要显示的写出system.serviceModel,不信你试试,把服务端的配置文件中system.serviceModel节删除,程序一样可以运行!服务器端的endpoint确定了,客户端的endpoint自然要和服务端去对应,所以IDE在生成客户端的配置文件里endpoint写的很详细的,而服务端却没有endpoint。
宿主
WCF本身不能够独自运行(每个WCF服务必须宿主在一个Windows进程中)。.net 提供了多种宿主供WCF运行,WCF还是非常灵活的。WCF的宿主可以是 Windows 服务、COM+应用程序、WAS(Windows Activation Services,Windows进程激活服务)或IIS、Windows应用程序,或简单的控制台应用程序及任何.net程序。
控制台应用程序宿主
建立宿主
(1)在解决方案下新建控制台输出项目 WCFHost_Console。
(2)添加 System.ServiceModel.dll 的引用。
(3)添加 WCF 服务类库(WCFLibrary)的项目引用。
(4)创建宿主程序,代码如下:
using System;
using WCFLibrary;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace WCFHost_Console
{
class Program
{
static void Main(string[] args)
{
//创建宿主的基地址
Uri baseAddress = new Uri("http://localhost:8080/User");
//创建宿主
using (ServiceHost host = new ServiceHost(typeof(User), baseAddress))
{
//向宿主中添加终结点
host.AddServiceEndpoint(typeof(IUser), new WSHttpBinding(), "");
//将HttpGetEnabled属性设置为true
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
//将行为添加到Behaviors中
host.Description.Behaviors.Add(smb);
//打开宿主
host.Open();
Console.WriteLine("WCF中的HTTP监听已启动....");
Console.ReadLine();
host.Close();
}
}
}
}
在这个示例中我们把Endpoint中的ABC,基地址,Behaviors等都**直接写在了代码里,但实际应用过程中都是去依赖配置文件,**为了对比说明我们下面的例子中会使用配置文件。
因为上面是部署到IIS中,协议就是http 所以binding 就不需要再客户端绑定了。
Windows应用程序宿主
建立宿主
(1)在解决方案下新建Windows窗体应用程序项目 WCFHost_Form。
(2)添加 System.ServiceModel.dll 的引用。
(3)添加 WCF 服务类库(WCFLibrary)的项目引用。
(4)添加应用程序配置文件App.config。
(5)创建宿主程序MainForm窗体,并修改App.config,代码如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="WCFLibrary.User">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8081/User"/>
</baseAddresses>
</host>
<endpoint address="" binding="wsHttpBinding" contract="WCFLibrary.IUser"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
using System;
using WCFLibrary;
using System.ServiceModel;
using System.Windows.Forms;
using System.Configuration;
namespace WCFHost_Form
{
public partial class MainForm : Form
{
ServiceHost host;
public MainForm()
{
InitializeComponent();
}
//应用程序加载
private void MainForm_Load(object sender, EventArgs e)
{
host = new ServiceHost(typeof(User));
//打开宿主
host.Open();
this.lblState.Text = "WCF中的HTTP监听已启动....";
}
//应用程序关闭
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
{
host.Close();
}
}
}
配置也是WCF编程中的主要组成部分。在以往的.net应用程序中,我们会把DBConn和一些动态加载类及变量写在配置文件里。但WCF有所不同。他指定向客户端公开的服务,包括服务的地址、服务用于发送和接收消息的传输和消息编码,以及服务需要的安全类型等。使用配置文件后,我们无需编译即可修改WCF的变化的信息,提高了程序的灵活性。
如果在代码里写了配置,那么配置文件将不起作用。
Web程序在Web.config中配置,应用程序中在App.config中配置。
**
服务配置的主要部分
**
在Config中配置服务的结点为:<system.serviceModel></system.serviceModel>,在这个节点中主要有三个平级的部分。如下代码所示:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<!--配置服务和终结点开始-->
<services>
<service>
<endpoint></endpoint>
</service>
</services>
<!--配置服务和终结点结束-->
<!--配置绑定开始-->
<bindings>
<netTcpBinding>
<binding>
</binding>
</netTcpBinding>
</bindings>
<!--配置绑定结束-->
<!--配置行为开始-->
<behaviors>
<serviceBehaviors>
<behavior>
</behavior>
</serviceBehaviors>
</behaviors>
<!--配置行为结束-->
</system.serviceModel>
</configuration>
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<!--服务-->
<services>
<!--name:名称空间.类型名 name:指定提供服务协定实现的类型,它是完全限定名称(命名空间和类型名称)-->
<!--behaviorConfiguration:behavior的名称,请看behavior配置节的名称-->
<service name="WCFLibrary.User" behaviorConfiguration="MyBehavior">
<host>
<baseAddresses>
<!-- 每种传输协议的baseAddress,用于跟使用同样传输协议Endpoint定义的相对地址组成完整的地址,
每种传输协议只能定义一个baseAddress。HTTP的baseAddress同时是service对外发布服务说明页面的URL -->
<add baseAddress="http://localhost:8732/Design_Time_Addresses/WCFLibrary/Service/"/>
</baseAddresses>
</host>
<!-- 除非完全限定,否则地址将与上面提供的基址相关,每个服务可以有多个Endpoint -->
<!-- Address:指定这个Endpoint对外的URI,这个URI可以是个绝对地址,也可以是个相对于baseAddress的
相对地址。如果此属性为空,则这个Endpoint的地址就是baseAddress-->
<!--bindingConfiguration:binding的名称,请看binding配置节的名称-->
<endpoint address="" binding="wsHttpBinding" contract="WCFLibrary.IUser" bindingConfiguration="myHttpBinding">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- 此终结点不使用安全绑定,应在部署前确保其安全或将其删除-->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<!--绑定-->
<bindings>
<wsHttpBinding>
<binding name="myHttpBinding">
<security mode="None">
<message clientCredentialType="Windows" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<!--行为-->
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<!-- httpGetEnabled - bool类型的值,表示是否允许通过HTTP的get方法获取sevice的WSDL元数据 -->
<serviceMetadata httpGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
完整案例:
WCF在通信过程中有三种模式:请求与答复、单向、双工通信。以下我们一一介绍。
请求应答模式这种交换模式是使用最多的一中,它有如下特征:
调用服务方法后需要等待服务的消息返回,即便该方法返回 void 类型
相比Duplex来讲,这种模式强调的是客户端的被动接受,也就是说客户端接受到响应后,消息交换就结束了。
在这种模式下,服务端永远是服务端,客户端就是客户端,职责分明。
它是缺省的消息交换模式,设置OperationContract便可以设置为此种消息交换模式
单向模式:
存在着如下的特征:
只有客户端发起请求,服务端并不会对请求进行回复
不能包含ref或者out类型的参数
没有返回值,返回类型只能为void
通过设置OperationContract的IsOneWay=True可以将满足要求的方法设置为这种消息交换模式
双工通讯Duplex具有以下特点:
1它可以在处理完请求之后,通过请求客户端中的回调进行响应操作
2.消息交换过程中,服务端和客户端角色会发生调换
3.服务端处理完请求后,返回给客户端的不是reply,而是callback请求。
4.Duplex模式对Bindding有特殊的要求,它要求支持Duplex MEP(Message Exchange Pattern),如WSDualHttpBinding和NetTcpBinding
注意:在WCF预定义绑定类型中,WSDualHttpBinding和NetTcpBinding均提供了对双工通信的支持,但是两者在对双工通信的实现机制上却有本质的区别。WSDualHttpBinding是基于HTTP传输协议的;而HTTP协议本身是基于请求-回复的传输协议,基于HTTP的通道本质上都是单向的。WSDualHttpBinding实际上创建了两个通道,一个用于客户端向服务端的通信,而另一个则用于服务端到客户端的通信,从而间接地提供了双工通信的实现。而NetTcpBinding完全基于支持双工通信的TCP协议。
支持回调的绑定有4种:WSDualHttpBinding、NetTcpBinding、NetNamedPipeBinding、NetPeerTcpBinding。我们这里用WSDualHttpBinding为例
//配置文件中的 binding 指定
<endpoint address="" binding="wsDualHttpBinding" contract="WCFService_DualPlex.IUser"></endpoint>
//服务端接口
using System.ServiceModel;
namespace WCFService_DualPlex
{
[ServiceContract(CallbackContract = typeof(IUserCallback))]
public interface IUser
{
[OperationContract]
string ShowName(string name);
}
public interface IUserCallback
{
[OperationContract(IsOneWay = true)]
void PrintSomething(string str);
}
}
//服务端实现
using System.ServiceModel;
namespace WCFService_DualPlex
{
public class User : IUser
{
IUserCallback callback = null;
public User()
{
//获取调用当前操作的客户端实例的通道。
callback = OperationContext.Current.GetCallbackChannel<IUserCallback>();
}
public string ShowName(string name)
{
//在服务器端定义字符串,调用客户端的方法向客户端打印
string str = "服务器调用客户端...";
callback.PrintSomething(str);
//返回服务端方法
return "WCF服务,显示名称:" + name;
}
}
}
//客户端调用
using System;
using System.ServiceModel;
using WCFClient_DualPlex.WCFService_DualPlex;
namespace WCFClient_DualPlex
{
//实现服务端的回调接口
public class CallbackHandler : IUserCallback
{
public void PrintSomething(string str)
{
Console.WriteLine(str);
}
}
class Program
{
static void Main(string[] args)
{
InstanceContext instanceContext = new InstanceContext(new CallbackHandler());
UserClient client = new UserClient(instanceContext);
Console.WriteLine(DateTime.Now);
string result = client.ShowName("xxxx");
Console.WriteLine(result);
Console.WriteLine(DateTime.Now);
Console.ReadLine();
}
}
}
**
操作协定的属性:
**
**
**
WCF 客户端调用服务几种情况
ChannelFactory
一个创建不同类型通道的工厂,客户端使用这些通道将消息发送到不同配置的服务终结点。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Service;
using System.ServiceModel;
using System.ServiceModel.Channels;
namespace Client3
{
class Program
{
static void Main(string[] args)
{
EndpointAddress address = new EndpointAddress("http://localhost:1234/UserInfo");
WSHttpBinding binding = new WSHttpBinding();
ChannelFactory<IUserInfo> factory = new ChannelFactory<IUserInfo>(binding,address);
IUserInfo channel = factory.CreateChannel();
User[] Users = channel.GetInfo(null);
Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}", "ID", "Name", "Age", "Nationality");
for (int i = 0; i < Users.Length; i++)
{
Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}",
Users[i].ID.ToString(),
Users[i].Name.ToString(),
Users[i].Age.ToString(),
Users[i].Nationality.ToString());
}
((IChannel)channel).Close();
factory.Close();
Console.Read();
}
}
}
WCF客户端----异 步—调用服务
有时我们需要长时间处理应用程序并得到返回结果,但又不想影响程序后面代码部分的执行,这时我们就需要考虑使用异步的方式来调用服务。注意这里的异步是完全针对客户端而言的,与WCF服务契约的方法是否异步无关,也就是在不改变操作契约的情况下,我们可以用同步或者异步的方式调用WCF服务。
服务引用和生成代理类 异步的客户端均如下代码
数据协定概念
默认情况下,任何给定的 CLR 命名空间(采用 Clr.Namespace 格式)都会映射到“http://schemas.datacontract.org/2004/07/Clr.Namespace”命名空间。 若要重写此默认值,请对整个模块或程序集应用 ContractNamespaceAttribute 属性。 或者,若要控制每种类型的数据协定命名空间,请设置 DataContractAttribute 的 Namespace 属性。
**
数据协定等效性特点概述
**
KnownTypeAttribute 类概述
在数据到达接收终结点时,WCF 运行库尝试将数据反序列化为公共语言运行库 (CLR) 类型的实例。通过首先检查传入消息选择为反序列化而实例化的类型,以确定消息内容遵循的数据协定。然后反序列化引擎尝试查找实现与消息内容兼容的数据协定的 CLR 类型。反序列化引擎在此过程中允许的侯选类型集称为反序列化程序的“已知类型”集。
让反序列化引擎了解某个类型的一种方法是使用 KnownTypeAttribute。不能将属性应用于单个数据成员,只能将它应用于整个数据协定类型。将属性应用于可能为类或结构的“外部类型”。在其最基本的用法中,应用属性会将类型指定为“已知类型”。只要反序列化外部类型的对象或通过其成员引用的任何对象,这就会导致已知类型成为已知类型集的一部分。可以将多个 KnownTypeAttribute 属性应用于同一类型。
IUserInfo.cs代码如下:
Service:类库程序,WCF服务端程序。在服务协定接口IUserInfo.cs中定义数据协定类Person,再定义一个数据协定类User。User派生至Person,继承基类Person的构造方法,定义新的属性成员SayHello。定义操作协定GetInfo和GetInfoEx,两者返回类型都为Person。在UserInfo.cs中实现数据协定,在GetInfo中,我们返回Person对象类型,在GetInfoEx中我们返回派生类User类型。由于在GetInfoEx中我们需要传递派生类User类型,所以要在基类数据协定Person上面加上KnownType(typeof(User))特性标记,这样User就能够服务端进行反序列化,供客户端使用。
using System.ServiceModel;using System.Runtime.Serialization;using System;
namespace Service{
[ServiceContract]
public interface IUserInfo
{
[OperationContract]
Person GetInfo(int id,string name);
[OperationContract]
Person GetInfoEx(int id, string name);
}
[DataContract]
[KnownType(typeof(User))]
public class Person
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
public Person(int id, string name)
{
this.ID = id;
this.Name = name;
}
}
[DataContract]
public class User:Person
{
public User(int id, string name): base(id,name){}
[DataMember]
public string SayHello
{
get { return "Hello:" + Name; }
set { throw new NotImplementedException(); }
}
}
}
UserInfo.cs代码如下:
using System;using System.Collections.Generic;
using System.Linq;using System.Text;
namespace Service{
public class UserInfo:IUserInfo
{
public Person GetInfo(int id, string name)
{
return new Person(id, name);
}
public Person GetInfoEx(int id, string name)
{
return new User(id, name);
}
}
WCF消息协定概述
异常
WCF服务配置编辑器【可视化】
个可视化的配置界面(Microsoft Service Configuration Editor),极大的方便开发者进行服务配置
点击文件菜单下的另存为选项保存文件,将配置文件内容复制到先前建好的Host工程下的App.config文件中,编译程序后,就可以运行寄宿服务了,到此我们就完成了一个服务程序配置任务。
文章来源:https://www.toymoban.com/news/detail-442495.html
WAS
文章来源地址https://www.toymoban.com/news/detail-442495.html
到了这里,关于.net WCF的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!