在ASP.NET Core MVC 1.0.1(ASP.NET Core 1.1)中覆盖控制器/操作中的全局操作筛选器

时间:2017-03-09 14:00:08

标签: c# asp.net-core asp.net-core-mvc

我正在构建一个ASP.NET Core MVC应用程序,并且我正在尝试创建一个全局操作过滤器,记录执行操作所花费的时间(它应该只记录花费的时间是否高于某个阈值)。我已成功完成此操作但现在我希望能够说单个操作或单个控制器应具有不同的阈值。当我尝试这个时,我的动作过滤器被应用了两次(这不是我想要的)但是具有正确的两个不同的阈值。

我尝试过很多东西并四处寻找。在MVC 3和MVC 4项目中,我使用Global.asax中的RegisterGlobalFilters()成功完成了这项工作,当我在控制器/操作上使用该属性时,它会自动覆盖全局的项目。我也试过这篇文章中列出的方法,但没有运气:

Override global authorize filter in ASP.NET Core MVC 1.0

我的ActionFilterAttribute的代码:

public class PerformanceLoggingAttribute : ActionFilterAttribute
{
    public int ExpectedMax = -1; // Log everything unless this is explicitly set
    private Stopwatch sw;

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        sw = Stopwatch.StartNew();
    }

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        sw.Stop();
        if (sw.ElapsedMilliseconds >= ExpectedMax)
        {
            // Log here
        }
    }

    //public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    //{
    //    // If there is another performance filter, do nothing
    //    if (context.Filters.Any(item => item is PerformanceLoggingAttribute && item != this))
    //    {
    //        return Task.FromResult(0);
    //    }
    //    return base.OnActionExecutionAsync(context, next);
    //}
}

我在Startup.cs中应用了这个全局过滤器:

services.AddMvc(options =>
            {
                if (_env.IsProduction()) options.Filters.Add(new RequireHttpsAttribute());
                //options.Filters.Add(new PerformanceLoggingFilter() { ExpectedMax = 1 }); // Add Performance Logging filter
                options.Filters.Add(new PerformanceLoggingAttribute() { ExpectedMax = 1 }); // Add Performance Logging filter
            });

在我的控制器中,我正在应用属性:

//[TypeFilter(typeof(PerformanceLoggingFilter))]
[PerformanceLogging(ExpectedMax = 2)]
public IActionResult Index()
{
    var vm = _performanceBuilder.BuildPerformanceViewModel();
    return View(vm);
}

从上面的代码片段可以看出,我已经尝试过OnActionExecutionAsync方法,我也尝试了IActionFilter,并使用[TypeFilter(typeof(PerformanceLoggingFilter))]进行操作,但没有运气。

任何人都可以帮助我吗?

2 个答案:

答案 0 :(得分:1)

建议您使用一个操作过滤器和其他自定义属性,尝试实现一些不同的实现:

  • 创建一个新的简单属性(我们将其命名为ExpectedMaxAttribute),它只保存ExpectedMax值。将此属性应用于具有不同值的控制器操作。

  • 将您的PerformanceLogging操作过滤器保持为全局,但修改实现。在OnActionExecuted方法上检查控制器的操作是否为ExpectedMaxAttribute。如果是,则从属性中读取ExpectedMax值,否则使用操作过滤器中的默认值。

另外,我建议您根据惯例命名PerformanceLoggingActionFilter来重命名动作过滤器。

答案 1 :(得分:0)

我得到了它的工作,感谢上面@ Set的答案和这个答案: https://stackoverflow.com/a/36932793/5762645

我最终得到了一个应用于所有操作的全局操作,然后有一个简单的ExpectedMaxAttribute,我将其置于阈值应该不同的操作上。在我的全局操作过滤器的OnActionExecuted中,然后我检查有问题的操作是否附加了ExpectedMaxAttribute,然后从中读取ExpectedMax。以下是我的属性:

public class PerformanceLoggingExpectedMaxAttribute : ActionFilterAttribute
{
    public int ExpectedMax = -1;
}

我添加到ActionFilter的OnActionExecuted部分:

 public override void OnActionExecuted(ActionExecutedContext context)
 {
     sw.Stop();
     foreach (var filterDescriptor in context.ActionDescriptor.FilterDescriptors)
     {
         if (filterDescriptor.Filter is PerformanceLoggingExpectedMaxAttribute)
         {
             var expectedMaxAttribute = filterDescriptor.Filter as PerformanceLoggingExpectedMaxAttribute;
             if (expectedMaxAttribute != null) ExpectedMax = expectedMaxAttribute.ExpectedMax;
             break;
         }
     }
     if (sw.ElapsedMilliseconds >= ExpectedMax)
     {
         _logger.LogInformation("Test log from PerformanceLoggingActionFilter");
     }
 }