WCF初探-15:WCF操作协定
前言:
- 在前面的文章中,我们定义服务协定时,在它的操作方法上都会加上OperationContract特性,此特性属于OperationContractAttribute 类,将OperationContract应用于方法,以指示该方法实现作为服务协定(由 ServiceContractAttribute 属性指定)一部分的服务操作。OperationContractAttribute 属性声明方法是服务协定中的操作。 只有具有 OperationContractAttribute 属性的方法可作为服务操作公开。 不含有 OperationContractAttribute 标记的所有方法的服务协定不公开任何操作。公开的操作方法我们称之为操作协定。
操作协定的属性:
- Action: 获取或设置请求消息的 WS-Addressing 操作。 WCF 根据请求消息的操作将它们调度至方法。
- 使用 Action 属性控制方法的输入消息的操作。 由于 WCF 使用该操作将传入消息调度至相应方法,因此在协定操作中使用的消息必须具有唯一的操作。 默认操作值由以下几项组成:协定命名空间(默认值为“http://tempuri.org/”)、协定名称(如果没有使用显式服务接口,则为接口名称或类名)、操作名称,并且如果该消息是一个相关的响应,则还有一个附加字符串(“Response”)。 您可以使用 Action 属性重写该默认值。
- 若要指示服务操作可处理该服务接收的所有消息,但又不能定向到服务操作,请指定值“*”(星号)。 这种类型的操作(称为不匹配的消息处理程序)必须具有下列方法签名之一,否则会引发 InvalidOperationException :该服务操作只能接受一个 Message 对象,并且返回一个 Message 对象;该服务操作只能接受一个 Message 对象,并且不返回任何内容(即返回 void)。
- 服务协定只能有一个 Action 属性设置为“*”的服务操作。 当 IsInitiating 属性设置为 false 时,服务类实现的相同 listenUri 所承载的任何服务协定组可具有多个 Action 属性设置为“*”的服务操作。 然而,其中只有一个服务操作可将 Action 属性设置为“*”,并将 IsInitiating 属性设置为 true。
- AsyncPattern :属性指示使用 Begin/End 方法对可以实现或异步调用该操作。
- 使用 AsyncPattern 属性生成可在服务器和/或客户端异步调用的服务操作。 AsyncPattern 属性通知运行库 Begin 方法有一个符合 .NET Framework 异步方法设计模式的匹配的 End 方法。 生成用以实现服务操作的服务器异步方法可增强服务器的可伸缩性和性能,而不会影响服务的客户端。如果服务操作在执行完可异步执行的较长操作后,必须将某些内容返回至客户端,建议使用此方法。
- 这不会影响客户端,因为服务器上的异步方法对是实现详细信息,该信息不会影响操作的基础 Web 服务描述语言 (WSDL) 描述。 此类方法在客户端显示为包含 <input> 和相关 <output> 消息的单个操作。 WCF 自动将入站消息路由至 Begin<methodName> method and routes the results of the End<methodName> 调用的结果路由至出站消息。 因此,客户端信道可将方法对表示为单个同步操作或一个异步操作对。 客户端表示形式在任何情况下都不会以任何方式影响服务器上的异步实现。
- 客户端协定可使用 AsyncPattern 属性指示异步方法对,即客户端可使用该方法对异步调用操作。 通常,客户端应用程序使用 ServiceModel 元数据实用工具 (Svcutil.exe) 工具和 /async 选项生成客户端可以调用使用异步操作的 Begin<methodName> 和 End<methodName> 方法对。
- 如果服务操作具有异步和同步两个版本,则服务上的默认行为是调用同步版本。
- IsOneWay :获取或设置一个值,该值指示操作是否返回答复消息。
- 使用 IsOneWay 属性可以指示操作不返回答复消息。 这种类型的操作对通知或事件样式通信十分有用,特别是双向通信。 如果不等待基础响应消息,则单向操作的调用方在处理请求消息时无法直接检测错误。
- 在面向双工(或双向)服务的应用程序中,客户端和服务器相互独立地通信,并且客户端信道可使用其方法中的 IsOneWay 属性指示服务可单向调用客户端(该客户端可作为事件处理)。 这不会返回调用或生成消息,因为该服务不需要任何响应消息。
- 如果 IsOneWay 属性设置为 false(默认值),即使返回 void 的方法也会生成答复消息。 在此种情况下,基础结构将创建并发送一条空消息,以向调用方指示该方法已返回内容。(通过此方法使基础结构可以将 SOAP 错误发送回客户端。)将 IsOneWay 设置为 true 是取消创建和调度响应消息的唯一方法。
- 单向方法不得返回一个值或具有 ref 或 out 参数;否则将引发 System.InvalidOperationException 异常。
- 指定操作是单向操作,只表示它没有响应消息。 如果无法建立连接、出站消息非常大或该服务无法足够快地读取入站信息,则可能会阻止。 如果客户端要求非阻止调用,则会生成 AsyncPattern 操作。
- IsInitiating: 获取或设置一个值,该值指示方法是否实现可在服务器上启动会话(如果存在会话)的操作。
- ServiceContractAttribute.SessionMode 的值必须为 Allowed 或 Required 且使用的绑定必须要求或允许会话,IsInitiating 属性才能正常工作。
- 默认为 true,这意味着操作可以是通道上调用的第一个操作。 除了调用该方法之外,后续的调用对于启动方法无效。 不会创建其他任何会话。 如果协定不使用会话,则将 IsInitiating 设置为 false 会被忽略。通常,将 IsInitiating 设置为 false 可强制客户端在调用此方法之前,调用服务上的另一个方法。
- IsInitiating 和 Action 属性之间存在交互操作。 服务协定只能有一个 Action 属性设置为“*”的服务操作。 当 IsInitiating 属性设置为 false 时,服务类实现的相同侦听 URI 所承载的任何服务协定组可具有多个 Action 属性设置为“*”的服务操作。 然而,其中只有一个服务方法可将 Action 属性设置为“*”,并将 IsInitiating 属性设置为 true。
- 如果服务收到非启动操作的消息,则该服务返回 ActionNotSupported SOAP 错误。 客户端将这种情况当作 FaultException。 如果客户端首先调用非启动操作,则客户端运行库会引发 System.InvalidOperationException。
- IsTerminating: 获取或设置一个值,该值指示服务操作在发送答复消息(如果存在)后,是否会导致服务器关闭会话。
- 使用 IsTerminating 属性指示调用服务操作可终止通信会话。
- 在客户端应用程序中,将 IsTerminating 值设置为 true 以指示 WCF 在答复到达后,关闭信道。
- 在服务中,如果客户端在该期间内不关闭信道,则将会设置计时器并中止信道。
- 如果调用方侦听的是 OperationContractAttribute.IsTerminating 操作的 OperationContext.OperationCompleted 事件,则在收到响应时可能会阻塞。 处理这种情况的正确方法是,当引发 OperationCompleted 时在其他线程上调度工作,然后从该事件处理程序立即返回。
- ProtectionLevel 获取或设置一个值,该值指定是否必须对操作的消息进行加密和/或签名。
- 运行时的保护行为是在下列属性中设置的保护级别值的组合,这一点很重要。 这些属性具有层次结构。 除非已为较窄范围显式设置了某个不同的值,否则设置最外层的值将为所有较窄的范围确定默认设置。 在这种情况下,外层的值将保持所有较窄的范围的默认设置,但特定的设置除外。例如,如果将 ServiceContractAttribute.ProtectionLevel 设置为 ProtectionLevel.EncryptAndSign,并且其他较窄范围都没有设置保护级别,则会对操作协定中的所有消息进行加密和签名。 但是,如果其中一个操作将 ProtectionLevel 设置为 ProtectionLevel.Sign,那么对此操作的消息只进行签名,而对协定中的所有其他消息进行加密和签名。
- 当协定上没有显式指定保护级别并且基础绑定支持安全性时(无论处于传输级别还是处于消息级别),整个协定的有效保护级别将为 ProtectionLevel.EncryptAndSign。 如果绑定不支持安全性(如 BasicHttpBinding),则整个协定的有效 System.Net.Security.ProtectionLevel 为 ProtectionLevel.None。 因此,根据终结点绑定,即使协定指定了 ProtectionLevel.None,客户端也可以要求不同的消息或传输级别安全保护。
- 消息保护级别的层级结构:
- ReplyAction:获取或设置用于该操作答复消息的 SOAP 操作的值。
- 除指定答复消息操作标头的特定值以外,还可以指定字符串“*”(星号)。 在服务中指定星号可指示 WCF 不向消息中添加答复操作,如果您是直接对消息进行编程会十分有用。 在客户端应用程序中指定星号可指示 WCF 不验证答复操作。
WCF操作协定示例:
- 解决方案如下:
- 工程结构说明:
- Service:服务契约定义和实现。在服务契约接口中,我们定义了MethodOne、MethodTwo、MethodThree三个操作契约,其中MethodThree使用异步实现,这个示例也说明了异步服务的实现。在服务契约中,我们启用会话要求,将SessionMode设置为Required,目的是为了验证IsInitiating(启动服务器会话)和IsTerminating(服务操作在发送答复消息后,关闭会话)。
设置了操作契约Action(设置请求消息的 WS-Addressing 操作)和ReplyAction(设置用于该操作答复消息的 SOAP 操作的值)
ISampleMethod.cs的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel; namespace Service
{
[ServiceContract(Name = "SampleMethodContract",
Namespace = "http://wangweimutou.SampleMethodContract",
SessionMode=SessionMode.Required)]
public interface ISampleMethod
{
/// <summary>
/// IsInitiating默认值为true,IsTerminating默认值为false
/// </summary>
/// <param name="msg"></param>
[OperationContract(Name="OCMethodOne",
AsyncPattern=false,
IsInitiating=true,
IsTerminating=false,
Action = "http://wangweimutou.SampleMethodContract/RequestMethodOne",
ReplyAction = "http://wangweimutou.SampleMethodContract/ResponseMethodOne")]
string MethodOne(string msg); [OperationContract(Name = "OCMethodTwo",
AsyncPattern = false,
IsInitiating = true,
IsTerminating = false,
Action = "http://wangweimutou.SampleMethodContract/RequestMethodTwo",
ReplyAction = "http://wangweimutou.SampleMethodContract/ResponseMethodTwo")]
string MethodTwo(string msg); [OperationContract(Name = "OCMethodThree",
AsyncPattern = true,
IsInitiating = true,
IsTerminating = false,
Action = "http://wangweimutou.SampleMethodContract/RequestMethodThree",
ReplyAction = "http://wangweimutou.SampleMethodContract/ResponseMethodThree")]
IAsyncResult BeginMethodThree(string msg, AsyncCallback callback, object asyncState);
string EndMethodThree(IAsyncResult result);
}
}
SampleMethod.cs的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.ServiceModel; namespace Service
{
public class SampleMethod :ISampleMethod
{
public string MethodOne(string msg)
{
return "You called MethodOne return message is: " + msg;
} public string MethodTwo(string msg)
{
return "You called MethodTwo return message is: " + msg;
} public IAsyncResult BeginMethodThree(string msg, AsyncCallback callback, object asyncState)
{
return new CompletedAsyncResult<string>(msg);
} public string EndMethodThree(IAsyncResult r)
{
CompletedAsyncResult<string> result = r as CompletedAsyncResult<string>;
return "You called MethodThree return message is: " + result.Data;
}
} class CompletedAsyncResult<T> : IAsyncResult
{
T data; public CompletedAsyncResult(T data)
{ this.data = data; } public T Data
{ get { return data; } } #region IAsyncResult Members
public object AsyncState
{ get { return (object)data; } } public WaitHandle AsyncWaitHandle
{ get { throw new Exception("The method or operation is not implemented."); } } public bool CompletedSynchronously
{ get { return true; } } public bool IsCompleted
{ get { return true; } }
#endregion
}
}
2. Host:控制台应用程序,服务承载程序。添加对Service程序集的引用,实现以下代码。Program.cs的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Service;
using System.ServiceModel; namespace Host
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(SampleMethod)))
{
host.Opened += delegate { Console.WriteLine("服务已经启动,按任意键终止!"); };
host.Open();
Console.Read();
}
}
}
}
App.config代码如下:
<?xml version="1.0"?>
<configuration>
<system.serviceModel> <services>
<service name="Service.SampleMethod" behaviorConfiguration="mexBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:1234/SampleMethod/"/>
</baseAddresses>
</host>
<endpoint address="" binding="wsHttpBinding" contract="Service.ISampleMethod" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services> <behaviors>
<serviceBehaviors>
<behavior name="mexBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
3. Client:控制台应用程序。客户端应用程序,启动Host服务承载程序,添加对服务地址http://localhost:1234/SampleMethod/引用后,将命名空间设置为ServiceRef,
勾选生成异步操作复选框,生成异步客户端代理类(参照WCF初探-11:WCF客户端异步调用服务),我们就可以对程序进行同步和异步的调用了。Program.cs代码如下:
运行程序,结果显示如下:
从结果中,我们可以看到,程序停止了对MethodTwo和MethodThree的调用,这是因为MethodOne的IsTerminating设置为true,所以客户端代理在调用完MethodOne
后就关闭了对服务器会话的支持。接下来,我们将调用MethodOne的代码注释掉,编译Client后再次运行,会得到一下结果:
由于我们将MethodTwo的IsInitiating设置为了false,导致服务器会话没有启动,所以服务调用失败。接下来,我们将MethodOne、MethodTwo、MethodThree三个操作
契约的IsInitiating和IsTerminating分别设置为true和false,也就是设置为默认值,重新编译程序后,运行客户端我们可以看到如下结果:
接下来,我们再来查看一下操作契约设置的属性值,从上面的客户端程序代码可以看出,服务契约和操作契约的方法和名称都改成了设定值,如MethodOne变成了OCMethodOne。
打开客户端测试程序,添加对服务地址的引用后,我们就可以看到消息的请求和响应,如观察到MethodOne调用的结果如下:
总结:
- 在上面的示例中,我们修改了操作契约的部分属性,也从运行结果和交换的消息中验证了这些修改的属性。并且还完成了异步服务的实现。关于消息保护级别属性将在以后的博文中做解析。
- 关于OperationContract的IsOneWay可以查看以下博文:
WCF初探-5:WCF消息交换模式之双工通讯(Duplex)
- 关于客户端异步调用服务可以查看以下博文:
WCF初探-15:WCF操作协定的更多相关文章
- WCF初探文章列表
WCF初探-1:认识WCF WCF初探-6:WCF服务配置 WCF初探-2:手动实现WCF程序 WCF初探-7:WCF服务配置工具使用 WCF初探-3:WCF消息交换模式之单向模式 WCF初探-8:W ...
- WCF初探-26:WCF中的会话
理解WCF中的会话机制 在WCF应用程序中,会话将一组消息相互关联,从而形成对话.会话”是在两个终结点之间发送的所有消息的一种相互关系.当某个服务协定指定它需要会话时,该协定会指定所有调用(即,支持调 ...
- WCF初探-14:WCF服务协定
前言: 在前面的文章中,我们定义的服务协定上都会有一个ServiceContract的特性来修饰,这是因为服务契约的实现要靠ServiceContractAttribute 属性定义,然后使用一个或多 ...
- WCF初探-20:WCF错误协定
WCF错误协定概述 在所有托管应用程序中,处理错误由 Exception 对象表示. 在基于 SOAP 的应用程序(如 WCF 应用程序)中,服务方法使用 SOAP 错误消息来传递处理错误信息. SO ...
- WCF初探-17:WCF数据协定之等效性
数据协定等效性特点概述 对于客户端要将某种类型的数据成功发送到服务,或者服务要将数据成功发送到客户端的情况,接收端上并不一定必须存在此发送数据类型. 唯一的要求是两种类型的数据协定应该等效. 要使数据 ...
- WCF初探-18:WCF数据协定之KnownType
KnownTypeAttribute 类概述 在数据到达接收终结点时,WCF 运行库尝试将数据反序列化为公共语言运行库 (CLR) 类型的实例.通过首先检查传入消息选择为反序列化而实例化的类型,以确定 ...
- WCF初探-19:WCF消息协定
WCF消息协定概述 在生成 WCF应用程序时,开发人员通常会密切关注数据结构和序列化问题,而不必关心携带数据的消息结构. 对于这些应用程序,为参数或返回值创建数据协定的过程很简单.但是,有时完全控制 ...
- WCF系列教程之WCF操作协定
一.简介 1.在定义服务协定时,在它的操作方法上都会加上OperationContract特性,此特性属于OperationContractAttribute 类,将OperationContract ...
- WCF初探-10:WCF客户端调用服务
创建WCF 服务客户端应用程序需要执行下列步骤: 获取服务终结点的服务协定.绑定以及地址信息 使用该信息创建 WCF 客户端 调用操作 关闭该 WCF 客户端对象 WCF客户端调用服务存在以下特点: ...
随机推荐
- 学习 Linux,101: 使用基本 SQL 命令
概述 在本教程中,将学习结构化查询语言 (SQL),包括: 使用基本 SQL 命令 执行基本数据操作 本教程将简要介绍您需要知道的与 LPI 102 考试相关的 SQL 概念. 回页首 数据库和 ...
- Asp.Net alert 方法
public static void ExcuteAlert(Page page, string strAlerts) { ClientScriptManager ...
- MVC 移除复数表名的契约
在数据库上下文中添加: using System.Data.Entity.ModelConfiguration.Conventions; protected override void OnModel ...
- Url中處理空格、特殊字符
publicvoid UrlEncodeTest(){ string url ="C++ C#"; Console.WriteLine(HttpUtility.UrlE ...
- Jquery 处理字符串
1.去掉空格var txt=$.trim($("txt1").val()); 2.转为数字 txtNum=Number($.trim(txt)) + 1; var thisEle ...
- easyui DataGrid 工具类之 Utils class
import java.lang.reflect.InvocationTargetException;import java.text.ParseException;import java.text. ...
- 异步加载JS的4种方式(详解)
方案1:$(document).ready <!DOCTYPE html> <html> <head> <script src="http://co ...
- HDU 4944 FSF’s game 一道好题
FSF’s game Time Limit: 9000/4500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Tota ...
- 微信小程序注册app
App() App() 函数用来注册一个小程序.接受一个 object 参数,其指定小程序的生命周期函数等. object参数说明 onLaunch Function 生命周期函数--监听小程序初 ...
- C#中的多线程 - 基础知识
原文:http://www.albahari.com/threading/ 文章来源:http://blog.gkarch.com/threading/part1.html 1简介及概念 C# 支持通 ...