Skip to content

Commit 6423058

Browse files
author
John Luo
committed
Consolidate decouple logic
1 parent c21e293 commit 6423058

File tree

4 files changed

+109
-162
lines changed

4 files changed

+109
-162
lines changed

src/Middleware/Diagnostics.EntityFrameworkCore/src/DatabaseErrorPageMiddleware.cs

Lines changed: 9 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -117,92 +117,18 @@ public virtual async Task Invoke(HttpContext httpContext)
117117
if (ShouldDisplayErrorPage(exception))
118118
{
119119
var contextType = _localDiagnostic.Value.ContextType;
120-
var context = (DbContext)httpContext.RequestServices.GetService(contextType);
120+
var details = await httpContext.GetContextDetailsAsync(contextType, _logger);
121121

122-
if (context == null)
122+
if (details != null && (details.PendingModelChanges || details.PendingMigrations.Count() > 0))
123123
{
124-
_logger.ContextNotRegisteredDatabaseErrorPageMiddleware(contextType.FullName);
125-
}
126-
else
127-
{
128-
var relationalDatabaseCreator = context.GetService<IDatabaseCreator>() as IRelationalDatabaseCreator;
129-
if (relationalDatabaseCreator == null)
130-
{
131-
_logger.NotRelationalDatabase();
132-
}
133-
else
124+
var page = new DatabaseErrorPage
134125
{
135-
var databaseExists = await relationalDatabaseCreator.ExistsAsync();
136-
137-
if (databaseExists)
138-
{
139-
databaseExists = await relationalDatabaseCreator.HasTablesAsync();
140-
}
141-
142-
var migrationsAssembly = context.GetService<IMigrationsAssembly>();
143-
var modelDiffer = context.GetService<IMigrationsModelDiffer>();
144-
145-
var snapshotModel = migrationsAssembly.ModelSnapshot?.Model;
146-
if (snapshotModel is IConventionModel conventionModel)
147-
{
148-
var conventionSet = context.GetService<IConventionSetBuilder>().CreateConventionSet();
149-
150-
var typeMappingConvention = conventionSet.ModelFinalizingConventions.OfType<TypeMappingConvention>().FirstOrDefault();
151-
if (typeMappingConvention != null)
152-
{
153-
typeMappingConvention.ProcessModelFinalizing(conventionModel.Builder, null);
154-
}
155-
156-
var relationalModelConvention = conventionSet.ModelFinalizedConventions.OfType<RelationalModelConvention>().FirstOrDefault();
157-
if (relationalModelConvention != null)
158-
{
159-
snapshotModel = relationalModelConvention.ProcessModelFinalized(conventionModel);
160-
}
161-
}
162-
163-
if (snapshotModel is IMutableModel mutableModel)
164-
{
165-
snapshotModel = mutableModel.FinalizeModel();
166-
}
167-
168-
// HasDifferences will return true if there is no model snapshot, but if there is an existing database
169-
// and no model snapshot then we don't want to show the error page since they are most likely targeting
170-
// and existing database and have just misconfigured their model
171-
172-
var pendingModelChanges
173-
= (!databaseExists || migrationsAssembly.ModelSnapshot != null)
174-
&& modelDiffer.HasDifferences(snapshotModel?.GetRelationalModel(), context.Model.GetRelationalModel());
175-
176-
var pendingMigrations
177-
= (databaseExists
178-
? await context.Database.GetPendingMigrationsAsync()
179-
: context.Database.GetMigrations())
180-
.ToArray();
181-
182-
if (pendingModelChanges || pendingMigrations.Length > 0)
183-
{
184-
var page = new DatabaseErrorPage
185-
{
186-
Model = new DatabaseErrorPageModel(
187-
exception,
188-
new DatabaseContextDetails[]
189-
{
190-
new DatabaseContextDetails
191-
{
192-
Type = contextType,
193-
DatabaseExists = databaseExists,
194-
PendingMigrations = pendingMigrations,
195-
PendingModelChanges = pendingModelChanges
196-
}
197-
},
198-
_options)
199-
};
200-
201-
await page.ExecuteAsync(httpContext);
202-
203-
return;
204-
}
205-
}
126+
Model = new DatabaseErrorPageModel(exception, new DatabaseContextDetails[] { details }, _options)
127+
};
128+
129+
await page.ExecuteAsync(httpContext);
130+
131+
return;
206132
}
207133
}
208134
}

src/Middleware/Diagnostics.EntityFrameworkCore/src/DatabaseExceptionHandler.cs

