在MVC中,AOP是很常用的功能,我们经常会使用如 ActionFilter,IAuthorizeFilter 等描述对Controller和Action进行约束和扩展,一般做法如下:

public class TestActionFilterAttribute : Attribute, IActionFilter
{ public void OnActionExecuted(ActionExecutedContext context)
{
if (context.HttpContext.Request.Query.TryGetValue("id", out StringValues value))
{
Console.WriteLine(value.First());
}
else
{
context.HttpContext.Response.Redirect("/Error/404");
}
} public void OnActionExecuting(ActionExecutingContext context)
{ }
}

上面的代码很简单,就是判断请求中是否包含id参数,如果有,则打印id;如果没有,则跳转到错误页面。用法也很简单,在需要约束的Action上添加[TestActionFilter]即可。

[TestActionFilter]
public IActionResult Index()
{
return View();
}

这是Filter最基本的用法,但是,如果我们需要在Filter中使用注入的服务怎么办?比如说修改下 TestActionFilterAttribute:

public class TestActionFilterAttribute : Attribute, IActionFilter
{
private readonly ILogger _logger; public TestActionFilterAttribute(ILoggerFactory logger)
{
_logger = logger.CreateLogger("TestActionFilterAttribute");
} public void OnActionExecuted(ActionExecutedContext context)
{
var path = context.HttpContext.Request.Path;
_logger.LogDebug($"{path} 开始运行了");
} public void OnActionExecuting(ActionExecutingContext context)
{ }
}

我们在Filter的构造函数中注入ILoggerFactory参数,这是系统默认提供的日志工厂服务,用来在控制台打印消息。

回到Controller文件,发现[TestActionFilter]报错:未提供与"TestActionFilterAttribute"的必需形参logger对应的实参。好吧,下面我们尝试构造一个logger对象

public class HomeController : Controller
{
private readonly ILoggerFactory _loggerFactory; public HomeController(ILoggerFactory factory)
{
_loggerFactory = factory;
} [TestActionFilter(_loggerFactory)]
public IActionResult Index()
{
return View();
}
}

修改过后,继续报错:特性构造函数参数"logger"具有类型ILoggerFactory,这不是有效特性参数类型。由此可见,如果在Filter中需要注入服务,常规的方式是无法实现的。

如果一定需要调用注入服务该怎么实现呢?其实框架已经为我们提供了两种途径:TypeFilter和ServiceFilter

public class TestTypeFilter : IActionFilter
{
private readonly ILogger _logger; public TestTypeFilter(ILoggerFactory logger)
{
_logger = logger.CreateLogger("TestTypeFilter");
} public void OnActionExecuted(ActionExecutedContext context)
{
var path = context.HttpContext.Request.Path;
_logger.LogDebug($"{path} 开始运行了");
} public void OnActionExecuting(ActionExecutingContext context)
{ }
}

这里的代码和上面修改过的TestActionFilterAttribute一模一样,修改下Controller文件:

[TypeFilter(typeof(TestTypeFilter))]
public IActionResult Index()
{
return View();
}

运行测试,效果如下:

可以看到,代码运行正常。

下面再看看ServiceFilter的用法,新建文件 TestServiceFilter

public class TestServiceFilter : IActionFilter
{
private readonly ILogger _logger; public TestServiceFilter(ILoggerFactory logger)
{
_logger = logger.CreateLogger("TestServiceFilter");
} public void OnActionExecuted(ActionExecutedContext context)
{
var path = context.HttpContext.Request.Path;
_logger.LogDebug($"{path} 开始运行了");
} public void OnActionExecuting(ActionExecutingContext context)
{ }
}

修改Controller文件:

//[TypeFilter(typeof(TestTypeFilter))]
[ServiceFilter(typeof(TestServiceFilter))]
public IActionResult Index()
{
return View();
}

仅仅这样是不够的,顾名思义,ServiceFilter(服务过滤器),我们需要到startup.cs的ConfiguraionServices中注册TestServiceFilter:

services.AddSingleton<TestServiceFilter>();

运行测试,效果如下:

OK,运行正常!

下面是补充内容,添加一个全局异常过滤器:

新建文件 MvcGlobalExceptionFilter.cs

public class MvcGlobalExceptionFilter : IExceptionFilter
{
private readonly ILogger _logger; public MvcGlobalExceptionFilter(ILoggerFactory logger)
{
_logger = logger.CreateLogger("MvcGlobalExceptionFilter");
} public void OnException(ExceptionContext context)
{
// 全局异常的错误处理
_logger.LogError(context.Exception, "全局异常");
}
}

修改Startup.cs中的ConfigurationServices:

services.AddMvc(options =>
{
// 添加全局异常
options.Filters.Add<MvcGlobalExceptionFilter>();
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

修改Controller文件,手动抛出异常:

[ServiceFilter(typeof(TestServiceFilter))]
public IActionResult Index()
{
throw new Exception("异常测试,这是手动抛出的异常");
return View();
}

运行测试,效果如下:

可以看到,我们定义的过滤器捕获并打印了异常信息。

最新文章

  1. 我的angularjs源码学习之旅2——依赖注入
  2. delphi之TDataset
  3. 关于激活Bentley软件详细步骤介绍(再补充一个)
  4. windows多线程框架
  5. C语言与MATLAB接口 编程与实例 李传军编着
  6. 黄聪:如何删除wordpress登录之后wp_footer、wp_head自行加载的Open Sans字体、fonts.googleapis.com连接导致卡死的问题
  7. 使用Handler和Timer+Timertask实现简单的图片轮播
  8. 《自己动手写操作系统》pmtest2笔记
  9. c#装B指南
  10. python字符串操作(连接、比较、格式化等)(转)
  11. Error 1937.An error occurred during the installation of assembly...
  12. android弧形进度条,有详细注释的,比较简单
  13. Python的基本配置
  14. [转]数位dp小记
  15. Goffi and Squary Partition
  16. logback KafkaAppender 写入Kafka队列,集中日志输出.
  17. Django目录
  18. win7 升级Power Shell到4.0
  19. npm i 和 npm install 的区别
  20. SQL 并联更新

热门文章

  1. HDU2829 Lawrence —— 斜率优化DP
  2. BZOJ 1621 [Usaco2008 Open]Roads Around The Farm分岔路口:分治 递归
  3. struts2 小例子(教训篇)
  4. Idea中的插件-列出Java Bean的所有set方法
  5. 启动jmeter报错
  6. LeetCode 889. Construct Binary Tree from Preorder and Postorder Traversal
  7. codevs 1154 能量项链
  8. JavaWeb----文件的上传和下载
  9. C++之PIMPL模式
  10. MT8735A平台配置MT6630