ASP.NET MVC: регистрировать фильтр действий без изменения контроллера
Я работаю с nopCommerce, и мне нужно добавить в свой единственный Action Filter, однако я не хочу изменять основные контроллеры, чтобы избежать перезаписывания моего кода при выпуске нового обновления.
Я установил свой фильтр действий:
public class ProductActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result is ViewResult)
{
...
}
base.OnActionExecuted(filterContext);
}
}
Если бы я должен был изменить контроллер, я мог бы просто добавить [ProductActionFilter]
к действию, которое я хочу, чтобы оно было назначено.
Есть ли способ зарегистрировать свой настраиваемый Action Filter для конкретного действия без изменения контроллера?
Ответы
Ответ 1
Я думаю, что вам нужны глобальные фильтры.
Как только вы создали фильтр, зарегистрируйте его в файле 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 позволяет применять Глобальные фильтры действий. Конечно, для этого требуется, чтобы nopCommerce была построена на MVC 3, и я считаю, что самая новая версия?
Ответ 3
В 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; }
}
}
Ответ 4
Как насчет создания частичного класса. Начиная с версии 2.60 все контроллеры являются частичными:
public partial class CatalogController : BaseNopController
Вы можете поместить фильтр в класс и затем запросить имя действия.