2016-11-02 2 views
0

J'ai une application héritée qui enregistre les entrées/sorties de services. Actuellement, chaque méthode a les mêmes lignes pour consigner les objets de demande et de réponse. Je voudrais utiliser AOP, mais sans ajouter d'outil supplémentaire (Postsharp, Castle, etc), ou envelopper chaque classe de service dans une autre classe (ServiceWrapper). Pour ce faire, j'essaie de créer une classe Generic qui sait qu'elle doit enregistrer les objets de requête et de réponse. Voilà ce que je suis en train:Le paramètre C# func n'est pas utilisé

using System; 

namespace ProxyTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var request = "request"; 
      var fooService = new FooService(); 

      ServiceProxy.Invoke(r => fooService.DoFoo(request), "abc"); 

      Console.Read(); 
     } 
    } 

    class ServiceProxy 
    { 
     public static void Invoke(Func<object, object> service, object request) 
     { 
      Console.WriteLine("input:" + request); 

      var response = service(request); 

      Console.WriteLine("output:" + response); 
     } 
    } 

    class FooService 
    { 
     public string DoFoo(object a) 
     { 
      return a + ": returning: Do Foo"; 
     } 
    } 

} 

Bien qu'il fonctionne, la chaîne « abc » est juste pour compiler l'application, mais il n'est pas utilisé comme paramètre de demande. Si je supprime cela, le code ne compile pas. Est-ce que je manque quelque chose?

MISE À JOUR

Changement au suivant a fait l'affaire:

static void Main(string[] args) 
    { 
     var request = "request"; 
     var fooService = new FooService(); 

     ServiceProxy.Invoke(r => fooService.DoFoo(r), request); 

     Console.Read(); 
    } 
+0

Avez-vous accès à une source de services? Est-ce le service WCF? – eocron

+0

"mais il n'est pas utilisé comme paramètre de requête" - c'est pour le moment dans ServiceProxy.Invoke. Ce n'est pas clair pour moi ce que vous demandez ici ... –

+2

Pourquoi ne pas l'appeler comme ceci 'ServiceProxy.Invoke (r => fooService.DoFoo (r), demande);' ou juste 'ServiceProxy.Invoke (fooService.DoFoo , request); ' – juharr

Répondre

1

Vous devriez l'appeler comme ceci:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var request = "request"; 
     var fooService = new FooService(); 

     ServiceProxy.Invoke(fooService.DoFoo, "abc"); // lose the DoFoo parameter. 

     Console.Read(); 
    } 
} 

Vous devriez passer le DoFoo comme Func, au lieu de l'appeler. Vous devez également remplacer la signature de méthode par:

class FooService 
{ 
    public object DoFoo(object a) 
    { 
     return a + ": returning: Do Foo"; 
    } 
} 
+0

Expliquer les -1? –

+0

Vous voulez dire 'ServiceProxy.Invoke (fooService.DoFoo," abc ");', parce que ce que vous avez ne compilera pas. – juharr

+0

@juharr Merci, je ne l'ai pas remarqué. corrigé que –

1

Pour cette tâche, vous pouvez simplement ajouter un comportement de journalisation sur le répartiteur. Tout d'abord, vous créez ServiceBehavior avec un tel contenu:

public class ServiceLoggingBehavior : Attribute, IServiceBehavior 
{ 
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) 
    { 
    } 

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
    { 
     foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints) 
     { 
      foreach (OperationDescription operation in endpoint.Contract.Operations) 
      { 
       IOperationBehavior behavior = new LoggingOperationBehavior(); 
       operation.Behaviors.Add(behavior); 
      } 
     } 
    } 

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
    { 
    } 
} 

Ensuite, vous devez créer un comportement de fonctionnement:

internal class LoggingOperationBehavior : IOperationBehavior 
{ 
    public void Validate(OperationDescription operationDescription) 
    { 

    } 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
    { 
     dispatchOperation.Invoker = new LoggingOperationInvoker(dispatchOperation.Invoker, dispatchOperation); 
    } 

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) 
    { 

    } 

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) 
    { 
    } 
} 

Et enfin créer invocateur pour toutes les méthodes sur le côté serveur:

internal class LoggingOperationInvoker : IOperationInvoker 
{ 
    private readonly IOperationInvoker _baseInvoker; 
    private readonly string _operationName; 

    public LoggingOperationInvoker(IOperationInvoker baseInvoker, DispatchOperation operation) 
    { 
     _baseInvoker = baseInvoker; 
     _operationName = operation.Name; 
    } 

    public bool IsSynchronous 
    { 
     get { return _baseInvoker.IsSynchronous; } 
    } 

    public object[] AllocateInputs() 
    { 
     return _baseInvoker.AllocateInputs(); 
    } 

    public object Invoke(object instance, object[] inputs, out object[] outputs) 
    { 
     var sw = new Stopwatch(); 
     try 
     { 
      LogBegin(); 
      sw.Start(); 
      var response = _baseInvoker.Invoke(instance, inputs, out outputs); 
      return response; 
     } 
     finally 
     { 
      sw.Stop(); 
      LogEnd(sw.Elapsed); 
     } 
    } 

    private void LogBegin() 
    { 
     //you can log begin here. 
    } 

    private void LogEnd(TimeSpan elapsed) 
    { 
     //you can log end here. 
    } 

    public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) 
    { 
     return _baseInvoker.InvokeBegin(instance, inputs, callback, state); 
    } 

    public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) 
    { 
     return _baseInvoker.InvokeEnd(instance, out outputs, result); 
    } 
} 

Si vous souhaitez enregistrer une requête, vous pouvez simplement sérialiser et enregistrer les variables entrées dans la méthode Invoke. Pour la réponse - juste sérialiser et enregistrer réponse variable.

Et finalement, partie la plus agréable, attacher tout comme attribut:

[ServiceLoggingBehavior] 
public MyService : IMyServiceContract 
{ 
    ... 
} 
1

Votre Invoke -method demande clairement un Func - et un object -parameter, vous devez fournir à la fois. Aucune idée de ce que vous attendez exactement quand vous omettez l'un des paramètres. Je suppose que vous voulez faire le Func pour retourner la réponse créée par un request -objet spécifique. En outre, il pourrait être une bonne idée de faire votre demande- et de réponse arguments génériques:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var request = "request"; 
     var fooService = new FooService(); 

     ServiceProxy.Invoke(r => fooService.DoFoo(r), request); 

     Console.Read(); 
    } 
} 

class ServiceProxy 
{ 
    public static void Invoke<TRequest, TResponse>(Func<TRequest, TResponse> service, TRequest request) 
    { 
     Console.WriteLine("input:" + request.ToString()); 

     var response = service(request); 

     Console.WriteLine("output:" + response.ToString()); 
    } 
} 

Le Invoke -call peut encore être simplyfied à ServiceProxy.Invoke(fooService.DoFoo, request);

+0

Vous devez définir les types génériques sur la méthode ou la classe pour que cela fonctionne. – juharr

+0

Ce dont j'ai besoin, c'est de supprimer le besoin de passer l'objet request dans DoFoo et le même paramètre au Func. –

0

Merci pour toutes les réponses.Je suis en mesure de réaliser ce que je cherchais en utilisant:

static void Main(string[] args) 
    { 
     var request = "request"; 
     var fooService = new FooService(); 

     ServiceProxy.Invoke(fooService.DoFoo, request); 

     Console.Read(); 
    } 

ou

static void Main(string[] args) 
    { 
     var request = "request"; 
     var fooService = new FooService(); 

     ServiceProxy.Invoke(r => fooService.DoFoo(r), request); 

     Console.Read(); 
    }