我正在使用MVC4 Web API构建一个Web API,其中包含一个IoC容器(在这种情况下为Simple Injector,但我不认为这个问题与该容器有关)应该暴露各种CRUD和查询操作。在我的案例中使用IOC的原因是我们是一个开发商店,我需要能够让客户构建他们自己的Web API控制器,以暴露他们需要从我们的系统公开需要的数据。因此,我希望设计我的解决方案的方式允许我通过IOC将所有控制器(包括我们的和客户的,外部的和可加载的)控制自己的产品。
该网站没有任何对该库的引用,但该库包含我想在网站中使用的控制器。类型在容器中注册,DependencyResolver设置为自定义依赖项解析程序。我有代码找到DLL插件并加载控制器类型,但当我尝试导航到它将代表它的路线说它找不到它。
即。如果我尝试导航到/ api / Test1Api,我应该看到文本“hello world”
我的问题是,虽然我已经加载了我的控制器类型,但我无法将其转换为网站所说的路线。
我收到错误
未找到与请求URI匹配的HTTP资源
未找到与名为“Test1Api”的控制器匹配的类型。
以下是我如何注册容器
public static class SimpleInjectorInitializer
{
/// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
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);
}
}
}
感谢任何帮助。
答案 0 :(得分:4)
关于您的解决方案的一个重要警告。将控制器注册到容器中也是非常重要的(这个建议适用于所有DI框架,尽管默认情况下某些框架会强制您注册具体类型)。否则你肯定会被this developer had的同样问题所困扰。
由于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<Assembly> GetAssemblies()
{
var appPath =
AppDomain.CurrentDomain.BaseDirectory;
return base.GetAssemblies()
.Union(this.plugins).ToArray();
}
}
答案 1 :(得分:3)
我明白了!
所以我在Web Api调用CustomAssembliesResolver中创建了一个新类,它继承自DefaultAssembliesResolver。基本上我将我的程序集添加到查找控制器时解析的程序集列表中。我仍然有使用Simple Injector的代码用于解决方案的DI部分。
public class CustomAssembliesResolver : DefaultAssembliesResolver
{
public override ICollection<Assembly> GetAssemblies()
{
var appPath = AppDomain.CurrentDomain.BaseDirectory;
var baseAssemblies = base.GetAssemblies();
var assemblies = new List<Assembly>(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());
希望这有助于某人!
非常感谢Steven对他的帮助和见解!我真的很感激!!