我正试图将IApplicationConfigurationSection
实现注入这个MVC5Controller
,这样我就可以在所有视图中访问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
});
});
}
}
My 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大师-有一种更好的方法可以避免必须构造函数注入基类依赖项。如果你知道我应该怎么做,但不知道,请分享。
虽然在这种情况下构造函数注入似乎是解决所述问题的更好方案,因为它遵循显式依赖性原则
方法和类应该显式地要求(通常通过方法参数或构造函数参数(它们需要的任何协作对象才能正常工作。
在您的观点中提到只需要访问AppConfig
,这让我认为这更像是一个XY问题,也是一个跨领域的问题。
控制器本身似乎不需要使用依赖项,因此不需要将它们显式注入控制器,以便视图可以使用依赖项。
考虑使用一个操作过滤器,该过滤器可以解析依赖关系,并在请求通过管道时通过相同的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;
}
}
这使得视图可以获得所需的信息,而不需要对可能有用的控制器进行紧密耦合。消除了将依赖项注入派生类的需要。
通过使用过滤器属性装饰控制器/操作
[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
中所需的信息