Search code examples
.netaopstructuremapcastle-dynamicproxy

Decorate all instances returned by structuremap 4 with castle.Dynamicproxy


Right now I am decorating my StructureMap4 mapped types like, IFormsAuthenticationProvider with a Castle-generated proxy with tryCatchInterceptor in the StructureMap4 registry. For example:

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
{..}

But as you can see, I have to specify the type in the decoration method. so, will have to define similar decorators for all IType->Type, at which point the code becomes repetitive.

Question: is there a way to do this at a common place, for all types without repetition?


Solution

  • after much R&D, I don't think there is an existing mechanism to do it in the structuremap4.0 version.

    however, I came up with a dynamic solution of my own.

    created a class template and created the class on the fly. loaded the class into memory after compiling and ran the code.

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

    and in my Global.asax, wrote code for loading it

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