1

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

5 Answers 5

3

This depends on what the appropriate time is.

See my original blog post

Or read the other pages of the doc:

(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)
Sign up to request clarification or add additional context in comments.

2 Comments

One quick question.. say I want to use it for another controller as well... LabTests Controller... should I just duplicate the binding and change PhysicalTestsController to LabTestsController or there is a way to define all the conditions in the same command?
Just change the Func you pass to When so that it returns true for both controllers. Or change to WhenControlerHas<SomeAttribute> and add the attribute to all controllers you want to apply this to. Read the doc for more info.
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.

2 Comments

Yes, that is one way and I appreciate your answer... however, taken from the ninject wiki itself " While injection of filter attributes is still supported it is recommended using this new pattern for filter configuration because it has the advantage to support constructor injection and does not require the InjectAttribute anymore."
-1 Constructor injection isn't possible for attributes because they are not created by ninject but the .NET Framework. Because of this using attributes isn't a good way for dependency injection.
2
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 Comments

Why reinventing the wheel if there is an even more powerful implementation available from the Ninject.MVC3 extension?
One simple binding does the same: kernel.BindFilter<AllowedToEditEHRFilter>(FilterScope.Controller, 0).When((controllerContext, actionDescriptor) => controllerContext.Controller is PhysicalTestsController)
I have NinjectMVC3 nuget package installed and there doesnt seem to be a BindFilter method at all... :s
Nevermind I just needed to add the Ninject.Web.Mvc.FilterBindingSyntax namespace!... it works beatifully.
1

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.

Comments

0

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
{
    // ...
}

2 Comments

Good catch - I didn't spot that he inherits the wrong type as well.
I dont want to do that cause then I cant inject dependencies into the filter. github.com/ninject/ninject.web.mvc/wiki/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.