Fixes null ref in DatabaseErrorPageMiddleware.

Fix aspnet/Home#2820 - UseDatabaseErrorPage throws NullReferenceException when ef exception occur in background task
Fix aspnet/EntityFrameworkCore#9599 - Insert entity in non existing table throws NullException

Added null checks to async local access in event callback.

Related to aspnet/Home#2825
This commit is contained in:
Andrew Peters 2018-01-25 18:14:23 -08:00
parent 2b3e05a46e
commit 0ec3dedc88
2 changed files with 34 additions and 3 deletions

View File

@ -78,6 +78,8 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
_options = options.Value;
_logger = loggerFactory.CreateLogger<DatabaseErrorPageMiddleware>();
// Note: this currently leaks if the server hosting this middleware is disposed.
// See aspnet/Home #2825
DiagnosticListener.AllListeners.Subscribe(this);
}
@ -121,7 +123,6 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
else
{
var relationalDatabaseCreator = context.GetService<IDatabaseCreator>() as IRelationalDatabaseCreator;
if (relationalDatabaseCreator == null)
{
_logger.NotRelationalDatabase();
@ -216,15 +217,17 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
{
switch (keyValuePair.Value)
{
// NB: _localDiagnostic.Value can be null when this middleware has been leaked.
case DbContextErrorEventData contextErrorEventData:
{
_localDiagnostic.Value.Hold(contextErrorEventData.Exception, contextErrorEventData.Context.GetType());
_localDiagnostic.Value?.Hold(contextErrorEventData.Exception, contextErrorEventData.Context.GetType());
break;
}
case DbContextTypeErrorEventData contextTypeErrorEventData:
{
_localDiagnostic.Value.Hold(contextTypeErrorEventData.Exception, contextTypeErrorEventData.ContextType);
_localDiagnostic.Value?.Hold(contextTypeErrorEventData.Exception, contextTypeErrorEventData.ContextType);
break;
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
@ -16,7 +17,9 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Xunit;
@ -140,6 +143,31 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests
}
}
[ConditionalFact]
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
public void No_exception_on_diagnostic_event_received_when_null_state()
{
using (var database = SqlServerTestStore.CreateScratch())
{
using (var server = SetupTestServer<BloggingContext, NoMigrationsMiddleware>(database))
{
using (var db = server.Host.Services.GetService<BloggingContext>())
{
db.Blogs.Add(new Blog());
try
{
db.SaveChanges();
}
catch (SqlException)
{
}
}
}
}
}
[ConditionalFact]
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]