2011-02-07 25 views
4

我試圖從UI(DNN模塊)向其使用的各種服務中的某些日誌記錄進行日誌記錄,試圖剖析人們與站點交互的方式。我使用StructureMap 2.5.3.0和log4net的嘗試使用DynamicProxy爲StructureMap製作日誌截取器

我得到的東西個人類/實例對運作良好,但我必須配置這樣的事情:

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

具有IRegService兩次感覺有點亂,但我可以忍受它。

測井實現這樣的:

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()); 
    } 
} 

這工作,但有幾個問題:

  1. 我必須手動配置每個服務< - >接口對
  2. 我只當從UI調用服務時想要連接日誌記錄

我試圖通過實施StructureMap一個TypeInterceptor來解決這個問題:

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); 
    } 
} 

但我發現了一個問題,與地方調用Process是給我的,不落實定義的接口的類建立上下文。這導致其在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; 
    } 

從未達到的return interfaceProxy;斷點,這表明context.BuildStack.Current.RequestedType沒有返回正確的接口。奇怪的是,我所有的類似乎都被正確注入。

此外,即使這是工作,我仍然只是想攔截來自UI層的調用的問題。

我正在尋找一種方式我第2個問題,也是我在做什麼毛病TypeInterceptor

+0

嗨,遇到同樣的問題。你有解決這個問題嗎? TNX。 – daxsorbito 2012-05-11 19:23:17

回答

1

我利用公約這一傳開。以下是我爲達到此目的所做的步驟。

首先,我對指定的程序集進行掃描,在那裏附加我的裝飾器。

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

       }); 

然後我創建了一個公約類。我其實從這個線程Decorating a generic interface with Structuremap得到它,並根據你的實現做了一些修改。

最後這是公約類。

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)); 
      } 

     } 
    } 

我使用您擁有的相同的LoggingEnrichment類。

希望這可以解決您提到的問題。