2015-02-13 3 views
2

Я звоню в службу WCF, размещенную в IIS через HTTP, используя basicHttpBinding. Чтобы пройти проверку на сервере, необходимо передать значение пользовательского заголовка, вычисленное из самого HTTP-запроса (заголовки и тело, если они есть).Получить тело запроса HTTP от basicHttpBinding прокси WCF

я могу получить большую часть информации от вызова с использованием сообщений клиента инспектора (System.ServiceModel.Dispatcher.IClientMessageInspector) пользовательские конечные точками поведения на прокси (System.ServiceModel.Description.IEndpointBehavior), а затем доступ к httpRequest заголовку объекта сообщения.

Однако получение содержимого сообщения, которое сериализуется для передачи по кабелю, не представляется незамедлительным или явно доступным. Однако я могу получить само сообщение, которое хранится в XmlSerializer, что не делает его доступным в том же формате, что и его передача по кабелю.

Есть ли способ получить доступ к этому значению? Возможно, другой инспектор или поведение, которое может быть введено, чтобы оно было вызвано во время открытия или обращения к каналу?

+0

Кажется, что происходит с помощью конечной точки или поведений маршрут вряд ли будет возможно. Возможно ли (в пределах разумного) иметь производный класс basicHttpBinding, в котором можно манипулировать HTTP-связью каким-то образом? – Hugo

ответ

2

Вы должны ввести пользовательский IDispatchMessageInspector и ввести его в атрибут IOperationBehavior или IEndpointBehavior. (В методе ApplyDispatchBehavior())

В AfterReceiveRequest() методе в IDispatchMessageInspector, вы можете получить тело сообщения только путем копирования (это недопустимый раз обращались):

private String GetRequestBody(ref Message message) 
{ 
    MessageBuffer buffer = message.CreateBufferedCopy(Int32.MaxValue); 
    message = buffer.CreateMessage(); 
    String xml = null; 
    try 
    { 
     var copy = buffer.CreateMessage(); 
     var dicReader = copy.GetReaderAtBodyContents(); 
     xml = dicReader.ReadOuterXml(); 
    } 
    catch (Exception e) 
    { 
    } 
    return xml; 
} 

Но если вы просто хотите, чтобы найти значение заголовка, вы можете просто получить его:

private String TryGetHeader(Message request, String headerName) 
{ 
    if (request.Headers.FindHeader(headerName, "HeaderMessageNamespace") != -1) 
     return request.Headers.GetHeader<String>(headerName, "HeaderMessageNamespace"); 
    return null; 
} 

Создать атрибут, как этот, и положил его на метод, который вы хотите отслеживать в службе WCF:

public class MyOperationBehaviorAttribute : Attribute, IOperationBehavior 
    { 
     public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
     { 
      if (dispatchOperation.Parent.MessageInspectors.OfType<MyMessageInspector>().Any() == false) 
       dispatchOperation.Parent.MessageInspectors.Add(new MyMessageInspector()); 
     } 
     [...] 
    } 

и реализует инспектор так:

public class MyMessageInspector : IDispatchMessageInspector 
    { 
     public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
     { 
      var result = TryGetHeader(request, "name"); 
      return null; 
     } 
     [...] 
    } 

И для клиентской стороны:

Вы должны вводить поведение сразу после создания экземпляра службы. С MyServiceClient типа ClientBase, и IEndpointBehavior myBehavior:

((ClientBase<ISomething>)service).Endpoint.Behaviors.Add(myBehavior); 

с

public class MyBehavior : IEndpointBehavior 
{ 
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
    { 
     clientRuntime.MessageInspectors.Add(new MyMessageInspector()); 
    } 
    [...] 
} 
+0

Я создал «IDispatchMessageInspector» и попытался ввести его в «IEndpointBehavior» в методе «ApplyDispatchBehavior()», но не кажется, что метод вызван. Возможно, это должно быть в «IOperationBehavior», однако я не могу найти, где я буду прикреплять пользовательское поведение операций. – Hugo

+0

Это на сервере? Я пытаюсь сделать это на стороне клиента через прокси-класс (сгенерированный Visual Studio/svcutil) для каждой операции. Это похоже на серверную сторону, или я что-то пропустил? – Hugo

+0

Это для серверной стороны да .. Я добавляю вам образец для клиентской стороны – rducom