Ninject 到动作过滤器中

2023-12-28

我创建了一个自定义操作过滤器,并将其与 Ninject 的 BindFilter 方法绑定:

public class ExtendModelAttribute : FilterAttribute {}

public class ExtendModelFilter : IActionFilter
{
    private IKernel kernel;
    public ExtendModelFilter(Func<IKernel> kernel)
    {
        this.kernel = kernel;
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // TODO:
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
    }
}

我像这样绑定我的过滤器:

 kernel.BindFilter<ExtendModelFilter>(FilterScope.Action, 0).WhenActionMethodHas<ExtendModelAttribute>();

到目前为止一切都进展顺利。我想要完成的任务如下:

[ExtendModel]
public ActionResult Index()
{
    return View(new IndexModel());
}

我希望 ExtendModel 过滤器做的是确定正在使用的模型类型,然后找到正确的依赖项:

public interface IModelExtender<TModel> {
    void Extend(TModel model);
}

public class IndexModelExtender : IModelExtender<IndexModel> {
    public void Extend(IndexModel model)
    {
        // extend the model here with anything extra that is required
    }
}

我不确定如何在操作过滤器中编写代码来获取 IModelExtender 的实例:

public void OnActionExecuted(ActionExecutedContext filterContext)
{
    // TODO:
    // I Need to look at the filterContext Model to determine which 
    // type of IModelExtender<T> to create:
    // For Example, when [ExtendModel] is applied on the Index() method above
    // then I need it to resolve to IndexModelExtender
}

也许我想做的事情根本不可能实现?由于我在编译时不知道 T 是什么,有什么办法可以做到我想要的吗?

EDIT
以下是 ModelExtender 可能执行的操作的示例:

public class IndexModelExtender : IModelExtender<IndexModel>
{
    public IndexModelExtender(IFooRepository fooRepository, IBarRepository barRepository)
     {
        // ...
     }

     public void Extend(IndexModel model)
     {
         model.SelectList1 = new SelectList(fooRepository.GetFoos(), "Description", "Id");
         model.SelectList2 = new SelectList(barRepository.GetBars(), "Description", "Id");
     }
}

我想避免在我的控制器中出现这样的代码:

 public ActionResult Index()
 {
     var model = new IndexModel();
     // populate select lists here
     return View(model);
 }

 [HttpPost]
 public ActionResult Index(IndexModel model)
 {
     if(!ModelState.IsValid ) {
        // populate the same stuff here
     }
  }

您将必须使用反射,因为模型类型仅在运行时已知,并且您的扩展程序是通用的:

public class ExtendModelFilter : IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        object model = null;
        if (filterContext.Result is ViewResultBase)
        {
            model = ((ViewResultBase)filterContext.Result).Model;
        }
        else if (filterContext.Result is JsonResult)
        {
            model = ((JsonResult)filterContext.Result).Data;
        }
        // TODO: you could continue with the else if here to take
        // into account some other action results that have the notion of model
        // like for example some custom action results that you might have written

        if (model == null)
        {
            // we have no model => nothing to extend
            return;
        }

        var extenderType = typeof(IModelExtender<>).MakeGenericType(model.GetType());
        var extender = DependencyResolver.Current.GetService(extenderType);
        var extend = extenderType.GetMethod("Extend");
        extend.Invoke(extender, new[] { model });
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
    }
}

您还会注意到,我重构了自定义操作过滤器,以便使用当前的依赖项解析器并使其与 NInject 无关。你当然可以保留IKernel如果您愿意的话,可以依赖。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Ninject 到动作过滤器中 的相关文章

随机推荐