【发布时间】:2013-03-14 05:17:04
【问题描述】:
我有一个问题,我不太确定它是如何开始的。我相当肯定它以前运行良好,但不记得做过任何更改。
首先,请不要过分关注设置,除非它直接影响它为什么不起作用。我不是在寻找批评,而是在寻找导致它不起作用的原因。
我公开了一个使用 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。
编辑我接受了 Carlos 的建议(在 cmets 中)并简化了调用,并使用了以下调用来代替它。我很高兴它可以工作,但是,我想找出问题出在我的原始代码中,这样我就不必每次需要使用服务引用时都调用样板代码。
以下代码有效:
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 });
知道为什么初始代码不起作用,而这个起作用吗?
【问题讨论】:
-
这段代码中有很多间接...你可以尝试使用简单的方法(即没有工厂、泛型、反射等)来简化它,看看它什么时候开始工作;那时开始追溯抽象,看看它在哪里中断。这将为您指出问题所在。
-
我会试试的。此外,这与最近从 .NET 4.5 降级到 4.0 有什么关系吗?我不得不修改一些我必须让它编译的可扩展性实现。主要是端点行为
-
@carlosfigueira ,我听取了您的建议,并将其简化为上面编辑中显示的更具体的版本,并且可以正常工作。现在,我想弄清楚第一个版本有什么问题。你有没有看到头顶上的东西?
-
但我仍然遇到问题,不确定最好的解决方案是什么。我觉得我可能过于复杂了这个过程。
-
我走了一条更简单的替代路线,我意识到我正在做的事情过于复杂。感谢您一直以来的帮助!
标签: c# wcf soap soap-client wcf-endpoint