2014-01-15 4 views
0

У меня возникают проблемы с строкой «builder.RegisterInstance (Activator.CreateInstance (repoClass));». В принципе, я хочу отразить отдельную сборку, чтобы зарегистрировать мой WebApiController и типы ... для подключения к игровой архитектуре. Я новичок в AutoFac. RegisterInstance не может разрешить repoInterface в repoClass, я получаю ошибку компиляции. «Тип аргумента« объект »не присваивается параметру типа repoClass». Я понимаю ошибку. Как еще я могу это сделать, чтобы он работал?AutoFac - WebApi не может регистрировать отраженные типы

Благодаря

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

ответ

1

Autofac имеет способ регистрации типов и иметь экземпляры, созданные путем отражения.

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

Обновлено обратиться комментарии

Я думаю, что путаница может быть, что в вашем первоначальном вопросе ваш конкретный вопрос о ошибки вы получали за RegisterInstance призыв к repoClass. Мой ответ касался этого. Проблема с контроллерами MVC, которые не были найдены, - это другая проблема, а не проблема с автозагрузкой, а проблема маршрутизации MVC. Чтобы решить эту проблему, вам нужно будет указать систему маршрутизации, где можно найти другие контроллеры. Для того, чтобы исправить, что вам нужно будет сделать что-то вроде этого:

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

Чтобы найти значение (ы), чтобы заменить «ExternalAssembly.Controllers» с вами нужно будет отражать в вашу внешнюю сборку аналогично тому, как ваш код уже делает и откройте эти пространства имен.

+0

Нет кубиков ... Я получаю 404 на своем модульном тесте на WebApi. – chdev77

+0

Что такое 404 связано с регистрацией Autofac? – Nathan

+0

404 Not Found ... посмотреть его [ссылка] (http://en.wikipedia.org/wiki/HTTP_404). Это означает, что он не регистрируется правильно. Если я переведу контроллер и наберусь на одного и того же осла. как проходит тест WebApi, если я переведу их в отдельную задницу. и отражать типы, а не работать. Как я уже сказал, я новичок в AutoFac. Может быть, вы могли бы уточнить, пожалуйста? – chdev77

1

Так что в моем исходном посте я получал ошибку компиляции на строке «builder.RegisterInstance (Activator.CreateInstance (repoClass)); Это было связано с тем, что repoClass не мог смотреть на repoInterface во время разработки. Поэтому я создал динамический класс времени выполнения, который получает фактические типы из repoClass и repoInterface во время выполнения, затем компилирует и выполняет класс «на лету», чтобы вернуть ContainerBuilder из моего Assembly.LoadFile.

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 (строитель, контроллер, 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; 
    } 

Следующий шаг, чтобы сделать его более generic, чтобы загружать сборки в массив и настраивать RuntimeContainerBuilder для каждого ... затем builder.Build должен правильно разрешать и активировать все. Моя конечная цель для этого прототипа - перетащить сборки и заставить WebApi динамически их подбирать.

Смежные вопросы