diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageMiddleware.cs b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageMiddleware.cs index 3dffe8818d..c7dee3cf1f 100644 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageMiddleware.cs +++ b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageMiddleware.cs @@ -78,6 +78,8 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore _options = options.Value; _logger = loggerFactory.CreateLogger(); + // 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() 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; } diff --git a/test/Diagnostics.EFCore.FunctionalTests/DatabaseErrorPageMiddlewareTest.cs b/test/Diagnostics.EFCore.FunctionalTests/DatabaseErrorPageMiddlewareTest.cs index 5afffbe3a4..d6ede3ef2e 100644 --- a/test/Diagnostics.EFCore.FunctionalTests/DatabaseErrorPageMiddlewareTest.cs +++ b/test/Diagnostics.EFCore.FunctionalTests/DatabaseErrorPageMiddlewareTest.cs @@ -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(database)) + { + using (var db = server.Host.Services.GetService()) + { + db.Blogs.Add(new Blog()); + + try + { + db.SaveChanges(); + } + catch (SqlException) + { + } + } + } + } + } + [ConditionalFact] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)]