File: HttpContextDatabaseContextDetailsExtensions.cs
Web Access
Project: src\src\Middleware\Diagnostics.EntityFrameworkCore\src\Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.csproj (Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
 
namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore;
 
internal static class HttpContextDatabaseContextDetailsExtensions
{
    [RequiresDynamicCode("DbContext migrations operations are not supported with NativeAOT")]
    public static async ValueTask<DatabaseContextDetails?> GetContextDetailsAsync(this HttpContext httpContext, Type dbcontextType, ILogger logger)
    {
        var context = (DbContext?)httpContext.RequestServices.GetService(dbcontextType);
 
        if (context == null)
        {
            logger.ContextNotRegisteredDatabaseErrorPageMiddleware(dbcontextType.FullName!);
            return null;
        }
 
        var relationalDatabaseCreator = context.GetService<IDatabaseCreator>() as IRelationalDatabaseCreator;
        if (relationalDatabaseCreator == null)
        {
            logger.NotRelationalDatabase();
            return null;
        }
 
        var databaseExists = await relationalDatabaseCreator.ExistsAsync();
 
        if (databaseExists)
        {
            databaseExists = await relationalDatabaseCreator.HasTablesAsync();
        }
 
        var migrationsAssembly = context.GetService<IMigrationsAssembly>();
        var modelDiffer = context.GetService<IMigrationsModelDiffer>();
 
        var snapshotModel = migrationsAssembly.ModelSnapshot?.Model;
 
        if (snapshotModel is IMutableModel mutableModel)
        {
            snapshotModel = mutableModel.FinalizeModel();
        }
 
        if (snapshotModel != null)
        {
            snapshotModel = context.GetService<IModelRuntimeInitializer>().Initialize(snapshotModel);
        }
 
        // HasDifferences will return true if there is no model snapshot, but if there is an existing database
        // and no model snapshot then we don't want to show the error page since they are most likely targeting
        // and existing database and have just misconfigured their model
 
        return new DatabaseContextDetails(
            type: dbcontextType,
            databaseExists: databaseExists,
            pendingModelChanges: (!databaseExists || migrationsAssembly.ModelSnapshot != null)
                && modelDiffer.HasDifferences(
                    snapshotModel?.GetRelationalModel(),
                    context.GetService<IDesignTimeModel>().Model.GetRelationalModel()),
            pendingMigrations: databaseExists
                ? await context.Database.GetPendingMigrationsAsync()
                : context.Database.GetMigrations());
    }
}