🔥 Remove migrations end point

This commit is contained in:
Rowan Miller 2015-03-23 15:54:35 -07:00
parent f644aea3b1
commit 105d3353cf
14 changed files with 23 additions and 974 deletions

View File

@ -21,14 +21,7 @@ namespace Microsoft.AspNet.Builder
Check.NotNull(builder, "builder");
Check.NotNull(options, "options");
builder = builder.UseMiddleware<DatabaseErrorPageMiddleware>(options);
if(options.EnableMigrationCommands)
{
builder.UseMigrationsEndPoint(new MigrationsEndPointOptions { Path = options.MigrationsEndPointPath });
}
return builder;
return builder.UseMiddleware<DatabaseErrorPageMiddleware>(options);
}
}
}

View File

@ -8,11 +8,9 @@ namespace Microsoft.AspNet.Diagnostics.Entity
{
public class DatabaseErrorPageOptions
{
private PathString _migrationsEndPointPath = MigrationsEndPointOptions.DefaultPath;
private bool _defaultVisibility;
private bool? _showExceptionDetails;
private bool? _listMigrations;
private bool? _enableMigrationCommands;
public static DatabaseErrorPageOptions ShowAll
{
@ -23,21 +21,10 @@ namespace Microsoft.AspNet.Diagnostics.Entity
{
ShowExceptionDetails = true,
ListMigrations = true,
EnableMigrationCommands = true
};
}
}
public virtual PathString MigrationsEndPointPath
{
get { return _migrationsEndPointPath; }
set
{
Check.NotNull(value, "value");
_migrationsEndPointPath = value;
}
}
public virtual bool ShowExceptionDetails
{
get { return _showExceptionDetails ?? _defaultVisibility; }
@ -50,12 +37,6 @@ namespace Microsoft.AspNet.Diagnostics.Entity
set { _listMigrations = value; }
}
public virtual bool EnableMigrationCommands
{
get { return _enableMigrationCommands ?? _defaultVisibility; }
set { _enableMigrationCommands = value; }
}
public virtual void SetDefaultVisibility(bool isVisible)
{
_defaultVisibility = isVisible;

View File

@ -1,27 +0,0 @@
// 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 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(new MigrationsEndPointOptions());
}
public static IApplicationBuilder UseMigrationsEndPoint([NotNull] this IApplicationBuilder builder, [NotNull] MigrationsEndPointOptions options)
{
Check.NotNull(builder, "builder");
Check.NotNull(options, "options");
return builder.UseMiddleware<MigrationsEndPointMiddleware>(options);
}
}
}

View File

@ -1,117 +0,0 @@
// 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.Framework.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] ILoggerFactory loggerFactory, [NotNull] MigrationsEndPointOptions options)
{
Check.NotNull(next, "next");
Check.NotNull(serviceProvider, "serviceProvider");
Check.NotNull(loggerFactory, "loggerFactory");
Check.NotNull(options, "options");
_next = next;
_serviceProvider = serviceProvider;
_logger = loggerFactory.CreateLogger<MigrationsEndPointMiddleware>();
_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).WithCurrentCulture();
if (db != null)
{
try
{
_logger.LogVerbose(Strings.FormatMigrationsEndPointMiddleware_ApplyingMigrations(db.GetType().FullName));
db.Database.AsRelational().ApplyMigrations();
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);
_logger.LogError(message);
throw new InvalidOperationException(message, ex);
}
}
}
else
{
await _next(context).WithCurrentCulture();
}
}
private static async Task<DbContext> GetDbContext(HttpContext context, ILogger logger)
{
var form = await context.Request.ReadFormAsync().WithCurrentCulture();
var contextTypeName = form["context"];
if (string.IsNullOrWhiteSpace(contextTypeName))
{
logger.LogError(Strings.MigrationsEndPointMiddleware_NoContextType);
await WriteErrorToResponse(context.Response, Strings.MigrationsEndPointMiddleware_NoContextType).WithCurrentCulture();
return null;
}
var contextType = Type.GetType(contextTypeName);
if (contextType == null)
{
var message = Strings.FormatMigrationsEndPointMiddleware_InvalidContextType(contextTypeName);
logger.LogError(message);
await WriteErrorToResponse(context.Response, message).WithCurrentCulture();
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).WithCurrentCulture();
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)).WithCurrentCulture();
}
}
}

View File

