出现错误异常的示例代码
1) Startup.cs代码
public class Startup
{
public IConfiguration Configuration { get; protected set; }
private APIEnvironment _environment { get; set; }
public Startup(IConfiguration configuration, IHostingEnvironment env)
{
Configuration = configuration;
_environment = APIEnvironment.Development;
if (env.IsProduction()) _environment = APIEnvironment.Production;
if (env.IsStaging()) _environment = APIEnvironment.Staging;
}
public void ConfigureServices(IServiceCollection services)
{
var dataConnect = new DataConnect(_environment);
services.AddDbContext<GeneralInfoContext>(opt => opt.UseSqlServer(dataConnect.GetConnectString(Database.GeneralInfo)));
services.AddDbContext<EmailRouterContext>(opt => opt.UseSqlServer(dataConnect.GetConnectString(Database.EmailRouter)));
services.AddWebEncoders();
services.AddMvc();
services.AddScoped<IGenInfoNoteRepository, GenInfoNoteRepository>();
services.AddScoped<IEventLogRepository, EventLogRepository>();
services.AddScoped<IStateRepository, StateRepository>();
services.AddScoped<IEmailRepository, EmailRepository>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
app.UseAuthentication();
app.UseStatusCodePages();
app.UseEmailingExceptionHandling();
app.UseMvcWithDefaultRoute();
}
}
2) EmailRepository的代码
public interface IEmailRepository
{
void SendEmail(Email email);
}
public class EmailRepository : IEmailRepository, IDisposable
{
private bool disposed;
private readonly EmailRouterContext edc;
public EmailRepository(EmailRouterContext emailRouterContext)
{
edc = emailRouterContext;
}
public void SendEmail(Email email)
{
edc.EmailMessages.Add(new EmailMessages
{
DateAdded = DateTime.Now,
FromAddress = email.FromAddress,
MailFormat = email.Format,
MessageBody = email.Body,
SubjectLine = email.Subject,
ToAddress = email.ToAddress
});
edc.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
edc.Dispose();
disposed = true;
}
}
}
3) 处理异常中间件(Middleware)代码
public class ExceptionHandlingMiddleware { private const string ErrorEmailAddress = "errors@ourdomain.com"; private readonly IEmailRepository _emailRepository; private readonly RequestDelegate _next; public ExceptionHandlingMiddleware(RequestDelegate next, IEmailRepository emailRepository) { _next = next; _emailRepository = emailRepository; } public async Task Invoke(HttpContext context) { try { await _next.Invoke(context); } catch (Exception ex) { await HandleExceptionAsync(context, ex, _emailRepository); } } private static Task HandleExceptionAsync(HttpContext context, Exception exception, IEmailRepository emailRepository) { var code = HttpStatusCode.InternalServerError; // 500 if unexpected var email = new Email { Body = exception.Message, FromAddress = ErrorEmailAddress, Subject = "API Error", ToAddress = ErrorEmailAddress }; emailRepository.SendEmail(email); context.Response.ContentType = "application/json"; context.Response.StatusCode = (int) code; return context.Response.WriteAsync("An error occured."); } } public static class AppErrorHandlingExtensions { public static IApplicationBuilder UseEmailingExceptionHandling(this IApplicationBuilder app) { if (app == null) throw new ArgumentNullException(nameof(app)); return app.UseMiddleware<ExceptionHandlingMiddleware>(); } }
解决错误异常的3种方法
1)修改中间件代码解决
IEmailRepository
在Startup
类别中将其注册为范围服务。这意味着您不能将其作为构造函数参数注入,因为中的构造函数注入Middleware只能Singleton解析服务Middleware。应该将依赖项移动到这样的Invoke
方法:
public ExceptionHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context, IEmailRepository emailRepository)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex, emailRepository);
}
}
2) 通过IServiceProvider获取依赖实例
using (var scope = _serviceProvider.CreateScope()) {
var _emailRepository = scope.ServiceProvider.GetRequiredService<IEmailRepository>);
//.....
}
3) 关闭作用域嵌套验证
.NET Core 1.1中默认为关闭,.NET Core 2.0中默认打开的,关闭后就不会在运行时检查范围级别是否嵌套不正确。修改Program.cs
文件的BuildWebHost
方法,如下:
public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseDefaultServiceProvider(options =>
options.ValidateScopes = false)
.Build();
}
参考文档:https://github.com/aspnet/DependencyInjection/issues/578