Search code examples
asp.net-mvcaction-filternopcommerce

Dynamically register custom ActionFilter on ActionMethod with shared name


I'm building a NopCommerce plugin and want to register a custom ActionFilter with a FilterProvider on an ActionMethod that has shared ActionName with other methods.

Here are two of the ActionMethods with same ActionName

[HttpPost, ActionName("Edit")]
[FormValueRequired("cancelorder")]      
public ActionResult CancelOrder(int id)
{...}

[HttpPost, ActionName("Edit")]
[FormValueRequired("captureorder")]      
public ActionResult CaptureOrder(int id)
{...}

In my filter provider I somehow need to separate the CancelOrder method from CaptureOrder:

public class OrderFilterProvider : IFilterProvider
{
    private readonly IActionFilter _actionFilter;

    public OrderFilterProvider(IActionFilter actionFilter)
    {
        _actionFilter = actionFilter;
    }

    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {       
        if (actionDescriptor.ControllerDescriptor.ControllerType == typeof(OrderController) &&
            actionDescriptor.ActionName.Equals("Edit"))
        {
            return new Filter[] 
            { 
                new Filter(_actionFilter, FilterScope.Action, null)
            };
        }

        return new Filter[] { };
    }
}

With this code the filter gets registered on both CancelOrder and CaptureOrder, how can I register it only on the CancelOrder method?

My idea was to separate them based on method name or the parameter value in the FormValueRequired attribute but no luck in finding a way of doing that.

FormValueRequired doesnt have any public properties and looks like:

public class FormValueRequiredAttribute : ActionMethodSelectorAttribute {
private readonly string[] _submitButtonNames;
private readonly FormValueRequirement _requirement;

public FormValueRequiredAttribute(params string[] submitButtonNames):
    this(FormValueRequirement.Equal, submitButtonNames)
{
}

public FormValueRequiredAttribute(FormValueRequirement requirement, params string[] submitButtonNames)
{
    //at least one submit button should be found
    this._submitButtonNames = submitButtonNames;
    this._requirement = requirement;
}
}

And here is what it looks like in my debugger: http://www.tiikoni.com/tis/view/?id=4843369

Is there no way to get the name of the method?


Solution

  • The only difference I can see between those 2 actions is the presence of some custom FormValueRequired attribute which unfortunately you haven't shown nor explain what it does, but I guess it is some action selector. Anyway, you could retrieve this attribute:

    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        if (actionDescriptor.ControllerDescriptor.ControllerType == typeof(OrderController) &&
            actionDescriptor.ActionName.Equals("Edit"))
        {
            // Get the FormValueRequiredAttribute that was used to decorate the action
            var formValueRequiredAttribute = actionDescriptor
                .GetCustomAttributes(typeof(FormValueRequiredAttribute), false)
                .Cast<FormValueRequiredAttribute>()
                .FirstOrDefault();
    
            // if the action was decorated with this attribute we could read the
            // property that was passed to the constructor (hopefully it is exposed
            // as a public property)
            if (formValueRequiredAttribute != null && 
                formValueRequiredAttribute.SomeParameter == "captureorder")
            {
                // The CaptureOrder action was invoked
                return new Filter[] 
                { 
                    new Filter(_actionFilter, FilterScope.Action, null)
                };
            }
        }
    
        return new Filter[] { };
    }