@ -1,24 +0,0 @@
// 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.Diagnostics.Entity.Utilities;
using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Diagnostics.Entity
{
public class MigrationsEndPointOptions
{
public static PathString DefaultPath = new PathString("/ApplyDatabaseMigrations");
private PathString _path = DefaultPath;
public virtual PathString Path
{
get { return _path; }
set
{
Check.NotNull(value, "value");
_path = value;
}
}
}
}

View File

@ -90,70 +90,6 @@ 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>
@ -170,22 +106,6 @@ 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>
@ -314,118 +234,6 @@ 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&lt;{0}&gt;() 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&lt;{0}&gt;() 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>
@ -442,22 +250,6 @@ namespace Microsoft.AspNet.Diagnostics.Entity
return GetString("DatabaseErrorPage_Title");
}
/// <summary>
/// To use migrations from a command prompt you will need to &lt;a href='http://go.microsoft.com/fwlink/?LinkId=518242'&gt;install .NET Version Manager (dnvm)&lt;/a&gt;. Once installed, you can run migration commands from a standard command prompt in the project directory.
/// </summary>
internal static string DatabaseErrorPage_EnableMigrationsCommandsInfo
{
get { return GetString("DatabaseErrorPage_EnableMigrationsCommandsInfo"); }
}
/// <summary>
/// To use migrations from a command prompt you will need to &lt;a href='http://go.microsoft.com/fwlink/?LinkId=518242'&gt;install .NET Version Manager (dnvm)&lt;/a&gt;. Once installed, you can run migration commands from a standard command prompt in the project directory.
/// </summary>
internal static string FormatDatabaseErrorPage_EnableMigrationsCommandsInfo()
{
return GetString("DatabaseErrorPage_EnableMigrationsCommandsInfo");
}
/// <summary>
/// {0} occurred, checking if Entity Framework recorded this exception as resulting from a failed database operation.
/// </summary>

View File

@ -132,24 +132,9 @@
<data name="DatabaseErrorPage_AddMigrationCommand" xml:space="preserve">
<value>&gt; dnx . ef migration 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>
@ -174,33 +159,9 @@
<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&lt;{0}&gt;() 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>
<data name="DatabaseErrorPage_EnableMigrationsCommandsInfo" xml:space="preserve">
<value>To use migrations from a command prompt you will need to &lt;a href='http://go.microsoft.com/fwlink/?LinkId=518242'&gt;install .NET Version Manager (dnvm)&lt;/a&gt;. Once installed, you can run migration commands from a standard command prompt in the project directory.</value>
</data>
<data name="DatabaseErrorPage_AttemptingToMatchException" xml:space="preserve">
<value>{0} occurred, checking if Entity Framework recorded this exception as resulting from a failed database operation.</value>
</data>

View File

