我想要实现的是在每个请求中将凭证/令牌传递给WCF服务。顺便说一句,这个凭证不是Windows凭证,它们是从自定义数据库中提取的,而且身份验证逻辑非常简单,tenantId +用户名+密码。
我目前正在使用消息检查器在标头中插入这些信息,并从服务器端检查器中获取它们(使用OperationContext
)。
但为了保持线程安全,我必须在每个winform请求中包装请求,如下所示:
using (new OperationContextScope((WcfService as ServiceClient).InnerChannel))
{
MessageHeader hdXXId = MessageHeader.CreateHeader("XXId", "CustomHeader", WinformSomeVariable.XXId);
OperationContext.Current.OutgoingMessageHeaders.Add(hdXXId);
_objXX = WcfService.GetXXById(id);
}
如上所示,这很重,显然不是处理这种情况的聪明方法。那么有没有办法安全地保存这些信息,并且可以在WCF检查员中获取它们?
非常感谢!
PS。感谢@Abraham Qian,我一直很傻。只需将客户端检查器置于同一个winform项目中即可解决此问题。
只需忽略如何重构身份验证的问题。至于如何使用IClientMessageInspector接口创建持久性消息头,以下代码片段可能很有用(假设使用Channel Factory调用)
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("http://localhost:1300");
IService service = ChannelFactory<IService>.CreateChannel(new BasicHttpBinding(), new EndpointAddress(uri));
try
{
Console.WriteLine(service.SayHello());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
[ServiceContract(Namespace = "mydomain")]
[CustomContractBehavior]
public interface IService
{
[OperationContract]
string SayHello();
}
public class ClientMessageLogger : IClientMessageInspector
{
public void AfterReceiveReply(ref Message reply, object correlationState)
{
string displayText = $"the client has received the reply:\n{reply}\n";
Console.Write(displayText);
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
//Add custom message header
request.Headers.Add(MessageHeader.CreateHeader("myheader","mynamespace",2000));
string displayText = $"the client send request message:\n{request}\n";
Console.WriteLine(displayText);
return null;
}
}
public class CustomContractBehaviorAttribute : Attribute, IContractBehavior, IContractBehaviorAttribute
{
public Type TargetContract => typeof(IService);
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new ClientMessageLogger());
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
return;
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
return;
}
}