Lines changed: 6 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -49,81 +49,23 @@ public async Task HandleExceptionAsync(ErrorContext errorContext, Func<ErrorCont
4949

5050
foreach (var registeredContext in registeredContexts)
5151
{
52-
// TODO: Decouple
53-
var context = (DbContext)errorContext.HttpContext.RequestServices.GetService(registeredContext);
54-
// TODO: Decouple
55-
var relationalDatabaseCreator = context.GetService<IDatabaseCreator>() as IRelationalDatabaseCreator;
56-
if (relationalDatabaseCreator == null)
57-
{
58-
_logger.NotRelationalDatabase();
59-
}
60-
else
61-
{
62-
var databaseExists = await relationalDatabaseCreator.ExistsAsync();
63-
64-
if (databaseExists)
65-
{
66-
databaseExists = await relationalDatabaseCreator.HasTablesAsync();
67-
}
68-
69-
// TODO: Decouple
70-
var migrationsAssembly = context.GetService<IMigrationsAssembly>();
71-
// TODO: Decouple
72-
var modelDiffer = context.GetService<IMigrationsModelDiffer>();
73-
74-
var snapshotModel = migrationsAssembly.ModelSnapshot?.Model;
75-
// TODO: Decouple
76-
if (snapshotModel is IConventionModel conventionModel)
77-
{
78-
// TODO: Decouple
79-
var conventionSet = context.GetService<IConventionSetBuilder>().CreateConventionSet();
52+
var details = await errorContext.HttpContext.GetContextDetailsAsync(registeredContext, _logger);
8053

81-
// TODO: Decouple
82-
var typeMappingConvention = conventionSet.ModelFinalizingConventions.OfType<TypeMappingConvention>().FirstOrDefault();
83-
if (typeMappingConvention != null)
84-
{
85-
typeMappingConvention.ProcessModelFinalizing(conventionModel.Builder, null);
86-
}
87-
88-
// TODO: Decouple
89-
var relationalModelConvention = conventionSet.ModelFinalizedConventions.OfType<RelationalModelConvention>().FirstOrDefault();
90-
if (relationalModelConvention != null)
91-
{
92-
snapshotModel = relationalModelConvention.ProcessModelFinalized(conventionModel);
93-
}
94-
}
95-
96-
// TODO: Decouple
97-
if (snapshotModel is IMutableModel mutableModel)
98-
{
99-
snapshotModel = mutableModel.FinalizeModel();
100-
}
101-
102-
// HasDifferences will return true if there is no model snapshot, but if there is an existing database
103-
// and no model snapshot then we don't want to show the error page since they are most likely targeting
104-
// and existing database and have just misconfigured their model
105-
106-
contextDetails.Add(new DatabaseContextDetails
107-
{
108-
Type = registeredContext,
109-
DatabaseExists = databaseExists,
110-
PendingModelChanges = (!databaseExists || migrationsAssembly.ModelSnapshot != null)
111-
&& modelDiffer.HasDifferences(snapshotModel?.GetRelationalModel(), context.Model.GetRelationalModel()),
112-
PendingMigrations = databaseExists
113-
? await context.Database.GetPendingMigrationsAsync()
114-
: context.Database.GetMigrations()
115-
});
54+
if (details != null)
55+
{
56+
contextDetails.Add(details);
11657
}
11758
}
11859

119-
if (contextDetails.Count > 0)
60+
if (contextDetails.Any(c => c.PendingModelChanges || c.PendingMigrations.Any()))
12061
{
12162
var page = new DatabaseErrorPage
12263
{
12364
Model = new DatabaseErrorPageModel(errorContext.Exception, contextDetails, _options)
12465
};
12566

12667
await page.ExecuteAsync(errorContext.HttpContext);
68+
return;
12769
}
12870
}
12971
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
using Microsoft.AspNetCore.Http;
8+
using Microsoft.EntityFrameworkCore;
9+
using Microsoft.EntityFrameworkCore.Infrastructure;
10+
using Microsoft.EntityFrameworkCore.Metadata;
11+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
12+
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
13+
using Microsoft.EntityFrameworkCore.Migrations;
14+
using Microsoft.EntityFrameworkCore.Storage;
15+
using Microsoft.Extensions.DependencyInjection;
16+
using Microsoft.Extensions.Logging;
17+
18+
19+
namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
20+
{
21+
internal static class HttpContextDatabaseContextDetailsExtensions
22+
{
23+
public static async Task<DatabaseContextDetails> GetContextDetailsAsync(this HttpContext httpContext, Type dbcontextType, ILogger logger)
24+
{
25+
// TODO: Decouple
26+
var context = (DbContext)httpContext.RequestServices.GetService(dbcontextType);
27+
// TODO: Decouple
28+
var relationalDatabaseCreator = context.GetService<IDatabaseCreator>() as IRelationalDatabaseCreator;
29+
if (relationalDatabaseCreator == null)
30+
{
31+
logger.NotRelationalDatabase();
32+
}
33+
else
34+
{
35+
var databaseExists = await relationalDatabaseCreator.ExistsAsync();
36+
37+
if (databaseExists)
38+
{
39+
databaseExists = await relationalDatabaseCreator.HasTablesAsync();
40+
}
41+
42+
// TODO: Decouple
43+
var migrationsAssembly = context.GetService<IMigrationsAssembly>();
44+
// TODO: Decouple
45+
var modelDiffer = context.GetService<IMigrationsModelDiffer>();
46+
47+
var snapshotModel = migrationsAssembly.ModelSnapshot?.Model;
48+
// TODO: Decouple
49+
if (snapshotModel is IConventionModel conventionModel)
50+
{
51+
// TODO: Decouple
52+
var conventionSet = context.GetService<IConventionSetBuilder>().CreateConventionSet();
53+
54+
// TODO: Decouple
55+
var typeMappingConvention = conventionSet.ModelFinalizingConventions.OfType<TypeMappingConvention>().FirstOrDefault();
56+
if (typeMappingConvention != null)
57+
{
58+
typeMappingConvention.ProcessModelFinalizing(conventionModel.Builder, null);
59+
}
60+
61+
// TODO: Decouple
62+
var relationalModelConvention = conventionSet.ModelFinalizedConventions.OfType<RelationalModelConvention>().FirstOrDefault();
63+
if (relationalModelConvention != null)
64+
{
65+
snapshotModel = relationalModelConvention.ProcessModelFinalized(conventionModel);
66+
}
67+
}
68+
69+
// TODO: Decouple
70+
if (snapshotModel is IMutableModel mutableModel)
71+
{
72+
snapshotModel = mutableModel.FinalizeModel();
73+
}
74+
75+
// HasDifferences will return true if there is no model snapshot, but if there is an existing database
76+
// and no model snapshot then we don't want to show the error page since they are most likely targeting
77+
// and existing database and have just misconfigured their model
78+
79+
return new DatabaseContextDetails
80+
{
81+
Type = dbcontextType,
82+
DatabaseExists = databaseExists,
83+
PendingModelChanges = (!databaseExists || migrationsAssembly.ModelSnapshot != null)
84+
&& modelDiffer.HasDifferences(snapshotModel?.GetRelationalModel(), context.Model.GetRelationalModel()),
85+
PendingMigrations = databaseExists
86+
? await context.Database.GetPendingMigrationsAsync()
87+
: context.Database.GetMigrations()
88+
};
89+
}
90+
91+
return null;
92+
}
93+
}
94+
}

src/Middleware/Middleware.sln

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Perf", "Perf", "{4623F52E-2
301301
EndProject
302302
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ResponseCaching.Microbenchmarks", "perf\ResponseCaching.Microbenchmarks\Microsoft.AspNetCore.ResponseCaching.Microbenchmarks.csproj", "{80C8E810-1206-482E-BE17-961DD2EBFB11}"
303303
EndProject
304-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApplication", "Diagnostics.EntityFrameworkCore\sample\WebApplication\WebApplication.csproj", "{A988422C-5455-4DFD-8B3C-11BB97BA75EF}"
305-
EndProject
306304
Global
307305
GlobalSection(SolutionConfigurationPlatforms) = preSolution
308306
Debug|Any CPU = Debug|Any CPU
@@ -1645,18 +1643,6 @@ Global
16451643
{80C8E810-1206-482E-BE17-961DD2EBFB11}.Release|x64.Build.0 = Release|Any CPU
16461644
{80C8E810-1206-482E-BE17-961DD2EBFB11}.Release|x86.ActiveCfg = Release|Any CPU
16471645
{80C8E810-1206-482E-BE17-961DD2EBFB11}.Release|x86.Build.0 = Release|Any CPU
1648-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1649-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
1650-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Debug|x64.ActiveCfg = Debug|Any CPU
1651-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Debug|x64.Build.0 = Debug|Any CPU
1652-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Debug|x86.ActiveCfg = Debug|Any CPU
1653-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Debug|x86.Build.0 = Debug|Any CPU
1654-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
1655-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Release|Any CPU.Build.0 = Release|Any CPU
1656-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Release|x64.ActiveCfg = Release|Any CPU
1657-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Release|x64.Build.0 = Release|Any CPU
1658-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Release|x86.ActiveCfg = Release|Any CPU
1659-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF}.Release|x86.Build.0 = Release|Any CPU
16601646
EndGlobalSection
16611647
GlobalSection(SolutionProperties) = preSolution
16621648
HideSolutionNode = FALSE
@@ -1786,7 +1772,6 @@ Global
17861772
{C4D624B3-749E-41D8-A43B-B304BC3885EA} = {4623F52E-2070-4631-8DEE-7D2F48733FFD}
17871773
{8A9C1F6C-3A47-4868-AA95-3EBE0260F5A0} = {D6FA4ABE-E685-4EDD-8B06-D8777E76B472}
17881774
{80C8E810-1206-482E-BE17-961DD2EBFB11} = {4623F52E-2070-4631-8DEE-7D2F48733FFD}
1789-
{A988422C-5455-4DFD-8B3C-11BB97BA75EF} = {7FB67FE0-AC08-4C33-9904-8D33CE4D84F7}
17901775
EndGlobalSection
17911776
GlobalSection(ExtensibilityGlobals) = postSolution
17921777
SolutionGuid = {83786312-A93B-4BB4-AB06-7C6913A59AFA}

0 commit comments

Comments
 (0)