如何在asp.net-mvc的Controller中实现依赖注入的最佳实践?

2026-03-30 12:211阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计746个文字,预计阅读时间需要3分钟。

如何在asp.net-mvc的Controller中实现依赖注入的最佳实践?

我有下面的代码,没有遇到任何问题 +MAUserController.cs+public class MAUserController : ApiController { +ILogService loggerService; +IMAUserService _service; +public MAUserController(ILogService loggerService, IMAUserService Service) { +th+

我有下面的代码,没有任何问题
MAUserController.cs

public class MAUserController : ApiController { ILogService loggerService; IMAUserService _service; public MAUserController(ILogService loggerService, IMAUserService Service) { this.loggerService = loggerService; this._service = Service; } }

DependencyInstaller.cs

public class DependencyInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register( Component.For<ILogService>().ImplementedBy<LogService>().LifeStyle.PerWebRequest, Component.For<IDatabaseFactory>().ImplementedBy<DatabaseFactory>().LifeStyle.PerWebRequest, Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>().LifeStyle.PerWebRequest, AllTypes.FromThisAssembly().BasedOn<IHttpController>().LifestyleTransient(), AllTypes.FromAssemblyNamed("ISOS.Health.Service").Where(type => type.Name.EndsWith("Service")).WithServiceAllInterfaces().LifestylePerWebRequest(), AllTypes.FromAssemblyNamed("ISOS.Health.Repository").Where(type => type.Name.EndsWith("Repository")).WithServiceAllInterfaces().LifestylePerWebRequest() ); } }

如果我使用普通的控制器而不是ApiController,那么它会给我一个错误
UserController.cs

public class UserController : Controller { ILogService loggerService; IMAUserService _service; public UserController(ILogService loggerService, IMAUserService Service) { this.loggerService = loggerService; this._service = Service; } }

这会产生错误:

No parameterless constructor defined for this object

我使用CastleDI Windsor进行依赖注入.

我需要做任何事情或注册一些东西吗?

第一种方法

建议:谨慎使用,因为它可能会导致Castle Windsor的内存泄漏.

您必须创建一个控制器激活器,它应该实现IControllerActivator接口,以便使用您的DI容器来创建控制器实例:

public class MyWindsorControllerActivator : IControllerActivator { public MyWindsorControllerActivator(IWindsorContainer container) { _container = container; } private IWindsorContainer _container; public IController Create(RequestContext requestContext, Type controllerType) { return _container.Resolve(controllerType) as IController; } }

然后,将此类添加到DependencyInstaller:

如何在asp.net-mvc的Controller中实现依赖注入的最佳实践?

