C# 使用Unity将依赖项注入自定义ActionFilter
目前,我有一个定制的ControllerFactory,我将Unity容器注入其中:C# 使用Unity将依赖项注入自定义ActionFilter,c#,asp.net-mvc-3,dependency-injection,unity-container,C#,Asp.net Mvc 3,Dependency Injection,Unity Container,目前,我有一个定制的ControllerFactory,我将Unity容器注入其中: protected override ActionExecutedContext InvokeActionMethodWithFilters( ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor,
protected override ActionExecutedContext InvokeActionMethodWithFilters(
ControllerContext controllerContext,
IList<IActionFilter> filters,
ActionDescriptor actionDescriptor,
IDictionary<string, object> parameters)
{
var builtUpFilters = new List<IActionFilter>();
foreach (IActionFilter actionFilter in filters)
{
builtUpFilters.Add(_container.BuildUp<IActionFilter>(actionFilter));
}
return base.InvokeActionMethodWithFilters(controllerContext, builtUpFilters, actionDescriptor, parameters);
}
在global.asax应用程序_Start()中:
在控制器工厂中,我将控制器设置为使用自定义ActionInvoker,如下所示:
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
var controller = base.GetControllerInstance(requestContext, controllerType) as Controller;
if (controller != null)
controller.ActionInvoker = new UnityActionInvoker(_container);
return controller;
}
最后,在我的自定义ActionInvoker中,我尝试使用ActionInvokers容器构建正在调用的操作:
protected override ActionExecutedContext InvokeActionMethodWithFilters(
ControllerContext controllerContext,
IList<IActionFilter> filters,
ActionDescriptor actionDescriptor,
IDictionary<string, object> parameters)
{
var builtUpFilters = new List<IActionFilter>();
foreach (IActionFilter actionFilter in filters)
{
builtUpFilters.Add(_container.BuildUp<IActionFilter>(actionFilter));
}
return base.InvokeActionMethodWithFilters(controllerContext, builtUpFilters, actionDescriptor, parameters);
}
protected override ActionExecutedContext InvokeActionMethodWithFilters(
ControllerContext ControllerContext,
IList过滤器,
ActionDescriptor ActionDescriptor,
(字典参数)
{
var builtUpFilters=新列表();
foreach(过滤器中的IActionFilter actionFilter)
{
builtUpFilters.Add(_container.build(actionFilter));
}
返回base.InvokeActionMethodWithFilters(controllerContext、builtUpFilters、actionDescriptor、参数);
}
下面是正在构建的一个ActionFilter的示例:
public class PopulatRolesAttribute : ActionFilterAttribute, IActionFilter
{
private const string RolesKey = "roles";
[Dependency]
public Func<IMetadataService> Service { get; set; }
public PopulatRolesAttribute()
{
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.Controller.ViewData[RolesKey] == null)
{
filterContext.Controller.ViewData[RolesKey] = Service().GetRoles();
}
}
}
public类populateRolesAttribute:ActionFilterAttribute,IActionFilter
{
私有常量字符串RolesKey=“roles”;
[依赖性]
公共函数服务{get;set;}
公共PopulatorLesAttribute()
{
}
公共覆盖无效OnActionExecuting(ActionExecutingContext filterContext)
{
if(filterContext.Controller.ViewData[RolesKey]==null)
{
filterContext.Controller.ViewData[RolesKey]=Service().GetRoles();
}
}
}
问题是,我的自定义ActionFilterAttribute上的公共属性从未注入任何内容,它在执行时仍然为null!我看不出为什么容器没有正确构建过滤器。正在注入的类型已正确注册,如下所示:
container.RegisterInstance(new ChannelFactory<IMetadataService>(
new BasicHttpBinding(),
new EndpointAddress("http://example.com/ABSApplication/MetadataService.svc")));
container.RegisterInstance<Func<IMetadataService>>(
() => container.Resolve<ChannelFactory<IMetadataService>>().CreateChannel());
container.RegisterInstance(新通道工厂)(
新的BasicHttpBinding(),
新端点地址(“http://example.com/ABSApplication/MetadataService.svc")));
容器.RegisterInstance(
()=>container.Resolve().CreateChannel());
并且也被注入到应用程序的其他地方(尽管不是通过.build)。这与下面的过程差不多。我错过了拼图的哪一部分?我会稍微改变一下。我想:
protected void Application_Start() {
// ...
var oldProvider = FilterProviders.Providers.Single(
f => f is FilterAttributeFilterProvider
);
FilterProviders.Providers.Remove(oldProvider);
var container = new UnityContainer();
var provider = new UnityFilterAttributeFilterProvider(container);
FilterProviders.Providers.Add(provider);
// ...
}
过滤器本身:
using System;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
public class InjectedFilterAttribute : ActionFilterAttribute {
[Dependency]
public IMathService MathService { get; set; }
public override void OnResultExecuted(ResultExecutedContext filterContext) {
filterContext.HttpContext.Response.Write(
String.Format("The filter says 2 + 3 is {0}.",
MathService.Add(2, 3))
);
}
}
我很欣赏Unity.Mvc3包的方向——它很好地使用Unity封装了Mvc3的依赖项解析。然而,我不认为它解决了我的问题。如果我在控制器中有一个用过滤器修饰的方法,比如:
[PopulatRoles]public ActionResult Add(){
如何在PopulateRoles ActionFilterAttribute上实现注入?我不能使用构造函数注入,因为它是一个属性,也不能使用它的构造函数。因此,我需要在创建属性时构建它。作为附录,我看到ninject做了完全不同的事情,允许构造函数注入关于过滤器,但是我不确定这是否可以通过Unity实现。过滤器是在MVC内部解决的,我必须在这里尝试一个快速测试。实际上,这应该在这里起作用-在聚会上很晚才尝试,但是Unity Bootstrapper for ASP.NET MVC
包为您完成了所有这些工作。出于好奇,我为什么不这样做呢例如,验证请求、预授权请求等并缓存它们(会话等)因此,当用户登录时,每个请求都有它们?我的初衷是封装此功能,以便在操作需要时添加它。如果经过审查,我打算大量使用过滤器检索的数据,我肯定会全局缓存它,以便在整个应用程序中重用。这是实际上,不管如何重用,这看起来都是一个更简单的解决方案!我仍然很好奇为什么容器。但是,构建不起作用。我确实找到了这个示例,很快就会查看它。源代码也可以在那里下载,我看到了那篇文章,这促使我进一步提出问题这里。查看那篇文章中的代码,它似乎有点不完整。我看不到自定义IFilterProvider连接在哪里。当然,仅仅在容器中注册它是不够的,它不能被使用。它确实避免了上面使用Building发布的问题。如果我不能很快得到关于为什么Building不能在orig中工作的响应最后,我将接受您的回答,因为我很感谢您确认我的想法与其他开发人员的想法相同:)
using System.Collections.Generic;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
public class UnityFilterAttributeFilterProvider : FilterAttributeFilterProvider {
private IUnityContainer _container;
public UnityFilterAttributeFilterProvider(IUnityContainer container) {
_container = container;
}
protected override IEnumerable GetControllerAttributes(
ControllerContext controllerContext,
ActionDescriptor actionDescriptor) {
var attributes = base.GetControllerAttributes(controllerContext,
actionDescriptor);
foreach (var attribute in attributes) {
_container.BuildUp(attribute.GetType(), attribute);
}
return attributes;
}
protected override IEnumerable GetActionAttributes(
ControllerContext controllerContext,
ActionDescriptor actionDescriptor) {
var attributes = base.GetActionAttributes(controllerContext,
actionDescriptor);
foreach (var attribute in attributes) {
_container.BuildUp(attribute.GetType(), attribute);
}
return attributes;
}
}