【aspnetcore】在过滤器(Filter)中使用注入服务(ServiceFilter|TypeFilter)

摘要:
例如,修改TestActionFilterAttribute:publicclassTestActionFilterAttribute:Attribute,IActionFilter{privateeadonlyILogger_logger;publicTestActionFilterAttributes{_logger=logger.CreateLogger;}publicvoidOnActionExecuted{varpath=context.HttpContext.Request.Path;_logger.LogDebug;}Publicvoid OnActionExecuting{}}我们将ILoggerFactory参数注入Filter的构造函数中,Filter是系统提供的默认日志工厂服务,用于在控制台上打印消息。返回到Controller文件,我们发现[TestActionFilter]报告了一个错误:没有提供与“TestActionFilterAttribute”所需参数记录器对应的实际参数。可以看出,如果您需要将服务注入Filter,则无法实现常规方法。事实上,框架为我们提供了两种方式:TypeFilter和ServiceFilterpublicclassTestTypeFilter:IActionFilter{privatereadonlyILogger_logger;publicTestTypeFilter{_logger=logger.CreateLogger;}publicvoidOnActionExecuted{varpath=context.HttpContext.Request.Path;_logger.LogDebug;}Publicvoid OnActionExecuting{}这里的代码与上面修改的TestActionFilterAttribute相同。修改控制器文件:[TypeFilter]publicIActionResultIndex(){returnView();}运行测试,结果如下:如您所见,代码运行正常。

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

运行测试,效果如下:

【aspnetcore】在过滤器(Filter)中使用注入服务(ServiceFilter|TypeFilter)第1张

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

下面再看看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>();

运行测试,效果如下:

【aspnetcore】在过滤器(Filter)中使用注入服务(ServiceFilter|TypeFilter)第2张

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)第3张

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

免责声明:文章转载自《【aspnetcore】在过滤器(Filter)中使用注入服务(ServiceFilter|TypeFilter)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇在TOMCAT下配置工程的默认访问设置(转)解决SharePoint2010中Excel刷新出错的问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

spring获取webapplicationcontext,applicationcontext几种方法详解[转载]

方法一:在初始化时保存ApplicationContext对象 代码: ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml"); ac.getBean("beanId"); 或者通过classpath 路径获取 ApplicationCont...

Android透明无边框圆形进度条之最简单实现

很多人在项目中做长时间操作时,比如访问web service后台数据,都想显示一个透明无边框的圆形进度条,如下图: 不幸的是,Android系统自带的ProgressDialog,无论如何设置Theme、style,或者用java代码设置什么属性,边框都是去不掉的,至少我现在还不知道怎么去掉: 怎么办? 其实很简单,自定义一个ProgressDialo...

LTE信令流程之专用承载流程介绍

https://www.mscbsc.com/viewnews-102220.html  感谢作者! 【LTE基础知识】LTE信令流程之专用承载流程介绍 发布: 2014-08-11 16:40 | 作者: MSCBSC | 来源: 移动通信网 | 字体:  小  中  大  相关专题:基础知识无线   专用承载建立流程    专用承载建立流程说...

Android 获取网络类型(WIFI、CMNET、CMWAP)

下面这个方法用于获取系统当前网络类型: 1: public static int getNetworkType(Context context) { 2: ConnectivityManager connectivity = (ConnectivityManager)context.getSystemService(Conte...

ASP.NET Core:使用EntityFrameworkCore操作MySql来丰富仓储模块

概述 上一篇简单介绍了Dapper的基本用法,数据的存储为SqlServer。那么这一篇就记录一下使用EFCore来操作MySql的一些方式,这种模式比较适合那种一个项目中需要操作多种数据库的模式。不过因为微软官方并没有提供其驱动,所以我们需要借助MySql官方提供的驱动进行基本的增删改查操作。这样一来我们也可以将数据库迁移到Linux服务器上了,是不是很...

【MyBatis源码分析】Configuration加载(下篇)

元素设置 继续MyBatis的Configuration加载源码分析: 1 private void parseConfiguration(XNode root) { 2 try { 3 Properties settings = settingsAsPropertiess(root.evalNode("settings"))...