ASP.NET Core中使用自定义MVC过滤器属性的依赖注入
除了将自己的中间件添加到ASP.NET MVC Core应用程序管道之外,您还可以使用自定义MVC过滤器属性来控制响应,并有选择地将它们应用于整个控制器或控制器操作。
ASP.NET Core中常用的MVC过滤器之一是 ExceptionFilterAttribute,用于处理Wep API应用程序中的错误响应。它很容易实现,开发人员和我在ASP.NET Core中使用MVC过滤器属性所面临的问题是访问Startup.cs类中注入的组件。这些通常是配置,环境或日志记录。
通常依赖注入对象的一个非常有用的用法,例如上面提到的IEnvironment,IConfiguration和ILogger <T>,是您正在实现的MVC过滤器属性的不同行为。根据这些值,您的属性行为可能会有所不同。例如,您不希望将错误详细信息和堆栈跟踪公开给Production Web API服务错误响应,尤其是在该服务端点是公共的情况下。您希望仅针对隔离的开发和登台环境执行此操作。
示例MVC过滤器属性
在一个自定义ExceptionFilterAttrubute类的简单示例中,我将向您演示如何在自定义属性中使用依赖注入对象。让我们从代码开始吧。
public class ExceptionMessage
{
private object errorMessage;
public string Message { get; private set; }
public string Description { get; private set; }
public IDictionary<string,string> ValidationErrors { get; private set;}
public ExceptionMessage(ExceptionContext context)
{
if (context.ModelState != null && context.ModelState.Any(m => m.Value.Errors.Any()))
{
this.Message = "Model validation failed.";
this.ValidationErrors = context.ModelState.Keys
.SelectMany(key => context.ModelState[key].Errors.ToDictionary(k => key, v => v.ErrorMessage))
.ToDictionary(k => k.Key, v => v.Value);
}
else
{
this.Message = context.Exception.Message;
this.Description = context.Exception.StackTrace;
}
}
}
由于本文重点不是错误消息结构,不过在Microsoft REST API准则 Github存储库中提供了一些错误消息准则,这些可能会给你带来帮助。
现在您的错误响应理想情况下是一条JSON消息,但是让我们将序列化留给应用程序的管道并返回一个ObjectResponse派生实例。为此我创建了ErrorObjectResult。
using Microsoft.AspNetCore.Mvc;
using System.Net; namespace CzarCms.Models
{
public class ErrorObjectResult : ObjectResult
{
public ErrorObjectResult(object value, HttpStatusCode statusCode = HttpStatusCode.InternalServerError) : base(value)
{
StatusCode = (int)statusCode;
}
}
}
除了获取状态代码的构造函数(默认为500内部服务器错误)和ObjectResponse基础构造函数的对象之外,此类中没有什么特别之处。我们在本文中关注的核心组件是我们的自定义ExceptionFilterAttribute派生类。
public class ApiExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
var errorMessage = new ExceptionMessage(context);
if (context.ModelState.ErrorCount==)
context.Result = new ErrorObjectResult(errorMessage);
else
context.Result = new ErrorObjectResult(errorMessage,HttpStatusCode.BadRequest);
base.OnException(context);
}
}
让我们用这个属性来装饰我们的控制器来处理它可能发生的错误。
// GET api/values
[HttpGet]
[ApiExceptionFilter]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
设置依赖注入
我们首先需要为我们要在Startup类的MVC过滤器属性中访问的这三个接口设置依赖注入。
public class Startup
{
public IConfiguration Configuration { get; private set; }
public IHostingEnvironment HostingEnvironment { get; private set; } public Startup(IConfiguration configuration, IHostingEnvironment env)
{
Configuration = configuration;
HostingEnvironment = env;
ILogger Logger = new LoggerFactory()
.AddConsole()
.AddDebug()
.CreateLogger(typeof(Program));
} public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfiguration>(new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile($"appsettings.{this.HostingEnvironment.EnvironmentName.ToLower()}.json")
.Build());
services.AddLogging();
services.AddMvc(); services.AddScoped<ApiExceptionFilter>();
} public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
app.UseMvc();
}
}
您可以看到我们将ApiExceptionFilter添加为我们的DI的作用域服务。这是因为我们将在控制器上以不同的方式引用它,以便通过带有参数的新构造函数的依赖注入来初始化它。
我们已经在Startup类中的ConfigureServices方法中注入了我们的IEnvironment和ILogger,但我们无法在属性中访问它。如果我们使用IEnvironment和ILogger参数添加属性的构造函数,我们将得到编译错误,因为您无法使用[ApiExceptionFilter]装饰Controller / Action,因为它现在需要通过IEnvironment和ILogger接口实现。为此,我们使用带有属性ServiceFilter的控制器来装饰 它,它将我们的 ApiExceptionFilter类的类型作为构造函数参数。
[HttpGet]
[ServiceFilter(typeof(ApiExceptionFilter))]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
最后,我们必须更新MVC过滤器属性的构造函数以接受IEnvironment,IConfiguration和ILogger参数。
public class ApiExceptionFilter : ExceptionFilterAttribute
{
private ILogger<ApiExceptionFilter> logger;
private IHostingEnvironment environment;
private IConfiguration configuration;
public ApiExceptionFilter(IHostingEnvironment environment, IConfiguration configuration, ILogger<ApiExceptionFilter> logger)
{
this.environment = environment;
this.configuration = configuration;
this.logger = logger;
}
public override void OnException(ExceptionContext context)
{
var errorMessage = new ExceptionMessage(context);
if (context.ModelState.ErrorCount==)
context.Result = new ErrorObjectResult(errorMessage);
else
context.Result = new ErrorObjectResult(errorMessage,HttpStatusCode.BadRequest);
base.OnException(context);
}
}
我们在自定义过滤器属性类中注入了IEnvironment和ILogger <T>。从Microsoft.AspNetCore.Mvc.Filters命名空间中的任何操作过滤器属性派生的任何类都可以使用相同的方法。
ASP.NET Core中使用自定义MVC过滤器属性的依赖注入的更多相关文章
- ASP.NET Core中使用自定义路由
上一篇文章<ASP.NET Core中使用默认MVC路由>提到了如何使用默认的MVC路由配置,通过这个配置,我们就可以把请求路由到Controller和Action,通常情况下我们使用默认 ...
- ASP.NET Core中显示自定义错误页面-增强版
之前的博文 ASP.NET Core中显示自定义错误页面 中的方法是在项目中硬编码实现的,当有多个项目时,就会造成不同项目之间的重复代码,不可取. 在这篇博文中改用middleware实现,并且放在独 ...
- ExpandoObject与DynamicObject的使用 RabbitMQ与.net core(一)安装 RabbitMQ与.net core(二)Producer与Exchange ASP.NET Core 2.1 : 十五.图解路由(2.1 or earler) .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了
ExpandoObject与DynamicObject的使用 using ImpromptuInterface; using System; using System.Dynamic; names ...
- ASP.NET Core中显示自定义错误页面
在 ASP.NET Core 中,默认情况下当发生500或404错误时,只返回http状态码,不返回任何内容,页面一片空白. 如果在 Startup.cs 的 Configure() 中加上 app. ...
- ASP.NET Core中使用默认MVC路由
ASP.NET Core里Route这块的改动不大,只是一些用法上有了调整,提供了一些更加简洁的语法. 而对于自定义路由的支持当然也是没有问题的,这个功能应该是从MVC1.0版本就已经有这个功能. 先 ...
- 在ASP.NET Core中创建自定义端点可视化图
在上篇文章中,我为构建自定义端点可视化图奠定了基础,正如我在第一篇文章中展示的那样.该图显示了端点路由的不同部分:文字值,参数,动词约束和产生结果的端点: 在本文中,我将展示如何通过创建一个自定义的D ...
- ASP.NET Core 中间件的使用(二):依赖注入的使用
写在前面 上一篇大家已经粗略接触了解到.NET Core中间件的使用:ASP .Net Core 中间件的使用(一):搭建静态文件服务器/访问指定文件, .NET Core框架中很多核心对象都是通过依 ...
- .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了
最近有个需求就是一个抽象仓储层接口方法需要SqlServer以及Oracle两种实现方式,为了灵活我在依赖注入的时候把这两种实现都给注入进了依赖注入容器中,但是在服务调用的时候总是获取到最后注入的那个 ...
- asp.net core中写入自定义中间件
首先要明确什么是中间件?微软官方解释:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?tabs=aspnet ...
随机推荐
- css3绘制三角形
将div的宽和高设置为0:利用border-width.border-style.border-color属性绘制不同位置边框的样式.将不需要展示的三角颜色填充为transparent透明即可,就能得 ...
- HTTP引流神器Goreplay详解【官译】
0.背景 校验系统的正确性和可靠性时,仅靠用例场景无法覆盖全生产环境下的所有场景,需要一套引流工具,在系统正式上线前,用线上的请求测试待上线系统,在正常请求下,是否有报错:在数倍请求下,系统的性能瓶颈 ...
- segmenter_worker.go
package; ; i < engine.initOptions.NumShards; i++ { if i == shard { ...
- 【小白学C#】谈谈C#多播委托因异常而终止的解决方案
一.前言 前几天,马三在与朋友闲聊技术的时候,朋友忽然抛出一个问题,把马三难倒了,本着求知的精神,回来以后马三就查阅了相关资料并做了一些实验,终于把问题搞明白了,因此写下本篇博客记录一下.首先,问题是 ...
- enumerate取下标
for index,item in enumerate(product_list): # print(product_list.index(item),item) print(index,item) ...
- djanogo class meta
1.指定字段名: 在定义字段的时候,增加参数db_column='real_field': 2.指定表名: 在model的class中,添加Meta类,在Meta类中指定表名db_table 例如在某 ...
- HTTPS和TCP协议三次握手设计
1. 我们的TCP 三次握手大概是长这样 2.那么为什么 TCP 要采取三次握手,而不是两次或其他 首先我们要知道握手的目的: 为了保证通讯双方建立的连接是可靠的. 同时,为了保证性能,握手的次数要求 ...
- 软件测试自动化的最新趋势对开源测试管理软件ITEST的启示
https://www.infoq.cn/article/c-LHJS2ksuDxp1WkrGl4 理面提到几点,DevOps 的关键原则是开发团队.测试团队和运营团队协作,无缝发布软件.这意味着集中 ...
- 使用Kubernetes演示金丝雀发布
使用Kubernetes演示金丝雀发布 为了更直观的看出金丝雀发布的效果,我们这里使用了Prometheus监控来观察这个过程.不知道怎么使用Prometheus的同学请看使用Prometheus监控 ...
- OAuth2.0记录
阮一峰老师讲解OAuth2.0 http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 举例详解: https://www.cnblogs.com/ ...