Copy of Microsoft.AspNet.Diagnostics.Entity code from EntityFramework
Straight copy of code with no modification so that we have a baseline of changes made to port the code to the Diagnostics repo
This commit is contained in:
parent
b466013235
commit
fad5ba4323
|
|
@ -0,0 +1,108 @@
|
|||
// 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.Utilities;
|
||||
using Microsoft.Data.Entity.Storage;
|
||||
using Microsoft.Framework.Logging;
|
||||
using System;
|
||||
#if ASPNETCORE50
|
||||
using System.Threading;
|
||||
#else
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
#endif
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity
|
||||
{
|
||||
public class DataStoreErrorLogger : ILogger
|
||||
{
|
||||
#if ASPNETCORE50
|
||||
private readonly AsyncLocal<DataStoreErrorLog> _log = new AsyncLocal<DataStoreErrorLog>();
|
||||
#else
|
||||
private const string ContextName = "__DataStoreErrorLog";
|
||||
#endif
|
||||
|
||||
public virtual DataStoreErrorLog LastError
|
||||
{
|
||||
get
|
||||
{
|
||||
#if ASPNETCORE50
|
||||
return _log.Value;
|
||||
#else
|
||||
return (DataStoreErrorLog)CallContext.LogicalGetData(ContextName);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void StartLoggingForCurrentCallContext()
|
||||
{
|
||||
// Because CallContext is cloned at each async operation we cannot
|
||||
// lazily create the error object when an error is encountered, otherwise
|
||||
// it will not be available to code outside of the current async context.
|
||||
// We create it ahead of time so that any cloning just clones the reference
|
||||
// to the object that will hold any errors.
|
||||
#if ASPNETCORE50
|
||||
_log.Value = new DataStoreErrorLog();
|
||||
#else
|
||||
CallContext.LogicalSetData(ContextName, new DataStoreErrorLog());
|
||||
#endif
|
||||
}
|
||||
|
||||
public virtual void Write(LogLevel logLevel, int eventId, [CanBeNull] object state, [CanBeNull] Exception exception, [CanBeNull] Func<object, Exception, string> formatter)
|
||||
{
|
||||
var errorState = state as DataStoreErrorLogState;
|
||||
if (errorState != null && exception != null && LastError != null)
|
||||
{
|
||||
LastError.SetError(errorState.ContextType, exception);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual IDisposable BeginScope(object state)
|
||||
{
|
||||
return NullScope.Instance;
|
||||
}
|
||||
|
||||
private class NullScope : IDisposable
|
||||
{
|
||||
public static NullScope Instance = new NullScope();
|
||||
|
||||
public void Dispose()
|
||||
{ }
|
||||
}
|
||||
|
||||
public class DataStoreErrorLog
|
||||
{
|
||||
private Type _contextType;
|
||||
private Exception _exception;
|
||||
|
||||
public virtual void SetError([NotNull] Type contextType, [NotNull] Exception exception)
|
||||
{
|
||||
Check.NotNull(contextType, "contextType");
|
||||
Check.NotNull(exception, "exception");
|
||||
|
||||
_contextType = contextType;
|
||||
_exception = exception;
|
||||
}
|
||||
|
||||
public virtual bool IsErrorLogged
|
||||
{
|
||||
get { return _exception != null; }
|
||||
}
|
||||
|
||||
public virtual Type ContextType
|
||||
{
|
||||
get { return _contextType; }
|
||||
}
|
||||
|
||||
public virtual Exception Exception
|
||||
{
|
||||
get { return _exception; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// 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.Framework.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity
|
||||
{
|
||||
public class DataStoreErrorLoggerProvider : ILoggerProvider
|
||||
{
|
||||
private readonly DataStoreErrorLogger _logger = new DataStoreErrorLogger();
|
||||
|
||||
public virtual ILogger Create(string name)
|
||||
{
|
||||
return _logger;
|
||||
}
|
||||
|
||||
public virtual DataStoreErrorLogger Logger
|
||||
{
|
||||
get { return _logger; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// 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 DatabaseErrorPageExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseDatabaseErrorPage([NotNull] this IApplicationBuilder builder)
|
||||
{
|
||||
Check.NotNull(builder, "builder");
|
||||
|
||||
return builder.UseDatabaseErrorPage(DatabaseErrorPageOptions.ShowAll);
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseDatabaseErrorPage([NotNull] this IApplicationBuilder builder, [NotNull] DatabaseErrorPageOptions options)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
// 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.Builder;
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Utilities;
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Views;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.RequestContainer;
|
||||
using Microsoft.Data.Entity;
|
||||
using Microsoft.Data.Entity.Migrations;
|
||||
using Microsoft.Data.Entity.Migrations.Infrastructure;
|
||||
using Microsoft.Data.Entity.Migrations.Utilities;
|
||||
using Microsoft.Data.Entity.Relational;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity
|
||||
{
|
||||
public class DatabaseErrorPageMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly DatabaseErrorPageOptions _options;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger _logger;
|
||||
private readonly DataStoreErrorLoggerProvider _loggerProvider;
|
||||
|
||||
public DatabaseErrorPageMiddleware([NotNull] RequestDelegate next, [NotNull] IServiceProvider serviceProvider, [NotNull] ILoggerFactory loggerFactory, [NotNull] DatabaseErrorPageOptions options)
|
||||
{
|
||||
Check.NotNull(next, "next");
|
||||
Check.NotNull(serviceProvider, "serviceProvider");
|
||||
Check.NotNull(loggerFactory, "loggerFactory");
|
||||
Check.NotNull(options, "options");
|
||||
|
||||
_next = next;
|
||||
_serviceProvider = serviceProvider;
|
||||
_options = options;
|
||||
_logger = loggerFactory.Create<DatabaseErrorPageMiddleware>();
|
||||
|
||||
_loggerProvider = new DataStoreErrorLoggerProvider();
|
||||
loggerFactory.AddProvider(_loggerProvider);
|
||||
}
|
||||
|
||||
public virtual async Task Invoke([NotNull] HttpContext context)
|
||||
{
|
||||
Check.NotNull(context, "context");
|
||||
|
||||
try
|
||||
{
|
||||
#if !ASPNETCORE50
|
||||
// TODO This probably isn't the correct place for this workaround, it
|
||||
// needs to be called before anything is written to CallContext
|
||||
// http://msdn.microsoft.com/en-us/library/dn458353(v=vs.110).aspx
|
||||
System.Configuration.ConfigurationManager.GetSection("system.xml/xmlReader");
|
||||
#endif
|
||||
_loggerProvider.Logger.StartLoggingForCurrentCallContext();
|
||||
|
||||
await _next(context).WithCurrentCulture();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_loggerProvider.Logger.LastError.IsErrorLogged
|
||||
&& _loggerProvider.Logger.LastError.Exception == ex)
|
||||
{
|
||||
using (RequestServicesContainer.EnsureRequestServices(context, _serviceProvider))
|
||||
{
|
||||
var dbContextType = _loggerProvider.Logger.LastError.ContextType;
|
||||
var dbContext = (DbContext)context.RequestServices.GetService(dbContextType);
|
||||
if (dbContext == null)
|
||||
{
|
||||
_logger.WriteError(Strings.DatabaseErrorPageMiddleware_ContextNotRegistered(dbContextType.FullName));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dbContext.Database is RelationalDatabase)
|
||||
{
|
||||
var databaseExists = dbContext.Database.AsRelational().Exists();
|
||||
|
||||
var services = (MigrationsDataStoreServices)dbContext.Configuration.DataStoreServices;
|
||||
|
||||
var pendingMigrations = services.Migrator.GetPendingMigrations().Select(m => m.GetMigrationId());
|
||||
|
||||
var pendingModelChanges = true;
|
||||
var snapshot = services.Migrator.MigrationAssembly.Model;
|
||||
if (snapshot != null)
|
||||
{
|
||||
pendingModelChanges = services.Migrator.ModelDiffer.Diff(snapshot, dbContext.Model).Any();
|
||||
}
|
||||
|
||||
if ((!databaseExists && pendingMigrations.Any()) || pendingMigrations.Any() || pendingModelChanges)
|
||||
{
|
||||
var page = new DatabaseErrorPage();
|
||||
page.Model = new DatabaseErrorPageModel(dbContextType, ex, databaseExists, pendingModelChanges, pendingMigrations, _options);
|
||||
await page.ExecuteAsync(context).WithCurrentCulture();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.WriteError(Strings.DatabaseErrorPageMiddleware_Exception, e);
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// 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 DatabaseErrorPageOptions
|
||||
{
|
||||
private PathString _migrationsEndPointPath = MigrationsEndPointOptions.DefaultPath;
|
||||
private bool _defaultVisibility;
|
||||
private bool? _showExceptionDetails;
|
||||
private bool? _listMigrations;
|
||||
private bool? _enableMigrationCommands;
|
||||
|
||||
public static DatabaseErrorPageOptions ShowAll
|
||||
{
|
||||
get
|
||||
{
|
||||
// We don't use a static instance because it's mutable.
|
||||
return new DatabaseErrorPageOptions()
|
||||
{
|
||||
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; }
|
||||
set { _showExceptionDetails = value; }
|
||||
}
|
||||
|
||||
public virtual bool ListMigrations
|
||||
{
|
||||
get { return _listMigrations ?? _defaultVisibility; }
|
||||
set { _listMigrations = value; }
|
||||
}
|
||||
|
||||
public virtual bool EnableMigrationCommands
|
||||
{
|
||||
get { return _enableMigrationCommands ?? _defaultVisibility; }
|
||||
set { _enableMigrationCommands = value; }
|
||||
}
|
||||
|
||||
public virtual void SetDefaultVisibility(bool isVisible)
|
||||
{
|
||||
_defaultVisibility = isVisible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?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)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>4f5a6a72-ffe4-49c4-b4c6-58132cfcb9fe</ProjectGuid>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
// 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.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.Data.Entity.Migrations.Infrastructure;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using System.Net;
|
||||
using Microsoft.Framework.Logging;
|
||||
using Microsoft.AspNet.RequestContainer;
|
||||
|
||||
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.Create<MigrationsEndPointMiddleware>();
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public virtual async Task Invoke([NotNull] HttpContext context)
|
||||
{
|
||||
Check.NotNull(context, "context");
|
||||
|
||||
if (context.Request.Path.Equals(_options.Path))
|
||||
{
|
||||
_logger.WriteVerbose(Strings.MigrationsEndPointMiddleware_RequestPathMatched(context.Request.Path));
|
||||
|
||||
using (RequestServicesContainer.EnsureRequestServices(context, _serviceProvider))
|
||||
{
|
||||
var db = await GetDbContext(context, _logger).WithCurrentCulture();
|
||||
if (db != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.WriteVerbose(Strings.MigrationsEndPointMiddleware_ApplyingMigrations(db.GetType().FullName));
|
||||
|
||||
db.Database.AsMigrationsEnabled().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.WriteVerbose(Strings.MigrationsEndPointMiddleware_Applied(db.GetType().FullName));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var message = Strings.MigrationsEndPointMiddleware_Exception(db.GetType().FullName);
|
||||
_logger.WriteError(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.GetFormAsync().WithCurrentCulture();
|
||||
var contextTypeName = form["context"];
|
||||
if (string.IsNullOrWhiteSpace(contextTypeName))
|
||||
{
|
||||
logger.WriteError(Strings.MigrationsEndPointMiddleware_NoContextType);
|
||||
await WriteErrorToResponse(context.Response, Strings.MigrationsEndPointMiddleware_NoContextType).WithCurrentCulture();
|
||||
return null;
|
||||
}
|
||||
|
||||
var contextType = Type.GetType(contextTypeName);
|
||||
if (contextType == null)
|
||||
{
|
||||
var message = Strings.MigrationsEndPointMiddleware_InvalidContextType(contextTypeName);
|
||||
logger.WriteError(message);
|
||||
await WriteErrorToResponse(context.Response, message).WithCurrentCulture();
|
||||
return null;
|
||||
}
|
||||
|
||||
var db = (DbContext)context.RequestServices.GetService(contextType);
|
||||
if (db == null)
|
||||
{
|
||||
var message = Strings.MigrationsEndPointMiddleware_ContextNotRegistered(contextType.FullName);
|
||||
logger.WriteError(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
// <auto-generated />
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity
|
||||
{
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
public static class Strings
|
||||
{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("Microsoft.AspNet.Diagnostics.Entity.Strings", typeof(Strings).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// The string argument '{argumentName}' cannot be empty.
|
||||
/// </summary>
|
||||
public static string ArgumentIsEmpty([CanBeNull] object argumentName)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentIsEmpty", "argumentName"), argumentName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The collection argument '{argumentName}' must contain at least one element.
|
||||
/// </summary>
|
||||
public static string CollectionArgumentIsEmpty([CanBeNull] object argumentName)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("CollectionArgumentIsEmpty", "argumentName"), argumentName);
|
||||
}
|
||||
|
||||
/// <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. Skipping display of the database error page.
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPageMiddleware_ContextNotRegistered([CanBeNull] object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("DatabaseErrorPageMiddleware_ContextNotRegistered"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An exception occurred while calculating the database error page content. Skipping display of the database error page.
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPageMiddleware_Exception
|
||||
{
|
||||
get { return GetString("DatabaseErrorPageMiddleware_Exception"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// > k ef migration add [migration name]
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_AddMigrationCommand
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_AddMigrationCommand"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply Migrations
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_ApplyMigrationsButton
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_ApplyMigrationsButton"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrations Applied
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_ApplyMigrationsButtonDone
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_ApplyMigrationsButtonDone"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applying Migrations...
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_ApplyMigrationsButtonRunning
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_ApplyMigrationsButtonRunning"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An error occurred applying migrations, try applying them from the command line
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_ApplyMigrationsFailed
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_ApplyMigrationsFailed"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// You can also apply migrations from the command line:
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_HowToApplyFromCmd
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_HowToApplyFromCmd"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try refreshing the page
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_MigrationsAppliedRefresh
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_MigrationsAppliedRefresh"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// From the command line, scaffold a new migration and apply it to the database:
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_NoDbOrMigrationsInfo
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_NoDbOrMigrationsInfo"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use migrations to create the database for {0}
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_NoDbOrMigrationsTitle([CanBeNull] object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("DatabaseErrorPage_NoDbOrMigrationsTitle"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scaffold a new migration for these changes and apply them to the database from the command line:
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_PendingChangesInfo
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_PendingChangesInfo"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// There are pending model changes for {0}
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_PendingChangesTitle([CanBeNull] object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("DatabaseErrorPage_PendingChangesTitle"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// There are migrations for {0} that have not been applied to the database
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_PendingMigrationsInfo([CanBeNull] object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("DatabaseErrorPage_PendingMigrationsInfo"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applying existing migrations for {0} may resolve this issue
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_PendingMigrationsTitle([CanBeNull] object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("DatabaseErrorPage_PendingMigrationsTitle"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// > k ef migration apply
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_ApplyMigrationsCommand
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_ApplyMigrationsCommand"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The value provided for argument '{argumentName}' must be a valid value of enum type '{enumType}'.
|
||||
/// </summary>
|
||||
public static string InvalidEnumValue([CanBeNull] object argumentName, [CanBeNull] object enumType)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("InvalidEnumValue", "argumentName", "enumType"), argumentName, enumType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrations successfully applied for context '{0}'.
|
||||
/// </summary>
|
||||
public static string MigrationsEndPointMiddleware_Applied([CanBeNull] object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("MigrationsEndPointMiddleware_Applied"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request is valid, applying migrations for context '{0}'.
|
||||
/// </summary>
|
||||
public static string MigrationsEndPointMiddleware_ApplyingMigrations([CanBeNull] 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>
|
||||
public static string MigrationsEndPointMiddleware_ContextNotRegistered([CanBeNull] 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>
|
||||
public static string MigrationsEndPointMiddleware_Exception([CanBeNull] 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>
|
||||
public static string MigrationsEndPointMiddleware_InvalidContextType([CanBeNull] 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>
|
||||
public static string MigrationsEndPointMiddleware_NoContextType
|
||||
{
|
||||
get { return GetString("MigrationsEndPointMiddleware_NoContextType"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request path matched the path configured for this migrations endpoint ({0}). Attempting to process the migrations request.
|
||||
/// </summary>
|
||||
public static string MigrationsEndPointMiddleware_RequestPathMatched([CanBeNull] object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("MigrationsEndPointMiddleware_RequestPathMatched"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A database operation failed while processing the request.
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_Title
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_Title"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To use migrations from a command prompt you will need to <a href='http://go.microsoft.com/fwlink/?LinkId=518242'>install K Version Manager (KVM)</a>. Once installed, you can run migration commands from a standard command prompt in the project directory.
|
||||
/// </summary>
|
||||
public static string DatabaseErrorPage_EnableMigrationsCommandsInfo
|
||||
{
|
||||
get { return GetString("DatabaseErrorPage_EnableMigrationsCommandsInfo"); }
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
||||
Debug.Assert(value != null);
|
||||
|
||||
if (formatterNames != null)
|
||||
{
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ArgumentIsEmpty" xml:space="preserve">
|
||||
<value>The string argument '{argumentName}' cannot be empty.</value>
|
||||
</data>
|
||||
<data name="CollectionArgumentIsEmpty" xml:space="preserve">
|
||||
<value>The collection argument '{argumentName}' must contain at least one element.</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPageMiddleware_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. Skipping display of the database error page.</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPageMiddleware_Exception" xml:space="preserve">
|
||||
<value>An exception occurred while calculating the database error page content. Skipping display of the database error page.</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_AddMigrationCommand" xml:space="preserve">
|
||||
<value>> k 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>
|
||||
<data name="DatabaseErrorPage_NoDbOrMigrationsTitle" xml:space="preserve">
|
||||
<value>Use migrations to create the database for {0}</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_PendingChangesInfo" xml:space="preserve">
|
||||
<value>Scaffold a new migration for these changes and apply them to the database from the command line:</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_PendingChangesTitle" xml:space="preserve">
|
||||
<value>There are pending model changes for {0}</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_PendingMigrationsInfo" xml:space="preserve">
|
||||
<value>There are migrations for {0} that have not been applied to the database</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_PendingMigrationsTitle" xml:space="preserve">
|
||||
<value>Applying existing migrations for {0} may resolve this issue</value>
|
||||
</data>
|
||||
<data name="DatabaseErrorPage_ApplyMigrationsCommand" xml:space="preserve">
|
||||
<value>> k ef migration apply</value>
|
||||
</data>
|
||||
<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>
|
||||
<data name="DatabaseErrorPage_EnableMigrationsCommandsInfo" xml:space="preserve">
|
||||
<value>To use migrations from a command prompt you will need to <a href='http://go.microsoft.com/fwlink/?LinkId=518242'>install K Version Manager (KVM)</a>. Once installed, you can run migration commands from a standard command prompt in the project directory.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
// 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.Diagnostics;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Utilities
|
||||
{
|
||||
[DebuggerStepThrough]
|
||||
internal static class Check
|
||||
{
|
||||
[ContractAnnotation("value:null => halt")]
|
||||
public static T NotNull<T>([NoEnumeration] T value, [InvokerParameterName] [NotNull] string parameterName)
|
||||
{
|
||||
NotEmpty(parameterName, "parameterName");
|
||||
|
||||
if (ReferenceEquals(value, null))
|
||||
{
|
||||
throw new ArgumentNullException(parameterName);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[ContractAnnotation("value:null => halt")]
|
||||
public static IReadOnlyList<T> NotEmpty<T>(IReadOnlyList<T> value, [InvokerParameterName] [NotNull] string parameterName)
|
||||
{
|
||||
NotEmpty(parameterName, "parameterName");
|
||||
NotNull(value, parameterName);
|
||||
|
||||
if (value.Count == 0)
|
||||
{
|
||||
throw new ArgumentException(Strings.CollectionArgumentIsEmpty(parameterName));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
[ContractAnnotation("value:null => halt")]
|
||||
public static string NotEmpty(string value, [InvokerParameterName] [NotNull] string parameterName)
|
||||
{
|
||||
if (ReferenceEquals(parameterName, null))
|
||||
{
|
||||
throw new ArgumentNullException("parameterName");
|
||||
}
|
||||
|
||||
if (parameterName.Length == 0)
|
||||
{
|
||||
throw new ArgumentException(Strings.ArgumentIsEmpty("parameterName"));
|
||||
}
|
||||
|
||||
if (ReferenceEquals(value, null))
|
||||
{
|
||||
throw new ArgumentNullException(parameterName);
|
||||
}
|
||||
|
||||
if (value.Length == 0)
|
||||
{
|
||||
throw new ArgumentException(Strings.ArgumentIsEmpty(parameterName));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static T IsDefined<T>(T value, [InvokerParameterName] [NotNull] string parameterName)
|
||||
where T : struct
|
||||
{
|
||||
NotEmpty(parameterName, "parameterName");
|
||||
|
||||
if (!Enum.IsDefined(typeof(T), value))
|
||||
{
|
||||
throw new ArgumentException(Strings.InvalidEnumValue(parameterName, typeof(T)));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
namespace Microsoft.AspNet.Diagnostics.Entity.Views
|
||||
{
|
||||
#line 1 "DatabaseErrorPage.cshtml"
|
||||
using System
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
;
|
||||
#line 2 "DatabaseErrorPage.cshtml"
|
||||
using System.Linq
|
||||
|
||||
#line default
|
||||
#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"
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Views
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class DatabaseErrorPage : Microsoft.AspNet.Diagnostics.Views.BaseView
|
||||
{
|
||||
#line 14 "DatabaseErrorPage.cshtml"
|
||||
|
||||
private DatabaseErrorPageModel _model;
|
||||
|
||||
public virtual DatabaseErrorPageModel Model
|
||||
{
|
||||
get { return _model; }
|
||||
[param: NotNull]
|
||||
set
|
||||
{
|
||||
Check.NotNull(value, "value");
|
||||
|
||||
_model = value;
|
||||
}
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
#line hidden
|
||||
public DatabaseErrorPage()
|
||||
{
|
||||
}
|
||||
|
||||
#pragma warning disable 1998
|
||||
public override async Task ExecuteAsync()
|
||||
{
|
||||
#line 7 "DatabaseErrorPage.cshtml"
|
||||
|
||||
Response.StatusCode = 500;
|
||||
// TODO: Response.ReasonPhrase = "Internal Server Error";
|
||||
Response.ContentType = "text/html";
|
||||
Response.ContentLength = null; // Clear any prior Content-Length
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral("\r\n");
|
||||
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"
|
||||
Write(Strings.DatabaseErrorPage_Title);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</h1>\r\n");
|
||||
#line 42 "DatabaseErrorPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 42 "DatabaseErrorPage.cshtml"
|
||||
if (Model.Options.ShowExceptionDetails)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <p>\r\n");
|
||||
#line 45 "DatabaseErrorPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 45 "DatabaseErrorPage.cshtml"
|
||||
for (Exception ex = Model.Exception; ex != null; ex = ex.InnerException)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <span>");
|
||||
#line 47 "DatabaseErrorPage.cshtml"
|
||||
Write(ex.GetType().Name);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(": ");
|
||||
#line 47 "DatabaseErrorPage.cshtml"
|
||||
Write(ex.Message);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</span>\r\n <br />\r\n");
|
||||
#line 49 "DatabaseErrorPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" </p>\r\n <hr />\r\n");
|
||||
#line 52 "DatabaseErrorPage.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral("\r\n");
|
||||
#line 54 "DatabaseErrorPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 54 "DatabaseErrorPage.cshtml"
|
||||
if (!Model.DatabaseExists && !Model.PendingMigrations.Any())
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <h2>");
|
||||
#line 56 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_NoDbOrMigrationsTitle(Model.ContextType.Name));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</h2>\r\n <p>");
|
||||
#line 57 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_NoDbOrMigrationsInfo);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</p>\r\n <code> ");
|
||||
#line 58 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_AddMigrationCommand);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" </code>\r\n <br />\r\n <code> ");
|
||||
#line 60 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_ApplyMigrationsCommand);
|
||||
|
||||
#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"
|
||||
}
|
||||
else if (Model.PendingMigrations.Any())
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <div>\r\n <h2>");
|
||||
#line 67 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_PendingMigrationsTitle(Model.ContextType.Name));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</h2>\r\n <p>");
|
||||
#line 68 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_PendingMigrationsInfo(Model.ContextType.Name));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</p>\r\n\r\n");
|
||||
#line 70 "DatabaseErrorPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 70 "DatabaseErrorPage.cshtml"
|
||||
if (Model.Options.ListMigrations)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <ul>\r\n");
|
||||
#line 73 "DatabaseErrorPage.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 73 "DatabaseErrorPage.cshtml"
|
||||
foreach (var migration in Model.PendingMigrations)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <li>");
|
||||
#line 75 "DatabaseErrorPage.cshtml"
|
||||
Write(migration);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</li>\r\n");
|
||||
#line 76 "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 default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral("\r\n <p>");
|
||||
#line 124 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_HowToApplyFromCmd);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</p>\r\n <code>");
|
||||
#line 125 "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"
|
||||
}
|
||||
else if (Model.PendingModelChanges)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral(" <div>\r\n <h2>");
|
||||
#line 133 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_PendingChangesTitle(Model.ContextType.Name));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</h2>\r\n <p>");
|
||||
#line 134 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_PendingChangesInfo);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</p>\r\n <code>");
|
||||
#line 135 "DatabaseErrorPage.cshtml"
|
||||
Write(Strings.DatabaseErrorPage_AddMigrationCommand);
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</code>\r\n <br />\r\n <code>");
|
||||
#line 137 "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"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
WriteLiteral("</body>\r\n</html>");
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
@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 virtual DatabaseErrorPageModel Model
|
||||
{
|
||||
get { return _model; }
|
||||
[param: NotNull]
|
||||
set
|
||||
{
|
||||
Check.NotNull(value, "value");
|
||||
|
||||
_model = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Internal Server Error</title>
|
||||
<style>
|
||||
<%$ include: ErrorPage.css %>
|
||||
@string.Empty
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>@Strings.DatabaseErrorPage_Title</h1>
|
||||
@if (Model.Options.ShowExceptionDetails)
|
||||
{
|
||||
<p>
|
||||
@for (Exception ex = Model.Exception; ex != null; ex = ex.InnerException)
|
||||
{
|
||||
<span>@ex.GetType().Name: @ex.Message</span>
|
||||
<br />
|
||||
}
|
||||
</p>
|
||||
<hr />
|
||||
}
|
||||
|
||||
@if (!Model.DatabaseExists && !Model.PendingMigrations.Any())
|
||||
{
|
||||
<h2>@Strings.DatabaseErrorPage_NoDbOrMigrationsTitle(Model.ContextType.Name)</h2>
|
||||
<p>@Strings.DatabaseErrorPage_NoDbOrMigrationsInfo</p>
|
||||
<code> @Strings.DatabaseErrorPage_AddMigrationCommand </code>
|
||||
<br />
|
||||
<code> @Strings.DatabaseErrorPage_ApplyMigrationsCommand </code>
|
||||
<p><strong>@Strings.DatabaseErrorPage_EnableMigrationsCommandsInfo</strong></p>
|
||||
<hr />
|
||||
}
|
||||
else if (Model.PendingMigrations.Any())
|
||||
{
|
||||
<div>
|
||||
<h2>@Strings.DatabaseErrorPage_PendingMigrationsTitle(Model.ContextType.Name)</h2>
|
||||
<p>@Strings.DatabaseErrorPage_PendingMigrationsInfo(Model.ContextType.Name)</p>
|
||||
|
||||
@if (Model.Options.ListMigrations)
|
||||
{
|
||||
<ul>
|
||||
@foreach (var migration in Model.PendingMigrations)
|
||||
{
|
||||
<li>@migration</li>
|
||||
}
|
||||
</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>
|
||||
}
|
||||
else if (Model.PendingModelChanges)
|
||||
{
|
||||
<div>
|
||||
<h2>@Strings.DatabaseErrorPage_PendingChangesTitle(Model.ContextType.Name)</h2>
|
||||
<p>@Strings.DatabaseErrorPage_PendingChangesInfo</p>
|
||||
<code>@Strings.DatabaseErrorPage_AddMigrationCommand</code>
|
||||
<br />
|
||||
<code>@Strings.DatabaseErrorPage_ApplyMigrationsCommand</code>
|
||||
<p><strong>@Strings.DatabaseErrorPage_EnableMigrationsCommandsInfo</strong></p>
|
||||
<hr />
|
||||
</div>
|
||||
}
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// 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.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Views
|
||||
{
|
||||
public class DatabaseErrorPageModel
|
||||
{
|
||||
private readonly Type _contextType;
|
||||
private readonly Exception _exception;
|
||||
private readonly bool _databaseExists;
|
||||
private readonly bool _pendingModelChanges;
|
||||
private readonly IEnumerable<string> _pendingMigrations;
|
||||
private readonly DatabaseErrorPageOptions _options;
|
||||
|
||||
public DatabaseErrorPageModel(
|
||||
[NotNull] Type contextType,
|
||||
[NotNull] Exception exception,
|
||||
bool databaseExists,
|
||||
bool pendingModelChanges,
|
||||
[NotNull] IEnumerable<string> pendingMigrations,
|
||||
[NotNull] DatabaseErrorPageOptions options)
|
||||
{
|
||||
Check.NotNull(contextType, "contextType");
|
||||
Check.NotNull(exception, "exception");
|
||||
Check.NotNull(pendingMigrations, "pendingMigrations");
|
||||
Check.NotNull(options, "options");
|
||||
|
||||
_contextType = contextType;
|
||||
_exception = exception;
|
||||
_databaseExists = databaseExists;
|
||||
_pendingModelChanges = pendingModelChanges;
|
||||
_pendingMigrations = pendingMigrations;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public virtual Type ContextType
|
||||
{
|
||||
get { return _contextType; }
|
||||
}
|
||||
|
||||
public virtual Exception Exception
|
||||
{
|
||||
get { return _exception; }
|
||||
}
|
||||
|
||||
public virtual bool DatabaseExists
|
||||
{
|
||||
get { return _databaseExists; }
|
||||
}
|
||||
|
||||
public virtual bool PendingModelChanges
|
||||
{
|
||||
get { return _pendingModelChanges; }
|
||||
}
|
||||
|
||||
public virtual IEnumerable<string> PendingMigrations
|
||||
{
|
||||
get { return _pendingMigrations; }
|
||||
}
|
||||
|
||||
public virtual DatabaseErrorPageOptions Options
|
||||
{
|
||||
get { return _options; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;
|
||||
font-size: .813em;
|
||||
line-height: 1.4em;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #44525e;
|
||||
margin: 15px 0 15px 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 10px 5px 0 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #363636;
|
||||
margin: 5px 5px 0 0;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: Consolas, "Courier New", courier, monospace;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #1ba1e2;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #13709e;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px #ddd solid;
|
||||
}
|
||||
|
||||
body .titleerror {
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
#applyMigrations {
|
||||
font-size: 14px;
|
||||
background: #44c5f2;
|
||||
color: #ffffff;
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
margin-bottom: 0;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
#applyMigrations:disabled {
|
||||
background-color: #a9e4f9;
|
||||
border-color: #44c5f2;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.expanded {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"version": "7.0.0-*",
|
||||
"description": "ASP.NET 5 Middleware for Entity Framework error pages.",
|
||||
"compilationOptions": {
|
||||
"warningsAsErrors": true
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Diagnostics": "1.0.0-*",
|
||||
"EntityFramework.Migrations": "7.0.0-*"
|
||||
},
|
||||
"code": [ "**\\*.cs", "..\\Shared\\*.cs" ],
|
||||
"frameworks": {
|
||||
"aspnet50": {
|
||||
"frameworkAssemblies": {
|
||||
"System.Configuration": ""
|
||||
}
|
||||
},
|
||||
"aspnetcore50": {
|
||||
"dependencies": {
|
||||
"System.Threading.ExecutionContext": "4.0.0-beta-*"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,367 @@
|
|||
// 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.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Diagnostics.Entity.FunctionalTests.Helpers;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Microsoft.Data.Entity;
|
||||
using Microsoft.Data.Entity.Migrations.Infrastructure;
|
||||
using Microsoft.Data.Entity.SqlServer.FunctionalTests;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Logging;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
||||
{
|
||||
public class DatabaseErrorPageMiddlewareTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task Successful_requests_pass_thru()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app
|
||||
.UseDatabaseErrorPage()
|
||||
.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 Non_database_exceptions_pass_thru()
|
||||
{
|
||||
TestServer server = TestServer.Create(app => app
|
||||
.UseDatabaseErrorPage()
|
||||
.UseMiddleware<ExceptionMiddleware>());
|
||||
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
|
||||
await server.CreateClient().GetAsync("http://localhost/"));
|
||||
|
||||
Assert.Equal("Exception requested from TestMiddleware", ex.Message);
|
||||
}
|
||||
|
||||
class ExceptionMiddleware
|
||||
{
|
||||
public ExceptionMiddleware(RequestDelegate next)
|
||||
{ }
|
||||
|
||||
public virtual Task Invoke(HttpContext context)
|
||||
{
|
||||
throw new InvalidOperationException("Exception requested from TestMiddleware");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Error_page_displayed_no_migrations()
|
||||
{
|
||||
TestServer server = await SetupTestServer<BloggingContext, NoMigrationsMiddleware>();
|
||||
HttpResponseMessage response = await server.CreateClient().GetAsync("http://localhost/");
|
||||
|
||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.Contains(Strings.DatabaseErrorPage_NoDbOrMigrationsTitle(typeof(BloggingContext).Name), content);
|
||||
Assert.Contains(Strings.DatabaseErrorPage_AddMigrationCommand.Replace(">", ">"), content);
|
||||
Assert.Contains(Strings.DatabaseErrorPage_ApplyMigrationsCommand.Replace(">", ">"), content);
|
||||
}
|
||||
|
||||
class NoMigrationsMiddleware
|
||||
{
|
||||
public NoMigrationsMiddleware(RequestDelegate next)
|
||||
{ }
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Error_page_displayed_pending_migrations()
|
||||
{
|
||||
TestServer server = await SetupTestServer<BloggingContextWithMigrations, PendingMigrationsMiddleware>();
|
||||
HttpResponseMessage response = await server.CreateClient().GetAsync("http://localhost/");
|
||||
|
||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.Contains(Strings.DatabaseErrorPage_PendingMigrationsTitle(typeof(BloggingContextWithMigrations).Name), content);
|
||||
Assert.Contains(Strings.DatabaseErrorPage_ApplyMigrationsCommand.Replace(">", ">"), content);
|
||||
Assert.Contains("<li>111111111111111_MigrationOne</li>", content);
|
||||
Assert.Contains("<li>222222222222222_MigrationTwo</li>", content);
|
||||
|
||||
Assert.DoesNotContain(Strings.DatabaseErrorPage_AddMigrationCommand.Replace(">", ">"), content);
|
||||
}
|
||||
|
||||
class PendingMigrationsMiddleware
|
||||
{
|
||||
public PendingMigrationsMiddleware(RequestDelegate next)
|
||||
{ }
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Error_page_displayed_pending_model_changes()
|
||||
{
|
||||
TestServer server = await SetupTestServer<BloggingContextWithPendingModelChanges, PendingModelChangesMiddleware>();
|
||||
HttpResponseMessage response = await server.CreateClient().GetAsync("http://localhost/");
|
||||
|
||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.Contains(Strings.DatabaseErrorPage_PendingChangesTitle(typeof(BloggingContextWithPendingModelChanges).Name), content);
|
||||
Assert.Contains(Strings.DatabaseErrorPage_AddMigrationCommand.Replace(">", ">"), content);
|
||||
Assert.Contains(Strings.DatabaseErrorPage_ApplyMigrationsCommand.Replace(">", ">"), content);
|
||||
}
|
||||
|
||||
class PendingModelChangesMiddleware
|
||||
{
|
||||
public PendingModelChangesMiddleware(RequestDelegate next)
|
||||
{ }
|
||||
|
||||
public virtual Task Invoke(HttpContext context)
|
||||
{
|
||||
using (var db = context.ApplicationServices.GetService<BloggingContextWithPendingModelChanges>())
|
||||
{
|
||||
var services = (MigrationsDataStoreServices)db.Configuration.DataStoreServices;
|
||||
services.Migrator.ApplyMigrations();
|
||||
|
||||
db.Blogs.Add(new Blog());
|
||||
db.SaveChanges();
|
||||
throw new Exception("SaveChanges should have thrown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Error_page_then_apply_migrations()
|
||||
{
|
||||
TestServer server = await 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 = await SqlServerTestStore.CreateScratchAsync(createDatabase: false))
|
||||
{
|
||||
var server = TestServer.Create(app =>
|
||||
{
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddEntityFramework().AddSqlServer();
|
||||
services.AddScoped<BloggingContextWithMigrations>();
|
||||
services.AddInstance<DbContextOptions>(new DbContextOptions().UseSqlServer(database.Connection.ConnectionString));
|
||||
});
|
||||
|
||||
var options = DatabaseErrorPageOptions.ShowAll;
|
||||
options.MigrationsEndPointPath = new PathString(migrationsEndpoint);
|
||||
app.UseDatabaseErrorPage(options);
|
||||
|
||||
app.UseMiddleware<PendingMigrationsMiddleware>();
|
||||
});
|
||||
|
||||
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()
|
||||
{
|
||||
using (var database = await SqlServerTestStore.CreateScratchAsync(createDatabase: false))
|
||||
{
|
||||
var logProvider = new TestLoggerProvider();
|
||||
|
||||
var server = TestServer.Create(app =>
|
||||
{
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddEntityFramework()
|
||||
.AddSqlServer();
|
||||
|
||||
services.AddInstance<DbContextOptions>(
|
||||
new DbContextOptions()
|
||||
.UseSqlServer(database.Connection.ConnectionString));
|
||||
});
|
||||
|
||||
app.UseDatabaseErrorPage();
|
||||
|
||||
app.UseMiddleware<ContextNotRegisteredInServicesMiddleware>();
|
||||
|
||||
app.ApplicationServices.GetService<ILoggerFactory>().AddProvider(logProvider);
|
||||
});
|
||||
|
||||
var ex = await Assert.ThrowsAsync<SqlException>(async () =>
|
||||
await server.CreateClient().GetAsync("http://localhost/"));
|
||||
|
||||
Assert.True(logProvider.Logger.Messages.Any(m =>
|
||||
m.StartsWith(Strings.DatabaseErrorPageMiddleware_ContextNotRegistered(typeof(BloggingContext)))));
|
||||
}
|
||||
}
|
||||
|
||||
class ContextNotRegisteredInServicesMiddleware
|
||||
{
|
||||
public ContextNotRegisteredInServicesMiddleware(RequestDelegate next)
|
||||
{ }
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Pass_thru_when_exception_in_logic()
|
||||
{
|
||||
using (var database = await SqlServerTestStore.CreateScratchAsync(createDatabase: false))
|
||||
{
|
||||
var logProvider = new TestLoggerProvider();
|
||||
|
||||
var server = await SetupTestServer<BloggingContextWithSnapshotThatThrows, ExceptionInLogicMiddleware>(logProvider);
|
||||
|
||||
var ex = await Assert.ThrowsAsync<SqlException>(async () =>
|
||||
await server.CreateClient().GetAsync("http://localhost/"));
|
||||
|
||||
Assert.True(logProvider.Logger.Messages.Any(m =>
|
||||
m.StartsWith(Strings.DatabaseErrorPageMiddleware_Exception)));
|
||||
}
|
||||
}
|
||||
|
||||
class ExceptionInLogicMiddleware
|
||||
{
|
||||
public ExceptionInLogicMiddleware(RequestDelegate next)
|
||||
{ }
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<TestServer> SetupTestServer<TContext, TMiddleware>(ILoggerProvider logProvider = null)
|
||||
where TContext : DbContext
|
||||
{
|
||||
using (var database = await SqlServerTestStore.CreateScratchAsync(createDatabase: false))
|
||||
{
|
||||
return TestServer.Create(app =>
|
||||
{
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddEntityFramework()
|
||||
.AddSqlServer();
|
||||
|
||||
services.AddScoped<TContext>();
|
||||
services.AddInstance<DbContextOptions>(
|
||||
new DbContextOptions()
|
||||
.UseSqlServer(database.Connection.ConnectionString));
|
||||
});
|
||||
|
||||
app.UseDatabaseErrorPage();
|
||||
|
||||
app.UseMiddleware<TMiddleware>();
|
||||
|
||||
if (logProvider != null)
|
||||
{
|
||||
app.ApplicationServices.GetService<ILoggerFactory>().AddProvider(logProvider);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// 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 Microsoft.Framework.Logging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.FunctionalTests.Helpers
|
||||
{
|
||||
public class TestLoggerProvider : ILoggerProvider
|
||||
{
|
||||
private readonly TestLogger _logger = new TestLogger();
|
||||
|
||||
public TestLogger Logger
|
||||
{
|
||||
get { return _logger; }
|
||||
}
|
||||
|
||||
public ILogger Create(string name)
|
||||
{
|
||||
return _logger;
|
||||
}
|
||||
|
||||
public class TestLogger : ILogger
|
||||
{
|
||||
private List<string> _messages = new List<string>();
|
||||
|
||||
public IEnumerable<string> Messages
|
||||
{
|
||||
get { return _messages; }
|
||||
}
|
||||
|
||||
public void Write(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
|
||||
{
|
||||
_messages.Add(formatter(state, exception));
|
||||
}
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public IDisposable BeginScope(object state)
|
||||
{
|
||||
return NullScope.Instance;
|
||||
}
|
||||
|
||||
public class NullScope : IDisposable
|
||||
{
|
||||
public static NullScope Instance = new NullScope();
|
||||
|
||||
public void Dispose()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?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)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>2f9b479d-8247-4210-804b-78e6dd5c3e98</ProjectGuid>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
// 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.Migrations.Infrastructure;
|
||||
using Microsoft.Data.Entity.Migrations.Utilities;
|
||||
using Microsoft.Data.Entity.SqlServer.FunctionalTests;
|
||||
using Microsoft.Framework.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;
|
||||
}
|
||||
}
|
||||
|
||||
[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 = await SqlServerTestStore.CreateScratchAsync(createDatabase: false))
|
||||
{
|
||||
var options = new DbContextOptions().UseSqlServer(database.Connection.ConnectionString);
|
||||
var path = useCustomPath ? new PathString("/EndPoints/ApplyMyMigrations") : MigrationsEndPointOptions.DefaultPath;
|
||||
|
||||
TestServer server = TestServer.Create(app =>
|
||||
{
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddEntityFramework().AddSqlServer();
|
||||
services.AddScoped<BloggingContextWithMigrations>();
|
||||
services.AddInstance<DbContextOptions>(options);
|
||||
});
|
||||
|
||||
if (useCustomPath)
|
||||
{
|
||||
app.UseMigrationsEndPoint(new MigrationsEndPointOptions { Path = path });
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseMigrationsEndPoint();
|
||||
}
|
||||
});
|
||||
|
||||
using (var db = BloggingContextWithMigrations.CreateWithoutExternalServiceProvider(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 services = (MigrationsDataStoreServices)db.Configuration.DataStoreServices;
|
||||
var appliedMigrations = services.Migrator.GetDatabaseMigrations();
|
||||
Assert.Equal(2, appliedMigrations.Count);
|
||||
Assert.Equal("111111111111111_MigrationOne", appliedMigrations.ElementAt(0).GetMigrationId());
|
||||
Assert.Equal("222222222222222_MigrationTwo", appliedMigrations.ElementAt(1).GetMigrationId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[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(Strings.MigrationsEndPointMiddleware_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(Strings.MigrationsEndPointMiddleware_InvalidContextType(typeName), content);
|
||||
Assert.True(content.Length > 512);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Context_not_registered_in_services()
|
||||
{
|
||||
var server = TestServer.Create(app =>
|
||||
{
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddEntityFramework().AddSqlServer();
|
||||
});
|
||||
app.UseMigrationsEndPoint();
|
||||
});
|
||||
|
||||
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(Strings.MigrationsEndPointMiddleware_ContextNotRegistered(typeof(BloggingContext)), content);
|
||||
Assert.True(content.Length > 512);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Exception_while_applying_migrations()
|
||||
{
|
||||
using (var database = await SqlServerTestStore.CreateScratchAsync(createDatabase: false))
|
||||
{
|
||||
var options = new DbContextOptions().UseSqlServer(database.Connection.ConnectionString);
|
||||
|
||||
TestServer server = TestServer.Create(app =>
|
||||
{
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddEntityFramework().AddSqlServer();
|
||||
services.AddScoped<BloggingContextWithSnapshotThatThrows>();
|
||||
services.AddInstance<DbContextOptions>(options);
|
||||
});
|
||||
|
||||
app.UseMigrationsEndPoint();
|
||||
});
|
||||
|
||||
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(Strings.MigrationsEndPointMiddleware_Exception(typeof(BloggingContextWithSnapshotThatThrows)), ex.Message);
|
||||
Assert.Equal("Welcome to the invalid snapshot!", ex.InnerException.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
||||
{
|
||||
public class Blog
|
||||
{
|
||||
public int BlogId { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// 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.Data.Entity;
|
||||
using Microsoft.Data.Entity.Migrations.Infrastructure;
|
||||
using Microsoft.Data.Entity.SqlServer.FunctionalTests;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
||||
{
|
||||
public class BloggingContext : DbContext
|
||||
{
|
||||
protected static readonly string CurrentProductVersion = typeof(HistoryRepository)
|
||||
.GetTypeInfo()
|
||||
.Assembly
|
||||
.GetCustomAttributes<AssemblyInformationalVersionAttribute>()
|
||||
.Single()
|
||||
.InformationalVersion;
|
||||
|
||||
protected BloggingContext(DbContextOptions options)
|
||||
: base(options)
|
||||
{ }
|
||||
|
||||
public BloggingContext(IServiceProvider provider, DbContextOptions options)
|
||||
: base(provider, options)
|
||||
{ }
|
||||
|
||||
public DbSet<Blog> Blogs { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
// 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.Data.Entity;
|
||||
using Microsoft.Data.Entity.Metadata;
|
||||
using Microsoft.Data.Entity.Migrations;
|
||||
using Microsoft.Data.Entity.Migrations.Builders;
|
||||
using Microsoft.Data.Entity.Migrations.Infrastructure;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
||||
{
|
||||
public class BloggingContextWithMigrations : BloggingContext
|
||||
{
|
||||
protected BloggingContextWithMigrations(DbContextOptions options)
|
||||
: base(options)
|
||||
{ }
|
||||
|
||||
public BloggingContextWithMigrations(IServiceProvider provider, DbContextOptions options)
|
||||
: base(provider, options)
|
||||
{ }
|
||||
|
||||
// Providing a factory method so that the ctor is hidden from DI
|
||||
public static BloggingContextWithMigrations CreateWithoutExternalServiceProvider(DbContextOptions options)
|
||||
{
|
||||
return new BloggingContextWithMigrations(options);
|
||||
}
|
||||
|
||||
[ContextType(typeof(BloggingContextWithMigrations))]
|
||||
public class BloggingContextWithMigrationsModelSnapshot : ModelSnapshot
|
||||
{
|
||||
public override IModel Model
|
||||
{
|
||||
get
|
||||
{
|
||||
var builder = new BasicModelBuilder();
|
||||
|
||||
builder.Entity("Blogging.Models.Blog", b =>
|
||||
{
|
||||
b.Property<int>("BlogId");
|
||||
b.Property<int>("BlogId").GenerateValueOnAdd();
|
||||
b.Property<string>("Name");
|
||||
b.Key("BlogId");
|
||||
});
|
||||
|
||||
return builder.Model;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ContextType(typeof(BloggingContextWithMigrations))]
|
||||
public class MigrationOne : Migration, IMigrationMetadata
|
||||
{
|
||||
string IMigrationMetadata.MigrationId
|
||||
{
|
||||
get { return "111111111111111_MigrationOne"; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.ProductVersion
|
||||
{
|
||||
get { return CurrentProductVersion; }
|
||||
}
|
||||
|
||||
IModel IMigrationMetadata.TargetModel
|
||||
{
|
||||
get { return new BloggingContextWithMigrationsModelSnapshot().Model; }
|
||||
}
|
||||
|
||||
public override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable("Blog",
|
||||
c => new
|
||||
{
|
||||
BlogId = c.Int(nullable: false, identity: true),
|
||||
Name = c.String(),
|
||||
})
|
||||
.PrimaryKey("PK_Blog", t => t.BlogId);
|
||||
}
|
||||
|
||||
public override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable("Blog");
|
||||
}
|
||||
}
|
||||
|
||||
[ContextType(typeof(BloggingContextWithMigrations))]
|
||||
public class MigrationTwo : Migration, IMigrationMetadata
|
||||
{
|
||||
string IMigrationMetadata.MigrationId
|
||||
{
|
||||
get { return "222222222222222_MigrationTwo"; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.ProductVersion
|
||||
{
|
||||
get { return CurrentProductVersion; }
|
||||
}
|
||||
|
||||
IModel IMigrationMetadata.TargetModel
|
||||
{
|
||||
get { return new BloggingContextWithMigrationsModelSnapshot().Model; }
|
||||
}
|
||||
|
||||
public override void Up(MigrationBuilder migrationBuilder)
|
||||
{ }
|
||||
|
||||
public override void Down(MigrationBuilder migrationBuilder)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
// 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.Data.Entity;
|
||||
using Microsoft.Data.Entity.Metadata;
|
||||
using Microsoft.Data.Entity.Migrations;
|
||||
using Microsoft.Data.Entity.Migrations.Builders;
|
||||
using Microsoft.Data.Entity.Migrations.Infrastructure;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
||||
{
|
||||
public class BloggingContextWithPendingModelChanges : BloggingContext
|
||||
{
|
||||
public BloggingContextWithPendingModelChanges(IServiceProvider provider, DbContextOptions options)
|
||||
: base(provider, options)
|
||||
{ }
|
||||
|
||||
[ContextType(typeof(BloggingContextWithPendingModelChanges))]
|
||||
public class BloggingModelSnapshot : ModelSnapshot
|
||||
{
|
||||
public override IModel Model
|
||||
{
|
||||
get { return new BasicModelBuilder().Model; }
|
||||
}
|
||||
}
|
||||
|
||||
[ContextType(typeof(BloggingContextWithPendingModelChanges))]
|
||||
public partial class MigrationOne : Migration, IMigrationMetadata
|
||||
{
|
||||
string IMigrationMetadata.MigrationId
|
||||
{
|
||||
get { return "111111111111111_MigrationOne"; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.ProductVersion
|
||||
{
|
||||
get { return CurrentProductVersion; }
|
||||
}
|
||||
|
||||
IModel IMigrationMetadata.TargetModel
|
||||
{
|
||||
get { return new BasicModelBuilder().Model; }
|
||||
}
|
||||
|
||||
public override void Up(MigrationBuilder migrationBuilder)
|
||||
{ }
|
||||
|
||||
public override void Down(MigrationBuilder migrationBuilder)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// 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.Data.Entity;
|
||||
using Microsoft.Data.Entity.Metadata;
|
||||
using Microsoft.Data.Entity.Migrations;
|
||||
using Microsoft.Data.Entity.Migrations.Builders;
|
||||
using Microsoft.Data.Entity.Migrations.Infrastructure;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
||||
{
|
||||
public class BloggingContextWithSnapshotThatThrows : BloggingContext
|
||||
{
|
||||
public BloggingContextWithSnapshotThatThrows(IServiceProvider provider, DbContextOptions options)
|
||||
: base(provider, options)
|
||||
{ }
|
||||
|
||||
[ContextType(typeof(BloggingContextWithSnapshotThatThrows))]
|
||||
public class BloggingContextWithSnapshotThatThrowsModelSnapshot : ModelSnapshot
|
||||
{
|
||||
public override IModel Model
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new Exception("Welcome to the invalid snapshot!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ContextType(typeof(BloggingContextWithSnapshotThatThrows))]
|
||||
public class MigrationOne : Migration, IMigrationMetadata
|
||||
{
|
||||
string IMigrationMetadata.MigrationId
|
||||
{
|
||||
get { return "111111111111111_MigrationOne"; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.ProductVersion
|
||||
{
|
||||
get { return CurrentProductVersion; }
|
||||
}
|
||||
|
||||
IModel IMigrationMetadata.TargetModel
|
||||
{
|
||||
get { return new BloggingContextWithSnapshotThatThrowsModelSnapshot().Model; }
|
||||
}
|
||||
|
||||
public override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
throw new Exception("Welcome to the invalid migration!");
|
||||
}
|
||||
|
||||
public override void Down(MigrationBuilder migrationBuilder)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"EntityFramework.SqlServer": "7.0.0-*",
|
||||
"EntityFramework.SqlServer.FunctionalTests": "1.0.0",
|
||||
"Microsoft.AspNet.Diagnostics.Entity": "7.0.0-*",
|
||||
"Microsoft.AspNet.Diagnostics.Entity.Tests": "1.0.0",
|
||||
"Microsoft.AspNet.TestHost": "1.0.0-*",
|
||||
"Xunit.KRunner": "1.0.0-*"
|
||||
},
|
||||
"commands": {
|
||||
"test": "Xunit.KRunner"
|
||||
},
|
||||
"frameworks": {
|
||||
"aspnet50": { }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// 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;
|
||||
using Microsoft.Data.Entity;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.EntityTests
|
||||
{
|
||||
public class ApiConsistencyTest : ApiConsistencyTestBase
|
||||
{
|
||||
protected override Assembly TargetAssembly
|
||||
{
|
||||
get { return typeof(DatabaseErrorPageMiddleware).Assembly; }
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> GetCancellationTokenExceptions()
|
||||
{
|
||||
return new string[]
|
||||
{
|
||||
"DatabaseErrorPageMiddleware.Invoke",
|
||||
"MigrationsEndPointMiddleware.Invoke",
|
||||
"DatabaseErrorPage.ExecuteAsync",
|
||||
"BaseView.ExecuteAsync"
|
||||
};
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> GetAsyncSuffixExceptions()
|
||||
{
|
||||
return new string[]
|
||||
{
|
||||
"DatabaseErrorPageMiddleware.Invoke",
|
||||
"MigrationsEndPointMiddleware.Invoke"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// 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 Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
||||
{
|
||||
public class DatabaseErrorPageOptionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void Default_visibility_is_false()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
|
||||
Assert.False(options.ShowExceptionDetails);
|
||||
Assert.False(options.ListMigrations);
|
||||
Assert.False(options.EnableMigrationCommands);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Default_visibility_can_be_changed()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.SetDefaultVisibility(true);
|
||||
|
||||
Assert.True(options.ShowExceptionDetails);
|
||||
Assert.True(options.ListMigrations);
|
||||
Assert.True(options.EnableMigrationCommands);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShowExceptionDetails_overides_default_visibility()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions { ShowExceptionDetails = false };
|
||||
options.SetDefaultVisibility(true);
|
||||
|
||||
Assert.False(options.ShowExceptionDetails);
|
||||
Assert.True(options.ListMigrations);
|
||||
Assert.True(options.EnableMigrationCommands);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ListMigrations_overides_default_visibility()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions { ListMigrations = false };
|
||||
options.SetDefaultVisibility(true);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
// 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.Tests.Helpers;
|
||||
using Microsoft.AspNet.Diagnostics.Entity.Views;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Data.Entity;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests
|
||||
{
|
||||
public class DatabaseErrorPageTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task No_database_or_migrations_only_displays_scaffold_first_migration()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.SetDefaultVisibility(true);
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
exception: new Exception(),
|
||||
databaseExists: false,
|
||||
pendingModelChanges: false,
|
||||
pendingMigrations: new string[] { },
|
||||
options: options);
|
||||
|
||||
var content = await ExecutePage(options, model);
|
||||
|
||||
AssertHelpers.DisplaysScaffoldFirstMigration(typeof(BloggingContext), content);
|
||||
AssertHelpers.NotDisplaysApplyMigrations(typeof(BloggingContext), content);
|
||||
AssertHelpers.NotDisplaysScaffoldNextMigraion(typeof(BloggingContext), content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_database_with_migrations_only_displays_apply_migrations()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.SetDefaultVisibility(true);
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
exception: new Exception(),
|
||||
databaseExists: false,
|
||||
pendingModelChanges: false,
|
||||
pendingMigrations: new string[] { "111_MigrationOne" },
|
||||
options: options);
|
||||
|
||||
var content = await ExecutePage(options, model);
|
||||
|
||||
AssertHelpers.NotDisplaysScaffoldFirstMigration(typeof(BloggingContext), content);
|
||||
AssertHelpers.DisplaysApplyMigrations(typeof(BloggingContext), content);
|
||||
AssertHelpers.NotDisplaysScaffoldNextMigraion(typeof(BloggingContext), content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Existing_database_with_migrations_only_displays_apply_migrations()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
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);
|
||||
|
||||
AssertHelpers.NotDisplaysScaffoldFirstMigration(typeof(BloggingContext), content);
|
||||
AssertHelpers.DisplaysApplyMigrations(typeof(BloggingContext), content);
|
||||
AssertHelpers.NotDisplaysScaffoldNextMigraion(typeof(BloggingContext), content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Existing_database_with_migrations_and_pending_model_changes_only_displays_apply_migrations()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.SetDefaultVisibility(true);
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
exception: new Exception(),
|
||||
databaseExists: true,
|
||||
pendingModelChanges: true,
|
||||
pendingMigrations: new string[] { "111_MigrationOne" },
|
||||
options: options);
|
||||
|
||||
var content = await ExecutePage(options, model);
|
||||
|
||||
AssertHelpers.NotDisplaysScaffoldFirstMigration(typeof(BloggingContext), content);
|
||||
AssertHelpers.DisplaysApplyMigrations(typeof(BloggingContext), content);
|
||||
AssertHelpers.NotDisplaysScaffoldNextMigraion(typeof(BloggingContext), content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Pending_model_changes_only_displays_scaffold_next_migration()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.SetDefaultVisibility(true);
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
exception: new Exception(),
|
||||
databaseExists: true,
|
||||
pendingModelChanges: true,
|
||||
pendingMigrations: new string[] { },
|
||||
options: options);
|
||||
|
||||
var content = await ExecutePage(options, model);
|
||||
|
||||
AssertHelpers.NotDisplaysScaffoldFirstMigration(typeof(BloggingContext), content);
|
||||
AssertHelpers.NotDisplaysApplyMigrations(typeof(BloggingContext), content);
|
||||
AssertHelpers.DisplaysScaffoldNextMigraion(typeof(BloggingContext), content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Exception_details_are_displayed()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.SetDefaultVisibility(true);
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
exception: new Exception("Something bad happened"),
|
||||
databaseExists: false,
|
||||
pendingModelChanges: false,
|
||||
pendingMigrations: new string[] { },
|
||||
options: options);
|
||||
|
||||
var content = await ExecutePage(options, model);
|
||||
|
||||
Assert.Contains("Something bad happened", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Inner_exception_details_are_displayed()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions();
|
||||
options.SetDefaultVisibility(true);
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
exception: new Exception("Something bad happened", new Exception("Because something more badder happened")),
|
||||
databaseExists: false,
|
||||
pendingModelChanges: false,
|
||||
pendingMigrations: new string[] { },
|
||||
options: options);
|
||||
|
||||
var content = await ExecutePage(options, model);
|
||||
|
||||
Assert.Contains("Something bad happened", content);
|
||||
Assert.Contains("Because something more badder happened", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ShowExceptionDetails_is_respected()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions { ShowExceptionDetails = false };
|
||||
options.SetDefaultVisibility(true);
|
||||
|
||||
var model = new DatabaseErrorPageModel(
|
||||
contextType: typeof(BloggingContext),
|
||||
exception: new Exception("Something bad happened"),
|
||||
databaseExists: false,
|
||||
pendingModelChanges: false,
|
||||
pendingMigrations: new string[] { },
|
||||
options: options);
|
||||
|
||||
var content = await ExecutePage(options, model);
|
||||
|
||||
Assert.DoesNotContain("Something bad happened", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListMigrations_is_respected()
|
||||
{
|
||||
var options = new DatabaseErrorPageOptions { ListMigrations = 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("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();
|
||||
var context = new Mock<HttpContext>();
|
||||
var response = new Mock<HttpResponse>();
|
||||
var stream = new MemoryStream();
|
||||
|
||||
response.Setup(r => r.Body).Returns(stream);
|
||||
context.Setup(c => c.Response).Returns(response.Object);
|
||||
|
||||
page.Model = model;
|
||||
|
||||
await page.ExecuteAsync(context.Object);
|
||||
var content = Encoding.ASCII.GetString(stream.ToArray());
|
||||
return content;
|
||||
}
|
||||
|
||||
private class BloggingContext : DbContext
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// 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 Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Diagnostics.Entity.Tests.Helpers
|
||||
{
|
||||
public static class AssertHelpers
|
||||
{
|
||||
public static void DisplaysScaffoldFirstMigration(Type contextType, string content)
|
||||
{
|
||||
Assert.Contains(Strings.DatabaseErrorPage_NoDbOrMigrationsTitle(contextType.Name), content);
|
||||
}
|
||||
|
||||
public static void NotDisplaysScaffoldFirstMigration(Type contextType, string content)
|
||||
{
|
||||
Assert.DoesNotContain(Strings.DatabaseErrorPage_NoDbOrMigrationsTitle(contextType.Name), content);
|
||||
}
|
||||
|
||||
public static void DisplaysApplyMigrations(Type contextType, string content)
|
||||
{
|
||||
Assert.Contains(Strings.DatabaseErrorPage_PendingMigrationsTitle(contextType.Name), content);
|
||||
}
|
||||
|
||||
public static void NotDisplaysApplyMigrations(Type contextType, string content)
|
||||
{
|
||||
Assert.DoesNotContain(Strings.DatabaseErrorPage_PendingMigrationsTitle(contextType.Name), content);
|
||||
}
|
||||
|
||||
public static void DisplaysScaffoldNextMigraion(Type contextType, string content)
|
||||
{
|
||||
Assert.Contains(Strings.DatabaseErrorPage_PendingChangesTitle(contextType.Name), content);
|
||||
}
|
||||
|
||||
public static void NotDisplaysScaffoldNextMigraion(Type contextType, string content)
|
||||
{
|
||||
Assert.DoesNotContain(Strings.DatabaseErrorPage_PendingChangesTitle(contextType.Name), content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?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)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>5486117b-a742-49e0-94fc-12b76f061803</ProjectGuid>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// 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.Framework.DependencyInjection;
|
||||
|
||||
namespace Microsoft.Data.Entity.Tests
|
||||
{
|
||||
public static class TestHelperExtensions
|
||||
{
|
||||
public static EntityServicesBuilder AddProviderServices(this EntityServicesBuilder entityServicesBuilder)
|
||||
{
|
||||
return entityServicesBuilder.AddInMemoryStore();
|
||||
}
|
||||
|
||||
public static DbContextOptions UseProviderOptions(this DbContextOptions options)
|
||||
{
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"EntityFramework.InMemory": "7.0.0-*",
|
||||
"Microsoft.AspNet.Diagnostics.Entity": "7.0.0-*",
|
||||
"Moq": "4.2.1312.1622",
|
||||
"Xunit.KRunner": "1.0.0-*"
|
||||
},
|
||||
"code": [ "**\\*.cs", "..\\Shared\\ApiConsistencyTestBase.cs", "..\\Shared\\TestHelpers.cs" ],
|
||||
"commands": {
|
||||
"test": "Xunit.KRunner"
|
||||
},
|
||||
"frameworks": {
|
||||
"aspnet50": { }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue