问题提出:
在WCF中如何实现登陆,典型的场景如下:
[ServiceContract]
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
public interface ILogin
{
![](/Images/OutliningIndicators/InBlock.gif)
[OperationContract]
![](/Images/OutliningIndicators/InBlock.gif)
bool Signin(string userName, string password);
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/None.gif)
[ServiceContract]
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
public interface IBizTest
{
![](/Images/OutliningIndicators/InBlock.gif)
[OperationContract]
![](/Images/OutliningIndicators/InBlock.gif)
string GetWelcomeInfo();
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/None.gif)
千万别从WCF自带的那个InstanceContextMode来想办法,因为WCF中的PerSession调用只是针对每个服务类而言的,除非你变态到服务端只有一个类来实现全部的接口;
变个思路,能不能用类似.NET Remoting中的CallContext呢?但是查了一下WCF的手册,好像也没有这么个东西,怎么解决呢?那就是Custom header.
解决方案提出前,需要知道一点的就是,服务端取客户端送出的Header的方法:
先遍历OperationContext.Current.IncomingMessageHeaders找出客户端发送的Header Name,然后再用 OperationContext.Current.IncomingMessageHeaders.GetHeader<T>(i)得到值就可以啦。
下面的问题就剩下客户端怎么发送Custom Header了。
策略1:在每个客户端Proxy中增加类似如下的代码
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
using (OperationContextScope scope = new OperationContextScope(InnerChannel))
{
![](/Images/OutliningIndicators/InBlock.gif)
MessageHeader mh = MessageHeader.CreateHeader("HeaderName", string.Empty, "HeaderValue");
![](/Images/OutliningIndicators/InBlock.gif)
OperationContext.Current.OutgoingMessageHeaders.Add(mh);
![](/Images/OutliningIndicators/InBlock.gif)
//…
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/None.gif)
但是每个客户端都要增加,太麻烦了,所以,引出
2.自定义一个CallContextAttribute,代码如下:
1. 先定义一个IClientMessageInspector接口的实现类
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
public class ContextHeader : IClientMessageInspector
{
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
![](/Images/OutliningIndicators/InBlock.gif)
//
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
{
![](/Images/OutliningIndicators/InBlock.gif)
MessageHeader clientHeader = MessageHeader.CreateHeader("headerName", string.Empty, "headerValue");
![](/Images/OutliningIndicators/InBlock.gif)
request.Headers.Add(clientHeader);
![](/Images/OutliningIndicators/InBlock.gif)
return null;
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
OK , 然后就可以实现CallContextAttribute了
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
public class CallContextAttribute : Attribute, IEndpointBehavior, IOperationBehavior
{
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
IEndpointBehavior Members#region IEndpointBehavior Members
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
![](/Images/OutliningIndicators/InBlock.gif)
clientRuntime.MessageInspectors.Add(new ContextHeader());
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void Validate(ServiceEndpoint endpoint)
{
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
#endregion
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
IOperationBehavior Members#region IOperationBehavior Members
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
![](/Images/OutliningIndicators/InBlock.gif)
clientOperation.Parent.MessageInspectors.Add(new ContextHeader ());
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void Validate(OperationDescription operationDescription)
{
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/InBlock.gif)
#endregion
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
完工大吉,最后在我们Contract中加入CallContextAttribute就可以啦,客户端不用增加任何代码了。
[ServiceContract]
![](/Images/OutliningIndicators/None.gif)
[CallContext]
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
public interface IBizTest
{
![](/Images/OutliningIndicators/InBlock.gif)
[OperationContract]
![](/Images/OutliningIndicators/InBlock.gif)
[CallContext]
![](/Images/OutliningIndicators/InBlock.gif)
string GetWelcomeInfo();
![](/Images/OutliningIndicators/InBlock.gif)
}
![](/Images/OutliningIndicators/None.gif)