C# ASP.NET MVC:在不修改控制器的情况下注册动作过滤器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8786192/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 04:25:20  来源:igfitidea点击:

ASP.NET MVC: Register action filter without modifying controller

c#asp.net-mvcaction-filter

提问by Dan Ellis

I'm working with nopCommerce and I need to add in my only Action Filter, however, I don't want to modify the core controllers to avoid my code being overwritten when a new update is released.

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

I've setup my Action Filter:

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

public class ProductActionFilterAttribute : ActionFilterAttribute
{

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

}

If I were to modify the controller, I could just add [ProductActionFilter]to the action I want it assigned to.

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

Is there a way I can register my custom Action Filter to a specific action without modifying the controller?

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

采纳答案by sashaeve

I think global filters is what you need.

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

Once you created the filter register it in the global.asax:

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

protected void Application_Start() {

    AreaRegistration.RegisterAllAreas();

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

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

Add custom validation logic to filter if you want to apply it not to all actions.

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

回答by rfmodulator

If you want your filter to be registered for every action (or it is otherwise OK to do so), then MVC 3 allows you to apply Global action filters. Of course this requires that nopCommerce is built on MVC 3, which I believe the newest version is?

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

回答by Carlos Martinez T

What about creating a partial class. As of version 2.60 all controllers are partials:

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

public partial class CatalogController : BaseNopController

You can put the filter to the class and then query the action name.

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

回答by ulty4life

In NopCommerce 3.5 (the latest as of this answer, and newer than the question date), the best way I've found to add a global action filter is by creating a plugin with an IStartupTaskimplementation in it. This method completely avoids altering any NopCommerce core files.

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

The NopCommerce Application_Startevent initializes the EngineContext, which creates the NopEngineinstance. The NopEngineinitialization finds all IStartupTaskimplementations, and executes them in their specified order. So an IStartupTaskis the place to do anything that needs to happen on application start.

NopCommerceApplication_Start事件初始化EngineContext,从而创建NopEngine实例。在NopEngine初始化找到所有IStartupTask的实现,并在其指定的顺序执行它们。所以一个IStartupTask地方可以做任何需要在应用程序启动时发生的事情。

Sample code below:

示例代码如下:

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

回答by zekeriya kocairi

This approach works for NopCommerce 4.10

这种方法适用于 NopCommerce 4.10

This code will redirect "/Register" requests with "GET" Method to "YourCustomAction" action inside "YourCustomController".

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

Step 1: implement INopStartup

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

Step 2 :

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

With this approach, you can cut down the registration process and add some extra check/process then you can go on the registration process.

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