无法解析从外部DLL加载的控制器

我正在使用MVC4 Web API构建一个Web API,其中包含一个IoC容器(在这种情况下是简单注入器,但我不认为这个问题与该容器有关),它应该公开各种CRUD和查询操作。 在我的案例中使用IOC的原因是我们是一个开发商店,我需要能够让客户构建自己的Web API控制器,以暴露他们需要从我们的系统公开需要的数据。 因此,我希望设计我的解决方案的方式允许我通过IOC制作所有控制器,包括我们和我们的客户,外部和可加载的产品。

该网站没有任何对该库的引用,但该库包含我想在网站中使用的控制器。 类型在容器中注册,DependencyResolver设置为自定义依赖项解析程序。 我有代码找到dll插件并加载控制器类型,但当我尝试导航到它将代表它的路线时说它无法找到它。

即如果我尝试导航到/ api / Test1Api我应该看到文本“hello world”

我的问题是虽然我已经加载了我的控制器类型,但我无法将其转换为网站所说的路线。

我收到了错误

未找到与请求URI匹配的HTTP资源

未找到与名为“Test1Api”的控制器匹配的类型。

这是我如何注册容器

public static class SimpleInjectorInitializer { /// Initialize the container and register it as MVC3 Dependency Resolver. public static void Initialize() { //// Did you know the container can diagnose your configuration? Go to: http://bit.ly/YE8OJj. // Create the IOC container. var container = new Container(); InitializeContainer(container); container.RegisterMvcAttributeFilterProvider(); // Verify the container configuration container.Verify(); // Register the dependency resolver. GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container); } private static void InitializeContainer(Container container) { var appPath = AppDomain.CurrentDomain.BaseDirectory; string[] files = Directory.GetFiles(appPath + "\\bin\\Plugins", "*.dll", SearchOption.AllDirectories); var assemblies = files.Select(Assembly.LoadFile); // register Web API controllers var apiControllerTypes = from assembly in assemblies where !assembly.IsDynamic from type in assembly.GetExportedTypes() where typeof(IHttpController).IsAssignableFrom(type) where !type.IsAbstract where !type.IsGenericTypeDefinition where type.Name.EndsWith("Controller", StringComparison.Ordinal) select type; // register MVC controllers var mvcControllerTypes = from assembly in assemblies where !assembly.IsDynamic from type in assembly.GetExportedTypes() where typeof(IController).IsAssignableFrom(type) where !type.IsAbstract where !type.IsGenericTypeDefinition where type.Name.EndsWith("Controller", StringComparison.Ordinal) select type; foreach (var controllerType in apiControllerTypes) { container.Register(controllerType); } foreach (var controllerType in mvcControllerTypes) { container.Register(controllerType); } } } 

任何帮助表示赞赏。

关于您的解决方案的一个重大警 将控制器注册到容器中也是非常重要的(这个建议适用于所有DI框架,尽管默认情况下某些框架会强制您注册具体类型)。 否则你肯定会被这个开发人员遇到的同样问题所困扰。

由于IHttpControllerTypeResolver使用IAssembliesResolver ,因此最简单(也是最安全)的解决方案是简单地要求IHttpControllerTypeResolver注册所有控件。 在这种情况下,您的SimpleInjectorInitializer将如下所示:

 public static class SimpleInjectorInitializer { public static void Initialize() { // Create the IOC container. var container = new Container(); InitializeContainer(container); container.RegisterMvcAttributeFilterProvider(); // Verify the container configuration container.Verify(); // Register the dependency resolver. GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container); } private static void InitializeContainer(Container container) { GlobalConfiguration.Configuration.Services .Replace(typeof(IAssembliesResolver), new CustomAssembliesResolver()); var services = GlobalConfiguration.Configuration.Services; var controllerTypes = services.GetHttpControllerTypeResolver() .GetControllerTypes(services.GetAssembliesResolver()); // register Web API controllers (important!) foreach (var controllerType in controllerTypes) { container.Register(controllerType); } } } 

另请注意,您的CustomAssembliesResolver可以变得更加容易:

 public class CustomAssembliesResolver : DefaultAssembliesResolver { private Assembly[] plugins = ( from file in Directory.GetFiles( appPath + "\\bin\\Plugins", "*.dll", SearchOption.AllDirectories) let assembly = Assembly.LoadFile(file) select assembly) .ToArray(); public override ICollection GetAssemblies() { var appPath = AppDomain.CurrentDomain.BaseDirectory; return base.GetAssemblies() .Union(this.plugins).ToArray(); } } 

我想到了!

所以我在Web Api调用CustomAssembliesResolver中创建了一个新类,它inheritance自DefaultAssembliesResolver。 基本上我将我的程序集添加到查找控制器时解析的程序集列表中。 我仍然有使用Simple Injector的代码用于解决方案的DI部分。

 public class CustomAssembliesResolver : DefaultAssembliesResolver { public override ICollection GetAssemblies() { var appPath = AppDomain.CurrentDomain.BaseDirectory; var baseAssemblies = base.GetAssemblies(); var assemblies = new List(baseAssemblies); var files = Directory.GetFiles(appPath + "\\bin\\Plugins", "*.dll", SearchOption.AllDirectories); var customAssemblies = files.Select(Assembly.LoadFile); // register Web API controllers var apiControllerAssemblies = from assembly in customAssemblies where !assembly.IsDynamic from type in assembly.GetExportedTypes() where typeof(IHttpController).IsAssignableFrom(type) where !type.IsAbstract where !type.IsGenericTypeDefinition where type.Name.EndsWith("Controller", StringComparison.Ordinal) select assembly; foreach (var assembly in apiControllerAssemblies) { baseAssemblies.Add(assembly); } return assemblies; } } 

我还将以下行添加到Global.asax.cs中App_Start的开头

 GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver), new CustomAssembliesResolver()); 

希望这有助于某人!

非常感谢史蒂文的帮助和见解! 对此,我真的非常感激!!