Application_Start 中的 StructureMap IoC
StructureMap IoC in Application_Start
我无法让 StructureMap 将值注入到 Global.asax.cs 文件的 MvcApplication 的构造函数中。我创建了一个全新的干净项目,并使用 StructureMap.MVC5 包在 DependencyResolution 子文件夹中生成必要的结构。
我要注入的class很简单:
namespace SMTest.Models {
public interface ITestSM
{
int OnePlusTwo();
}
public class TestSM : ITestSM
{
public int OnePlusTwo()
{
return 1 + 2;
}
} }
IoC.cs 是:
namespace SMTest.DependencyResolution {
using StructureMap;
public static class IoC {
public static IContainer Initialize() {
return new Container(c => c.AddRegistry<DefaultRegistry>());
}
}
}
StructuremapMvc.cs 包含:
public static void Start() {
IContainer container = IoC.Initialize();
StructureMapDependencyScope = new StructureMapDependencyScope(container);
DependencyResolver.SetResolver(StructureMapDependencyScope);
DynamicModuleUtility.RegisterModule(typeof(StructureMapScopeModule));
}
并且DefaultRegistry.cs包含:
public DefaultRegistry() {
Scan(
scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
For<ITestSM>().Singleton().Use<TestSM>();
}
我可以轻松地将它注入到 HomeController 中:
public class HomeController : Controller
{
private ITestSM _testsm;
public HomeController(ITestSM testsm):base()
{
_testsm = testsm;
}
public ActionResult Index()
{
return View();
}
但是当我在 Global.asax.cs 中尝试这样做时:
public class MvcApplication : System.Web.HttpApplication
{
private ITestSM _testsm;
public MvcApplication(ITestSM testsm)
{
_testsm = testsm;
}
protected void Application_Start()
{...
我收到错误:
编译器错误消息:CS7036:没有给定的参数对应于 'MvcApplication.MvcApplication(ITestSM)'
的所需形式参数 'testsm'
尽管 IoC init 在 Application_Start 之前触发,StructuremapMvc.cs:
[assembly: PreApplicationStartMethod(typeof(StructuremapMvc), "Start")]
[assembly: ApplicationShutdownMethod(typeof(StructuremapMvc), "End")]
有什么想法吗?
编辑:
我能够将其显式注入 Global.asax.cs:
protected void Application_EndRequest(object sender, System.EventArgs e)
{
if (!this.Request.Path.Contains("Content") && !this.Request.Path.Contains("Scripts") && !this.Request.Path.Contains("less"))
{
ISession currentSession = SMTest.App_StartStructuremapMvc.StructureMapDependencyScope.Container.GetInstance<ISession>();
currentSession.Flush();
currentSession.Close();
}
}
但是,我在这里得到的会话不是注入控制器的会话,所以我刷新并关闭了错误的会话,导致数据未提交到数据库。
不幸的是,无法通过构造函数注入将依赖项注入 MvcApplication
class。正如您所发现的那样,唯一的方法是通过容器的静态实例(也称为服务定位器模式)访问容器。
让我解释一下我对为什么会这样的理解。
设置容器后,调用以下行:
DependencyResolver.SetResolver(StructureMapDependencyScope);
此行将您的 IoC 容器(在本例中为 StructureMap)设置为 ASP.NET MVC 的依赖解析器。最终充当 ASP.NET 和您的 StructureMap 容器之间的接口。
当控制器被 MVC 框架实例化时,依赖关系将通过在您的 DependencyResolver
中配置的实例来解决。但是,在创建 MvcApplication
实例时,依赖关系不会通过 DependencyResolver
实例解析。唯一通过 DependencyResolver
解决依赖关系的实例类型是控制器。归根结底,这是 ASP.NET MVC 框架中的一个缺陷(已在 ASP.NET Core MVC 中得到纠正)。
除此之外,您的容器甚至在调用构造函数时都未配置,仅在调用控制器后调用的 Start()
方法中配置。
我无法让 StructureMap 将值注入到 Global.asax.cs 文件的 MvcApplication 的构造函数中。我创建了一个全新的干净项目,并使用 StructureMap.MVC5 包在 DependencyResolution 子文件夹中生成必要的结构。
我要注入的class很简单:
namespace SMTest.Models {
public interface ITestSM
{
int OnePlusTwo();
}
public class TestSM : ITestSM
{
public int OnePlusTwo()
{
return 1 + 2;
}
} }
IoC.cs 是:
namespace SMTest.DependencyResolution {
using StructureMap;
public static class IoC {
public static IContainer Initialize() {
return new Container(c => c.AddRegistry<DefaultRegistry>());
}
}
}
StructuremapMvc.cs 包含:
public static void Start() {
IContainer container = IoC.Initialize();
StructureMapDependencyScope = new StructureMapDependencyScope(container);
DependencyResolver.SetResolver(StructureMapDependencyScope);
DynamicModuleUtility.RegisterModule(typeof(StructureMapScopeModule));
}
并且DefaultRegistry.cs包含:
public DefaultRegistry() {
Scan(
scan => {
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.With(new ControllerConvention());
});
For<ITestSM>().Singleton().Use<TestSM>();
}
我可以轻松地将它注入到 HomeController 中:
public class HomeController : Controller
{
private ITestSM _testsm;
public HomeController(ITestSM testsm):base()
{
_testsm = testsm;
}
public ActionResult Index()
{
return View();
}
但是当我在 Global.asax.cs 中尝试这样做时:
public class MvcApplication : System.Web.HttpApplication
{
private ITestSM _testsm;
public MvcApplication(ITestSM testsm)
{
_testsm = testsm;
}
protected void Application_Start()
{...
我收到错误: 编译器错误消息:CS7036:没有给定的参数对应于 'MvcApplication.MvcApplication(ITestSM)'
的所需形式参数 'testsm'尽管 IoC init 在 Application_Start 之前触发,StructuremapMvc.cs:
[assembly: PreApplicationStartMethod(typeof(StructuremapMvc), "Start")]
[assembly: ApplicationShutdownMethod(typeof(StructuremapMvc), "End")]
有什么想法吗?
编辑: 我能够将其显式注入 Global.asax.cs:
protected void Application_EndRequest(object sender, System.EventArgs e)
{
if (!this.Request.Path.Contains("Content") && !this.Request.Path.Contains("Scripts") && !this.Request.Path.Contains("less"))
{
ISession currentSession = SMTest.App_StartStructuremapMvc.StructureMapDependencyScope.Container.GetInstance<ISession>();
currentSession.Flush();
currentSession.Close();
}
}
但是,我在这里得到的会话不是注入控制器的会话,所以我刷新并关闭了错误的会话,导致数据未提交到数据库。
不幸的是,无法通过构造函数注入将依赖项注入 MvcApplication
class。正如您所发现的那样,唯一的方法是通过容器的静态实例(也称为服务定位器模式)访问容器。
让我解释一下我对为什么会这样的理解。
设置容器后,调用以下行:
DependencyResolver.SetResolver(StructureMapDependencyScope);
此行将您的 IoC 容器(在本例中为 StructureMap)设置为 ASP.NET MVC 的依赖解析器。最终充当 ASP.NET 和您的 StructureMap 容器之间的接口。
当控制器被 MVC 框架实例化时,依赖关系将通过在您的 DependencyResolver
中配置的实例来解决。但是,在创建 MvcApplication
实例时,依赖关系不会通过 DependencyResolver
实例解析。唯一通过 DependencyResolver
解决依赖关系的实例类型是控制器。归根结底,这是 ASP.NET MVC 框架中的一个缺陷(已在 ASP.NET Core MVC 中得到纠正)。
除此之外,您的容器甚至在调用构造函数时都未配置,仅在调用控制器后调用的 Start()
方法中配置。