用 castle.Dynamicproxy 修饰 structuremap 4 返回的所有实例
Decorate all instances returned by structuremap 4 with castle.Dynamicproxy
现在我正在装饰我的 StructureMap4 映射类型,例如 IFormsAuthenticationProvider
在 StructureMap4 注册表中使用 Castle 生成的代理和 tryCatchInterceptor
。例如:
public class AuthenticationRegistry : Registry
{
public AuthenticationRegistry()
{
var proxyGenerator = new ProxyGenerator();
var tryCatchInterceptor = new TryCatchInterceptor();
For<IFormsAuthenticationProvider>().Use<FormsAuthenticationProvider>()
.DecorateWith(x => proxyGenerator.CreateInterfaceProxyWithTarget<IFormsAuthenticationProvider>(x, tryCatchInterceptor));
}
}
public class TryCatchInterceptor : IInterceptor
{..}
但是如你所见,我必须在装饰方法中指定类型。因此,将不得不为所有 IType->Type 定义类似的装饰器,此时代码变得重复。
问题:有没有办法在一个共同的地方为所有类型做到这一点而不重复?
经过大量研发,我认为structuremap4.0版本中没有现成的机制可以做到这一点。
不过,我自己想出了一个动态的解决方案。
创建了一个 class 模板并即时创建了 class。编译后将 class 加载到内存中,并 运行 代码。
classTemplate.txt
using Castle.DynamicProxy;
using StructureMap;
using System.Web;
using Company1.WebApplication.App1.Meta;
using Company1.WebApplication.App1.Meta.Interceptors;
namespace Company1.WebApplication.App1
{
public class DynamicUtils
{
private static StructureMapDependencyResolver _structureMapResolver { get; set; }
private static ProxyGenerator _ProxyGenerator = new ProxyGenerator();
public static void ConfigureCastleInterceptor(Container container)
{
container.Configure(x =>
{
##INTERFACE##
});
}
}
}
并在我的 Global.asax 中编写了加载代码
private static void ConfigureCastleInterceptor(Container container)
{
string classBody = File.ReadAllText(HttpRuntime.AppDomainAppPath + "/RuntimeClasses/RegisterInterceptors.txt");
var classBuilder = new StringBuilder();
string interfaceTemplate = "x.For<##INTERFACE##>()
.DecorateAllWith(y => _ProxyGenerator
.CreateInterfaceProxyWithTarget<##INTERFACE##>(y, new TryCatchLoggingInterceptor())); \n";
foreach (var instance in container.Model.AllInstances)
{
if (instance.PluginType.FullName.Contains("Company1.WebApplication"))
classBuilder.Append(interfaceTemplate.Replace("##INTERFACE##", instance.PluginType.FullName));
}
classBody = classBody.Replace("##INTERFACE##", classBuilder.ToString());
var csharp = new CSharpCodeProvider();
var compiler = new CompilerParameters();
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
compiler.ReferencedAssemblies.Add(asm.Location);
}
compiler.GenerateInMemory = true;
compiler.GenerateExecutable = false;
CompilerResults results = csharp.CompileAssemblyFromSource(compiler, classBody);
if (!results.Errors.HasErrors)
{
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("Company1.WebApplication.App1.DynamicUtils");
MethodInfo configureCastleInterceptor = program.GetMethod("ConfigureCastleInterceptor");
configureCastleInterceptor.Invoke(null, new Object[] { container });
}
else
{
throw new Exception(results.Errors.ToString());
}
}
现在我正在装饰我的 StructureMap4 映射类型,例如 IFormsAuthenticationProvider
在 StructureMap4 注册表中使用 Castle 生成的代理和 tryCatchInterceptor
。例如:
public class AuthenticationRegistry : Registry
{
public AuthenticationRegistry()
{
var proxyGenerator = new ProxyGenerator();
var tryCatchInterceptor = new TryCatchInterceptor();
For<IFormsAuthenticationProvider>().Use<FormsAuthenticationProvider>()
.DecorateWith(x => proxyGenerator.CreateInterfaceProxyWithTarget<IFormsAuthenticationProvider>(x, tryCatchInterceptor));
}
}
public class TryCatchInterceptor : IInterceptor
{..}
但是如你所见,我必须在装饰方法中指定类型。因此,将不得不为所有 IType->Type 定义类似的装饰器,此时代码变得重复。
问题:有没有办法在一个共同的地方为所有类型做到这一点而不重复?
经过大量研发,我认为structuremap4.0版本中没有现成的机制可以做到这一点。
不过,我自己想出了一个动态的解决方案。
创建了一个 class 模板并即时创建了 class。编译后将 class 加载到内存中,并 运行 代码。
classTemplate.txt
using Castle.DynamicProxy;
using StructureMap;
using System.Web;
using Company1.WebApplication.App1.Meta;
using Company1.WebApplication.App1.Meta.Interceptors;
namespace Company1.WebApplication.App1
{
public class DynamicUtils
{
private static StructureMapDependencyResolver _structureMapResolver { get; set; }
private static ProxyGenerator _ProxyGenerator = new ProxyGenerator();
public static void ConfigureCastleInterceptor(Container container)
{
container.Configure(x =>
{
##INTERFACE##
});
}
}
}
并在我的 Global.asax 中编写了加载代码
private static void ConfigureCastleInterceptor(Container container)
{
string classBody = File.ReadAllText(HttpRuntime.AppDomainAppPath + "/RuntimeClasses/RegisterInterceptors.txt");
var classBuilder = new StringBuilder();
string interfaceTemplate = "x.For<##INTERFACE##>()
.DecorateAllWith(y => _ProxyGenerator
.CreateInterfaceProxyWithTarget<##INTERFACE##>(y, new TryCatchLoggingInterceptor())); \n";
foreach (var instance in container.Model.AllInstances)
{
if (instance.PluginType.FullName.Contains("Company1.WebApplication"))
classBuilder.Append(interfaceTemplate.Replace("##INTERFACE##", instance.PluginType.FullName));
}
classBody = classBody.Replace("##INTERFACE##", classBuilder.ToString());
var csharp = new CSharpCodeProvider();
var compiler = new CompilerParameters();
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
compiler.ReferencedAssemblies.Add(asm.Location);
}
compiler.GenerateInMemory = true;
compiler.GenerateExecutable = false;
CompilerResults results = csharp.CompileAssemblyFromSource(compiler, classBody);
if (!results.Errors.HasErrors)
{
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("Company1.WebApplication.App1.DynamicUtils");
MethodInfo configureCastleInterceptor = program.GetMethod("ConfigureCastleInterceptor");
configureCastleInterceptor.Invoke(null, new Object[] { container });
}
else
{
throw new Exception(results.Errors.ToString());
}
}