[英]Custom Endpoint Behavior not being used in WCF Client with Service Reference
我有一个问题,我不太确定它是如何开始的。 我相当确定它之前工作正常,但不记得做出任何改变。
首先,请不要过分关注设置,除非它直接影响它不工作的原因。 我不是在寻找批评,因为我正在导致它不起作用。
我公开了一个使用HTTP头认证的API。 我在我的解决方案中使用此API的操作。 为了避免样板代码,我创建了我要初始化的服务ClientFactory,使用CustomClientMessageInspector和CustomCredentialBehavior负责添加标题到消息。
我的想法是,当我需要使用服务时,代码看起来类似于:
IClientCredentials credentials = ClientCredentials.FromToken();
var service = ClientFactory.CreateClientInstance<API.Clients.ClientServiceClient>(credentials);
ClientFactory如下所示(请不要过多评判)。
public class ClientFactory
{
public static T CreateClientInstance<T>(IClientCredentials clientCredentials)
{
T t = Activator.CreateInstance<T>();
var factory = t.GetType().GetProperty("ChannelFactory");
using (var scope = new OperationContextScope((IContextChannel) t.GetType().GetProperty("InnerChannel").GetValue(t,null)))
{
var endpointBehavior = new CustomCredentialBehavior(clientCredentials);
if (((ChannelFactory) factory.GetValue((t),null)).Endpoint.Behaviors.Any(p => p.GetType() == typeof(CustomCredentialBehavior)))
{
var behavior =
((ChannelFactory) factory.GetValue((t),null)).Endpoint.Behaviors.FirstOrDefault(
p => p.GetType() == typeof (CustomCredentialBehavior));
((ChannelFactory) factory.GetValue((t),null)).Endpoint.Behaviors.Remove(behavior);
}
((ChannelFactory)factory.GetValue((t),null)).Endpoint.Behaviors.Add(endpointBehavior);
return t;
}
}
}
CustomEndpointBehavior:
public class CustomCredentialBehavior:IEndpointBehavior
{
private IClientCredentials _clientCredentials { get; set; }
public CustomCredentialBehavior(IClientCredentials clientCredentials)
{
_clientCredentials = clientCredentials;
}
public void Validate(ServiceEndpoint endpoint)
{
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new ClientCredentialMessageInspector(_clientCredentials));
}
}
ClientMessageInspector:
public class ClientCredentialMessageInspector:IClientMessageInspector
{
private IClientCredentials _clientCredentials;
public ClientCredentialMessageInspector(IClientCredentials clientCredentials)
{
_clientCredentials = clientCredentials;
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
var buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
HttpRequestMessageProperty messageProperty =
(HttpRequestMessageProperty) request.Properties["httpRequest"];
messageProperty.Headers.Add("AccessKey", _clientCredentials.AccessKey.ToString());
messageProperty.Headers.Add("ClientKey", _clientCredentials.ClientKey.ToString());
messageProperty.Headers.Add("AuthorizationKey", _clientCredentials.AuthorizationKey);
return null;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
}
我面临的问题是,即使我可以看到从ClientFactory返回的服务具有正确的端点行为,也永远不会调用ApplyClientBehavior()。 出于某种原因,它似乎不像原来那样使用WCF管道。
如何让ClientFactory创建一个实例,以便使用我添加的EndpointBehavior?
编辑只是为了显示我正在查看的内容,这里是调用服务操作之前的监视窗口的屏幕截图。 它显示我的CustomCredentialBehavior使用所有正确的值初始化。
编辑我接受了卡洛斯的建议(在评论中)并简化了呼叫,并使用了以下调用,而不是有效。 我很高兴它的工作原理,但是,我想知道原始代码中的问题所在,所以每次我需要使用服务引用时都不必调用样板代码。
以下代码有效:
API.Clients.Client client = new API.Clients.Client();
client.Active = true;
client.Enabled = true;
client.Name = model.ClientName;
API.Clients.ClientServiceClient service = new ClientServiceClient();
service.ChannelFactory.Endpoint.Behaviors.Add(new CustomCredentialBehavior(ClientCredentials.FromToken()));
var response = service.CreateClient(new CreateClientRequest() { Client = client });
知道为什么初始代码不起作用,而这个呢?
我可能会在这里遗漏一些东西,但我真的不明白为什么你会选择这么复杂的路线。
如果您有接口(而不是Client类)合同,请执行以下操作:
var factory = new ChannelFactory<T>(); //T is the interface of the service
factory.Endpoint.Behaviors.Add()
将为您提供添加行为的方法。 然后创建实际服务,你只需要调用factory.CreateChannel()
,它返回一个T
总结如下:
public T Create<T>()
{
var factory = new ChannelFactory<T>();
factory.Endpoint.Behaviors.Add(<here goes your behavior>);
return factory.CreateChannel();
}
还记得相应地处理客户端通道。 如果您正在使用IoC,容器可能会为您处理(例如,Autofac可以)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.