WCF創建在基於消息的通訊這一律念基礎上。經過方法調用(Method Call)形式體現的服務訪問須要轉化成具體的消息,並經過相應的編碼(Encoding)才能經過傳輸通道發送到服務端;服務操做執行的結果也只能以消息的形式才能被正常地返回到客戶端。因此,消息在整個WCF體系結構中處於一個核心的地位,WCF能夠當作是一個消息處理的管道,以下圖所示:
WCF的一個操做(以及操做的參數)被序列化爲Soap協議所支持的消息(XML結構),通過服務運行層,交給Binding中所定義的消息傳遞層,消息傳遞層由通道(Channel)組成。通道是以某種方式對消息進行處理(例如經過對消息進行身份驗證)的組件,通道對消息和消息頭進行操做,而服務運行層主要針對消息正文內容進行處理。
方法一. 經過OperationContext直接添加/訪問MessageHeader信息
使用OperationContext咱們能夠:訪問當前操做執行環境。 特別是,操做上下文用於訪問雙工服務中的回調通道、存儲整個操做部分的額外狀態數據、訪問傳入消息頭和屬性以及添加傳出消息頭和屬性。下面用代碼演示下如何在MessageHeader中添加額外的信息,進行用戶驗證。
1. 服務契約 ide
- using System;
- using System.Runtime.Serialization;
- using System.ServiceModel;
- namespace WcfSvcLib
- {
- [ServiceContract(Namespace="http://blog.csdn.net/fangxinggood")]
- public interface IService1
- {
- [OperationContract]
- string GetData(int value);
- }
- }
2. 服務實現 編碼
- using System;
- using System.Runtime.Serialization;
- using System.ServiceModel;
- namespace WcfSvcLib
- {
- public class Service1 : IService1
- {
- public string GetData(int value)
- {
- Console.WriteLine(OperationContext.Current.RequestContext.RequestMessage);
-
- var ns = "http://blog.csdn.net/fangxinggood";
- var user = GetHeaderValue("user", ns);
- var pwd = GetHeaderValue("pwd", ns);
-
- if (user != "fangxing" || pwd != "password")
- throw new FaultException("Invalid User!");
- return string.Format("You entered: {0}", value);
- }
- private string GetHeaderValue(string name, string ns = "http://tempuri.org")
- {
- var headers = OperationContext.Current.IncomingMessageHeaders;
- var index = headers.FindHeader(name, ns);
- if (index > -1)
- return headers.GetHeader<string>(index);
- else
- return null;
- }
- }
- }
3. 客戶端實現 spa
- using System;
- using System.ServiceModel;
- using System.ServiceModel.Channels;
- namespace WcfClient
- {
- class Program
- {
- static void Main(string[] args)
- {
- var client = new WcfSvc.Service1Client();
- using (var scope = new OperationContextScope(client.InnerChannel))
- {
-
- var myNamespace = "http://blog.csdn.net/fangxinggood";
-
- var user = MessageHeader.CreateHeader("user", myNamespace, "fangxing");
- var pwd = MessageHeader.CreateHeader("pwd", myNamespace, "password");
- OperationContext.Current.OutgoingMessageHeaders.Add(user);
- OperationContext.Current.OutgoingMessageHeaders.Add(pwd);
- var result = client.GetData(100);
- Console.WriteLine(result);
- Console.Read();
- }
- }
- }
- }
運行一下,在服務端經過 Console.WriteLine(OperationContext.Current.RequestContext.RequestMessage); 輸出了請求的Message。經過輸出的信息,咱們能夠看到Header裏添加的信息:
經過上面的代碼,咱們能夠完成相似WebService的SoapHeader驗證。可是這樣須要咱們每一個契約都作相似的添加、驗證,這樣豈不是很繁瑣。下面看方法二,經過消息檢查器完成統一的用戶驗證。
方法二. 消息檢查器方式添加/訪問MessageHeader信息
客戶端經過實現IClientMessageInspector接口,服務端經過實現IDispatchMessageInspector接口,來攔截消息。這種方式是經過擴展Behavior來加入攔截的,因此還須要分別實現IEndpointBehavior(客戶端)和IServiceBehavior(服務端)接口,並經過配置將消息檢查器加入。
工程結構:
實現說明:
【客戶端】
1. ClientInterpector 實現: .net
- using System;
- using System.ServiceModel.Dispatcher;
- using System.ServiceModel.Configuration;
- using System.ServiceModel.Channels;
- using System.ServiceModel;
- namespace WcfClientInterpector
- {
- public class ClientInterpector : IClientMessageInspector
- {
- public void AfterReceiveReply(ref Message reply, object correlationState)
- {
- }
- public object BeforeSendRequest(ref Message request, IClientChannel channel)
- {
- var userNameHeader = MessageHeader.CreateHeader("OperationUserName", "http://tempuri.org", "fangxing", false, "");
- var pwdNameHeader = MessageHeader.CreateHeader("OperationPwd", "http://tempuri.org", "password", false, "");
- request.Headers.Add(userNameHeader);
- request.Headers.Add(pwdNameHeader);
- Console.WriteLine(request);
- return null;
- }
- }
- }
2. MyClientBehavior 實現: (實現擴展endpointBehavior元素) orm
- using System;
- using System.ServiceModel.Configuration;
- using System.ServiceModel.Description;
- using System.ServiceModel.Dispatcher;
- using System.ServiceModel;
- namespace WcfClientInterpector
- {
- public class MyClientBehavior : BehaviorExtensionElement, IEndpointBehavior
- {
- public override Type BehaviorType
- {
- get { return typeof(MyClientBehavior); }
- }
- protected override object CreateBehavior()
- {
- return new MyClientBehavior();
- }
- #region IEndpointBehavior Members
- public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
- {
- }
- public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
- {
- clientRuntime.MessageInspectors.Add(new ClientInterpector());
- }
- public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
- {
- }
- public void Validate(ServiceEndpoint endpoint)
- {
- }
- #endregion
- }
- }
3. 配置
修改客戶端配置文件,步驟以下:
(1) 在Advanced>Extensions>behavior element extensions中加入自定義的ClientInterpector。
(2) 在Advanced>Endpoint Behaviors中定義一個Behavior,添加上面配置過的extension
(3) 修改Client>Endpoints下的Endpoint的Behavior Config指向(2)配置的Behavior。
【服務端】
1. ServiceInterpector 實現: server
- using System;
- using System.ServiceModel.Dispatcher;
- using System.ServiceModel;
- namespace WcfServiceInterpector
- {
- public class ServiceInterpector : IDispatchMessageInspector
- {
- #region IDispatchMessageInspector Members
- public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
- {
- Console.WriteLine(request);
- var user = GetHeaderValue("OperationUserName");
- var pwd = GetHeaderValue("OperationPwd");
- if (user != "fangxing" || pwd != "password")
- throw new FaultException("Invalid User!");
- return null;
- }
- public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
- {
- }
- private string GetHeaderValue(string name, string ns = "http://tempuri.org")
- {
- var headers = OperationContext.Current.IncomingMessageHeaders;
- var index = headers.FindHeader(name, ns);
- if (index > -1)
- return headers.GetHeader<string>(index);
- else
- return null;
- }
- #endregion
- }
- }
2. MyServiceBehavior 實現:(實現擴展serviceBehavior元素) blog
- using System;
- using System.ServiceModel.Configuration;
- using System.ServiceModel.Description;
- using System.ServiceModel.Dispatcher;
- namespace WcfServiceInterpector
- {
- public class MyServiceBehavior : BehaviorExtensionElement, IServiceBehavior
- {
- public override Type BehaviorType
- {
- get { return typeof(MyServiceBehavior); }
- }
- protected override object CreateBehavior()
- {
- return new MyServiceBehavior();
- }
- #region IServiceBehavior Members
- public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
- {
- }
- public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
- {
- foreach (ChannelDispatcher chDisp in serviceHostBase.ChannelDispatchers)
- {
- foreach (EndpointDispatcher epDisp in chDisp.Endpoints)
- {
- epDisp.DispatchRuntime.MessageInspectors.Add(new ServiceInterpector());
- }
- }
- }
- public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
- {
- }
- #endregion
- }
- }
3. 配置
修改服務端配置文件,步驟以下:
(1) 在Advanced>Extensions>behavior element extensions中加入自定義的ServiceInterpector。
(2) 在Advanced>Service Behaviors中定義一個Behavior,添加上面配置過的extension
(3) 修改Services下的服務節點的Behavior Config指向(2)配置的Behavior。
接口