2011-02-07 1 views
4

J'essaie de consigner les appels de l'interface utilisateur (module DNN) dans certains des différents services qu'il utilise, afin de déterminer comment les personnes interagissent avec le site. J'utilise StructureMap 2.5.3.0 et Log4NetEssayer de créer un Interceptor de journalisation pour StructureMap à l'aide de DynamicProxy

I GOT choses fonctionnent bien sur des paires classe/instance individuelle, mais je dois configurer des choses comme ceci:

ObjectFactory.Configure(ce => 
     ce.ForRequestedType<IRegService>() 
      .TheDefaultIsConcreteType<RegService>() 
      .EnrichWith(LoggingEnrichment.InterfaceLogger<IRegService>)); 

Ayant le feutre deux fois IRegService un peu en désordre mais je peux vivre avec.

L'exploitation forestière est mis en œuvre comme ceci:

public class LoggingEnrichment 
{ 
    public static object InterfaceLogger<TInterface>(object concrete) 
    { 
     return InterfaceLogger(typeof(TInterface), concrete); 
    } 

    public static object InterfaceLogger(Type iinterface, object concrete) 
    { 
     var dynamicProxy = new ProxyGenerator(); 
     return dynamicProxy.CreateInterfaceProxyWithTarget(iinterface, concrete, new LogInterceptor()); 
    } 
} 

public class LogInterceptor : IInterceptor 
{ 
    public void Intercept(IInvocation invocation) 
    { 
     var watch = new Stopwatch(); 
     watch.Start(); 
     invocation.Proceed(); 
     watch.Stop(); 
     ILog logger = LogManager.GetLogger(typeof(LogInterceptor)); 
     var sb = new StringBuilder(); 
     sb.AppendFormat("Calling: {0}.{1}\n", invocation.InvocationTarget.GetType(), invocation.MethodInvocationTarget.Name); 
     var param = invocation.Method.GetParameters(); 
     if (param.Length > 0) sb.Append("With:\n"); 
     for (int i = 0; i < param.Length; i++) 
     { 
      sb.AppendFormat("\t{0}\n\t\t{1}", param[i].Name, invocation.GetArgumentValue(i)); 
     } 
     if(invocation.Method.ReturnType != typeof(void)) 
     { 
      sb.AppendFormat("Returning: {0}\n", invocation.ReturnValue ?? "null"); 
     } 
     sb.AppendFormat("In: {0}ms\n", watch.ElapsedMilliseconds); 
     logger.Debug(sb.ToString()); 
    } 
} 

Cela fonctionne, mais il a un problèmes de couple:

  1. Je dois configurer manuellement chaque service < -> paire d'interface
  2. Je ne vous souhaitez câbler la journalisation lorsque le service est appelé à partir de l'interface utilisateur

J'ai essayé de contourner ce problème en mettant en œuvre un TypeInterceptor pour StructureMap:

public class ApplicationRegistry : Registry 
{ 
    public ApplicationRegistry() 
    { 
     RegisterInterceptor(new LoggingInterceptor()); 
     Scan(scanner => 
     { 
      scanner.TheCallingAssembly(); 
      var codeBase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase.Replace("file:///", String.Empty); 
      codeBase = codeBase.Substring(0, codeBase.LastIndexOf("/")); 
      scanner.AssembliesFromPath(codeBase); 
      scanner.WithDefaultConventions(); 
      scanner.LookForRegistries(); 
     }); 
    } 
} 

public class LoggingInterceptor :TypeInterceptor 
{ 
    public object Process(object target, IContext context) 
    { 
     var newTarget = target; 
     if (context.BuildStack.Current != null && context.BuildStack.Current.RequestedType != null) 
     { 
      newTarget = LoggingEnrichment.InterfaceLogger(context.BuildStack.Current.RequestedType, target); 
     } 
     return newTarget; 
    } 

    public bool MatchesType(Type type) 
    { 
     return type.Name.EndsWith("Service", StringComparison.OrdinalIgnoreCase); 
    } 
} 

Mais je me pose un problème où l'appel à Process me donne une classe qui ne met pas en oeuvre l'interface définie par la construire le contexte. Cela a donné lieu à devoir changer la mise en œuvre du InterfaceLogger à

public static object InterfaceLogger(Type iinterface, object concrete) 
    { 
     if(!iinterface.IsAssignableFrom(concrete.GetType())) return concrete; 
     var dynamicProxy = new ProxyGenerator(); 
     var interfaceProxy = dynamicProxy.CreateInterfaceProxyWithTarget(iinterface, concrete, new LogInterceptor()); 
     return interfaceProxy; 
    } 

Un point d'arrêt sur le return interfaceProxy; est jamais atteint, cela signifie que context.BuildStack.Current.RequestedType ne retourne pas l'interface droite. La chose étrange est que toutes mes classes semblent être injectées correctement.

De plus, même si cela fonctionnait, il me resterait toujours le problème de ne vouloir intercepter que les appels de la couche d'interface utilisateur.

Je suis à la recherche d'un moyen mes 2 premières questions, et aussi ce que je fais mal avec le TypeInterceptor

+0

Bonjour, rencontré le même problème. Avez-vous résolu cela? Tnx. – daxsorbito

+0

Salut, est-ce que ma réponse ci-dessous a résolu votre problème? Tnx. – daxsorbito

Répondre

1

Je suis autour de cela en utilisant la convention. Voici les étapes que j'ai suivies pour y parvenir.

D'abord, j'ai fait un scan sur mon assemblage spécifié où j'attacherais mon décorateur.

x.Scan(scanner => 
       { 
        scanner.Assembly("MyProject.Services"); // Specific assemblyname 
        scanner.Convention<ServiceRegistrationConvention>(); 
        scanner.WithDefaultConventions(); 
        scanner.LookForRegistries(); 

       }); 

Puis j'ai créé une classe Convention. En fait, je l'ai obtenu à partir de ce fil Decorating a generic interface with Structuremap et j'ai fait une révision en fonction de votre implémentation.

Et enfin c'est la classe Convention.

public class ServiceRegistrationConvention : IRegistrationConvention 
    { 
     public void Process(Type type, Registry registry) 
     { 
      var handlerInterfaces = (from t in type.GetInterfaces() 
            where 
             (t.Namespace.StartsWith("MyProject.UIServices", StringComparison.OrdinalIgnoreCase) 
             || t.Namespace.StartsWith("MyProject.Services", StringComparison.OrdinalIgnoreCase)) 
            select t); 


      foreach (var handler in handlerInterfaces) 
      { 
       registry.For(handler) 
        .EnrichWith((ctx, orig) => LoggingEnrichment.InterfaceLogger(handler, orig)); 
      } 

     } 
    } 

J'utilise la même classe LoggingEnrichment que vous avez.

Espérons que cela résout vos problèmes mentionnés.

Questions connexes