在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();
}

运行测试,效果如下:

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

【aspnetcore】在过滤器(Filter)中使用注入服务(ServiceFilter|TypeFilter)的更多相关文章

  1. java 过滤器Filter中chain.doFilter()之前和之后代码的执行顺序

    过滤器拦截到响应url的请求后会先执行doFilter()方法中chain.doFilter()之前的代码,然后执行下一个过滤器或者servelt.紧接着执行chain.doFilter()之后的代码 ...

  2. .Net Core中依赖注入服务使用总结

    一.依赖注入 引入依赖注入的目的是为了解耦和.说白了就是面向接口编程,通过调用接口的方法,而不直接实例化对象去调用.这样做的好处就是如果添加了另一个种实现类,不需要修改之前代码,只需要修改注入的地方将 ...

  3. FluentValidation 验证(二):WebApi 中使用 注入服务

    比如你要验证用户的时候判断一下这个用户名称在数据库是否已经存在了,这时候FluentValidation 就需要注入查询数据库 只需要注入一下就可以了 public class Login3Reque ...

  4. IoC容器Autofac(5) - Autofac在Asp.net MVC Filter中的应用

    Autofac结合EF在MVC中的使用,上一篇IoC容器Autofac(4) - Autofact + Asp.net MVC + EF Code First(附源码)已经介绍了.但是只是MVC中Co ...

  5. 如何在自定义Filter中优雅的实现静态资源放行

            在javaweb开发中,过滤器Filter比较常用于类似登录的拦截等场景.但是,当过滤器的配置不当时就会把所有的请求都拦截,静态资源也会被拦截掉,导致静态页面加载不出来. 一般的解决方 ...

  6. .NET 使用自带 DI 批量注入服务(Service)和 后台服务(BackgroundService)

    今天教大家如何在asp .net core 和 .net 控制台程序中 批量注入服务和 BackgroundService 后台服务 在默认的 .net 项目中如果我们注入一个服务或者后台服务,常规的 ...

  7. servlet filter中使用autowired无法注入

    问题: 我们为了避免未经授权的人直接通过url访问我们的页面,配置了如下filter <!-- 登录过滤器 --> <filter> <filter-name>se ...

  8. ASP.NET Core中使用自定义MVC过滤器属性的依赖注入

    除了将自己的中间件添加到ASP.NET MVC Core应用程序管道之外,您还可以使用自定义MVC过滤器属性来控制响应,并有选择地将它们应用于整个控制器或控制器操作. ASP.NET Core中常用的 ...

  9. 避免在ASP.NET Core 3.0中为启动类注入服务

    本篇是如何升级到ASP.NET Core 3.0系列文章的第二篇. Part 1 - 将.NET Standard 2.0类库转换为.NET Core 3.0类库 Part 2 - IHostingE ...

随机推荐

  1. CodeChef Forest Gathering —— 二分

    题目链接:https://vjudge.net/problem/CodeChef-FORESTGA 题解: 现场赛.拿到这题很快就知道是二分,但是一直wa,怎么修改也wa,后来又换了种错误的思路,最后 ...

  2. Technocup 2017 - Elimination Round 2 C. Road to Cinema —— 二分

    题目链接:http://codeforces.com/problemset/problem/729/C C. Road to Cinema time limit per test 1 second m ...

  3. 渲染树render tree

    CSSOM树和DOM树连接在一起形成一个render tree,渲染树用来计算可见元素的布局并且作为将像素渲染到屏幕上的过程的输入. DOM树和CSSOM树连接在一起形成render tree . r ...

  4. No result defined for action cn.crm.action.LinkManAction and result input

    这是struts2的一个拦截器报的错误,当你的form中的数据有问题,比如说<input type="text" name="receiverLoginID&quo ...

  5. AutoIt: 如何使用 AutoIt 解析,修改XML 文件

    项目组这次要发布一个项目,需要实施人员根据现场的机器情况,修改项目配置文件的几个节点,为了减轻实施人员的工作负担,我应用AutoIt写了一个小界面,实施人员只需在该界面上点几个按钮,就能够完成文件的配 ...

  6. Azure ARM (22) Azure Policy入门

    <Windows Azure Platform 系列文章目录> 我们知道,在Azure服务层级中,分为以下几个层次: 1.企业合同 2.订阅 3.资源组 4.资源 我们使用的Azure资源 ...

  7. mysql分区表之四:分区表性能

    一,      分区概念  分区允许根据指定的规则,跨文件系统分配单个表的多个部分.表的不同部分在不同的位置被存储为单独的表.MySQL从5.1.3开始支持Partition. 分区和手动分表对比 手 ...

  8. kafka之三:kafka java 生产消费程序demo示例

    kafka是吞吐量巨大的一个消息系统,它是用scala写的,和普通的消息的生产消费还有所不同,写了个demo程序供大家参考.kafka的安装请参考官方文档. 首先我们需要新建一个maven项目,然后在 ...

  9. Mysql错误: ERROR 1205: Lock wait timeout exceeded; try restarting transaction

    MySQL:innodb的事务锁,一个线程占用着,简单做法是:执行mysql命令: show full processlist; 然后找出查询语句的系统id:kill掉被锁住的线程id:kill 12 ...

  10. C#项目中一些文件类型说明

    designer.cs  是窗体设计器生成的代码文件,作用是对窗体上的控件做初始化工作 (在函数InitializeComponent()中)VS2003以前都把这部分代码放到窗体的cs文件中,由于这 ...