接触WCF很久了,一直没时间深入研究,现把最近一个月的娱乐时间拿来研究WCF,希望到年后能对WCF有新的认识。
WCF(Windows Communication Foundation)单向消息,请求答复消息,双工模式
WCF的 ABC:
Address: 每一个WCF的Service都有一个唯一的地址。这个地址给出了Service的地址和传输协议(Transport Protocol)
Binding: 通信(Communication)的方式很多,同步的request/reply模式,非同步的fire-and-forget模式。消息可以单向或者双向的发送接收,可以立即发
送或者把它放入到某一个队列中再处理。所供选择的传输协议也有Http, Tcp,P2P, IPC等。当要考虑Client/Server如何进行通讯的时候,除了考虑以
上提到的几点之外,还有其它很多需要考虑的因素,如安全,性能等。因此, 简单来说,Binding只不过是微软提供的一组考虑比较周全、常用的封装好的通信方式。
Contract:Contract描述了Service能提供的各种服务。Contract有四种,包括Service Contract, Data Contract, Fault Contract和Message Contract
WCF中的通讯模式单向:如果WCF 服务应用程序的客户端不必等待操作完成,并且不处理SOAP 错误,则该操作可以指定单向消息模式。
单向操作是客户端调用操作并在WCF将消息写入网络后继续进 单向操作是客户端调用操作并在WCF 将消息写入网络后继续进行处理的操作。通常这意味着,除非在出站消息中发送的数据极其庞大,否则客户端几乎立即继续运行(除非发送数据时出错)。此种类型的消息交换模式支持从客户端到服务应用程序的类似于事件的行为。
若要为返回void 的操作指定单向消息交换,请将IsOneWay 属性设置为true ,默认为false.
请求回复模式:通过请求/ 答复模式,请求发送方(客户端应用程序)将接收与请求相关的答复。这是默认的模式,因为它既支持传入操作(一个或多个参数传递到该操作中), 也支持返回操作(该操作将一个 或多个参数传递到该操作中 支持返回操作 该操作将 个或多个输出值传回给调用方)请注意,除非指定其他基础消息模式,否则,即使服务操作返回请注意,除非指定其他基础消息模式,否则,即使服务操作返回void (在Visual Basic 中为Nothing),也属于请求/ 答复消息交换。
操作的结果是除非客户端异步调用操作 否则客户端将停止处 – 操作的结果是:除非客户端异步调用操作,否则客户端将停止处理,直到收到返回消息,即使该消息正常情况下为空时也是如此。
优点:响应消息中可返回SOAP 错误这表明可能在通信或处理中发生 – 响应消息中可返回SOAP 错误,这表明可能在通信或处理中发生了一些与服务有关的错误状况
缺点:如果执行操作需要很长的时间,则会降低客户端性能和响应能力。
双工模式:双工模式的特点是,无论使用单向消息发送还是请求/ 答复消息发送方式,服务和客户端均能够独立地向对方发送消息。对于必须直接与客户端通信或向消息交换的任意一方提供异步体验(包括 接与客户端通信或向消息交换的任意 方提供异步体验 包括类似于事件的行为)的服务来说,这种双向通信形式非常有用。由于存在与客户端通信的附加机制,双向模式比请求/ 答复或单向模式要略为复杂。若要设计双工协定,还必须设计回调协定,并将该回调协定的类型分配给标记服务协定的ServiceContractAttribute 属性attribute) 的CallbackContract 属性(property)若要实现双工模式,您必须创建第二个接口,该接口包含在客户端调用的方法声明。双工模式要重新配置绑定。
先开看单向和请求回复模式(下面是新建WCF项目系统创建的接口):
[ServiceContract] public interface IService1 { [OperationContract] string GetData(int value); [OperationContract] CompositeType GetDataUsingDataContract(CompositeType composite); // TODO: 在此添加您的服务操作 [OperationContract(IsOneWay = true)] void OneWay(string s); } // 使用下面示例中说明的数据约定将复合类型添加到服务操作。 //DataContract修饰类型,DataMember修饰属性。一般修饰的自定义类型,标记后才会序列化。 [DataContract] public class CompositeType { bool boolValue = true; string stringValue = "Hello "; [DataMember] public bool BoolValue { get { return boolValue; } set { boolValue = value; } } [DataMember] public string StringValue { get { return stringValue; } set { stringValue = value; } } }
接口很简单,就定义了三个方法。方法GetValue传入一个int类型返回一个string类型。第二个方法传入一个自定义类CompositeType此类用DataContract,类里面属性都通过DataMember修饰了,此类可通过WCF方式序列化传输信息了。下面看看方法实现。
public class Service1 : IService1 { public string GetData(int value) { System.Threading.Thread.Sleep(10000); return string.Format("You entered: {0}", value); } public CompositeType GetDataUsingDataContract(CompositeType composite) { if (composite == null) { throw new ArgumentNullException("composite"); } if (composite.BoolValue) { composite.StringValue += "Suffix"; } return composite; } public void OneWay(string s) { System.Threading.Thread.Sleep(10000); } }
这接口的实现也很简单,就程序暂停十秒,然后输出字符串的程序。
我们通过Winform程序调用Wcf。先新建WinForm项目,在窗体新建按钮。然后按钮事件调用Wcf程序。
private void button1_Click(object sender, EventArgs e) { ServiceReference1.Service1Client ssc = new ServiceReference1.Service1Client(); MessageBox.Show(ssc.GetData(3)); ssc.OneWay("ss"); MessageBox.Show("adsf"); }
很显然我们调用第一个方法的时候,过了十秒才显示对话框。在请求答复模式下,客户端得接收到服务器返回的值才会继续执行下去的。但是单项模式就不一样,客户端只要请求了就会向下执行下去。
下面看看双工模式:同样新建Wcf项目在接口程序需要定义两个接口,一个做Wcf service一个作为服务器接受客户端信息接口类型。
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。 [ServiceContract(CallbackContract = typeof(IServiceClient))] public interface IService1 { [OperationContract(IsOneWay = true)] void Add(int i); } public interface IServiceClient { [OperationContract(IsOneWay = true)] void Client(int i); }
两个接口都很简单,一看就懂。值得注意的就是在IService1定义契约的时候后面跟了这个CallbackContract = typeof(IServiceClient)就是告诉客户端客户端的方法必须是IServiceClient接口类型的。下面方法实现
int n; IServiceClient isc = null; public Service1() { n = 6; isc = OperationContext.Current.GetCallbackChannel<IServiceClient>(); } public void Add(int i) { n += i; isc.Client(n); }
一看,是不是也很简单。哈哈,以简单为目的,就在类构造的时候//获得回调接口的类型,才能够调用接口的实现方法。实现服务器方法的同时,我们也调用一下客户端实现的方法。这样就实现双工模式了。但是就简单这样是会报错的,双工模式下配置得重新配一下。Wcf项目默认的配置不适用双工模式。配置文件,配置后最起码能让你的SVC文件在浏览器浏览。~~~~~~其实我现在对配置这一块不咋懂。
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <compilation debug="true" /> </system.web> <system.serviceModel> <bindings /> <client /> <services> <service name="WcfDuplex.Service1" behaviorConfiguration="WcfDuplex.Service1Behavior"> <host> <baseAddresses> <add baseAddress="http://localhost:5067/WcfDuplex/Service1/" /> </baseAddresses> </host> <endpoint address="" binding="wsDualHttpBinding" contract="WcfDuplex.IService1"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WcfDuplex.Service1Behavior"> <serviceMetadata httpGetEnabled="True"/> <serviceDebug includeExceptionDetailInFaults="False" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
最后调用Wcf,我们用控制台程序调用。新建一个控制台,引用WCF服务引用,界面直接出现刚才做好WCF的终结点,生成客户端代理类等。还生产相关的配置文件。
在调用服务器方法之前,这属于双工模式,我们必须得先实现服务端调用客户端的接口。
public class NewClient : ServiceReference1.IService1Callback { public void Client(int i) { Console.WriteLine("Client:" + i.ToString()); } }
然后再调用
static void Main(string[] args) { InstanceContext instanceContext = new InstanceContext(new NewClient()); ServiceReference1.Service1Client ssc = new ServiceReference1.Service1Client(instanceContext); ssc.Add(5); Console.ReadLine(); }
代码很简单 ,先通过客户端实现类创建一个上下文对象,把上下文对象传入给WCF在客户端的代理类。然后调用方法。程序运行结果就是。之前定义的n=6 + 传入的5
控制台输出11.oh yeah!也算实现了这个模式。
总结:本次主要学习WCF三张通讯模式,单项模式,请求回复(默认)。最重要的是双工模式,此模式必须定义两个接口,还有就是客户端实现服务器端调用的接口,然后怎么配置等等。还有数据怎么协定,数据协定后才能被WCF序列化传输。