我正在尝试将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
构造函数。
注意:如果有更好的方法来注入基类依赖项,请告诉我。我承认我可能不在这里。
在我的Global.asax
中,加载我的StructureMap配置:
private static IContainer _container;
protected void Application_Start()
{
_container = new Container();
StructureMapConfig.Configure(_container, () => Container ?? _container);
// redacted other registrations
}
我的StructureMapConfig
类加载我的注册表:
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
}
}
我也“举起手来”并尝试在BaseController上使用[SetterProperty]
属性-该技术也失败了。
尽管我尽力寻找解决方案,但控制器构造函数中的AppConfig
属性始终为null
。我以为
`Policies.SetAllProperties(p => p.OfType<IApplicationConfigurationSection>());`
可以解决问题,但是没有。
我发现,如果我放弃了setter注入而使用了构造函数注入,它会像广告中那样工作。我仍然想知道我要去哪里,但我想强调一点,我不是StructureMap专家-有一种更好的方法来避免必须构造函数注入我的基类依赖项。如果您知道我应该怎么做,但不是,请分享。
答案 0 :(得分:0)
在这种情况下,虽然遵循The Explicit Dependencies Principle
似乎是解决上述问题的更好的解决方案,方法和类应明确要求(通常通过方法参数或构造函数参数)它们所需的任何协作对象,以使其正常运行。
在您看来,仅需要访问AppConfig
的提法使我认为这更多是XY problem和跨领域关注点。
似乎控制器本身不需要使用依赖项,因此可以断定没有必要将它们明确地注入控制器中,从而使依赖项可用于 View
请考虑使用动作过滤器,该过滤器可以解决依赖关系,并通过与请求通过管道相同的ViewBag
将其提供给View。
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;
}
}
这现在使所需的信息可用于视图,而无需紧密耦合可能会用到的控制器。无需将依赖项注入派生类。
通过使用filter属性装饰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