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

时间:2017-08-21 22:23:09

标签: asp.net-core .net-core

我在.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。我需要捕获一个详细的错误,提供一些关于出错的线索。有什么想法吗?

谢谢!

1 个答案:

答案 0 :(得分:2)

如果您具有ModelState.IsValidData Annotations等适当的StringLength属性,

Required应该会收到大多数错误。但是,您无法预见任何可能的错误。

个人不喜欢在每个操作方法中使用try和catch块。相反,我会使用NLogLog4Net等日志框架,并向用户显示用户友好的错误消息。

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

仅供参考:截至今天,Log4Net for .NET Core中没有AdoNetAppender

Startup.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:\temp\internal-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();
    }
}