Ninject в фильтре действий - PullRequest
       3

Ninject в фильтре действий

3 голосов
/ 21 февраля 2012

Я создал собственный фильтр действий и привязываю его с помощью метода BindFilter от Ninject:

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

1 Ответ

4 голосов
/ 21 февраля 2012

Вам придется использовать отражение, потому что тип модели известен только во время выполнения, а ваш расширитель является общим:

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, если хотите.

...