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

问题描述 投票:19回答:5

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

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

public class ProductActionFilterAttribute : ActionFilterAttribute
{

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

}

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

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

c# asp.net-mvc action-filter
5个回答
30
投票

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

一旦你创建了过滤器,就在global.asax中注册它:

protected void Application_Start() {

    AreaRegistration.RegisterAllAreas();

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

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

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


2
投票

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


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

0
投票

怎么样创建一个部分类。从版本2.60开始,所有控制器都是部分控制器:

public partial class CatalogController : BaseNopController

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


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

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

© www.soinside.com 2019 - 2024. All rights reserved.