Ninject in an Action Filter

半腔热情 提交于 2019-12-07 14:26:09

问题


I have created a custom Action Filter and am binding it with Ninject's BindFilter method:

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)
    {
    }
}

I am binding my filter like so:

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

Everything so far is working great. What I want to accomplish is the following:

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

What I want the ExtendModel filter to do is determine what type of Model is being used and then find the correct dependency:

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
    }
}

I'm not sure how to write the code in the action filter to get an instance of 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
}

Maybe what I want to do isnt' even possible? Since I don't know at compile time what T is, is there any way to do what I want?

EDIT
Here is an example of what a ModelExtender might do:

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");
     }
}

I want to avoid code like this in my controller:

 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
     }
  }

回答1:


You will have to use reflection because the model type is known only at runtime and your extender is generic:

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)
    {
    }
}

You will also notice that I have refactored the custom action filter in order to use the current dependency resolver and make it NInject agnostic. You could of course keep the IKernel dependency if you prefer.



来源:https://stackoverflow.com/questions/9381557/ninject-in-an-action-filter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!