AutoFac - WebApi无法注册反射类型

时间:2014-01-15 20:28:12

标签: c# autofac asp.net-web-api

我遇到了“builder.RegisterInstance(Activator.CreateInstance(repoClass));”这一行的问题。基本上我想反思一个单独的程序集来注册我的WebApiController和Types ...用于即插即用架构。我是AutoFac的新手。 RegisterInstance无法解析repoClass中的repoInterface,我收到编译错误。 “参数类型'对象'不能分配给参数类型repoClass。”我理解错误。我怎么能做到这一点,所以它有效?

由于

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.EnableSystemDiagnosticsTracing();

        ContainerBuilder builder = new ContainerBuilder();

        string WebApisPath = ConfigurationManager.AppSettings["AutoFac_WebApiControllerAssembliesPath"];
        string titleLoanAsm = ConfigurationManager.AppSettings["WebApi_TitleLoanAssembly"];
        Assembly asm = Assembly.LoadFile(AssemblyDirectory.Replace("\\bin", "") + WebApisPath + titleLoanAsm);

        builder.RegisterApiControllers(asm);

        List<Type> exportedTypes = new List<Type>(asm.GetExportedTypes());

        Type repoClass = exportedTypes.FirstOrDefault(x => x.IsClass && x.Name.Contains("LGF"));

        if (repoClass == null)
            throw new ObjectNotFoundException(string.Format("No repositories found for controller"));

        Type repoInterface = repoClass.GetInterfaces().FirstOrDefault(x => x.IsInterface && x.Name.Contains("LGF"));

        if (repoInterface == null)
            throw new ObjectNotFoundException(string.Format("Interface not found for class {0}. Ensure class has and interface implemented with a name that contains LGF", repoClass.Name));

        builder.RegisterInstance<repoInterface>(Activator.CreateInstance(repoClass));


        IContainer container = builder.Build();

        AutofacWebApiDependencyResolver resolver = new AutofacWebApiDependencyResolver(container);

        config.DependencyResolver = resolver;
    }

2 个答案:

答案 0 :(得分:1)

Autofac可以注册类型并通过反射创建实例。

builder.RegisterType(repoClass).As(repoInterface);

已更新以发表评论

我认为这里的混淆可能是在您的初始问题中,您特别询问了您为repoclass调用RegisterInstance时遇到的错误。我的回答是解决这个问题。找不到MVC控制器的问题是一个不同的问题,不是真正的autofac问题,而是MVC路由问题。要解决这个问题,您需要告诉路由系统在哪里找到其他控制器。要解决此问题,您需要执行以下操作:

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = "" },
    new[] { "ExternalAssembly.Controllers" }
);

要找到要替换“ExternalAssembly.Controllers”的值,您需要反映到外部程序集中,类似于代码的作用,并发现这些名称空间。

答案 1 :(得分:1)

所以在我原来的帖子中,我在“builder.RegisterInstance(Activator.CreateInstance(repoClass))”行中收到编译错误;“这是因为repoClass在设计时无法查看repoInterface。所以我创建了一个动态运行时类,它在运行时从repoClass和repoInterface获取实际类型,然后它动态编译并执行该类以从Assembly.LoadFile返回ContainerBuilder。

public class RuntimeContainerBuilder
{
    public static object Evaluate(ContainerBuilder builder, Type controller, Type repoInterface, Type repoClass, Assembly assembly)
    {

        CSharpCodeProvider c = new CSharpCodeProvider();
        ICodeCompiler icc = c.CreateCompiler();
        CompilerParameters cp = new CompilerParameters();

        cp.ReferencedAssemblies.Add("system.dll");
        cp.ReferencedAssemblies.Add(AssemblyDirectory + "\\System.Web.Http.dll");
        cp.ReferencedAssemblies.Add(AssemblyDirectory + "\\Autofac.dll");
        cp.ReferencedAssemblies.Add(AssemblyDirectory + "\\Autofac.Integration.WebApi.dll");

        cp.ReferencedAssemblies.Add(@"E:\MainTrunk2\LeadGenFramework\trunk\LeadGenFramework.Web.Api\LeadGenFramework.Web.Api.Controller.TitleLoan\bin\LeadGenFramework.Web.Api.TitleLoan.dll");

