ASP.NET MVC:在不修改控制器的情况下注册操作筛选器

本文关键字:情况下 注册 操作 筛选 控制器 修改 MVC NET ASP | 更新日期: 2023-09-27 18:19:57

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

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

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

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

有没有一种方法可以在不修改控制器的情况下将自定义操作筛选器注册到特定操作?

ASP.NET MVC:在不修改控制器的情况下注册操作筛选器

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

创建过滤器后,将其注册到global.asax:中

protected void Application_Start() {
    AreaRegistration.RegisterAllAreas();
    // Register global filter
    GlobalFilters.Filters.Add(new MyActionFilterAttribute());
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes); 
}

如果您不想将自定义验证逻辑应用于所有操作,请添加自定义验证逻辑以进行筛选。

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

在NopCommerce Nop3.5(截至本答案的最新版本,比问题日期更新)中,我发现添加全局操作过滤器的最佳方法是创建一个包含IStartupTask实现的插件。这种方法完全避免了更改任何NopCommCommerce核心文件。

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

此方法适用于NopCommerce 4.10

此代码将使用"GET"方法将"/Register"请求重定向到"YourCustomController"内的"YourCustom action"操作。

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

有了这种方法,你可以减少注册过程,增加一些额外的检查/流程,然后你就可以继续注册过程了。

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

public partial class CatalogController : BaseNopController

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