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 ...
随机推荐
- selenium webdriver——设置元素等待
如今大多数Web应用程序使用ajax技术,当浏览器在加载页面时,页面上的元素可能并不是同时被加载完成,这给定位元素的定位增加了困难, 如果因为在加载某个元素时延迟而造成ElementNotVisibl ...
- 判断qq号码 规律
$qqs = array('2343232', "4323254","22222","5123123","23412341234& ...
- 深入js隐式类型转换
前言 相信刚开始了解js的时候,都会遇到 2 =='2',但是 1+'2' == '1'+'2'为false的情况,这时候应该会是一脸懵逼的状态,不得不感慨js弱类型的灵活让人发指,隐式类型转换就是这 ...
- 查看keras自动给文件夹标号
from tensorflow.contrib.keras.api.keras.preprocessing.image import ImageDataGenerator,img_to_array f ...
- Bootstrap优秀模板-INSPINIA.2.9.2
下载量最高的Bootstrap管理端模板,完美适配H5,.NET COre.MVC5.Ruby on Rails多种开发环境. 下面是官方介绍:INSPINIA Admin Theme is a pr ...
- 神奇的Scala Macro之旅(四)- BeanBuilder
在Java开发中,经常会有一个需求,将一个 Bean 复制到另外一个 Bean,尤其是在后台分层的场景下,在不同的层之间传递信息,经常需要进行 这样的一个对象复制工作,类似于: val source: ...
- C语言sprintf和sscanf函数用法
以前刚用C语言的时候,觉得字符串很难处理,后来用多了,发现其实并非如此,C语言也提供了许多函数给程序员使用.今天记录一下两个常用的两个字符串处理函数:sprintf和sscanf 1. sprintf ...
- java游戏开发杂谈 - 界面刷新、坐标系
之前几篇博客里的例子,大家运行过的话,就能看出来,界面是需要刷新的. JPanel里的绘制方法是paintComponent,界面上的东西都是这个方法画出来的. JPanel对象有一个repaint方 ...
- Docker最全教程之Go实战,墙裂推荐(十八)
前言 与其他语言相比,Go非常值得推荐和学习,真香!为什么?主要是可以直接编译成机器代码(性能优越,体积非常小,可达10来M,见实践教程图片)而且设计良好,上手门槛低.本篇主要侧重于讲解了Go语言的优 ...
- 解决小米手机USB安装apk时AS报错:INSTALL_FAILED_USER_RESTRICTED
今天,直接用AS在小米手机上运行安装的时候总是报错:INSTALL_FAILED_USER_RESTRICTED,于是乎,通过以下方式解决: 在开发者选项将USB安装打开,然后,哈,解决了.记录一下.