Mbp应用服务层的AOP实现

实现方法:asp.net core mvc 筛选器 + 中间件

日志,事务,和接口返回结果统一格式化采用操作筛选器,而异常处理采用中间件来处理.

最开始,我是打算用autofac的高级特性的拦截器来做AOP的,但是遇到一个问题,poco controller没办法注入到autofac的容器里面.导致拦截器不能正常工作,所以就采用了筛选器来做.这里的场景有以下几个:

  • AOP是在应用层,而应用层是用poco controller做的,而在asp.net core web api的基架中,controller处在管线的末端.所以可以在这层进行全局拦截.
  • 中间件处理异常更加灵活,可以有更多的定制化需求,而异常筛选器是响应抓捕的异常来处理,它相当于是异常发生后的一个处理程序,而中间件可以来实现类似异常筛选器.
  • 中间件不短路,只是在程序运行的管线上添加了try catch,同时也解决了异步方法出现的异常无法被捕获的问题.

实现代码

  • Mbp.AspNetCore.Filter 添加MbpLogFilter,MbpTransActionFilter,ResponseMiddleware三个操作筛选器
  • Mbp.AspNetCore.Middleware 添加MbpGlobaExceptionMiddleware中间件
  • 在模块MbpAspNetCoreModule中注册筛选器和中间件
public override IServiceCollection AddServices(IServiceCollection services)
{
services.AddMvc().AddNewtonsoftJson(options =>
{
// 忽略循环引用
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
// 不使用驼峰
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
// 设置时间格式
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
}).AddMvcOptions(options =>
{
// 禁用Version的绑定
options.ModelMetadataDetailsProviders.Add(new ExcludeBindingMetadataProvider(typeof(System.Version))); // 统一事务处理中间件
options.Filters.Add(typeof(MbpTransActionFilter)); // 统一日志处理中间件
options.Filters.Add(typeof(MbpLogFilter)); // 请求响应统一格式处理中间件
options.Filters.Add(typeof(ResponseMiddleware)); }); ; AddAutoWebApi(services, new AutoWebApiOptions()); // 创建Cors策略
services.AddCors(options =>
{
options.AddPolicy("MbpCors",
builder =>
{
builder.WithOrigins(services.BuildServiceProvider().GetService<IConfiguration>().GetSection("AllowedHosts").Value)
.AllowAnyMethod()
.AllowAnyHeader(); ;
});
}); return base.AddServices(services);
} public override void UseModule(IApplicationBuilder app)
{
// 启用跨域请求中间件
app.UseCors("MbpCors"); // 启用应用服务层全局错误处理中间件
app.UseMiddleware(typeof(MbpGlobaExceptionMiddleware)); base.UseModule(app);
}

异常中间件对并发冲突进行单独处理

 public async Task InvokeAsync(HttpContext context, ILogger<MbpGlobaExceptionMiddleware> logger)
{
try
{
// Call the next delegate/middleware in the pipeline
await _next(context);
}
catch (DbUpdateConcurrencyException ex)
{
// 发生冲突时候,牺牲后者.不做具体数据合并操作.提示当前用户数据已经发生修改,需要重试.
logger.LogError("并发冲突:" + ex.Message); context.Response.ContentType = "application/json"; await context.Response.WriteAsync(JsonConvert.SerializeObject(new { Code = 500, Message = "提交并发冲突", Version = "1", Data = new List<object>() }));
}
catch (Exception ex)
{
// 其他异常
logger.LogError($"请求[{context.Request.Path}]发生异常:" + ex.Message); context.Response.ContentType = "application/json"; await context.Response.WriteAsync(JsonConvert.SerializeObject(new { Code = 500, Message = "服务器异常", Version = "1", Data = new List<object>() }));
}
}

代码详细地址:https://github.com/mbpframework/Mbp

最新文章

  1. FlashBuilder项目环境配置
  2. iOS开发之SQLite-C语言接口规范(二) —— Prepared Your SQL Statements
  3. 读取bmp图片数据
  4. [Bug-IOS] - linker command failed with exit code 1 (use -v to see invocation)
  5. java jvm学习笔记八(实现jar包的代码签名)
  6. NOIP2013 货车运输 LCA倍增+最大生成树
  7. Jquery--仿制360右下角弹出窗口
  8. 适合Linux新手的发行版有哪些?
  9. LINUX下SYN攻防战 [转]
  10. python基础dict,集合,文件
  11. 春招实习面经分享(已拿到腾讯春招Offer)
  12. 求链表倒数第n个元素
  13. Object:所有类的超类
  14. Axure无法签出,团队配合时无法导入项目
  15. terraform 配置github module source
  16. nginx实现nginx/tomcat负载均衡
  17. Notepad++的右键菜单
  18. ComboBox Style
  19. bzoj千题计划137:bzoj [CQOI2014]危桥
  20. NOIP差不多可以退役的退役记录

热门文章

  1. pytorch代码调试工具
  2. 我的 2019 年 Python 文章榜单
  3. CodeForces - 1228D
  4. Jenkins配置QQ邮箱发送邮件
  5. Lambda函数到底是个什么
  6. $loj$10222 佳佳的$Fibonacci$ 矩阵快速幂
  7. 认识Web应用框架
  8. bootstrap4.4 Stretched link的使用
  9. Spring中常见的设计模式——模板模式
  10. Django常用字段及参数、事务、数据库查询优化