ASP.NET MVC:注册动作过滤器而不修改控制器

时间:2012-01-09 09:25:37

标签: c# asp.net-mvc action-filter

我正在使用nopCommerce,我需要添加我唯一的Action Filter,但是,我不想修改核心控制器以避免在发布新更新时覆盖我的代码。

我已经设置了动作过滤器:

public class ProductActionFilterAttribute : ActionFilterAttribute
{

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is ViewResult)
        {
            ...
        }
        base.OnActionExecuted(filterContext);
    }

}

如果我要修改控制器,我可以将[ProductActionFilter]添加到我想要分配给它的操作中。

有没有办法可以在不修改控制器的情况下将自定义操作过滤器注册到特定操作?

5 个答案:

答案 0 :(得分:30)

我认为全球过滤器就是您所需要的。

创建过滤器后,在global.asax中注册它:

protected void Application_Start() {

    AreaRegistration.RegisterAllAreas();

    // Register global filter
    GlobalFilters.Filters.Add(new MyActionFilterAttribute());

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes); 
}

如果要将其应用于所有操作,请添加自定义验证逻辑以进行过滤。

答案 1 :(得分:2)

如果您希望为每个操作注册过滤器(或者可以这样做),则MVC 3允许您应用Global action filters。当然这要求nopCommerce建立在MVC 3上,我相信最新版本是?

答案 2 :(得分:2)

在NopCommerce 3.5中(此答案的最新版本,比问题日期更新),我发现添加全局操作过滤器的最佳方法是创建一个IStartupTask实现的插件在里面。此方法完全避免更改任何NopCommerce核心文件。

NopCommerce Application_Start事件会初始化EngineContext,从而创建NopEngine个实例。 NopEngine初始化会查找所有IStartupTask实现,并按指定的顺序执行它们。因此,IStartupTask是执行应用程序启动时需要执行的任何操作的地方。

以下示例代码:

public class Plugin : BasePlugin
{
    public Plugin()
    {
    }

    /// <summary>
    /// Check to see if this plugin is installed
    /// </summary>
    public static bool IsInstalled(ITypeFinder typeFinder)
    {
        IEnumerable<Type> types = typeFinder.FindClassesOfType<IPluginFinder>(true);

        if (types.Count() == 1)
        {
            IPluginFinder plugins = Activator.CreateInstance(types.First()) as IPluginFinder;
            PluginDescriptor descriptor = plugins.GetPluginDescriptorBySystemName("MyPluginName");

            if (descriptor != null && descriptor.Installed)
            {
                return true;
            }
        }

        return false;
    }
}

/// <summary>
/// Redirects to the 404 page if criteria not met
/// </summary>
public class FluffyTextureRequiredAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (Kitten.Texture != Textures.Fluffy)
        {
            var routeValues = new RouteValueDictionary();
            routeValues.Add("controller", "Common");
            routeValues.Add("action", "PageNotFound");

            filterContext.Result = new RedirectToRouteResult(routeValues);
        }
    }
}

/// <summary>
/// Does application start event stuff for the plugin, e.g. registering
/// global action filters
/// </summary>
public class StartupTask : IStartupTask
{
    private ITypeFinder _typeFinder;

    public StartupTask()
    {
        //IStartupTask objects are created via Activator.CreateInstance with a parameterless constructor call, so dependencies must be manually resolved.
        _typeFinder = EngineContext.Current.Resolve<ITypeFinder>();
    }

    public void Execute()
    {
        // only execute if plugin is installed
        if (Plugin.IsInstalled(_typeFinder))
        {
            // GlobalFilters is in System.Web.Mvc
            GlobalFilters.Filters.Add(new FluffyTextureRequiredAttribute());
        }
    }

    public int Order
    {
        get { return int.MaxValue; }
    }
}

答案 3 :(得分:0)

如何创建分部课程。从版本2.60开始,所有控制器都是部分控制器:

public partial class CatalogController : BaseNopController

您可以将过滤器放到类中,然后查询操作名称。

答案 4 :(得分:0)

此方法适用于NopCommerce 4.10

此代码将使用“ GET”方法将“ / Register”请求重定向到“ YourCustomController”中的“ YourCustomAction”操作。

步骤1: 实施INopStartup

 public class NopStartup : INopStartup
 {
        public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
        {
            services.Configure<MvcOptions>(config =>
            {
                config.Filters.Add<YourCustomActionFilter>();
            });
        }

        public void Configure(IApplicationBuilder application)
        {

        }

        public int Order => 0;
    }

第2步:

public class YourCustomActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!(context.ActionDescriptor is ControllerActionDescriptor actionDescriptor)) return;

        if (actionDescriptor.ControllerTypeInfo == typeof(CustomerController) &&
            actionDescriptor.ActionName == "Register" &&
            context.HttpContext.Request.Method == "GET")
        {
                    string controllerName = nameof(YourCustomController).Replace("Controller", "");
                    string actionName = nameof(YourCustomController.YourCustomAction);
                    var values = new RouteValueDictionary(new
                    {
                        action = actionName,
                        controller = controllerName
                    });
                    context.Result = new RedirectToRouteResult(values);
        }
    }
}

使用这种方法,您可以减少注册过程并添加一些额外的检查/过程,然后才能继续进行注册过程。