简单的喷油器无法在注入API网络控制器依赖 [英] Simple Injector Unable to Inject Dependencies in Web API Controllers
问题描述
我试图做简单的喷油器的一些基本构造DI,这似乎是无法解决的Web API控制器的依赖关系。
- 我在API文件夹中的API控制器,那就是控制器文件夹之外。
- 我也曾尝试将其置于控制器文件夹中,但
这似乎并没有太大的差别。该堆栈跟踪
我收到类似于一个presented在<一个href=\"http://stackoverflow.com/questions/11347152/simpleinjector-injection-does-not-work-with-mvc-4-asp-net-web-api\">this问题。 - 我使用的是全新安装简单注射器MVC集成快速启动的NuGet包的(第2.1.0)。
- 我有基
SimpleInjectorWebApiDependencyResolver
从文档,这也是一样的发现<一个href=\"http://stackoverflow.com/questions/11254292/does-simple-injector-supports-mvc-4-asp-net-web-api\">here. - 我使用实体框架,并看了看讨论
螺纹了解更改正确加载的上下文。
这不
似乎是一个问题,但我仍然收到以下错误:
键入MyProject.API.ArticleController'没有默认
构造
在
System.ArgumentException
System.Linq.Ex pressions.Ex pression.New(类型类型)在
System.Web.Http.Internal.TypeActivator.Create [TBASE](类型
instanceType)在
System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HTT prequestMessage
要求,类型controllerType,Func`1&安培;激活剂)在
System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HTT prequestMessage
要求,HttpControllerDescriptor controllerDescriptor,类型
controllerType)
块引用>这将是AP preciated如果有人可以给我一些建议,是否有什么要从其当前状态/调用顺序进行修改。
ArticleController(基本结构):
公共类ArticleController:ApiController
{
私人只读IArticleRepository articleRepository;
私人只读IUserRepository userRepository;
私人只读IReleaseRepository releaseRepository; 公共ArticleController(IArticleRepository articleRepository,IUserRepository userRepository,IReleaseRepository releaseRepository)
{
this.articleRepository = articleRepository;
this.userRepository = userRepository;
this.releaseRepository = releaseRepository;
} //获取API /条
公共IEnumerable的&lt;物品&GT; GetArticles(){// code} //获取API /条/ 5
公共物品GetArticle(INT ID){// code} // PUT API /条/ 5
公众的Htt presponseMessage PutArticle(INT ID,文章文章){// code} // POST API /条
公众的Htt presponseMessage PostArticle(ArticleModel文章){// code} //删除API /条/ 5
公众的Htt presponseMessage DeleteArticle(INT ID){// code}
}SimpleInjectorInitializer:
公共静态类SimpleInjectorInitializer
{
公共静态无效初始化()
{
VAR集装箱=新容器();
InitializeContainer(容器);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcAttributeFilterProvider();
container.Verify(); DependencyResolver.SetResolver(新SimpleInjectorDependencyResolver(容器));
} 私有静态无效InitializeContainer(集装箱货柜)
{
container.Register&LT; IArticleRepository,ArticleRepository&GT;();
container.Register&LT; IUserRepository,UserRepository&GT;();
container.Register&LT; IReleaseRepository,ReleaseRepository&GT;();
}
}的Global.asax.cs:
公共类WebApiApplication:System.Web.HttpApplication
{
私人无效ConfigureApi()
{
//创建容器如常。
VAR集装箱=新容器(); //验证容器配置
// container.Verify(); //注册的依赖解析器。
GlobalConfiguration.Configuration.DependencyResolver =
新SimpleInjectorWebApiDependencyResolver(容器);
} 保护无效的Application_Start()
{
AreaRegistration.RegisterAllAreas();
ConfigureApi(); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
解决方案TLTR:的问题是由隐性方式的Web API造成的手柄控制器解决类型;明确注册你的Web API的控制器,你会看到问题出在哪里。
下面是一步步什么在幕后发生的事情:
- 的
System.Web.Http.DefaultHttpControllerActivator
调用到SimpleInjectorWebApiDependencyResolver
并请求API控制器的创建。SimpleInjectorWebApiDependencyResolver
调用到SimpleInjector.Container
实例前锋。- 这
集装箱
实例但是,不具有该API控制器任何明确的注册(因为你提供给解析器一个空的容器)。- 由于没有明确的登记,容器试图为该类型做最后一分钟的登记
- 该控制器类型但要看,因为他们没有在容器中注册的无法解析接口(请记住,你的容器是空的)。
- 虽然容器通常会抛出异常,则返回null在这种情况下,因为该类型通过
IServiceProvider.GetService
法要求和类型没有显式登记- 的的
SimpleInjectorWebApiDependencyResolver
的GetService
方法将返回空
为好,因为它是根据定义,它应该返回null;在没有登记的情况下,它应该返回空值(目前是这样)。- 因为
DependencyResolver
返回null,DefaultHttpControllerActivator
将回落到其默认行为,这意味着创建类型本身,但是这需要控制器有一个默认的构造函数。长话短说,这个问题是由隐性方式的Web API造成的手柄控制器解决类型。
所以这里的解决方案是:
- 只有一个单一的
集装箱
在你的Web应用程序。这prevents各种配置的麻烦和复杂性。- 注册的所有Web API控制器明确地在容器中。明确注册控制器将确保简单喷油器将抛出一个异常时,控制器不能得到解决。此外,这允许你调用
container.Verify()
这将使得启动时应用程序出现故障时的配置是无效的(A <一个href=\"https://simpleinjector.readthedocs.org/en/latest/howto.html#verify-the-container-s-configuration\"相对=nofollow>核实的配置是非常重要的)。这也可以让您诊断配置这给了你更多的信心配置的正确性。我的<一个href=\"https://stackoverflow.com/questions/15494920/what-is-the-difference-between-dependencyresolver-setresolver-and-httpconfigurat/15495934#15495934\">advice是把MVC和Web API在自己的项目。这将使事情变得更加简单。
注册所有网页API控制器可以用下面的code来完成:
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
更新:
由于这个错误是如此普遍,在
SimpleInjectorWebApiDependencyResolver
类的新版本将简单的从不返回空
当请求控制器类型。相反,它会抛出一个描述性的错误。正因为如此,你永远不应该看到的错误了,只要您使用官方的SimpleInjectorWebApiDependencyResolver
。I am attempting to do some basic constructor DI with Simple Injector, and it seems that it is unable to resolve the dependencies for Web API controllers.
- I have an API controller in an "API" folder, that is outside the "Controllers" folder.
- I have also tried placing it within the "Controllers" folder, but that did not seem to make much of a difference. The stack trace that I receive is similar to the one presented in this question.
- I am using a fresh install of the "Simple Injector MVC Integration Quick Start" NuGet Package (v. 2.1.0).
- I have the base
SimpleInjectorWebApiDependencyResolver
from the documentation, which is also the same as found here.- I am using Entity Framework, and have looked at the discussion thread about changes to correctly load the context.
This does not seem to be a problem, but I still receive the following error:
Type 'MyProject.API.ArticleController' does not have a default constructor
System.ArgumentException at
System.Linq.Expressions.Expression.New(Type type) at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
It would be appreciated if someone could offer me some suggestions, on whether anything should be modified from its current state/call order.
ArticleController (basic structure):
public class ArticleController : ApiController { private readonly IArticleRepository articleRepository; private readonly IUserRepository userRepository; private readonly IReleaseRepository releaseRepository; public ArticleController(IArticleRepository articleRepository, IUserRepository userRepository, IReleaseRepository releaseRepository) { this.articleRepository = articleRepository; this.userRepository = userRepository; this.releaseRepository = releaseRepository; } // GET api/Article public IEnumerable<Article> GetArticles(){ // code } // GET api/Article/5 public Article GetArticle(int id){ // code } // PUT api/Article/5 public HttpResponseMessage PutArticle(int id, Article article){ // code } // POST api/Article public HttpResponseMessage PostArticle(ArticleModel article){ // code } // DELETE api/Article/5 public HttpResponseMessage DeleteArticle(int id){ // code } }
SimpleInjectorInitializer:
public static class SimpleInjectorInitializer { public static void Initialize() { var container = new Container(); InitializeContainer(container); container.RegisterMvcControllers(Assembly.GetExecutingAssembly()); container.RegisterMvcAttributeFilterProvider(); container.Verify(); DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container)); } private static void InitializeContainer(Container container) { container.Register<IArticleRepository, ArticleRepository>(); container.Register<IUserRepository, UserRepository>(); container.Register<IReleaseRepository, ReleaseRepository>(); } }
Global.asax.cs:
public class WebApiApplication : System.Web.HttpApplication { private void ConfigureApi() { // Create the container as usual. var container = new Container(); // Verify the container configuration // container.Verify(); // Register the dependency resolver. GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container); } protected void Application_Start() { AreaRegistration.RegisterAllAreas(); ConfigureApi(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } }
解决方案TLTR: the problem is caused by the implicit way Web API handles resolving controller types; register your Web API controllers explicitly and you'll see where the problem is.
Here is a step by step what is happening under the covers:
- The
System.Web.Http.DefaultHttpControllerActivator
calls into theSimpleInjectorWebApiDependencyResolver
and requests the creation of an API controller.SimpleInjectorWebApiDependencyResolver
forwards that call to theSimpleInjector.Container
instance.- That
Container
instance however, does not have any explicit registrations for that API Controller (since you supplied an empty container to the resolver).- Since there is no explicit registration, the container tries to do a last minute registration for that type.
- That Controller type however depends on interfaces that can't be resolved because they are not registered in the container (remember, your container is empty).
- Although the container would normally throw an exception, null is returned in this case, because the type is requested through the
IServiceProvider.GetService
method and the type was not registered explictly.- The
SimpleInjectorWebApiDependencyResolver
'sGetService
method will returnnull
as well, since it's by definition that it should return null; It should return null when no registration exists (which currently is the case).- Since the
DependencyResolver
returned null,DefaultHttpControllerActivator
will fall back to its default behavior, which means creating that type itself, but this requires the controller to have a default constructor.Long story short, the problem is caused by the implicit way Web API handles resolving controller types.
So the solution here is to:
- Have only one single
Container
in your web application. This prevents all sorts of trouble and complication of your configuration.- Register all Web API Controllers explicitly in the container. Registering controllers explicitly will ensure that Simple Injector will throw an exception when a controller can't be resolved. Besides, this allows you to call
container.Verify()
which will make the application fail during startup when the configuration is invalid (a verifiable configuration is important). And this also allows you to diagnose the configuration which gives you even more confidence about the correctness of your configuration.My advice is to place MVC and Web API in their own project. This will make things much easier.
Registering all Web API controllers can be done with the following code:
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
UPDATE:
Because this error is so common, newer versions of the
SimpleInjectorWebApiDependencyResolver
class will simply never returnnull
when a controller type is requested. Instead it will throw a descriptive error. Because of this you should never see error anymore, as long as you use the officialSimpleInjectorWebApiDependencyResolver
.这篇关于简单的喷油器无法在注入API网络控制器依赖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!