示例#1
0
        /// <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);
        }
        public void Default_visibility_is_false()
        {
            var options = new DatabaseErrorPageOptions();

            Assert.False(options.ShowExceptionDetails);
            Assert.False(options.ListMigrations);
        }
示例#4
0
        /// <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);
        }
示例#8
0
        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);
        }
        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);
        }
示例#10
0
        /// <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);
        }
示例#15
0
        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);
        }
示例#16
0
 public DatabaseErrorPageModel(
     Exception exception,
     IEnumerable <DatabaseContextDetails> contextDetails,
     DatabaseErrorPageOptions options,
     PathString pathBase)
 {
     Exception      = exception;
     ContextDetails = contextDetails;
     Options        = options;
     PathBase       = pathBase;
 }
示例#17
0
        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);
        }
示例#18
0
        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);
        }
示例#19
0
        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);
        }
示例#21
0
        /// <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;
 }
示例#23
0
        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);
        }
示例#24
0
        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);
        }
示例#25
0
        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);
        }
示例#26
0
        /// <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);
        }
示例#27
0
        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);
        }
示例#28
0
        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);
        }
示例#30
0
        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);
        }
示例#34
0
        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);
        }
示例#35
0
        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;
        }
示例#37
0
        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);
    }
示例#39
0
        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);
        }
示例#40
0
        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 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 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;
        }