        cp.CompilerOptions = "/t:library";
        cp.GenerateInMemory = true;

        StringBuilder sb = new StringBuilder("");
        sb.Append("using System;\n");
        sb.Append("using Autofac;\n");
        sb.Append("using System.Web.Http;\n");
        sb.Append("using System.Web.Http.Controllers;\n");
        sb.Append("using Autofac.Integration.WebApi;\n");
        sb.Append(string.Format("using {0};\n", assembly.ManifestModule.Name.Replace(".dll","")));

        sb.Append("namespace LeadGenFramework.Web.Api{ \n");
        sb.Append("public class DynamicBuild{ \n");
        sb.Append("public ContainerBuilder Build(ContainerBuilder obj){\n");
        sb.Append(string.Format("obj.RegisterApiControllers(typeof({0}).Assembly).PropertiesAutowired();\n",controller.Name));
        sb.Append(string.Format("obj.RegisterInstance<{0}>(new {1}());\n", repoInterface.Name, repoClass.Name));
        sb.Append("return obj; \n");
        sb.Append("} \n");
        sb.Append("} \n");
        sb.Append("}\n");

        string s1 = sb.ToString();
        CompilerResults cr = icc.CompileAssemblyFromSource(cp, s1);
        if (cr.Errors.Count > 0)
        {
            //Factory.LogManager.MainProcessLogger.Info(string.Format("DynamicFormatScriptEngine:Evaluate(): Error: {0}, Code: {1}", cr.Errors[0], s1));
            return null;
        }

        Assembly a = cr.CompiledAssembly;
        object o = a.CreateInstance("LeadGenFramework.Web.Api.DynamicBuild");

        Type t = o.GetType();
        MethodInfo mi = t.GetMethod("Build");

        object s = mi.Invoke(o,new object[]{builder});

        return s;
    }

现在我的WebApiConfig就是这样......看到“RuntimeContainerBuilder.Evaluate(builder,controller,repoInterface,repoClass,asm)”这一行

   public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.EnableSystemDiagnosticsTracing();

        ContainerBuilder builder = new ContainerBuilder();

        //string WebApisPath = ConfigurationManager.AppSettings["AutoFac_WebApiControllerAssembliesPath"];
        string titleLoanAsm = ConfigurationManager.AppSettings["WebApi_TitleLoanAssembly"];
        //Assembly asm = Assembly.LoadFile(AssemblyDirectory.Replace("\\bin", "") + WebApisPath + titleLoanAsm);

        Assembly asm = Assembly.LoadFile(AssemblyDirectory + "\\" + titleLoanAsm);

        List<Type> exportedTypes = new List<Type>(asm.GetExportedTypes());

        Type controller = exportedTypes.FirstOrDefault(t => !t.IsAbstract && typeof(ApiController).IsAssignableFrom(t));

        if (controller == null)
            throw new ObjectNotFoundException(string.Format("Contoller not found in assembly {0}.", asm.FullName));

        Type repoClass = exportedTypes.FirstOrDefault(x => x.IsClass && x.Name.Contains("LGF"));

        if (repoClass == null)
            throw new ObjectNotFoundException(string.Format("No repositories found for controller"));

        Type repoInterface = repoClass.GetInterfaces().FirstOrDefault(x => x.IsInterface && x.Name.Contains("LGF"));

        if (repoInterface == null)
            throw new ObjectNotFoundException(string.Format("Interface not found for class {0}. Ensure class has and interface implemented with a name that contains LGF", repoClass.Name));

        RuntimeContainerBuilder.Evaluate(builder, controller, repoInterface, repoClass, asm);

        IContainer container = builder.Build();

        AutofacWebApiDependencyResolver resolver = new AutofacWebApiDependencyResolver(container);
        config.DependencyResolver = resolver;
    }

下一步是使程序集更加通用,将程序集加载到数组中,并为每个程序集设置RuntimeContainerBuilder ......然后builder.Build应该正确解析并激活所有内容。我对这个原型的最终目标是拖放程序集并让WebApi动态地选择它们。