Help with action filters in asp.net mvc 3

2019-07-27 23:39发布

问题:

I want to create an action filter that will be used by ONLY two controllers in my app... This action filter is supposed to be checked for every action inside the TWO controllers.

Heres my action filter code

public class AllowedToEditEHRFilter : IActionFilter
    {
        IUnitOfWork unitOfWork;
        IRepository<EHR> ehrRepository;
        public AllowedToEditEHRFilter(IUnitOfWork dependency)
        {
            unitOfWork = dependency;
            ehrRepository = unitOfWork.EHRs;
        }

        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            int ehrId;
            if (int.TryParse(filterContext.HttpContext.Request.QueryString["ehrId"], out ehrId))
            {
                EHR ehr = ehrRepository.FindById(ehrId);
                if (ehr.UserName != Membership.GetUser().UserName)
                    filterContext.Result = new ViewResult { ViewName = "InvalidOwner" };
            }
        }
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {

        }
    }

Now Im just not sure how can I configure MVC framework so that the action filter gets triggered at the appropriate times.

Im using this as reference but that is applying a GLOBAL actionfilter and it doesnt specify how to limit to just some of your controllers.

Please help.

btw Im using NinjectMVC3

回答1:

This depends on what the appropriate time is.

See my original blog post

  • http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for-mvc3/

Or read the other pages of the doc:

  • https://github.com/ninject/ninject.web.mvc/wiki/Conditional-bindings-for-filters
  • https://github.com/ninject/ninject.web.mvc/wiki/Filter-configurations

(Probably I should link them)

Basically you need to configure a binding for the filter and define some condition:

kernel.BindFilter<AllowedToEditEHRFilter>(FilterScope.Action, 0).When...

e.g.

.WhenActionHas<AllowedToEditEHRAttribute>()

Update: In your case simply

kernel.BindFilter<AllowedToEditEHRFilter>(FilterScope.Controller, 0).When(
    (controllerContext, actionDescriptor) =>  
     controllerContext.Controller is PhysicalTestsController)


回答2:

To apply the action filter to only some of your controllers, simply add the attribute to the controllers in question.

[AllowedToEditEHR]
public class YourController : Controller
{
    ...

For this to work, you should rename your filter to AllowedToEditEHRAttribute, i.e. replace "Filter" by "Attribute". This is a standard naming convention for attributes.

Update: To inject dependencies in the filter, just decorate it's constructor with the [Inject] attribute.



回答3:

public class AllowedToEditEHRFilter : IActionFilter
    {
        IUnitOfWork unitOfWork;
        IRepository<EHR> ehrRepository;

        public AllowedToEditEHRFilter(IUnitOfWork dependency)
        {
            unitOfWork = dependency;
            ehrRepository = unitOfWork.EHRs;
        }

        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            int ehrId;
            if (int.TryParse(filterContext.ActionParameters["ehrId"].ToString(), out ehrId))
            {
                EHR ehr = ehrRepository.FindById(ehrId);
                if (ehr.UserName != Membership.GetUser().UserName)
                    filterContext.Result = new ViewResult { ViewName = "InvalidOwner" };
            }
        }
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {

        }
    }

And the CustomFilterProvider

public class ConfiguredFilterProvider : IFilterProvider
    {
        private readonly IKernel _kernel;

        public ConfiguredFilterProvider(IKernel kernel)
        {
            _kernel = kernel;
        }

        public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            List<Filter> list = new List<Filter>();
            if (controllerContext.Controller is PhysicalTestsController)
            {

                list.Add(new Filter(
                            _kernel.Get(typeof(AllowedToEditEHRFilter)),
                            FilterScope.Global, order: null
                        ));
            }
            return list;
        }
    }

And in Ninject

kernel.Bind<IFilterProvider>()
              .To<ConfiguredFilterProvider>();

It might not be the cleanest solution but its working.



回答4:

You just have to decorate that two controllers with the action filter like this

[AllowedToEditEHRFilter]
public class YourController : Controller
{
    ...
}

However, I am not sure if it is allowed to have a complex object passed in a constructor of that filter.



回答5:

Instead of implementing IActionFilter, extend ActionFilterAttribute and then assign the attribute to the two controllers you want to affect:

public class AllowedToEditEHRFilter : ActionFilterAttribute
{
    // ...
}

and:

[AllowedToEditEHRFilter]
public class MyController : Controller
{
    // ...
}