public class DependencyInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register( // Current code... Component.For<IControllerActivator>() .ImplementedBy<MyWindsorControllerActivator>() .DependsOn(Dependency.OnValue("container", container)) .LifestyleSingleton(); ); } }

另外,根据Windsor容器创建自己的依赖项解析器:

public class MyWindsorDependencyResolver : IDependencyResolver { public MyWindsorDependencyResolver(IWindsorContainer container) { _container = container; } private IWindsorContainer _container; public object GetService(Type serviceType) { return _container.Resolve(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { return _container.ResolveAll(serviceType).Cast<object>(); } }

然后,最后,在Global.asax.cs中的Application_Start方法中注册依赖项解析器:

DependencyResolver.SetResolver(new MyWindsorDependencyResolver(windsorContainer));

这样,当MVC需要控制器激活器通过它的依赖解析器时,它将获得我们的,它将使用我们的Windsor容器来创建具有所有依赖性的控制器.

为了避免使用IControllerActivator导致内存泄漏,最简单的解决方案是使用每个线程或每个Web请求的生活方式,而不是默认(单例),瞬态和池化,用于已注册的组件.有关如何使用Castle Windsor Container避免内存泄漏的详细信息,请查看this link.

第二种方法

然而,正如@PhilDegenhardt所指出的,更好更正确的方法是实现自定义控制器工厂,以便能够释放由Castle Windsor DI Container创建的控制器组件. Here you can find an example (see the section about Dependency Injection).

从该示例中可以看出,实现可能是:

的Global.asax.cs:

public class MvcApplication : System.Web.HttpApplication { private WindsorContainer _windsorContainer; protected void Application_Start() { var _windsorContainer = new WindsorContainer(); _windsorContainer.Install( new DependencyInstaller(), // Other installers... ); ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(_windsorContainer.Kernel)); } protected void Application_End() { if (_windsorContainer != null) { _windsorContainer.Dispose(); } } }

WindsorControllerFactory.cs:

public class WindsorControllerFactory : DefaultControllerFactory { private readonly IKernel _kernel; public WindsorControllerFactory(IKernel kernel) { _kernel = kernel; } public override void ReleaseController(IController controller) { _kernel.ReleaseComponent(controller); // The important part: release the component } protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { if (controllerType == null) { throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path)); } return (IController)_kernel.Resolve(controllerType); } }

本文共计746个文字,预计阅读时间需要3分钟。

如何在asp.net-mvc的Controller中实现依赖注入的最佳实践?

我有下面的代码,没有遇到任何问题 +MAUserController.cs+public class MAUserController : ApiController { +ILogService loggerService; +IMAUserService _service; +public MAUserController(ILogService loggerService, IMAUserService Service) { +th+

我有下面的代码,没有任何问题
MAUserController.cs

public class MAUserController : ApiController { ILogService loggerService; IMAUserService _service; public MAUserController(ILogService loggerService, IMAUserService Service) { this.loggerService = loggerService; this._service = Service; } }

DependencyInstaller.cs

public class DependencyInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register( Component.For<ILogService>().ImplementedBy<LogService>().LifeStyle.PerWebRequest, Component.For<IDatabaseFactory>().ImplementedBy<DatabaseFactory>().LifeStyle.PerWebRequest, Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>().LifeStyle.PerWebRequest, AllTypes.FromThisAssembly().BasedOn<IHttpController>().LifestyleTransient(), AllTypes.FromAssemblyNamed("ISOS.Health.Service").Where(type => type.Name.EndsWith("Service")).WithServiceAllInterfaces().LifestylePerWebRequest(), AllTypes.FromAssemblyNamed("ISOS.Health.Repository").Where(type => type.Name.EndsWith("Repository")).WithServiceAllInterfaces().LifestylePerWebRequest() ); } }

如果我使用普通的控制器而不是ApiController,那么它会给我一个错误
UserController.cs

public class UserController : Controller { ILogService loggerService; IMAUserService _service; public UserController(ILogService loggerService, IMAUserService Service) { this.loggerService = loggerService; this._service = Service; } }

这会产生错误:

No parameterless constructor defined for this object

我使用CastleDI Windsor进行依赖注入.

我需要做任何事情或注册一些东西吗?

第一种方法

建议:谨慎使用,因为它可能会导致Castle Windsor的内存泄漏.

您必须创建一个控制器激活器,它应该实现IControllerActivator接口,以便使用您的DI容器来创建控制器实例:

public class MyWindsorControllerActivator : IControllerActivator { public MyWindsorControllerActivator(IWindsorContainer container) { _container = container; } private IWindsorContainer _container; public IController Create(RequestContext requestContext, Type controllerType) { return _container.Resolve(controllerType) as IController; } }

然后,将此类添加到DependencyInstaller:

如何在asp.net-mvc的Controller中实现依赖注入的最佳实践?

public class DependencyInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register( // Current code... Component.For<IControllerActivator>() .ImplementedBy<MyWindsorControllerActivator>() .DependsOn(Dependency.OnValue("container", container)) .LifestyleSingleton(); ); } }

另外,根据Windsor容器创建自己的依赖项解析器:

public class MyWindsorDependencyResolver : IDependencyResolver { public MyWindsorDependencyResolver(IWindsorContainer container) { _container = container; } private IWindsorContainer _container; public object GetService(Type serviceType) { return _container.Resolve(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { return _container.ResolveAll(serviceType).Cast<object>(); } }

然后,最后,在Global.asax.cs中的Application_Start方法中注册依赖项解析器:

DependencyResolver.SetResolver(new MyWindsorDependencyResolver(windsorContainer));

这样,当MVC需要控制器激活器通过它的依赖解析器时,它将获得我们的,它将使用我们的Windsor容器来创建具有所有依赖性的控制器.

为了避免使用IControllerActivator导致内存泄漏,最简单的解决方案是使用每个线程或每个Web请求的生活方式,而不是默认(单例),瞬态和池化,用于已注册的组件.有关如何使用Castle Windsor Container避免内存泄漏的详细信息,请查看this link.

第二种方法

然而,正如@PhilDegenhardt所指出的,更好更正确的方法是实现自定义控制器工厂,以便能够释放由Castle Windsor DI Container创建的控制器组件. Here you can find an example (see the section about Dependency Injection).

从该示例中可以看出,实现可能是:

的Global.asax.cs:

public class MvcApplication : System.Web.HttpApplication { private WindsorContainer _windsorContainer; protected void Application_Start() { var _windsorContainer = new WindsorContainer(); _windsorContainer.Install( new DependencyInstaller(), // Other installers... ); ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(_windsorContainer.Kernel)); } protected void Application_End() { if (_windsorContainer != null) { _windsorContainer.Dispose(); } } }

WindsorControllerFactory.cs:

public class WindsorControllerFactory : DefaultControllerFactory { private readonly IKernel _kernel; public WindsorControllerFactory(IKernel kernel) { _kernel = kernel; } public override void ReleaseController(IController controller) { _kernel.ReleaseComponent(controller); // The important part: release the component } protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { if (controllerType == null) { throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path)); } return (IController)_kernel.Resolve(controllerType); } }