@ -181,14 +181,8 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
#line default
#line hidden
WriteLiteral(" </code>\r\n <p><strong>");
#line 61 "DatabaseErrorPage.cshtml"
WriteLiteral(Strings.DatabaseErrorPage_EnableMigrationsCommandsInfo);
#line default
#line hidden
WriteLiteral("</strong></p>\r\n <hr />\r\n");
#line 63 "DatabaseErrorPage.cshtml"
WriteLiteral(" </code>\r\n <hr />\r\n");
#line 62 "DatabaseErrorPage.cshtml"
}
else if (Model.PendingMigrations.Any())
{
@ -197,25 +191,25 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
#line hidden
WriteLiteral(" <div>\r\n <h2>");
#line 67 "DatabaseErrorPage.cshtml"
#line 66 "DatabaseErrorPage.cshtml"
Write(Strings.FormatDatabaseErrorPage_PendingMigrationsTitle(Model.ContextType.Name));
#line default
#line hidden
WriteLiteral("</h2>\r\n <p>");
#line 68 "DatabaseErrorPage.cshtml"
#line 67 "DatabaseErrorPage.cshtml"
Write(Strings.FormatDatabaseErrorPage_PendingMigrationsInfo(Model.ContextType.Name));
#line default
#line hidden
WriteLiteral("</p>\r\n\r\n");
#line 70 "DatabaseErrorPage.cshtml"
#line 69 "DatabaseErrorPage.cshtml"
#line default
#line hidden
#line 70 "DatabaseErrorPage.cshtml"
#line 69 "DatabaseErrorPage.cshtml"
if (Model.Options.ListMigrations)
{
@ -223,13 +217,13 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
#line hidden
WriteLiteral(" <ul>\r\n");
#line 73 "DatabaseErrorPage.cshtml"
#line 72 "DatabaseErrorPage.cshtml"
#line default
#line hidden
#line 73 "DatabaseErrorPage.cshtml"
#line 72 "DatabaseErrorPage.cshtml"
foreach (var migration in Model.PendingMigrations)
{
@ -237,147 +231,39 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
#line hidden
WriteLiteral(" <li>");
#line 75 "DatabaseErrorPage.cshtml"
#line 74 "DatabaseErrorPage.cshtml"
Write(migration);
#line default
#line hidden
WriteLiteral("</li>\r\n");
#line 76 "DatabaseErrorPage.cshtml"
#line 75 "DatabaseErrorPage.cshtml"
}
#line default
#line hidden
WriteLiteral(" </ul>\r\n");
#line 78 "DatabaseErrorPage.cshtml"
}
#line default
#line hidden
WriteLiteral("\r\n");
#line 80 "DatabaseErrorPage.cshtml"
#line default
#line hidden
#line 80 "DatabaseErrorPage.cshtml"
if (Model.Options.EnableMigrationCommands)
{
#line default
#line hidden
WriteLiteral(" <p>\r\n <button id=\"applyMigrations\" onclick=\" A" +
"pplyMigrations() \">");
#line 83 "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 91 "DatabaseErrorPage.cshtml"
Write(Strings.DatabaseErrorPage_ApplyMigrationsButtonRunning);
#line default
#line hidden
WriteLiteral("\";\r\n\r\n var req = new XMLHttpRequest();\r\n " +
" req.open(\"POST\", \"");
#line 94 "DatabaseErrorPage.cshtml"
Write(Model.Options.MigrationsEndPointPath.Value);
#line default
#line hidden
WriteLiteral("\", true);\r\n var params = \"context=\" + encodeURIComponent(\"" +
"");
#line 95 "DatabaseErrorPage.cshtml"
Write(Model.ContextType.AssemblyQualifiedName);
#line default
#line hidden
WriteLiteral(@""");
req.setRequestHeader(""Content-type"", ""application/x-www-form-urlencoded"");
req.setRequestHeader(""Content-length"", params.length);
req.setRequestHeader(""Connection"", ""close"");
req.onload = function (e) {
if (req.status == 204) {
applyMigrations.innerHTML = """);
#line 102 "DatabaseErrorPage.cshtml"
Write(Strings.DatabaseErrorPage_ApplyMigrationsButtonDone);
#line default
#line hidden
WriteLiteral("\";\r\n applyMigrationsSuccess.innerHTML = \"");
#line 103 "DatabaseErrorPage.cshtml"
Write(Strings.DatabaseErrorPage_MigrationsAppliedRefresh);
#line default
#line hidden
WriteLiteral(@""";
} else {
ErrorApplyingMigrations();
}
};
req.onerror = function (e) {
ErrorApplyingMigrations();
};
req.send(params);
}
function ErrorApplyingMigrations() {
applyMigrations.innerHTML = """);
#line 117 "DatabaseErrorPage.cshtml"
Write(Strings.DatabaseErrorPage_ApplyMigrationsButton);
#line default
#line hidden
WriteLiteral("\";\r\n applyMigrationsError.innerHTML = \"");
#line 118 "DatabaseErrorPage.cshtml"
Write(Strings.DatabaseErrorPage_ApplyMigrationsFailed);
#line default
#line hidden
WriteLiteral("\";\r\n applyMigrations.disabled = false;\r\n " +
" }\r\n </script>\r\n");
#line 122 "DatabaseErrorPage.cshtml"
#line 77 "DatabaseErrorPage.cshtml"
}
#line default
#line hidden
WriteLiteral("\r\n <p>");
#line 124 "DatabaseErrorPage.cshtml"
#line 79 "DatabaseErrorPage.cshtml"
Write(Strings.DatabaseErrorPage_HowToApplyFromCmd);
#line default
#line hidden
WriteLiteral("</p>\r\n <code>");
#line 125 "DatabaseErrorPage.cshtml"
#line 80 "DatabaseErrorPage.cshtml"
Write(Strings.DatabaseErrorPage_ApplyMigrationsCommand);
#line default
#line hidden
WriteLiteral("</code>\r\n <p><strong>");
#line 126 "DatabaseErrorPage.cshtml"
WriteLiteral(Strings.DatabaseErrorPage_EnableMigrationsCommandsInfo);
#line default
#line hidden
WriteLiteral("</strong></p>\r\n <hr />\r\n </div>\r\n");
#line 129 "DatabaseErrorPage.cshtml"
WriteLiteral("</code>\r\n <hr />\r\n </div>\r\n");
#line 83 "DatabaseErrorPage.cshtml"
}
else if (Model.PendingModelChanges)
{
@ -386,37 +272,31 @@ using Microsoft.AspNet.Diagnostics.Entity.Views
#line hidden
WriteLiteral(" <div>\r\n <h2>");
#line 133 "DatabaseErrorPage.cshtml"
#line 87 "DatabaseErrorPage.cshtml"
Write(Strings.FormatDatabaseErrorPage_PendingChangesTitle(Model.ContextType.Name));
#line default
#line hidden
WriteLiteral("</h2>\r\n <p>");
#line 134 "DatabaseErrorPage.cshtml"
#line 88 "DatabaseErrorPage.cshtml"
Write(Strings.DatabaseErrorPage_PendingChangesInfo);
#line default
#line hidden
WriteLiteral("</p>\r\n <code>");
#line 135 "DatabaseErrorPage.cshtml"
#line 89 "DatabaseErrorPage.cshtml"
Write(Strings.DatabaseErrorPage_AddMigrationCommand);
#line default
#line hidden
WriteLiteral("</code>\r\n <br />\r\n <code>");
#line 137 "DatabaseErrorPage.cshtml"
#line 91 "DatabaseErrorPage.cshtml"
Write(Strings.DatabaseErrorPage_ApplyMigrationsCommand);
#line default
#line hidden
WriteLiteral("</code>\r\n <p><strong>");
#line 138 "DatabaseErrorPage.cshtml"
WriteLiteral(Strings.DatabaseErrorPage_EnableMigrationsCommandsInfo);
#line default
#line hidden
WriteLiteral("</strong></p>\r\n <hr />\r\n </div>\r\n");
#line 141 "DatabaseErrorPage.cshtml"
WriteLiteral("</code>\r\n <hr />\r\n </div>\r\n");
#line 94 "DatabaseErrorPage.cshtml"
}
#line default

View File

@ -58,7 +58,6 @@
<code> @Strings.DatabaseErrorPage_AddMigrationCommand </code>
<br />
<code> @Strings.DatabaseErrorPage_ApplyMigrationsCommand </code>
<p><strong>@Strings.DatabaseErrorPage_EnableMigrationsCommandsInfo</strong></p>
<hr />
}
else if (Model.PendingMigrations.Any())
@ -77,53 +76,8 @@
</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 = "@Strings.DatabaseErrorPage_ApplyMigrationsButtonRunning";
var req = new XMLHttpRequest();
req.open("POST", "@Model.Options.MigrationsEndPointPath.Value", true);
var params = "context=" + encodeURIComponent("@Model.ContextType.AssemblyQualifiedName");
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.setRequestHeader("Content-length", params.length);
req.setRequestHeader("Connection", "close");
req.onload = function (e) {
if (req.status == 204) {
applyMigrations.innerHTML = "@Strings.DatabaseErrorPage_ApplyMigrationsButtonDone";
applyMigrationsSuccess.innerHTML = "@Strings.DatabaseErrorPage_MigrationsAppliedRefresh";
} else {
ErrorApplyingMigrations();
}
};
req.onerror = function (e) {
ErrorApplyingMigrations();
};
req.send(params);
}
function ErrorApplyingMigrations() {
applyMigrations.innerHTML = "@Strings.DatabaseErrorPage_ApplyMigrationsButton";
applyMigrationsError.innerHTML = "@Strings.DatabaseErrorPage_ApplyMigrationsFailed";
applyMigrations.disabled = false;
}
</script>
}
<p>@Strings.DatabaseErrorPage_HowToApplyFromCmd</p>
<code>@Strings.DatabaseErrorPage_ApplyMigrationsCommand</code>
<p><strong>@Strings.DatabaseErrorPage_EnableMigrationsCommandsInfo</strong></p>
<hr />
</div>
}
@ -135,7 +89,6 @@
<code>@Strings.DatabaseErrorPage_AddMigrationCommand</code>
<br />
<code>@Strings.DatabaseErrorPage_ApplyMigrationsCommand</code>
<p><strong>@Strings.DatabaseErrorPage_EnableMigrationsCommandsInfo</strong></p>
<hr />
</div>
}

View File

