/// <summary> /// Initializes a new instance of the <see cref="DatabaseErrorPageMiddleware" /> class /// </summary> /// <param name="next">Delegate to execute the next piece of middleware in the request pipeline.</param> /// <param name="loggerFactory"> /// The <see cref="ILoggerFactory" /> for the application. This middleware both produces logging messages and /// consumes them to detect database related exception. /// </param> /// <param name="options">The options to control what information is displayed on the error page.</param> public DatabaseErrorPageMiddleware( RequestDelegate next, ILoggerFactory loggerFactory, IOptions <DatabaseErrorPageOptions> options) { if (next == null) { throw new ArgumentNullException(nameof(next)); } if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } _next = next; _options = options.Value; _logger = loggerFactory.CreateLogger <DatabaseErrorPageMiddleware>(); DiagnosticListener.AllListeners.Subscribe(this); }
public void Default_visibility_is_false() { var options = new DatabaseErrorPageOptions(); Assert.False(options.ShowExceptionDetails); Assert.False(options.ListMigrations); }
/// <summary> /// Initializes a new instance of the <see cref="DatabaseErrorPageMiddleware" /> class /// </summary> /// <param name="next">Delegate to execute the next piece of middleware in the request pipeline.</param> /// <param name="loggerFactory"> /// The <see cref="ILoggerFactory" /> for the application. This middleware both produces logging messages and /// consumes them to detect database related exception. /// </param> /// <param name="options">The options to control what information is displayed on the error page.</param> public DatabaseErrorPageMiddleware( RequestDelegate next, ILoggerFactory loggerFactory, IOptions <DatabaseErrorPageOptions> options) { if (next == null) { throw new ArgumentNullException(nameof(next)); } if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } _next = next; _options = options.Value; _logger = loggerFactory.CreateLogger <DatabaseErrorPageMiddleware>(); // Note: this currently leaks if the server hosting this middleware is disposed. // See aspnet/Home #2825 DiagnosticListener.AllListeners.Subscribe(this); }
public void Default_visibility_can_be_changed() { var options = new DatabaseErrorPageOptions(); options.SetDefaultVisibility(true); Assert.True(options.ShowExceptionDetails); Assert.True(options.ListMigrations); }
public void ListMigrations_overides_default_visibility() { var options = new DatabaseErrorPageOptions { ListMigrations = false }; options.SetDefaultVisibility(true); Assert.True(options.ShowExceptionDetails); Assert.False(options.ListMigrations); }
public void MigrationsEndPointPath_is_respected() { var options = new DatabaseErrorPageOptions(); options.MigrationsEndPointPath = "/test"; Assert.Equal("/test", options.MigrationsEndPointPath); }
public void Everything_disabled_by_default() { var options = new DatabaseErrorPageOptions(); Assert.False(options.ShowExceptionDetails); Assert.False(options.ListMigrations); Assert.False(options.EnableMigrationCommands); Assert.Equal(string.Empty, options.MigrationsEndPointPath); }
/// <summary> /// Sets the options to display the maximum amount of information available. /// </summary> /// <param name="options">The options to be configured.</param> public static void EnableAll([NotNull] this DatabaseErrorPageOptions options) { Check.NotNull(options, nameof(options)); options.ShowExceptionDetails = true; options.ListMigrations = true; options.EnableMigrationCommands = true; options.MigrationsEndPointPath = MigrationsEndPointOptions.DefaultPath; }
public void EnableAll_enables_everything() { var options = new DatabaseErrorPageOptions(); options.EnableAll(); Assert.True(options.ShowExceptionDetails); Assert.True(options.ListMigrations); Assert.True(options.EnableMigrationCommands); Assert.Equal(MigrationsEndPointOptions.DefaultPath, options.MigrationsEndPointPath); }
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); }
public void MigrationsEndPointPath_is_respected() { var options = new DatabaseErrorPageOptions(); options.EnableAll(); options.MigrationsEndPointPath = "/test"; Assert.True(options.ShowExceptionDetails); Assert.True(options.ListMigrations); Assert.True(options.EnableMigrationCommands); Assert.Equal("/test", options.MigrationsEndPointPath); }
public void EnableMigrationCommands_is_respected() { var options = new DatabaseErrorPageOptions(); options.EnableAll(); options.EnableMigrationCommands = false; Assert.True(options.ShowExceptionDetails); Assert.True(options.ListMigrations); Assert.False(options.EnableMigrationCommands); Assert.Equal(MigrationsEndPointOptions.DefaultPath, options.MigrationsEndPointPath); }
public DatabaseErrorPageModel( Exception exception, IEnumerable <DatabaseContextDetails> contextDetails, DatabaseErrorPageOptions options, PathString pathBase) { Exception = exception; ContextDetails = contextDetails; Options = options; PathBase = pathBase; }
public static IBuilder UseDatabaseErrorPage([NotNull] this IBuilder builder, [NotNull] DatabaseErrorPageOptions options) { Check.NotNull(builder, "builder"); Check.NotNull(options, "options"); /* TODO: Development, Staging, or Production * string appMode = new AppProperties(builder.Properties).Get<string>(Constants.HostAppMode); * bool isDevMode = string.Equals(Constants.DevMode, appMode, StringComparison.Ordinal);*/ bool isDevMode = true; return(builder.Use(next => new DatabaseErrorPageMiddleware(next, options, isDevMode).Invoke)); }
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); }
/// <summary> /// Initializes a new instance of the <see cref="DatabaseErrorPageMiddleware"/> class /// </summary> /// <param name="next">Delegate to execute the next piece of middleware in the request pipeline.</param> /// <param name="serviceProvider">The <see cref="IServiceProvider"/> to resolve services from.</param> /// <param name="loggerFactory"> /// The <see cref="ILoggerFactory"/> for the application. This middleware both produces logging messages and /// consumes them to detect database related exception. /// </param> /// <param name="options">The options to control what information is displayed on the error page.</param> public DatabaseErrorPageMiddleware([NotNull] RequestDelegate next, [NotNull] IServiceProvider serviceProvider, [NotNull] ILoggerFactory loggerFactory, [NotNull] IOptions <DatabaseErrorPageOptions> options) { Check.NotNull(next, nameof(next)); Check.NotNull(serviceProvider, nameof(serviceProvider)); Check.NotNull(loggerFactory, nameof(loggerFactory)); Check.NotNull(options, nameof(options)); _next = next; _serviceProvider = serviceProvider; _options = options.Value; _logger = loggerFactory.CreateLogger <DatabaseErrorPageMiddleware>(); _loggerProvider = new DataStoreErrorLoggerProvider(); loggerFactory.AddProvider(_loggerProvider); }
public DatabaseErrorPageModel( Type contextType, Exception exception, bool databaseExists, bool pendingModelChanges, IEnumerable <string> pendingMigrations, DatabaseErrorPageOptions options) { ContextType = contextType; Exception = exception; DatabaseExists = databaseExists; PendingModelChanges = pendingModelChanges; PendingMigrations = pendingMigrations; Options = options; }
public async Task Exception_details_are_displayed() { var options = new DatabaseErrorPageOptions(); 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); }
public async Task No_database_or_migrations_only_displays_scaffold_first_migration() { var options = new DatabaseErrorPageOptions(); 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); }
public async Task MigrationsEndPointPath_is_respected() { var options = new DatabaseErrorPageOptions(); options.MigrationsEndPointPath = "/HitThisEndPoint"; var model = new DatabaseErrorPageModel( contextType: typeof(BloggingContext), exception: new Exception(), databaseExists: true, pendingModelChanges: false, pendingMigrations: new string[] { "111_MigrationOne" }, options: options); var content = await ExecutePage(options, model); Assert.Contains(options.MigrationsEndPointPath.Value, content); }
/// <summary> /// Captures synchronous and asynchronous database related exceptions from the pipeline that may be resolved using Entity Framework /// migrations. When these exceptions occur an HTML response with details of possible actions to resolve the issue is generated. /// </summary> /// <param name="app">The <see cref="IApplicationBuilder"/> to register the middleware with.</param> /// <param name="optionsAction">An action to set the options for the middleware. All options are disabled by default.</param> /// <returns>The same <see cref="IApplicationBuilder"/> instance so that multiple calls can be chained.</returns> public static IApplicationBuilder UseDatabaseErrorPage([NotNull] this IApplicationBuilder app, [NotNull] Action <DatabaseErrorPageOptions> optionsAction) { Check.NotNull(app, nameof(app)); Check.NotNull(optionsAction, nameof(optionsAction)); var options = new DatabaseErrorPageOptions(); optionsAction(options); app = app.UseMiddleware <DatabaseErrorPageMiddleware>(options); if (options.EnableMigrationCommands) { app.UseMigrationsEndPoint(o => o.Path = options.MigrationsEndPointPath); } return(app); }
public async Task Existing_database_with_migrations_and_pending_model_changes_only_displays_apply_migrations() { var options = new DatabaseErrorPageOptions(); 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); }
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); }
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); }
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); }
public async Task No_database_or_migrations_only_displays_scaffold_first_migration() { var options = new DatabaseErrorPageOptions(); options.EnableAll(); 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); }
public async Task ListMigrations_is_respected() { var options = new DatabaseErrorPageOptions(); options.EnableAll(); options.ListMigrations = false; var model = new DatabaseErrorPageModel( contextType: typeof(BloggingContext), exception: new Exception(), databaseExists: true, pendingModelChanges: false, pendingMigrations: new string[] { "111_MigrationOne" }, options: options); var content = await ExecutePage(options, model); Assert.DoesNotContain("111_MigrationOne", content); }
public async Task ShowExceptionDetails_is_respected() { var options = new DatabaseErrorPageOptions(); options.EnableAll(); options.ShowExceptionDetails = false; 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); }
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); }
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 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 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); }
public static IApplicationBuilder UseDatabaseErrorPage( this IApplicationBuilder app, DatabaseErrorPageOptions options) { if (app == null) { throw new ArgumentNullException(nameof(app)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } app = app.UseMiddleware <DatabaseErrorPageMiddleware>(Options.Create(options)); app.UseMigrationsEndPoint(new MigrationsEndPointOptions { Path = options.MigrationsEndPointPath }); return(app); }
public async Task Inner_exception_details_are_displayed() { var options = new DatabaseErrorPageOptions(); var model = new DatabaseErrorPageModel( new Exception("Something bad happened", new Exception("Because something more badder happened")), new DatabaseContextDetails[] { new DatabaseContextDetails( type: typeof(BloggingContext), databaseExists: false, pendingModelChanges: false, pendingMigrations: new string[] { }) }, options: options, pathBase: PathString.Empty); var content = await ExecutePage(options, model); Assert.Contains("Something bad happened", content); Assert.Contains("Because something more badder happened", content); }
public async Task Existing_database_with_migrations_only_displays_apply_migrations() { var options = new DatabaseErrorPageOptions(); var model = new DatabaseErrorPageModel( new Exception(), new DatabaseContextDetails[] { new DatabaseContextDetails( type: typeof(BloggingContext), databaseExists: true, pendingModelChanges: false, pendingMigrations: new string[] { "111_MigrationOne" }) }, options: options, pathBase: PathString.Empty); var content = await ExecutePage(options, model); AssertHelpers.NotDisplaysScaffoldFirstMigration(typeof(BloggingContext), content); AssertHelpers.DisplaysApplyMigrations(typeof(BloggingContext), content); AssertHelpers.NotDisplaysScaffoldNextMigraion(typeof(BloggingContext), content); }
public async Task Exception_details_are_displayed() { var options = new DatabaseErrorPageOptions(); options.EnableAll(); 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); }
public async Task MigrationsEndPointPath_is_respected() { var options = new DatabaseErrorPageOptions(); options.EnableAll(); options.MigrationsEndPointPath = "/HitThisEndPoint"; var model = new DatabaseErrorPageModel( contextType: typeof(BloggingContext), exception: new Exception(), databaseExists: true, pendingModelChanges: false, pendingMigrations: new string[] { "111_MigrationOne" }, options: options); var content = await ExecutePage(options, model); Assert.Contains(options.MigrationsEndPointPath.Value, content); }
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); }
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); }
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; }