在哪里捕获实体框架异常?



我在.NET Core API应用程序中有以下控制器:

[HttpPost]
public async Task<IActionResult> PostCar([FromBody] Car car)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_context.Car.Add(car);
await _context.SaveChangesAsync();
return CreatedAtAction("GetCar", new { id = car.Id }, car);
}

我应该如何捕获(和显示(await _context.SaveChangesAsync();期间可能发生的任何错误?

有可能将数据滑过IsValid(),但仍然保存失败,留下无用的500。我需要捕获一个详细的错误,以提供有关出了什么问题的线索。有什么想法吗?

谢谢!

如果您有适当的Data Annotations属性(如StringLengthRequired(,ModelState.IsValid应该捕获大多数错误。 但是,您无法预见任何可能的错误。

个人不喜欢在每个操作方法中使用 try and catch 块。相反,我将使用像NLog或Log4Net这样的日志记录框架,并向用户显示用户友好的错误消息。

使用这些日志记录框架,您可以将日志保存到文件或数据库中。以下是使用 NLog 将日志保存到数据库中的示例代码。

仅供参考:截至今天,AdoNetAppender 在 Log4Net for .NET Core 中不可用。

启动.cs

public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
env.ConfigureNLog("nlog.config");
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseStatusCodePagesWithRedirects("/Common/Error/{0}");
app.UseExceptionHandler("/Common/Error");
}
loggerFactory.AddNLog();
app.AddNLogWeb();
LogManager.Configuration.Variables["connectionString"] = Configuration.GetConnectionString("DefaultConnection");
...
}
}

nlog.config

<?xml version="1.0" encoding="utf-8" ?>
<!--
NOTE: Use this to log internal error, if you have issue configuring NLog.
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Warn"
internalLogFile="C:tempinternal-nlog.txt">
-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true">
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<targets>
<target xsi:type="Null" name="blackhole" />
<target name="database" xsi:type="Database">
<connectionString>${var:connectionString}</connectionString>
<!-- 
Script for creating the dbo.Log table.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Logs](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Application] [nvarchar](50) NOT NULL,
[Logged] [datetime] NOT NULL,
[Level] [nvarchar](50) NOT NULL,
[Action] [nvarchar](50) NULL,
[Controller] [nvarchar](50) NULL,
[Identity] [nvarchar](50) NULL,
[Referrer] [nvarchar](250) NULL,
[UserAgent] [nvarchar](250) NULL,
[Url] [nvarchar](500) NULL,
[Message] [nvarchar](max) NOT NULL,
[Logger] [nvarchar](250) NULL,
[Callsite] [nvarchar](max) NULL,
[Exception] [nvarchar](max) NULL,
CONSTRAINT [PK_dbo.Logs] PRIMARY KEY CLUSTERED 
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
-->
<commandText>
INSERT INTO dbo.Logs (Application,Logged,[Level],Action,Controller,[Identity],Referrer,UserAgent,Url,Message,Logger,Callsite,Exception)
VALUES (@Application,@Logged,@Level,@Action,@Controller,@Identity,@Referrer,@UserAgent,@Url,@Message,@Logger,@Callsite,@Exception);
</commandText>
<parameter name="@Application" layout="ASP" />
<parameter name="@Logged" layout="${date}" />
<parameter name="@Level" layout="${level}" />
<parameter name="@Action" layout="${aspnet-MVC-Action}" />
<parameter name="@Controller" layout="${aspnet-MVC-Controller}" />
<parameter name="@Identity" layout="${aspnet-User-Identity}" />
<parameter name="@Referrer" layout="${aspnet-Request-Referrer}" />
<parameter name="@UserAgent" layout="${aspnet-Request-UserAgent}" />
<parameter name="@Url" layout="${aspnet-Request-Url}" />
<parameter name="@Message" layout="${message}" />
<parameter name="@Logger" layout="${logger}" />
<parameter name="@CallSite" layout="${callsite:filename=true}" />
<parameter name="@Exception" layout="${exception:tostring}" />
</target>
</targets>
<rules>
<!-- Skip Microsoft logs, and log only own logs-->
<logger name="Microsoft.*" minlevel="Trace" writeTo="blackhole" final="true" />
<logger name="*" minlevel="Trace" writeTo="database" />
</rules>
</nlog>

用法

public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(
ILogger<HomeController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Index()
{
_logger.LogError("Test Exception");
return View();
}
}

最新更新