@ -2,6 +2,7 @@
"version": "1.0.0-*",
"dependencies": {
"Microsoft.AspNet.Diagnostics.Elm": "1.0.0-*",
"Microsoft.AspNet.Diagnostics.Entity": "7.0.0-*",
"Microsoft.AspNet.Razor": "4.0.0-*"
},

View File

@ -171,91 +171,6 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
}
}
[Fact]
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
Assert.Contains("req.open(\"POST\", \"" + expectedMigrationsEndpoint + "\", true);", content);
Assert.Contains("var params = \"context=\" + encodeURIComponent(\"" + 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)
{
using (var db = context.ApplicationServices.GetService<BloggingContextWithMigrations>())
{
db.Blogs.Add(new Blog());
db.SaveChanges();
await context.Response.WriteAsync("Saved a Blog");
}
}
}
[Fact]
public async Task Customize_migrations_end_point()
{
var migrationsEndpoint = "/MyCustomEndPoints/ApplyMyMigrationsHere";
using (var database = SqlServerTestStore.CreateScratch())
{
var server = TestServer.Create(app =>
{
var options = DatabaseErrorPageOptions.ShowAll;
options.MigrationsEndPointPath = new PathString(migrationsEndpoint);
app.UseDatabaseErrorPage(options);
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\", \"" + migrationsEndpoint + "\", true);", content);
}
}
[Fact]
public async Task Pass_thru_when_context_not_in_services()
{

View File

@ -1,205 +0,0 @@
// 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.Http;
using Microsoft.AspNet.TestHost;
using Microsoft.Data.Entity;
using Microsoft.Data.Entity.Infrastructure;
using Microsoft.Data.Entity.Internal;
using Microsoft.Data.Entity.Relational.Migrations.History;
using Microsoft.Framework.DependencyInjection;
using Xunit;
using Microsoft.AspNet.Diagnostics.Entity.Tests.Helpers;
using Microsoft.AspNet.Hosting.Startup;
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;
}
}
[Fact]
public async Task Migration_request_default_path()
{
await Migration_request(useCustomPath: false);
}
[Fact]
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(new MigrationsEndPointOptions { Path = path });
}
else
{
app.UseMigrationsEndPoint();
}
},
services =>
{
services.AddEntityFramework().AddSqlServer();
services.AddScoped<BloggingContextWithMigrations>();
services.AddInstance<DbContextOptions>(optionsBuilder.Options);
});
using (var db = BloggingContextWithMigrations.CreateWithoutExternalServiceProvider(optionsBuilder.Options))
{
Assert.False(db.Database.AsRelational().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(db.Database.AsRelational().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);
}
[Fact]
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.Equal(StringsHelpers.GetResourceString("FormatMigrationsEndPointMiddleware_Exception", typeof(BloggingContextWithSnapshotThatThrows)), ex.Message);
Assert.Equal("Welcome to the invalid migration!", ex.InnerException.Message);
}
}
}
}

View File

@ -14,7 +14,6 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
Assert.False(options.ShowExceptionDetails);
Assert.False(options.ListMigrations);
Assert.False(options.EnableMigrationCommands);
}
[Fact]
@ -25,7 +24,6 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
Assert.True(options.ShowExceptionDetails);
Assert.True(options.ListMigrations);
Assert.True(options.EnableMigrationCommands);
}
[Fact]
@ -36,7 +34,6 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
Assert.False(options.ShowExceptionDetails);
Assert.True(options.ListMigrations);
Assert.True(options.EnableMigrationCommands);
}
[Fact]
@ -47,18 +44,6 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
Assert.True(options.ShowExceptionDetails);
Assert.False(options.ListMigrations);
Assert.True(options.EnableMigrationCommands);
}
[Fact]
public void EnableMigrationCommands_overides_default_visibility()
{
var options = new DatabaseErrorPageOptions { EnableMigrationCommands = false };
options.SetDefaultVisibility(true);
Assert.True(options.ShowExceptionDetails);
Assert.True(options.ListMigrations);
Assert.False(options.EnableMigrationCommands);
}
}
}

View File

@ -198,45 +198,6 @@ namespace Microsoft.AspNet.Diagnostics.Entity.Tests
Assert.DoesNotContain("111_MigrationOne", content);
}
[Fact]
public async Task EnableMigrationCommands_is_respected()
{
var options = new DatabaseErrorPageOptions { EnableMigrationCommands = false };
options.SetDefaultVisibility(true);
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 { MigrationsEndPointPath = new PathString("/HitThisEndPoint") };
options.SetDefaultVisibility(true);
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();