在我的 MVC5 控制器中使用 StructureMap[4.7.0] Setter 注入
Using StructureMap[4.7.0] Setter Injection in my MVC5 Controller
我正在尝试将 IApplicationConfigurationSection
实现注入到这个 MVC5 Controller
中,这样我就可以从我的 web.config
自定义部分访问一些信息(各种字符串)在我所有的观点中:
public class BaseController : Controller
{
public IApplicationConfigurationSection AppConfig { get; set; }
public BaseController()
{
ViewBag.AppConfig = AppConfig; // AppConfig is always null
}
}
我想使用 setter 注入,这样我就不必用它们并不真正关心的参数来扰乱派生的 Controller
构造函数。
注意:如果有更好的方法注入基础class依赖,请告诉我。我承认我可能不在正确的轨道上。
在我的 Global.asax
中加载我的 StructureMap 配置:
private static IContainer _container;
protected void Application_Start()
{
_container = new Container();
StructureMapConfig.Configure(_container, () => Container ?? _container);
// redacted other registrations
}
我的 StructureMapConfig
class 加载我的注册表:
public class StructureMapConfig
{
public static void Configure(IContainer container, Func<IContainer> func)
{
DependencyResolver.SetResolver(new StructureMapDependencyResolver(func));
container.Configure(cfg =>
{
cfg.AddRegistries(new Registry[]
{
new MvcRegistry(),
// other registries redacted
});
});
}
}
我的 MvcRegistry 提供了 StructureMap 的映射:
public class MvcRegistry : Registry
{
public MvcRegistry()
{
For<BundleCollection>().Use(BundleTable.Bundles);
For<RouteCollection>().Use(RouteTable.Routes);
For<IPrincipal>().Use(() => HttpContext.Current.User);
For<IIdentity>().Use(() => HttpContext.Current.User.Identity);
For<ICurrentUser>().Use<CurrentUser>();
For<HttpSessionStateBase>()
.Use(() => new HttpSessionStateWrapper(HttpContext.Current.Session));
For<HttpContextBase>()
.Use(() => new HttpContextWrapper(HttpContext.Current));
For<HttpServerUtilityBase>()
.Use(() => new HttpServerUtilityWrapper(HttpContext.Current.Server));
For<IApplicationConfigurationSection>()
.Use(GetConfig());
Policies.SetAllProperties(p => p.OfType<IApplicationConfigurationSection>());
}
private IApplicationConfigurationSection GetConfig()
{
var config = ConfigurationManager.GetSection("application") as ApplicationConfigurationSection;
return config; // this always returns a valid instance
}
}
我也 "thrown my hands up" 并尝试在 BaseController 上使用 [SetterProperty]
属性 - 该技术也失败了。
尽管我尽最大努力找到解决方案,但我的控制器构造函数中的 AppConfig
属性 始终是 null
。我以为
`Policies.SetAllProperties(p => p.OfType<IApplicationConfigurationSection>());`
可以解决问题,但事实并非如此。
我发现如果我放弃 setter 注入并使用构造函数注入,它会像宣传的那样工作。我仍然想知道我哪里出错了,但我想强调我不是 StructureMap 大师 - 可能有更好的方法来避免必须构造函数注入我的基础class 依赖项。如果你知道我应该怎么做但我不知道,请分享。
虽然在这种情况下构造函数注入似乎是解决所述问题的更好方法,如下所示 The Explicit Dependencies Principle
Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.
在您的观点中提到只需要访问 AppConfig
让我认为这更像是一个 XY problem 和一个横切关注点。
似乎控制器本身不需要使用依赖项,因此有理由认为没有必要将它们显式注入控制器,以便 View 可以使用依赖项.
考虑使用可以解决依赖关系的操作过滤器,并在请求通过管道时通过相同的 ViewBag
使其对视图可用。
public class AccessesAppConfigAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
var resolver = DependencyResolver.Current;
var appConfig = (IApplicationConfigurationSection)resolver.GetService(typeof(IApplicationConfigurationSection));
filterContext.Controller.ViewBag.AppConfig = appConfig;
}
}
这使得视图可以使用所需的信息,而无需与可能使用它的控制器紧密耦合。删除将依赖项注入派生 类 的需要。
要么通过装饰 Controller/Action 过滤器属性
[AccessesAppConfig] //available to all its actions
public class HomeController : Controller {
//[AccessesAppConfig] //Use directly if want to isolate to single action/view
public ActionResult Index() {
//...
return View();
}
}
或全局适用于所有请求。
public class FilterConfig {
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new AccessesAppConfigAttribute());
}
}
在这一点上,使用哪个 IoC 容器并不重要。配置依赖项解析器后,视图应该可以访问 ViewBag
中的所需信息
我正在尝试将 IApplicationConfigurationSection
实现注入到这个 MVC5 Controller
中,这样我就可以从我的 web.config
自定义部分访问一些信息(各种字符串)在我所有的观点中:
public class BaseController : Controller
{
public IApplicationConfigurationSection AppConfig { get; set; }
public BaseController()
{
ViewBag.AppConfig = AppConfig; // AppConfig is always null
}
}
我想使用 setter 注入,这样我就不必用它们并不真正关心的参数来扰乱派生的 Controller
构造函数。
注意:如果有更好的方法注入基础class依赖,请告诉我。我承认我可能不在正确的轨道上。
在我的 Global.asax
中加载我的 StructureMap 配置:
private static IContainer _container;
protected void Application_Start()
{
_container = new Container();
StructureMapConfig.Configure(_container, () => Container ?? _container);
// redacted other registrations
}
我的 StructureMapConfig
class 加载我的注册表:
public class StructureMapConfig
{
public static void Configure(IContainer container, Func<IContainer> func)
{
DependencyResolver.SetResolver(new StructureMapDependencyResolver(func));
container.Configure(cfg =>
{
cfg.AddRegistries(new Registry[]
{
new MvcRegistry(),
// other registries redacted
});
});
}
}
我的 MvcRegistry 提供了 StructureMap 的映射:
public class MvcRegistry : Registry
{
public MvcRegistry()
{
For<BundleCollection>().Use(BundleTable.Bundles);
For<RouteCollection>().Use(RouteTable.Routes);
For<IPrincipal>().Use(() => HttpContext.Current.User);
For<IIdentity>().Use(() => HttpContext.Current.User.Identity);
For<ICurrentUser>().Use<CurrentUser>();
For<HttpSessionStateBase>()
.Use(() => new HttpSessionStateWrapper(HttpContext.Current.Session));
For<HttpContextBase>()
.Use(() => new HttpContextWrapper(HttpContext.Current));
For<HttpServerUtilityBase>()
.Use(() => new HttpServerUtilityWrapper(HttpContext.Current.Server));
For<IApplicationConfigurationSection>()
.Use(GetConfig());
Policies.SetAllProperties(p => p.OfType<IApplicationConfigurationSection>());
}
private IApplicationConfigurationSection GetConfig()
{
var config = ConfigurationManager.GetSection("application") as ApplicationConfigurationSection;
return config; // this always returns a valid instance
}
}
我也 "thrown my hands up" 并尝试在 BaseController 上使用 [SetterProperty]
属性 - 该技术也失败了。
尽管我尽最大努力找到解决方案,但我的控制器构造函数中的 AppConfig
属性 始终是 null
。我以为
`Policies.SetAllProperties(p => p.OfType<IApplicationConfigurationSection>());`
可以解决问题,但事实并非如此。
我发现如果我放弃 setter 注入并使用构造函数注入,它会像宣传的那样工作。我仍然想知道我哪里出错了,但我想强调我不是 StructureMap 大师 - 可能有更好的方法来避免必须构造函数注入我的基础class 依赖项。如果你知道我应该怎么做但我不知道,请分享。
虽然在这种情况下构造函数注入似乎是解决所述问题的更好方法,如下所示 The Explicit Dependencies Principle
Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.
在您的观点中提到只需要访问 AppConfig
让我认为这更像是一个 XY problem 和一个横切关注点。
似乎控制器本身不需要使用依赖项,因此有理由认为没有必要将它们显式注入控制器,以便 View 可以使用依赖项.
考虑使用可以解决依赖关系的操作过滤器,并在请求通过管道时通过相同的 ViewBag
使其对视图可用。
public class AccessesAppConfigAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
var resolver = DependencyResolver.Current;
var appConfig = (IApplicationConfigurationSection)resolver.GetService(typeof(IApplicationConfigurationSection));
filterContext.Controller.ViewBag.AppConfig = appConfig;
}
}
这使得视图可以使用所需的信息,而无需与可能使用它的控制器紧密耦合。删除将依赖项注入派生 类 的需要。
要么通过装饰 Controller/Action 过滤器属性
[AccessesAppConfig] //available to all its actions
public class HomeController : Controller {
//[AccessesAppConfig] //Use directly if want to isolate to single action/view
public ActionResult Index() {
//...
return View();
}
}
或全局适用于所有请求。
public class FilterConfig {
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new AccessesAppConfigAttribute());
}
}
在这一点上,使用哪个 IoC 容器并不重要。配置依赖项解析器后,视图应该可以访问 ViewBag