除了将自己的中间件添加到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过滤器属性的依赖注入的更多相关文章

  1. ASP.NET Core中使用自定义路由

    上一篇文章<ASP.NET Core中使用默认MVC路由>提到了如何使用默认的MVC路由配置,通过这个配置,我们就可以把请求路由到Controller和Action,通常情况下我们使用默认 ...

  2. ASP.NET Core中显示自定义错误页面-增强版

    之前的博文 ASP.NET Core中显示自定义错误页面 中的方法是在项目中硬编码实现的,当有多个项目时,就会造成不同项目之间的重复代码,不可取. 在这篇博文中改用middleware实现,并且放在独 ...

  3. 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 ...

  4. ASP.NET Core中显示自定义错误页面

    在 ASP.NET Core 中,默认情况下当发生500或404错误时,只返回http状态码,不返回任何内容,页面一片空白. 如果在 Startup.cs 的 Configure() 中加上 app. ...

  5. ASP.NET Core中使用默认MVC路由

    ASP.NET Core里Route这块的改动不大,只是一些用法上有了调整,提供了一些更加简洁的语法. 而对于自定义路由的支持当然也是没有问题的,这个功能应该是从MVC1.0版本就已经有这个功能. 先 ...

  6. 在ASP.NET Core中创建自定义端点可视化图

    在上篇文章中,我为构建自定义端点可视化图奠定了基础,正如我在第一篇文章中展示的那样.该图显示了端点路由的不同部分:文字值,参数,动词约束和产生结果的端点: 在本文中,我将展示如何通过创建一个自定义的D ...

  7. .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了

    最近有个需求就是一个抽象仓储层接口方法需要SqlServer以及Oracle两种实现方式,为了灵活我在依赖注入的时候把这两种实现都给注入进了依赖注入容器中,但是在服务调用的时候总是获取到最后注入的那个 ...

  8. asp.net core中写入自定义中间件

    首先要明确什么是中间件?微软官方解释:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?tabs=aspnet ...

  9. 在ASP.NET Core中实现自定义验证特性(Custom Validation Attribute)

    这是我们在实际ASP.NET Core项目中用到的,验证用户名中是否包含空格. 开始是这么实现的(继承ValidationAttribute,重写IsValid方法): public class No ...

随机推荐

  1. 下拉框QComboBox相关函数

    QComboBox addItem (self, QString text, QVariant userData = QVariant())addItem (self, QIcon icon, QSt ...

  2. 【面试题030】最小的k个数

    [面试题030]最小的k个数 题目:     输入n个整数,找出其中最小的k个数.     例如输入4.5.1.6.2.7.3.8这8个字,则其中最小的4个数字是1.2.3.4.     思路一:   ...

  3. &lt;二&gt; ASP.NET AutoPostBack

    当把Web控件的AutoPostBack属性设置为True时,自动回送功能被开启,ASP.NET使用客户端的 JavaScript来连接客户端和服务器端的代码.创建一个Web控件属性包含AutoPos ...

  4. asp.net下用js实现弹出子窗口选定值并返回

    对应上一篇博客代码: 父页面: <head runat="server"> <meta http-equiv="X-UA-Compatible" ...

  5. Heritrix工具实现网络爬虫

    上次用的java相关知识实现了一个简单的网络爬虫,现在存在许多开源免费的爬虫工具,相对来说,可以很简单的获取网页数据,并写入到本地. 下面我就阐述一下我用Heritrix爬虫工具实现网页数据爬取. - ...

  6. VS2010下安装boost库

    在我们的C++项目中安装boost库,下面以VS2010版本作为例子,其它版本的设置也差不多. 一.编译生成boost库 1.下载最新的boost(本人下载的是boost_1_56_0).boost官 ...

  7. Bash 和 Zsh 开启 vi-mode

    Bash 和 Zsh 开启 vi-mode bash 有两种操作模式,分别是 emacs 和 vi . 在 bash 中 set -o vi # 临时开启 vi 模式 vi ~/.bashrc # 在 ...

  8. HBase的几个实示例

    1 开发环境 在进行Hbase开发前,需要安装JDK.Hadoop和Hbase,选择一款合适的开发IDE,具体安装方法就不介绍了,我的开发环境: 操作系统:Ubuntu Java版本:jdk1.8 H ...

  9. 【java排序】 归并排序算法、堆排序算法

    一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...

  10. CentOS 64位下安装Postfix+Dovecot 配置邮件server笔记

    Postfix 和Dovecot功能确实非常强大,支持各种认证方式, 配置非常灵活, 就由于太过于灵活, 反而安装配置的过程中,easy有各种各样的陷阱,碰到问题了. 日志是最好的解决的方法了.    ...