ASP.NET MVC: зарегистрировать фильтр действий без изменения контроллера - PullRequest
20 голосов
/ 09 января 2012

Я работаю с nopCommerce и мне нужно добавить свой единственный фильтр действий, однако я не хочу изменять основные контроллеры, чтобы избежать перезаписи моего кода при выпуске нового обновления.

Я настроил свой фильтр действий:

public class ProductActionFilterAttribute : ActionFilterAttribute
{

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

}

Если бы я изменил контроллер, я мог бы просто добавить [ProductActionFilter] к действию, которое я хочу назначить.

Есть ли способ, которым я могу зарегистрировать свой собственный фильтр действий для определенного действия без изменения контроллера?

Ответы [ 5 ]

30 голосов
/ 09 января 2012

Мне кажется, вам нужны глобальные фильтры.

После создания фильтра зарегистрируйте его в global.asax:

protected void Application_Start() {

    AreaRegistration.RegisterAllAreas();

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

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

Добавьте пользовательскую логику проверки в фильтр, если вы хотите применить ее не ко всем действиям.

2 голосов
/ 19 февраля 2015

В 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; }
    }
}
2 голосов
/ 09 января 2012

Если вы хотите, чтобы ваш фильтр регистрировался для каждого действия (или в противном случае это нормально), тогда MVC 3 позволяет применять Глобальные фильтры действий . Конечно, для этого требуется, чтобы nopCommerce была построена на MVC 3, что, я считаю, является самой новой версией?

0 голосов
/ 24 марта 2019

Этот подход работает для NopCommerce 4.10

Этот код перенаправит запросы "/ Register" с помощью метода "GET" на действие "YourCustomAction" внутри "YourCustomController".

Шаг 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);
        }
    }
}

При таком подходе вы можете сократить процесс регистрации и добавить дополнительную проверку / процесс, после чего вы можете перейти к процессу регистрации.

0 голосов
/ 03 октября 2012

Как насчет создания частичного класса. Начиная с версии 2.60 все контроллеры являются частичными:

public partial class CatalogController : BaseNopController

Вы можете поместить фильтр в класс и затем запросить имя действия.

...