2013-04-16 2 views
5

Я внедрил IClientMessageInspector, чтобы «перехватить» исходящий вызов веб-службы в моем приложении. Можно ли узнать, какая операция вызывается изнутри BeforeSendRequest и AfterReceiveReply?Как получить имя вызываемой операции в IClientMessageInspector?

Здесь есть аналогичный вопрос: How do i get the invoked operation name within a WCF Message Inspector, который предназначен для серверной части (сторона, получающая запрос). Я попытался сделать что-то подобное, например.

public object BeforeSendRequest(ref Message request, IClientChannel channel) 
    { 
     var v = OperationContext.Current.OutgoingMessageProperties["HttpOperationName"]; 
     return null; 
    } 

    public void AfterReceiveReply(ref Message reply, object correlationState) 
    { 
     var v = OperationContext.Current.OutgoingMessageProperties["HttpOperationName"]; 
    } 

но во время исходящего запроса, кажется, что OperationContext.Current имеет нулевое значение, поэтому я не могу использовать это. Любая идея, как его получить? Любая идея, как сделать это чисто (в отличие, скажем, разобрать SOAP xml)?

+0

Это трудно, потому что вы так низко в стеке клиента, что информация вам действительно нужно обернуть объект сообщения. Вы могли бы использовать другого инспектора? Например, для каждой операции применяется IParameterInspector и поэтому является прямым. Это также позволит избежать связывания определенных решений, таких как HTTPOperationName. – ErnieL

+0

Как будет работать контролер параметров? –

ответ

2

Как насчет reply.Headers.Action и request.Headers.Action. Конечно, все остальное так же сложно, как и в вопросе. Таким образом, полный код будет:

var action = reply.Headers.Action.Substring(reply.Headers.Action.LastIndexOf("/", StringComparison.OrdinalIgnoreCase) + 1); 

или

var action = request.Headers.Action.Substring(request.Headers.Action.LastIndexOf("/", StringComparison.OrdinalIgnoreCase) + 1); 
+4

странный .. когда я проверяю этот код 'request.Headers.Action' является пустой строкой' '' 'и' reply.Headers.Действие' равно нулю –

+1

, скорее всего, это потому, что на этом этапе выполняемая операция еще не определена. Http://msdn.microsoft.com/en-us/magazine/cc163302.aspx#S2 – mrd3650

4

Из комментариев вы спрашивали, как сделать это может быть сделано с IParameterInspector. Имя операции является частью методов Before/AfterCall.

Просто добавьте к моим комментариям, какой инспектор использовать. От Carlos Figueira's blogs:

В инспекторах сообщений, описанный в предыдущем посте этой серии, позволяет вам полный контроль над сообщением, проходящим через стек WCF . Они очень мощные, но вы должны знать, как обращаться с объектом Message, что не является наиболее желательным способом программирования . Если модель обслуживания в WCF скрывает всю структуру обмена сообщениями , позволяя нам определять наши услуги в терминах строго типизированных операций (т. Е. Используя примитивные примитивные и пользовательские типы ), должен быть способ перехвата запросов/ответов после завершения обработки для извлечения этих параметров из входящих сообщений (или до их отправки в исходящие сообщения). IParameterInspector - это то, что - до и после каждого звонка инспектор получает возможность проверять рабочие входы, выходы и возвращаемое значение в тех же типах, которые определены операцией , без необходимости конвертировать (единственное необходим листинг, поскольку параметры передаются как объекты).

Это полная командная строка программы, которая демонстрирует:

using System; 
using System.ServiceModel; 
using System.ServiceModel.Channels; 
using System.ServiceModel.Description; 
using System.ServiceModel.Dispatcher; 

namespace WCFClientInspector 
{ 
    public class OperationLogger : IParameterInspector 
    { 
     public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) 
     { 
      Console.WriteLine("Completed operation:" + operationName); 
     } 

     public object BeforeCall(string operationName, object[] inputs) 
     { 
      Console.WriteLine("Calling operation:" + operationName); 
      return null; 
     } 
    } 

    public class OperationLoggerEndpointBehavior : IEndpointBehavior 
    { 
     public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) 
     { 
     } 

     public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
     { 
      foreach (ClientOperation operation in clientRuntime.ClientOperations) 
      { 
       operation.ClientParameterInspectors.Add(new OperationLogger()); 
      } 
     } 

     public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
     { 
     } 

     public void Validate(ServiceEndpoint endpoint) 
     { 
     } 
    } 


    [ServiceContract] 
    public interface ISimple 
    { 
     [OperationContract] 
     void DoSomthing(string s); 
    } 

    public class SimpleService : ISimple 
    { 
     public void DoSomthing(string s) 
     { 
      Console.WriteLine("Called:" + s); 
     } 
    } 

    public static class AttributesAndContext 
    { 
     static void Main(string[] args) 
     { 
      ServiceHost simpleHost = new ServiceHost(typeof(SimpleService), new Uri("http://localhost/Simple")); 
      simpleHost.Open(); 

      ChannelFactory<ISimple> factory = new ChannelFactory<ISimple>(simpleHost.Description.Endpoints[0]); 
      factory.Endpoint.EndpointBehaviors.Add(new OperationLoggerEndpointBehavior()); 
      ISimple proxy = factory.CreateChannel(); 

      proxy.DoSomthing("hi"); 

      Console.WriteLine("Press ENTER to close the host."); 
      Console.ReadLine(); 

      ((ICommunicationObject)proxy).Shutdown(); 

      simpleHost.Shutdown(); 
     } 
    } 

    public static class Extensions 
    { 
     static public void Shutdown(this ICommunicationObject obj) 
     { 
      try 
      { 
       obj.Close(); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("Shutdown exception: {0}", ex.Message); 
       obj.Abort(); 
      } 
     } 
    } 
} 

Это должно дать выход:

Calling operation:DoSomthing 
    Called:hi 
    Completed operation:DoSomthing 
    Press ENTER to close the host. 
Смежные вопросы