Bring back "Apply Migrations" button on database error page
Mostly just a revert of the commit that removed this functionality, with a few changes: * Perform proper JavaScript encoding in the script part of the database error page Views/BaseView.cs * Use the builder pattern in the UseXyz extension methods on IApplicationBuilder (per #184). Also applying this to DatabaseErrorPageOptions to keep things consistent. * Fixing a few tests that were getting the context from DI but putting it in a using block so that it got disposed (rather than letting DI handle disposing).
This commit is contained in:
parent
111dab7ddf
commit
1c26436041
|
|
@ -42,6 +42,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Diagnostic
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ElmPageSample", "samples\ElmPageSample\ElmPageSample.xproj", "{FFD28DCF-C24F-4C59-9B6B-F3B74CE13129}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "DatabaseErrorPageSample", "samples\DatabaseErrorPageSample\DatabaseErrorPageSample.xproj", "{FF7F11A1-14E7-4948-A853-2487D99DE0C6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -206,6 +208,18 @@ Global
|
|||
{FFD28DCF-C24F-4C59-9B6B-F3B74CE13129}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{FFD28DCF-C24F-4C59-9B6B-F3B74CE13129}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FFD28DCF-C24F-4C59-9B6B-F3B74CE13129}.Release|x86.Build.0 = Release|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -225,5 +239,6 @@ Global
|
|||
{CC1F5841-FE10-4DDB-8477-C4DE92BA759F} = {ACAA0157-A8C4-4152-93DE-90CCDF304087}
|
||||
{83FFB65A-97B1-45AA-BCB8-3F43966BC8A3} = {509A6F36-AD80-4A18-B5B1-717D38DFF29D}
|
||||
{FFD28DCF-C24F-4C59-9B6B-F3B74CE13129} = {ACAA0157-A8C4-4152-93DE-90CCDF304087}
|
||||
{FF7F11A1-14E7-4948-A853-2487D99DE0C6} = {ACAA0157-A8C4-4152-93DE-90CCDF304087}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>ff7f11a1-14e7-4948-a853-2487d99de0c6</ProjectGuid>
|
||||
<RootNamespace>DatabaseErrorPageSample</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<DevelopmentServerPort>10233</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNET_ENV": "Development"
|
||||
}
|
||||
},
|
||||
"web": {
|
||||
"commandName": "web",
|
||||
"commandLineArgs": " "
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.Data.Entity;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DatabaseErrorPageSample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddEntityFramework()
|
||||
.AddSqlServer()
|
||||
.AddDbContext<MyContext>(options => options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=DatabaseErrorPageSample;Trusted_Connection=True;"));
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseDatabaseErrorPage();
|
||||
app.Run(context =>
|
||||
{
|
||||
context.ApplicationServices.GetService<MyContext>().Blog.FirstOrDefault();
|
||||
return Task.FromResult(0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class MyContext : DbContext
|
||||
{
|
||||
public DbSet<Blog> Blog { get; set; }
|
||||
}
|
||||
|
||||
public class Blog
|
||||
{
|
||||
public int BlogId { get; set; }
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"webroot": "wwwroot",
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Diagnostics.Entity": "7.0.0-*",
|
||||
"EntityFramework.MicrosoftSqlServer": "7.0.0-*",
|
||||
"EntityFramework.Commands": "7.0.0-*",
|
||||
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
|
||||
"Microsoft.AspNet.Server.Kestrel": "1.0.0-*"
|
||||
},
|
||||
"commands": {
|
||||
"ef": "EntityFramework.Commands",
|
||||
"web": "Microsoft.AspNet.Server.Kestrel"
|
||||
},
|
||||
"frameworks": {
|
||||
"dnx451": { },
|
||||
"dnxcore50": { }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
Sample demonstrating ErrorPage middleware.
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
|
||||
</handlers>
|
||||
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" forwardWindowsAuthToken="false" startupTimeLimit="3600" />
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNet.Diagnostics.Entity;
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Utilities;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Builder
|
||||
{
|
||||
|
|
@ -13,15 +14,35 @@ namespace Microsoft.AspNet.Builder
|
|||
{
|
||||
Check.NotNull(builder, nameof(builder));
|
||||
|
||||
return builder.UseDatabaseErrorPage(DatabaseErrorPageOptions.ShowAll);
|
||||
return builder.UseDatabaseErrorPage(options => options.EnableAll());
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseDatabaseErrorPage([NotNull] this IApplicationBuilder builder, [NotNull] DatabaseErrorPageOptions options)
|
||||
public static IApplicationBuilder UseDatabaseErrorPage([NotNull] this IApplicationBuilder builder, [NotNull] Action<DatabaseErrorPageOptions> optionsAction)
|
||||
{
|
||||
Check.NotNull(builder, nameof(builder));
|
||||
Check.NotNull(optionsAction, nameof(optionsAction));
|
||||
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
optionsAction(options);
|
||||
|
||||
builder = builder.UseMiddleware<DatabaseErrorPageMiddleware>(options);
|
||||
|
||||
if(options.EnableMigrationCommands)
|
||||
{
|
||||
builder.UseMigrationsEndPoint(o => o.Path = options.MigrationsEndPointPath);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static void EnableAll([NotNull] this DatabaseErrorPageOptions options)
|
||||
{
|
||||
Check.NotNull(options, nameof(options));
|
||||
|
||||
return builder.UseMiddleware<DatabaseErrorPageMiddleware>(options);
|
||||
options.ShowExceptionDetails = true;
|
||||
options.ListMigrations = true;
|
||||
options.EnableMigrationCommands = true;
|
||||
options.MigrationsEndPointPath = MigrationsEndPointOptions.DefaultPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity
|
||||
{
|
||||
public class DatabaseErrorPageOptions
|
||||
{
|
||||
public static DatabaseErrorPageOptions ShowAll => new DatabaseErrorPageOptions
|
||||
{
|
||||
ShowExceptionDetails = true,
|
||||
ListMigrations = true
|
||||
};
|
||||
|
||||
public virtual bool ShowExceptionDetails { get; set; }
|
||||
|
||||
public virtual bool ListMigrations { get; set; }
|
||||
public virtual bool EnableMigrationCommands { get; set; }
|
||||
public virtual PathString MigrationsEndPointPath { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNet.Diagnostics.Entity;
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Utilities;
|
||||
|
||||
namespace Microsoft.AspNet.Builder
|
||||
{
|
||||
public static class MigrationsEndPointExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseMigrationsEndPoint([NotNull] this IApplicationBuilder builder)
|
||||
{
|
||||
Check.NotNull(builder, "builder");
|
||||
|
||||
return builder.UseMigrationsEndPoint(options => { });
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseMigrationsEndPoint([NotNull] this IApplicationBuilder builder, [NotNull] Action<MigrationsEndPointOptions> optionsAction)
|
||||
{
|
||||
Check.NotNull(builder, "builder");
|
||||
Check.NotNull(optionsAction, "optionsAction");
|
||||
|
||||
var options = new MigrationsEndPointOptions();
|
||||
optionsAction(options);
|
||||
|
||||
return builder.UseMiddleware<MigrationsEndPointMiddleware>(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Utilities;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Data.Entity;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity
|
||||
{
|
||||
public class MigrationsEndPointMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger _logger;
|
||||
private readonly MigrationsEndPointOptions _options;
|
||||
|
||||
public MigrationsEndPointMiddleware(
|
||||
[NotNull] RequestDelegate next,
|
||||
[NotNull] IServiceProvider serviceProvider,
|
||||
[NotNull] ILogger<MigrationsEndPointMiddleware> logger,
|
||||
[NotNull] MigrationsEndPointOptions options)
|
||||
{
|
||||
Check.NotNull(next, "next");
|
||||
Check.NotNull(serviceProvider, "serviceProvider");
|
||||
Check.NotNull(logger, "logger");
|
||||
Check.NotNull(options, "options");
|
||||
|
||||
_next = next;
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public virtual async Task Invoke([NotNull] HttpContext context)
|
||||
{
|
||||
Check.NotNull(context, "context");
|
||||
|
||||
if (context.Request.Path.Equals(_options.Path))
|
||||
{
|
||||
_logger.LogVerbose(Strings.FormatMigrationsEndPointMiddleware_RequestPathMatched(context.Request.Path));
|
||||
|
||||
var db = await GetDbContext(context, _logger);
|
||||
if (db != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogVerbose(Strings.FormatMigrationsEndPointMiddleware_ApplyingMigrations(db.GetType().FullName));
|
||||
|
||||
db.Database.Migrate();
|
||||
|
||||
context.Response.StatusCode = (int)HttpStatusCode.NoContent;
|
||||
context.Response.Headers.Add("Pragma", new[] { "no-cache" });
|
||||
context.Response.Headers.Add("Cache-Control", new[] { "no-cache" });
|
||||
|
||||
_logger.LogVerbose(Strings.FormatMigrationsEndPointMiddleware_Applied(db.GetType().FullName));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var message = Strings.FormatMigrationsEndPointMiddleware_Exception(db.GetType().FullName) + ex.ToString();
|
||||
_logger.LogError(message);
|
||||
throw new InvalidOperationException(message, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<DbContext> GetDbContext(HttpContext context, ILogger logger)
|
||||
{
|
||||
var form = await context.Request.ReadFormAsync();
|
||||
var contextTypeName = form["context"];
|
||||
if (string.IsNullOrWhiteSpace(contextTypeName))
|
||||
{
|
||||
logger.LogError(Strings.MigrationsEndPointMiddleware_NoContextType);
|
||||
await WriteErrorToResponse(context.Response, Strings.MigrationsEndPointMiddleware_NoContextType);
|
||||
return null;
|
||||
}
|
||||
|
||||
var contextType = Type.GetType(contextTypeName);
|
||||
if (contextType == null)
|
||||
{
|
||||
var message = Strings.FormatMigrationsEndPointMiddleware_InvalidContextType(contextTypeName);
|
||||
logger.LogError(message);
|
||||
await WriteErrorToResponse(context.Response, message);
|
||||
return null;
|
||||
}
|
||||
|
||||
var db = (DbContext)context.RequestServices.GetService(contextType);
|
||||
if (db == null)
|
||||
{
|
||||
var message = Strings.FormatMigrationsEndPointMiddleware_ContextNotRegistered(contextType.FullName);
|
||||
logger.LogError(message);
|
||||
await WriteErrorToResponse(context.Response, message);
|
||||
return null;
|
||||
}
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
private static async Task WriteErrorToResponse(HttpResponse response, string error)
|
||||
{
|
||||
response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
response.Headers.Add("Pragma", new[] { "no-cache" });
|
||||
response.Headers.Add("Cache-Control", new[] { "no-cache" });
|
||||
response.ContentType = "text/plain";
|
||||
|
||||
// Padding to >512 to ensure IE doesn't hide the message
|
||||
// http://stackoverflow.com/questions/16741062/what-rules-does-ie-use-to-determine-whether-to-show-the-entity-body
|
||||
await response.WriteAsync(error.PadRight(513));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity
|
||||
{
|
||||
public class MigrationsEndPointOptions
|
||||
{
|
||||
public static PathString DefaultPath = new PathString("/ApplyDatabaseMigrations");
|
||||
|
||||
public virtual PathString Path { get; set; } = DefaultPath;
|
||||
}
|
||||
}
|
||||
|
|
@ -90,6 +90,70 @@ namespace Microsoft.AspNet.Diagnostics.Entity
|
|||
return GetString("DatabaseErrorPage_AddMigrationCommand");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply Migrations
|
||||
/// </summary>
|
||||
internal static string DatabaseErrorPage_ApplyMigrationsButton
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_ApplyMigrationsButton"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply Migrations
|
||||
/// </summary>
|
||||
internal static string FormatDatabaseErrorPage_ApplyMigrationsButton()
|
||||
{
|
||||
return GetString("DatabaseErrorPage_ApplyMigrationsButton");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrations Applied
|
||||
/// </summary>
|
||||
internal static string DatabaseErrorPage_ApplyMigrationsButtonDone
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_ApplyMigrationsButtonDone"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrations Applied
|
||||
/// </summary>
|
||||
internal static string FormatDatabaseErrorPage_ApplyMigrationsButtonDone()
|
||||
{
|
||||
return GetString("DatabaseErrorPage_ApplyMigrationsButtonDone");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applying Migrations...
|
||||
/// </summary>
|
||||
internal static string DatabaseErrorPage_ApplyMigrationsButtonRunning
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_ApplyMigrationsButtonRunning"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applying Migrations...
|
||||
/// </summary>
|
||||
internal static string FormatDatabaseErrorPage_ApplyMigrationsButtonRunning()
|
||||
{
|
||||
return GetString("DatabaseErrorPage_ApplyMigrationsButtonRunning");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An error occurred applying migrations, try applying them from the command line
|
||||
/// </summary>
|
||||
internal static string DatabaseErrorPage_ApplyMigrationsFailed
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_ApplyMigrationsFailed"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An error occurred applying migrations, try applying them from the command line
|
||||
/// </summary>
|
||||
internal static string FormatDatabaseErrorPage_ApplyMigrationsFailed()
|
||||
{
|
||||
return GetString("DatabaseErrorPage_ApplyMigrationsFailed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// You can also apply migrations from the command line:
|
||||
/// </summary>
|
||||
|
|
@ -106,6 +170,22 @@ namespace Microsoft.AspNet.Diagnostics.Entity
|
|||
return GetString("DatabaseErrorPage_HowToApplyFromCmd");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try refreshing the page
|
||||
/// </summary>
|
||||
internal static string DatabaseErrorPage_MigrationsAppliedRefresh
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_MigrationsAppliedRefresh"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try refreshing the page
|
||||
/// </summary>
|
||||
internal static string FormatDatabaseErrorPage_MigrationsAppliedRefresh()
|
||||
{
|
||||
return GetString("DatabaseErrorPage_MigrationsAppliedRefresh");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// From the command line, scaffold a new migration and apply it to the database:
|
||||
/// </summary>
|
||||
|
|
@ -234,6 +314,118 @@ namespace Microsoft.AspNet.Diagnostics.Entity
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("InvalidEnumValue", "argumentName", "enumType"), argumentName, enumType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrations successfully applied for context '{0}'.
|
||||
/// </summary>
|
||||
internal static string MigrationsEndPointMiddleware_Applied
|
||||
{
|
||||
get { return GetString("MigrationsEndPointMiddleware_Applied"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrations successfully applied for context '{0}'.
|
||||
/// </summary>
|
||||
internal static string FormatMigrationsEndPointMiddleware_Applied(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("MigrationsEndPointMiddleware_Applied"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request is valid, applying migrations for context '{0}'.
|
||||
/// </summary>
|
||||
internal static string MigrationsEndPointMiddleware_ApplyingMigrations
|
||||
{
|
||||
get { return GetString("MigrationsEndPointMiddleware_ApplyingMigrations"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request is valid, applying migrations for context '{0}'.
|
||||
/// </summary>
|
||||
internal static string FormatMigrationsEndPointMiddleware_ApplyingMigrations(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("MigrationsEndPointMiddleware_ApplyingMigrations"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The context type '{0}' was not found in services. This usually means the context was not registered in services during startup. You probably want to call AddScoped<{0}>() inside the UseServices(...) call in your application startup code.
|
||||
/// </summary>
|
||||
internal static string MigrationsEndPointMiddleware_ContextNotRegistered
|
||||
{
|
||||
get { return GetString("MigrationsEndPointMiddleware_ContextNotRegistered"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The context type '{0}' was not found in services. This usually means the context was not registered in services during startup. You probably want to call AddScoped<{0}>() inside the UseServices(...) call in your application startup code.
|
||||
/// </summary>
|
||||
internal static string FormatMigrationsEndPointMiddleware_ContextNotRegistered(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("MigrationsEndPointMiddleware_ContextNotRegistered"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An error occurred while applying the migrations for '{0}'. See InnerException for details.
|
||||
/// </summary>
|
||||
internal static string MigrationsEndPointMiddleware_Exception
|
||||
{
|
||||
get { return GetString("MigrationsEndPointMiddleware_Exception"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An error occurred while applying the migrations for '{0}'. See InnerException for details.
|
||||
/// </summary>
|
||||
internal static string FormatMigrationsEndPointMiddleware_Exception(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("MigrationsEndPointMiddleware_Exception"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The context type '{0}' could not be loaded. Ensure this is the correct type name for the context you are trying to apply migrations for.
|
||||
/// </summary>
|
||||
internal static string MigrationsEndPointMiddleware_InvalidContextType
|
||||
{
|
||||
get { return GetString("MigrationsEndPointMiddleware_InvalidContextType"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The context type '{0}' could not be loaded. Ensure this is the correct type name for the context you are trying to apply migrations for.
|
||||
/// </summary>
|
||||
internal static string FormatMigrationsEndPointMiddleware_InvalidContextType(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("MigrationsEndPointMiddleware_InvalidContextType"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// No context type was specified. Ensure the form data from the request includes a contextTypeName value, specifying the context to apply migrations for.
|
||||
/// </summary>
|
||||
internal static string MigrationsEndPointMiddleware_NoContextType
|
||||
{
|
||||
get { return GetString("MigrationsEndPointMiddleware_NoContextType"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// No context type was specified. Ensure the form data from the request includes a contextTypeName value, specifying the context to apply migrations for.
|
||||
/// </summary>
|
||||
internal static string FormatMigrationsEndPointMiddleware_NoContextType()
|
||||
{
|
||||
return GetString("MigrationsEndPointMiddleware_NoContextType");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request path matched the path configured for this migrations endpoint ({0}). Attempting to process the migrations request.
|
||||
/// </summary>
|
||||
internal static string MigrationsEndPointMiddleware_RequestPathMatched
|
||||
{
|
||||
get { return GetString("MigrationsEndPointMiddleware_RequestPathMatched"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request path matched the path configured for this migrations endpoint ({0}). Attempting to process the migrations request.
|
||||
/// </summary>
|
||||
internal static string FormatMigrationsEndPointMiddleware_RequestPathMatched(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("MigrationsEndPointMiddleware_RequestPathMatched"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A database operation failed while processing the request.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -132,9 +132,24 @@
|
|||
<data name="DatabaseErrorPage_AddMigrationCommand" xml:space="preserve">
|
||||
<value>> dnx ef migrations add [migration name]</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_ApplyMigrationsButton" xml:space="preserve">
|
||||
<value>Apply Migrations</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_ApplyMigrationsButtonDone" xml:space="preserve">
|
||||
<value>Migrations Applied</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_ApplyMigrationsButtonRunning" xml:space="preserve">
|
||||
<value>Applying Migrations...</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_ApplyMigrationsFailed" xml:space="preserve">
|
||||
<value>An error occurred applying migrations, try applying them from the command line</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_HowToApplyFromCmd" xml:space="preserve">
|
||||
<value>You can also apply migrations from the command line:</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_MigrationsAppliedRefresh" xml:space="preserve">
|
||||
<value>Try refreshing the page</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_NoDbOrMigrationsInfo" xml:space="preserve">
|
||||
<value>From the command line, scaffold a new migration and apply it to the database:</value>
|
||||
</data>
|
||||
|
|
@ -159,6 +174,27 @@
|
|||
<data name="InvalidEnumValue" xml:space="preserve">
|
||||
<value>The value provided for argument '{argumentName}' must be a valid value of enum type '{enumType}'.</value>
|
||||
</data>
|
||||
<data name="MigrationsEndPointMiddleware_Applied" xml:space="preserve">
|
||||
<value>Migrations successfully applied for context '{0}'.</value>
|
||||
</data>
|
||||
<data name="MigrationsEndPointMiddleware_ApplyingMigrations" xml:space="preserve">
|
||||
<value>Request is valid, applying migrations for context '{0}'.</value>
|
||||
</data>
|
||||
<data name="MigrationsEndPointMiddleware_ContextNotRegistered" xml:space="preserve">
|
||||
<value>The context type '{0}' was not found in services. This usually means the context was not registered in services during startup. You probably want to call AddScoped<{0}>() inside the UseServices(...) call in your application startup code.</value>
|
||||
</data>
|
||||
<data name="MigrationsEndPointMiddleware_Exception" xml:space="preserve">
|
||||
<value>An error occurred while applying the migrations for '{0}'. See InnerException for details.</value>
|
||||
</data>
|
||||
<data name="MigrationsEndPointMiddleware_InvalidContextType" xml:space="preserve">
|
||||
<value>The context type '{0}' could not be loaded. Ensure this is the correct type name for the context you are trying to apply migrations for.</value>
|
||||
</data>
|
||||
<data name="MigrationsEndPointMiddleware_NoContextType" xml:space="preserve">
|
||||
<value>No context type was specified. Ensure the form data from the request includes a contextTypeName value, specifying the context to apply migrations for.</value>
|
||||
</data>
|
||||
<data name="MigrationsEndPointMiddleware_RequestPathMatched" xml:space="preserve">
|
||||
<value>Request path matched the path configured for this migrations endpoint ({0}). Attempting to process the migrations request.</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_Title" xml:space="preserve">
|
||||
<value>A database operation failed while processing the request.</value>
|
||||
</data>
|
||||
|
|
|
|||
|
|
@ -13,22 +13,12 @@ using System.Linq
|
|||
#line hidden
|
||||
;
|
||||
#line 3 "DatabaseErrorPage.cshtml"
|
||||
using JetBrains.Annotations;
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
#line 4 "DatabaseErrorPage.cshtml"
|
||||
using Microsoft.AspNet.Diagnostics.Entity
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
;
|
||||
#line 5 "DatabaseErrorPage.cshtml"
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Utilities;
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
#line 6 "DatabaseErrorPage.cshtml"
|
||||
#line 4 "DatabaseErrorPage.cshtml"
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Views
|
||||
|
||||
#line default
|
||||
|
|
@ -38,20 +28,18 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
|
|||
|
||||
public class DatabaseErrorPage : Microsoft.AspNet.Diagnostics.Views.BaseView
|
||||
{
|
||||
#line 14 "DatabaseErrorPage.cshtml"
|
||||
#line 11 "DatabaseErrorPage.cshtml"
|
||||
|
||||
private DatabaseErrorPageModel _model;
|
||||
public DatabaseErrorPageModel Model { get; set; }
|
||||
|
||||
public virtual DatabaseErrorPageModel Model
|
||||
public string UrlEncode(string content)
|
||||
{
|
||||
get { return _model; }
|
||||
[param: NotNull]
|
||||
set
|
||||
{
|
||||
Check.NotNull(value, "value");
|
||||
return UrlEncoder.UrlEncode(content);
|
||||
}
|
||||
|
||||
_model = value;
|
||||
}
|
||||
public string JavaScriptEncode(string content)
|
||||
{
|
||||
return JavaScriptStringEncoder.JavaScriptStringEncode(content);
|
||||
}
|
||||
|
||||
#line default
|
||||
|
|
@ -64,10 +52,9 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
|
|||
#pragma warning disable 1998
|
||||
public override async Task ExecuteAsync()
|
||||
{
|
||||
#line 7 "DatabaseErrorPage.cshtml"
|
||||
#line 5 "DatabaseErrorPage.cshtml"
|
||||
|
||||
Response.StatusCode = 500;
|
||||
// TODO: Response.ReasonPhrase = "Internal Server Error";
|
||||
Response.ContentType = "text/html";
|
||||
Response.ContentLength = null; // Clear any prior Content-Length
|
||||
|
||||
|
|
@ -76,26 +63,21 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
|
|||
|
||||
WriteLiteral("<!DOCTYPE html>\r\n\r\n<html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r" +
|
||||
"\n <meta charset=\"utf-8\" />\r\n <title>Internal Server Error</title>\r\n <st" +
|
||||
"yle>\r\n body {\r\n font-family: 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;\r\n font-size: .813em;\r\n line-height: 1.4em;\r\n color: #222;\r\n}\r\n\r\nh1, h2, h3, h4, h5 {\r\n font-weight: 100;\r\n}\r\n\r\nh1 {\r\n color: #44525e;\r\n margin: 15px 0 15px 0;\r\n}\r\n\r\nh2 {\r\n margin: 10px 5px 0 0;\r\n}\r\n\r\nh3 {\r\n color: #363636;\r\n margin: 5px 5px 0 0;\r\n}\r\n\r\ncode {\r\n font-family: Consolas, \"Courier New\", courier, monospace;\r\n}\r\n\r\na {\r\n color: #1ba1e2;\r\n text-decoration: none;\r\n}\r\n\r\n a:hover {\r\n color: #13709e;\r\n text-decoration: underline;\r\n }\r\n\r\nhr {\r\n border: 1px #ddd solid;\r\n}\r\n\r\nbody .titleerror {\r\n padding: 3px;\r\n}\r\n\r\n#applyMigrations {\r\n font-size: 14px;\r\n background: #44c5f2;\r\n color: #ffffff;\r\n display: inline-block;\r\n padding: 6px 12px;\r\n margin-bottom: 0;\r\n font-weight: normal;\r\n text-align: center;\r\n white-space: nowrap;\r\n vertical-align: middle;\r\n cursor: pointer;\r\n border: 1px solid transparent;\r\n}\r\n\r\n #applyMigrations:disabled {\r\n background-color: #a9e4f9;\r\n border-color: #44c5f2;\r\n }\r\n\r\n.error {\r\n color: red;\r\n}\r\n\r\n.expanded {\r\n display: block;\r\n}\r\n\r\n.collapsed {\r\n display: none;\r\n}\r\n\r\n ");
|
||||
#line 37 "DatabaseErrorPage.cshtml"
|
||||
Write(string.Empty);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n </style>\r\n</head>\r\n<body>\r\n <h1>");
|
||||
#line 41 "DatabaseErrorPage.cshtml"
|
||||
"yle>\r\n body {\r\n font-family: 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;\r\n font-size: .813em;\r\n line-height: 1.4em;\r\n color: #222;\r\n}\r\n\r\nh1, h2, h3, h4, h5 {\r\n font-weight: 100;\r\n}\r\n\r\nh1 {\r\n color: #44525e;\r\n margin: 15px 0 15px 0;\r\n}\r\n\r\nh2 {\r\n margin: 10px 5px 0 0;\r\n}\r\n\r\nh3 {\r\n color: #363636;\r\n margin: 5px 5px 0 0;\r\n}\r\n\r\ncode {\r\n font-family: Consolas, \"Courier New\", courier, monospace;\r\n}\r\n\r\na {\r\n color: #1ba1e2;\r\n text-decoration: none;\r\n}\r\n\r\n a:hover {\r\n color: #13709e;\r\n text-decoration: underline;\r\n }\r\n\r\nhr {\r\n border: 1px #ddd solid;\r\n}\r\n\r\nbody .titleerror {\r\n padding: 3px;\r\n}\r\n\r\n#applyMigrations {\r\n font-size: 14px;\r\n background: #44c5f2;\r\n color: #ffffff;\r\n display: inline-block;\r\n padding: 6px 12px;\r\n margin-bottom: 0;\r\n font-weight: normal;\r\n text-align: center;\r\n white-space: nowrap;\r\n vertical-align: middle;\r\n cursor: pointer;\r\n border: 1px solid transparent;\r\n}\r\n\r\n #applyMigrations:disabled {\r\n background-color: #a9e4f9;\r\n border-color: #44c5f2;\r\n }\r\n\r\n.error {\r\n color: red;\r\n}\r\n\r\n.expanded {\r\n display: block;\r\n}\r\n\r\n.collapsed {\r\n display: none;\r\n}\r\n\r\n </style>\r\n</head>\r\n<body>\r\n" +
|
||||
" <h1>");
|
||||
#line 35 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_Title);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</h1>\r\n");
|
||||
#line 42 "DatabaseErrorPage.cshtml"
|
||||
#line 36 "DatabaseErrorPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 42 "DatabaseErrorPage.cshtml"
|
||||
#line 36 "DatabaseErrorPage.cshtml"
|
||||
if (Model.Options.ShowExceptionDetails)
|
||||
{
|
||||
|
||||
|
|
@ -103,13 +85,13 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
|
|||
#line hidden
|
||||
|
||||
WriteLiteral(" <p>\r\n");
|
||||
#line 45 "DatabaseErrorPage.cshtml"
|
||||
#line 39 "DatabaseErrorPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 45 "DatabaseErrorPage.cshtml"
|
||||
#line 39 "DatabaseErrorPage.cshtml"
|
||||
for (Exception ex = Model.Exception; ex != null; ex = ex.InnerException)
|
||||
{
|
||||
|
||||
|
|
@ -117,39 +99,39 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
|
|||
#line hidden
|
||||
|
||||
WriteLiteral(" <span>");
|
||||
#line 47 "DatabaseErrorPage.cshtml"
|
||||
#line 41 "DatabaseErrorPage.cshtml"
|
||||
Write(ex.GetType().Name);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(": ");
|
||||
#line 47 "DatabaseErrorPage.cshtml"
|
||||
#line 41 "DatabaseErrorPage.cshtml"
|
||||
Write(ex.Message);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</span>\r\n <br />\r\n");
|
||||
#line 49 "DatabaseErrorPage.cshtml"
|
||||
#line 43 "DatabaseErrorPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </p>\r\n <hr />\r\n");
|
||||
#line 52 "DatabaseErrorPage.cshtml"
|
||||
#line 46 "DatabaseErrorPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral("\r\n");
|
||||
#line 54 "DatabaseErrorPage.cshtml"
|
||||
#line 48 "DatabaseErrorPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 54 "DatabaseErrorPage.cshtml"
|
||||
#line 48 "DatabaseErrorPage.cshtml"
|
||||
if (!Model.DatabaseExists && !Model.PendingMigrations.Any())
|
||||
{
|
||||
|
||||
|
|
@ -157,31 +139,31 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
|
|||
#line hidden
|
||||
|
||||
WriteLiteral(" <h2>");
|
||||
#line 56 "DatabaseErrorPage.cshtml"
|
||||
#line 50 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.FormatDatabaseErrorPage_NoDbOrMigrationsTitle(Model.ContextType.Name));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</h2>\r\n <p>");
|
||||
#line 57 "DatabaseErrorPage.cshtml"
|
||||
#line 51 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_NoDbOrMigrationsInfo);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</p>\r\n <code> ");
|
||||
#line 58 "DatabaseErrorPage.cshtml"
|
||||
#line 52 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_AddMigrationCommand);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" </code>\r\n <br />\r\n <code> ");
|
||||
#line 60 "DatabaseErrorPage.cshtml"
|
||||
#line 54 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_ApplyMigrationsCommand);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" </code>\r\n <hr />\r\n");
|
||||
#line 62 "DatabaseErrorPage.cshtml"
|
||||
#line 56 "DatabaseErrorPage.cshtml"
|
||||
}
|
||||
else if (Model.PendingMigrations.Any())
|
||||
{
|
||||
|
|
@ -190,25 +172,25 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
|
|||
#line hidden
|
||||
|
||||
WriteLiteral(" <div>\r\n <h2>");
|
||||
#line 66 "DatabaseErrorPage.cshtml"
|
||||
#line 60 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.FormatDatabaseErrorPage_PendingMigrationsTitle(Model.ContextType.Name));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</h2>\r\n <p>");
|
||||
#line 67 "DatabaseErrorPage.cshtml"
|
||||
#line 61 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.FormatDatabaseErrorPage_PendingMigrationsInfo(Model.ContextType.Name));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</p>\r\n\r\n");
|
||||
#line 69 "DatabaseErrorPage.cshtml"
|
||||
#line 63 "DatabaseErrorPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 69 "DatabaseErrorPage.cshtml"
|
||||
#line 63 "DatabaseErrorPage.cshtml"
|
||||
if (Model.Options.ListMigrations)
|
||||
{
|
||||
|
||||
|
|
@ -216,13 +198,13 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
|
|||
#line hidden
|
||||
|
||||
WriteLiteral(" <ul>\r\n");
|
||||
#line 72 "DatabaseErrorPage.cshtml"
|
||||
#line 66 "DatabaseErrorPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 72 "DatabaseErrorPage.cshtml"
|
||||
#line 66 "DatabaseErrorPage.cshtml"
|
||||
foreach (var migration in Model.PendingMigrations)
|
||||
{
|
||||
|
||||
|
|
@ -230,39 +212,138 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
|
|||
#line hidden
|
||||
|
||||
WriteLiteral(" <li>");
|
||||
#line 74 "DatabaseErrorPage.cshtml"
|
||||
#line 68 "DatabaseErrorPage.cshtml"
|
||||
Write(migration);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</li>\r\n");
|
||||
#line 75 "DatabaseErrorPage.cshtml"
|
||||
#line 69 "DatabaseErrorPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </ul>\r\n");
|
||||
#line 77 "DatabaseErrorPage.cshtml"
|
||||
#line 71 "DatabaseErrorPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral("\r\n");
|
||||
#line 73 "DatabaseErrorPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 73 "DatabaseErrorPage.cshtml"
|
||||
if (Model.Options.EnableMigrationCommands)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <p>\r\n <button id=\"applyMigrations\" onclick=\"Ap" +
|
||||
"plyMigrations()\">");
|
||||
#line 76 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_ApplyMigrationsButton);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"</button>
|
||||
<span id=""applyMigrationsError"" class=""error""></span>
|
||||
<span id=""applyMigrationsSuccess""></span>
|
||||
</p>
|
||||
<script>
|
||||
function ApplyMigrations() {
|
||||
applyMigrations.disabled = true;
|
||||
applyMigrationsError.innerHTML = """";
|
||||
applyMigrations.innerHTML = """);
|
||||
#line 84 "DatabaseErrorPage.cshtml"
|
||||
Write(JavaScriptEncode(Strings.DatabaseErrorPage_ApplyMigrationsButtonRunning));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\";\r\n\r\n var req = new XMLHttpRequest();\r\n\r\n " +
|
||||
" req.onload = function (e) {\r\n if (req.status " +
|
||||
"=== 204) {\r\n applyMigrations.innerHTML = \"");
|
||||
#line 90 "DatabaseErrorPage.cshtml"
|
||||
Write(JavaScriptEncode(Strings.DatabaseErrorPage_ApplyMigrationsButtonDone));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\";\r\n applyMigrationsSuccess.innerHTML = \"");
|
||||
#line 91 "DatabaseErrorPage.cshtml"
|
||||
Write(JavaScriptEncode(Strings.DatabaseErrorPage_MigrationsAppliedRefresh));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@""";
|
||||
} else {
|
||||
ErrorApplyingMigrations();
|
||||
}
|
||||
};
|
||||
|
||||
req.onerror = function (e) {
|
||||
ErrorApplyingMigrations();
|
||||
};
|
||||
|
||||
var formBody = ""context=");
|
||||
#line 101 "DatabaseErrorPage.cshtml"
|
||||
Write(JavaScriptEncode(UrlEncode(Model.ContextType.AssemblyQualifiedName)));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\";\r\n req.open(\"POST\", \"");
|
||||
#line 102 "DatabaseErrorPage.cshtml"
|
||||
Write(JavaScriptEncode(Model.Options.MigrationsEndPointPath.Value));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@""", true);
|
||||
req.setRequestHeader(""Content-type"", ""application/x-www-form-urlencoded"");
|
||||
req.setRequestHeader(""Content-length"", formBody.length);
|
||||
req.setRequestHeader(""Connection"", ""close"");
|
||||
req.send(formBody);
|
||||
}
|
||||
|
||||
function ErrorApplyingMigrations() {
|
||||
applyMigrations.innerHTML = """);
|
||||
#line 110 "DatabaseErrorPage.cshtml"
|
||||
Write(JavaScriptEncode(Strings.DatabaseErrorPage_ApplyMigrationsButton));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\";\r\n applyMigrationsError.innerHTML = \"");
|
||||
#line 111 "DatabaseErrorPage.cshtml"
|
||||
Write(JavaScriptEncode(Strings.DatabaseErrorPage_ApplyMigrationsFailed));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\";\r\n applyMigrations.disabled = false;\r\n " +
|
||||
" }\r\n </script>\r\n");
|
||||
#line 115 "DatabaseErrorPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral("\r\n <p>");
|
||||
#line 79 "DatabaseErrorPage.cshtml"
|
||||
#line 117 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_HowToApplyFromCmd);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</p>\r\n <code>");
|
||||
#line 80 "DatabaseErrorPage.cshtml"
|
||||
#line 118 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_ApplyMigrationsCommand);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</code>\r\n <hr />\r\n </div>\r\n");
|
||||
#line 83 "DatabaseErrorPage.cshtml"
|
||||
#line 121 "DatabaseErrorPage.cshtml"
|
||||
}
|
||||
else if (Model.PendingModelChanges)
|
||||
{
|
||||
|
|
@ -271,31 +352,31 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
|
|||
#line hidden
|
||||
|
||||
WriteLiteral(" <div>\r\n <h2>");
|
||||
#line 87 "DatabaseErrorPage.cshtml"
|
||||
#line 125 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.FormatDatabaseErrorPage_PendingChangesTitle(Model.ContextType.Name));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</h2>\r\n <p>");
|
||||
#line 88 "DatabaseErrorPage.cshtml"
|
||||
#line 126 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_PendingChangesInfo);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</p>\r\n <code>");
|
||||
#line 89 "DatabaseErrorPage.cshtml"
|
||||
#line 127 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_AddMigrationCommand);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</code>\r\n <br />\r\n <code>");
|
||||
#line 91 "DatabaseErrorPage.cshtml"
|
||||
#line 129 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_ApplyMigrationsCommand);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</code>\r\n <hr />\r\n </div>\r\n");
|
||||
#line 94 "DatabaseErrorPage.cshtml"
|
||||
#line 132 "DatabaseErrorPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
|
|
|
|||
|
|
@ -1,29 +1,24 @@
|
|||
@using System
|
||||
@using System.Linq
|
||||
@using JetBrains.Annotations;
|
||||
@using Microsoft.AspNet.Diagnostics.Entity
|
||||
@using Microsoft.AspNet.Diagnostics.Entity.Utilities;
|
||||
@using Microsoft.AspNet.Diagnostics.Entity.Views
|
||||
@{
|
||||
Response.StatusCode = 500;
|
||||
// TODO: Response.ReasonPhrase = "Internal Server Error";
|
||||
Response.ContentType = "text/html";
|
||||
Response.ContentLength = null; // Clear any prior Content-Length
|
||||
}
|
||||
@functions
|
||||
{
|
||||
private DatabaseErrorPageModel _model;
|
||||
public DatabaseErrorPageModel Model { get; set; }
|
||||
|
||||
public virtual DatabaseErrorPageModel Model
|
||||
public string UrlEncode(string content)
|
||||
{
|
||||
get { return _model; }
|
||||
[param: NotNull]
|
||||
set
|
||||
{
|
||||
Check.NotNull(value, "value");
|
||||
return UrlEncoder.UrlEncode(content);
|
||||
}
|
||||
|
||||
_model = value;
|
||||
}
|
||||
public string JavaScriptEncode(string content)
|
||||
{
|
||||
return JavaScriptStringEncoder.JavaScriptStringEncode(content);
|
||||
}
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
|
|
@ -34,7 +29,6 @@
|
|||
<title>Internal Server Error</title>
|
||||
<style>
|
||||
<%$ include: ErrorPage.css %>
|
||||
@string.Empty
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -76,6 +70,50 @@
|
|||
</ul>
|
||||
}
|
||||
|
||||
@if (Model.Options.EnableMigrationCommands)
|
||||
{
|
||||
<p>
|
||||
<button id="applyMigrations" onclick="ApplyMigrations()">@Strings.DatabaseErrorPage_ApplyMigrationsButton</button>
|
||||
<span id="applyMigrationsError" class="error"></span>
|
||||
<span id="applyMigrationsSuccess"></span>
|
||||
</p>
|
||||
<script>
|
||||
function ApplyMigrations() {
|
||||
applyMigrations.disabled = true;
|
||||
applyMigrationsError.innerHTML = "";
|
||||
applyMigrations.innerHTML = "@JavaScriptEncode(Strings.DatabaseErrorPage_ApplyMigrationsButtonRunning)";
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
|
||||
req.onload = function (e) {
|
||||
if (req.status === 204) {
|
||||
applyMigrations.innerHTML = "@JavaScriptEncode(Strings.DatabaseErrorPage_ApplyMigrationsButtonDone)";
|
||||
applyMigrationsSuccess.innerHTML = "@JavaScriptEncode(Strings.DatabaseErrorPage_MigrationsAppliedRefresh)";
|
||||
} else {
|
||||
ErrorApplyingMigrations();
|
||||
}
|
||||
};
|
||||
|
||||
req.onerror = function (e) {
|
||||
ErrorApplyingMigrations();
|
||||
};
|
||||
|
||||
var formBody = "context=@JavaScriptEncode(UrlEncode(Model.ContextType.AssemblyQualifiedName))";
|
||||
req.open("POST", "@JavaScriptEncode(Model.Options.MigrationsEndPointPath.Value)", true);
|
||||
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
req.setRequestHeader("Content-length", formBody.length);
|
||||
req.setRequestHeader("Connection", "close");
|
||||
req.send(formBody);
|
||||
}
|
||||
|
||||
function ErrorApplyingMigrations() {
|
||||
applyMigrations.innerHTML = "@JavaScriptEncode(Strings.DatabaseErrorPage_ApplyMigrationsButton)";
|
||||
applyMigrationsError.innerHTML = "@JavaScriptEncode(Strings.DatabaseErrorPage_ApplyMigrationsFailed)";
|
||||
applyMigrations.disabled = false;
|
||||
}
|
||||
</script>
|
||||
}
|
||||
|
||||
<p>@Strings.DatabaseErrorPage_HowToApplyFromCmd</p>
|
||||
<code>@Strings.DatabaseErrorPage_ApplyMigrationsCommand</code>
|
||||
<hr />
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
|
|||
|
|
@ -45,6 +45,16 @@ namespace Microsoft.AspNet.Diagnostics.Views
|
|||
/// </summary>
|
||||
protected IHtmlEncoder HtmlEncoder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Url encoder used to encode content.
|
||||
/// </summary>
|
||||
protected IUrlEncoder UrlEncoder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JavaScript encoder used to encode content.
|
||||
/// </summary>
|
||||
protected IJavaScriptStringEncoder JavaScriptStringEncoder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Execute an individual request
|
||||
/// </summary>
|
||||
|
|
@ -56,6 +66,8 @@ namespace Microsoft.AspNet.Diagnostics.Views
|
|||
Response = Context.Response;
|
||||
Output = new StreamWriter(Response.Body, Encoding.UTF8, 4096, leaveOpen: true);
|
||||
HtmlEncoder = context.ApplicationServices.GetHtmlEncoder();
|
||||
UrlEncoder = context.ApplicationServices.GetUrlEncoder();
|
||||
JavaScriptStringEncoder = context.ApplicationServices.GetJavaScriptStringEncoder();
|
||||
await ExecuteAsync();
|
||||
Output.Dispose();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
|
@ -17,6 +18,7 @@ using Microsoft.Data.Entity;
|
|||
using Microsoft.Data.Entity.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.WebEncoders;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
||||
|
|
@ -121,12 +123,10 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
|
||||
public virtual Task Invoke(HttpContext context)
|
||||
{
|
||||
using (var db = context.ApplicationServices.GetService<BloggingContext>())
|
||||
{
|
||||
db.Blogs.Add(new Blog());
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
var db = context.ApplicationServices.GetService<BloggingContext>();
|
||||
db.Blogs.Add(new Blog());
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -155,12 +155,10 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
|
||||
public virtual Task Invoke(HttpContext context)
|
||||
{
|
||||
using (var db = context.ApplicationServices.GetService<BloggingContextWithMigrations>())
|
||||
{
|
||||
db.Blogs.Add(new Blog());
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
var db = context.ApplicationServices.GetService<BloggingContextWithMigrations>();
|
||||
db.Blogs.Add(new Blog());
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,19 +184,104 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
|
||||
public virtual Task Invoke(HttpContext context)
|
||||
{
|
||||
using (var db = context.ApplicationServices.GetService<BloggingContextWithPendingModelChanges>())
|
||||
{
|
||||
var db = context.ApplicationServices.GetService<BloggingContextWithPendingModelChanges>();
|
||||
db.Database.Migrate();
|
||||
|
||||
db.Blogs.Add(new Blog());
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
public async Task Error_page_then_apply_migrations()
|
||||
{
|
||||
TestServer server = SetupTestServer<BloggingContextWithMigrations, ApplyMigrationsMiddleware>();
|
||||
var client = server.CreateClient();
|
||||
|
||||
var expectedMigrationsEndpoint = "/ApplyDatabaseMigrations";
|
||||
var expectedContextType = typeof(BloggingContextWithMigrations).AssemblyQualifiedName;
|
||||
|
||||
// Step One: Initial request with database failure
|
||||
HttpResponseMessage response = await client.GetAsync("http://localhost/");
|
||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Ensure the url we're going to test is what the page is using in it's JavaScript
|
||||
var javaScriptEncoder = new JavaScriptStringEncoder();
|
||||
Assert.Contains("req.open(\"POST\", \"" + JavaScriptEncode(expectedMigrationsEndpoint) + "\", true);", content);
|
||||
Assert.Contains("var formBody = \"context=" + JavaScriptEncode(UrlEncode(expectedContextType)) + "\";", content);
|
||||
|
||||
// Step Two: Request to migrations endpoint
|
||||
var formData = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("context", expectedContextType)
|
||||
});
|
||||
|
||||
response = await client.PostAsync("http://localhost" + expectedMigrationsEndpoint, formData);
|
||||
content = await response.Content.ReadAsStringAsync();
|
||||
Console.WriteLine(content);
|
||||
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||
|
||||
// Step Three: Successful request after migrations applied
|
||||
response = await client.GetAsync("http://localhost/");
|
||||
content = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Saved a Blog", content);
|
||||
}
|
||||
|
||||
class ApplyMigrationsMiddleware
|
||||
{
|
||||
public ApplyMigrationsMiddleware(RequestDelegate next)
|
||||
{ }
|
||||
|
||||
public virtual async Task Invoke(HttpContext context)
|
||||
{
|
||||
var db = context.ApplicationServices.GetService<BloggingContextWithMigrations>();
|
||||
db.Blogs.Add(new Blog());
|
||||
db.SaveChanges();
|
||||
await context.Response.WriteAsync("Saved a Blog");
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
public async Task Customize_migrations_end_point()
|
||||
{
|
||||
var migrationsEndpoint = "/MyCustomEndPoints/ApplyMyMigrationsHere";
|
||||
|
||||
using (var database = SqlServerTestStore.CreateScratch())
|
||||
{
|
||||
var server = TestServer.Create(app =>
|
||||
{
|
||||
app.UseDatabaseErrorPage(options =>
|
||||
{
|
||||
options.EnableAll();
|
||||
options.MigrationsEndPointPath = new PathString(migrationsEndpoint);
|
||||
});
|
||||
|
||||
app.UseMiddleware<PendingMigrationsMiddleware>();
|
||||
},
|
||||
services =>
|
||||
{
|
||||
services.AddEntityFramework().AddSqlServer();
|
||||
services.AddScoped<BloggingContextWithMigrations>();
|
||||
|
||||
var optionsBuilder = new DbContextOptionsBuilder();
|
||||
optionsBuilder.UseSqlServer(database.ConnectionString);
|
||||
services.AddInstance<DbContextOptions>(optionsBuilder.Options);
|
||||
});
|
||||
|
||||
HttpResponseMessage response = await server.CreateClient().GetAsync("http://localhost/");
|
||||
|
||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.Contains("req.open(\"POST\", \"" + JavaScriptEncode(migrationsEndpoint) + "\", true);", content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Pass_thru_when_context_not_in_services()
|
||||
{
|
||||
using (var database = SqlServerTestStore.CreateScratch())
|
||||
|
|
@ -242,12 +325,10 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
public virtual Task Invoke(HttpContext context)
|
||||
{
|
||||
var options = context.ApplicationServices.GetService<DbContextOptions>();
|
||||
using (var db = new BloggingContext(context.ApplicationServices, options))
|
||||
{
|
||||
db.Blogs.Add(new Blog());
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
var db = new BloggingContext(context.ApplicationServices, options);
|
||||
db.Blogs.Add(new Blog());
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -276,12 +357,10 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
|
||||
public virtual Task Invoke(HttpContext context)
|
||||
{
|
||||
using (var db = context.ApplicationServices.GetService<BloggingContextWithSnapshotThatThrows>())
|
||||
{
|
||||
db.Blogs.Add(new Blog());
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
var db = context.ApplicationServices.GetService<BloggingContextWithSnapshotThatThrows>();
|
||||
db.Blogs.Add(new Blog());
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -305,18 +384,16 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
|
||||
public virtual Task Invoke(HttpContext context)
|
||||
{
|
||||
using (var db = context.ApplicationServices.GetService<BloggingContext>())
|
||||
var db = context.ApplicationServices.GetService<BloggingContext>();
|
||||
db.Blogs.Add(new Blog());
|
||||
try
|
||||
{
|
||||
db.Blogs.Add(new Blog());
|
||||
try
|
||||
{
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception("I wrapped your exception", ex);
|
||||
}
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception("I wrapped your exception", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -357,5 +434,17 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static UrlEncoder _urlEncoder = new UrlEncoder();
|
||||
private static string UrlEncode(string content)
|
||||
{
|
||||
return _urlEncoder.UrlEncode(content);
|
||||
}
|
||||
|
||||
private static JavaScriptStringEncoder _javaScriptEncoder = new JavaScriptStringEncoder();
|
||||
private static string JavaScriptEncode(string content)
|
||||
{
|
||||
return _javaScriptEncoder.JavaScriptStringEncode(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Tests.Helpers;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Microsoft.AspNet.Testing.xunit;
|
||||
using Microsoft.Data.Entity;
|
||||
using Microsoft.Data.Entity.Infrastructure;
|
||||
using Microsoft.Data.Entity.Migrations;
|
||||
using Microsoft.Data.Entity.Storage;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
||||
{
|
||||
public class MigrationsEndPointMiddlewareTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task Non_migration_requests_pass_thru()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app
|
||||
.UseMigrationsEndPoint()
|
||||
.UseMiddleware<SuccessMiddleware>());
|
||||
|
||||
HttpResponseMessage response = await server.CreateClient().GetAsync("http://localhost/");
|
||||
|
||||
Assert.Equal("Request Handled", await response.Content.ReadAsStringAsync());
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
|
||||
class SuccessMiddleware
|
||||
{
|
||||
public SuccessMiddleware(RequestDelegate next)
|
||||
{ }
|
||||
|
||||
public virtual async Task Invoke(HttpContext context)
|
||||
{
|
||||
await context.Response.WriteAsync("Request Handled");
|
||||
context.Response.StatusCode = (int)HttpStatusCode.OK;
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
public async Task Migration_request_default_path()
|
||||
{
|
||||
await Migration_request(useCustomPath: false);
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
public async Task Migration_request_custom_path()
|
||||
{
|
||||
await Migration_request(useCustomPath: true);
|
||||
}
|
||||
|
||||
private async Task Migration_request(bool useCustomPath)
|
||||
{
|
||||
using (var database = SqlServerTestStore.CreateScratch())
|
||||
{
|
||||
var optionsBuilder = new DbContextOptionsBuilder();
|
||||
optionsBuilder.UseSqlServer(database.ConnectionString);
|
||||
|
||||
var path = useCustomPath ? new PathString("/EndPoints/ApplyMyMigrations") : MigrationsEndPointOptions.DefaultPath;
|
||||
|
||||
TestServer server = TestServer.Create(app =>
|
||||
{
|
||||
if (useCustomPath)
|
||||
{
|
||||
app.UseMigrationsEndPoint(o => o.Path = path);
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseMigrationsEndPoint();
|
||||
}
|
||||
},
|
||||
services =>
|
||||
{
|
||||
services.AddEntityFramework().AddSqlServer();
|
||||
services.AddScoped<BloggingContextWithMigrations>();
|
||||
services.AddInstance(optionsBuilder.Options);
|
||||
});
|
||||
|
||||
using (var db = BloggingContextWithMigrations.CreateWithoutExternalServiceProvider(optionsBuilder.Options))
|
||||
{
|
||||
var databaseCreator = ((IAccessor<IServiceProvider>)db).GetService<IRelationalDatabaseCreator>();
|
||||
Assert.False(databaseCreator.Exists());
|
||||
|
||||
var formData = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("context", typeof(BloggingContextWithMigrations).AssemblyQualifiedName)
|
||||
});
|
||||
|
||||
HttpResponseMessage response = await server.CreateClient()
|
||||
.PostAsync("http://localhost" + path, formData);
|
||||
|
||||
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||
|
||||
Assert.True(databaseCreator.Exists());
|
||||
|
||||
var historyRepository = ((IAccessor<IServiceProvider>)db).Service.GetRequiredService<IHistoryRepository>();
|
||||
var appliedMigrations = historyRepository.GetAppliedMigrations();
|
||||
Assert.Equal(2, appliedMigrations.Count);
|
||||
Assert.Equal("111111111111111_MigrationOne", appliedMigrations.ElementAt(0).MigrationId);
|
||||
Assert.Equal("222222222222222_MigrationTwo", appliedMigrations.ElementAt(1).MigrationId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Context_type_not_specified()
|
||||
{
|
||||
var server = TestServer.Create(app =>
|
||||
{
|
||||
app.UseMigrationsEndPoint();
|
||||
});
|
||||
|
||||
var formData = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>());
|
||||
|
||||
var response = await server.CreateClient().PostAsync("http://localhost" + MigrationsEndPointOptions.DefaultPath, formData);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
Assert.StartsWith(StringsHelpers.GetResourceString("FormatMigrationsEndPointMiddleware_NoContextType"), content);
|
||||
Assert.True(content.Length > 512);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Invalid_context_type_specified()
|
||||
{
|
||||
var server = TestServer.Create(app =>
|
||||
{
|
||||
app.UseMigrationsEndPoint();
|
||||
});
|
||||
|
||||
var typeName = "You won't find this type ;)";
|
||||
var formData = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("context", typeName)
|
||||
});
|
||||
|
||||
var response = await server.CreateClient().PostAsync("http://localhost" + MigrationsEndPointOptions.DefaultPath, formData);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
Assert.StartsWith(StringsHelpers.GetResourceString("FormatMigrationsEndPointMiddleware_InvalidContextType", typeName), content);
|
||||
Assert.True(content.Length > 512);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Context_not_registered_in_services()
|
||||
{
|
||||
var server = TestServer.Create(
|
||||
app => app.UseMigrationsEndPoint(),
|
||||
services => services.AddEntityFramework().AddSqlServer());
|
||||
|
||||
var formData = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("context", typeof(BloggingContext).AssemblyQualifiedName)
|
||||
});
|
||||
|
||||
var response = await server.CreateClient().PostAsync("http://localhost" + MigrationsEndPointOptions.DefaultPath, formData);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
Assert.StartsWith(StringsHelpers.GetResourceString("FormatMigrationsEndPointMiddleware_ContextNotRegistered", typeof(BloggingContext)), content);
|
||||
Assert.True(content.Length > 512);
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
public async Task Exception_while_applying_migrations()
|
||||
{
|
||||
using (var database = SqlServerTestStore.CreateScratch())
|
||||
{
|
||||
var optionsBuilder = new DbContextOptionsBuilder();
|
||||
optionsBuilder.UseSqlServer(database.ConnectionString);
|
||||
|
||||
TestServer server = TestServer.Create(
|
||||
app => app.UseMigrationsEndPoint(),
|
||||
services =>
|
||||
{
|
||||
services.AddEntityFramework().AddSqlServer();
|
||||
services.AddScoped<BloggingContextWithSnapshotThatThrows>();
|
||||
services.AddInstance(optionsBuilder.Options);
|
||||
});
|
||||
|
||||
var formData = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("context", typeof(BloggingContextWithSnapshotThatThrows).AssemblyQualifiedName)
|
||||
});
|
||||
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
|
||||
await server.CreateClient().PostAsync("http://localhost" + MigrationsEndPointOptions.DefaultPath, formData));
|
||||
|
||||
Assert.StartsWith(StringsHelpers.GetResourceString("FormatMigrationsEndPointMiddleware_Exception", typeof(BloggingContextWithSnapshotThatThrows)), ex.Message);
|
||||
Assert.Equal("Welcome to the invalid migration!", ex.InnerException.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
||||
|
|
@ -8,39 +9,78 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
public class DatabaseErrorPageOptionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void Default_visibility_is_false()
|
||||
public void Everything_disabled_by_default()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
|
||||
Assert.False(options.ShowExceptionDetails);
|
||||
Assert.False(options.ListMigrations);
|
||||
Assert.False(options.EnableMigrationCommands);
|
||||
Assert.Equal(string.Empty, options.MigrationsEndPointPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShowAll_shows_all_errors()
|
||||
public void EnableAll_enables_everything()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
|
||||
Assert.True(options.ShowExceptionDetails);
|
||||
Assert.True(options.ListMigrations);
|
||||
Assert.True(options.EnableMigrationCommands);
|
||||
Assert.Equal(MigrationsEndPointOptions.DefaultPath, options.MigrationsEndPointPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShowExceptionDetails_is_respected()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
options.ShowExceptionDetails = false;
|
||||
|
||||
Assert.False(options.ShowExceptionDetails);
|
||||
Assert.True(options.ListMigrations);
|
||||
Assert.True(options.EnableMigrationCommands);
|
||||
Assert.Equal(MigrationsEndPointOptions.DefaultPath, options.MigrationsEndPointPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ListMigrations_is_respected()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
options.ListMigrations = false;
|
||||
|
||||
Assert.True(options.ShowExceptionDetails);
|
||||
Assert.False(options.ListMigrations);
|
||||
Assert.True(options.EnableMigrationCommands);
|
||||
Assert.Equal(MigrationsEndPointOptions.DefaultPath, options.MigrationsEndPointPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnableMigrationCommands_is_respected()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
options.EnableMigrationCommands = false;
|
||||
|
||||
Assert.True(options.ShowExceptionDetails);
|
||||
Assert.True(options.ListMigrations);
|
||||
Assert.False(options.EnableMigrationCommands);
|
||||
Assert.Equal(MigrationsEndPointOptions.DefaultPath, options.MigrationsEndPointPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MigrationsEndPointPath_is_respected()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
options.MigrationsEndPointPath = "/test";
|
||||
|
||||
Assert.True(options.ShowExceptionDetails);
|
||||
Assert.True(options.ListMigrations);
|
||||
Assert.True(options.EnableMigrationCommands);
|
||||
Assert.Equal("/test", options.MigrationsEndPointPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Tests.Helpers;
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Views;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
|
@ -19,7 +20,8 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
[Fact]
|
||||
public async Task No_database_or_migrations_only_displays_scaffold_first_migration()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
|
|
@ -39,7 +41,8 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
[Fact]
|
||||
public async Task No_database_with_migrations_only_displays_apply_migrations()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
|
|
@ -59,7 +62,8 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
[Fact]
|
||||
public async Task Existing_database_with_migrations_only_displays_apply_migrations()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
|
|
@ -79,7 +83,8 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
[Fact]
|
||||
public async Task Existing_database_with_migrations_and_pending_model_changes_only_displays_apply_migrations()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
|
|
@ -99,7 +104,8 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
[Fact]
|
||||
public async Task Pending_model_changes_only_displays_scaffold_next_migration()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
|
|
@ -119,7 +125,8 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
[Fact]
|
||||
public async Task Exception_details_are_displayed()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
|
|
@ -137,7 +144,8 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
[Fact]
|
||||
public async Task Inner_exception_details_are_displayed()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
|
|
@ -156,7 +164,8 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
[Fact]
|
||||
public async Task ShowExceptionDetails_is_respected()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
options.ShowExceptionDetails = false;
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
|
|
@ -175,7 +184,8 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
[Fact]
|
||||
public async Task ListMigrations_is_respected()
|
||||
{
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
options.ListMigrations = false;
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
|
|
@ -191,6 +201,47 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
|||
Assert.DoesNotContain("111_MigrationOne", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EnableMigrationCommands_is_respected()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
options.EnableMigrationCommands = false;
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
exception: new Exception(),
|
||||
databaseExists: true,
|
||||
pendingModelChanges: false,
|
||||
pendingMigrations: new string[] { "111_MigrationOne" },
|
||||
options: options);
|
||||
|
||||
var content = await ExecutePage(options, model);
|
||||
|
||||
Assert.DoesNotContain(options.MigrationsEndPointPath.Value, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MigrationsEndPointPath_is_respected()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.EnableAll();
|
||||
options.MigrationsEndPointPath = "/HitThisEndPoint";
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
exception: new Exception(),
|
||||
databaseExists: true,
|
||||
pendingModelChanges: false,
|
||||
pendingMigrations: new string[] { "111_MigrationOne" },
|
||||
options: options);
|
||||
|
||||
var content = await ExecutePage(options, model);
|
||||
|
||||
Assert.Contains(options.MigrationsEndPointPath.Value, content);
|
||||
}
|
||||
|
||||
|
||||
private static async Task<string> ExecutePage(DatabaseErrorPageOptions options, DatabaseErrorPageModel model)
|
||||
{
|
||||
var page = new DatabaseErrorPage();
|
||||
|
|
|
|||
Loading…
Reference in New Issue