У меня проблема, я не совсем уверен, как она началась. Я совершенно уверен, что раньше он работал нормально, но не помню, чтобы вносил какие-либо изменения.
Во-первых, пожалуйста, не уделяйте слишком много внимания настройке, если только она напрямую не влияет на то, почему она не работает. Я не столько критикую, сколько то, что заставляет это не работать.
Я предоставляю API, который использует аутентификацию HTTP-заголовка. Я использую операции из этого 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));
}
}
Инспектор сообщений клиента:
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 инициализирован со всеми правильными значениями.
EDIT Я последовал совету Карлоса (в комментариях) и упростил вызов, а вместо этого использовал следующий вызов, который работает. Я рад, что это работает, однако я хотел бы выяснить, где проблема в моем исходном коде, чтобы мне не приходилось вызывать шаблонный код каждый раз, когда мне нужно использовать ссылку на службу.
Работает следующий код:
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 });
Есть идеи, почему исходный код не работает, а этот работает?