diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/CodeAnnotations.cs b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/CodeAnnotations.cs deleted file mode 100644 index 45667b82c4..0000000000 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/CodeAnnotations.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace JetBrains.Annotations -{ - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | - AttributeTargets.Property | AttributeTargets.Delegate | - AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - internal sealed class NotNullAttribute : Attribute - { - } - - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | - AttributeTargets.Property | AttributeTargets.Delegate | - AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - internal sealed class CanBeNullAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] - internal sealed class InvokerParameterNameAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] - internal sealed class NoEnumerationAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] - internal sealed class ContractAnnotationAttribute : Attribute - { - public string Contract { get; private set; } - - public bool ForceFullStates { get; private set; } - - public ContractAnnotationAttribute([NotNull] string contract) - : this(contract, false) - { - } - - public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) - { - Contract = contract; - ForceFullStates = forceFullStates; - } - } - - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] - internal sealed class UsedImplicitlyAttribute : Attribute - { - public UsedImplicitlyAttribute() - : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) - { - } - - public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) - : this(useKindFlags, ImplicitUseTargetFlags.Default) - { - } - - public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) - : this(ImplicitUseKindFlags.Default, targetFlags) - { - } - - public UsedImplicitlyAttribute( - ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) - { - UseKindFlags = useKindFlags; - TargetFlags = targetFlags; - } - - public ImplicitUseKindFlags UseKindFlags { get; private set; } - public ImplicitUseTargetFlags TargetFlags { get; private set; } - } - - [Flags] - internal enum ImplicitUseKindFlags - { - Default = Access | Assign | InstantiatedWithFixedConstructorSignature, - Access = 1, - Assign = 2, - InstantiatedWithFixedConstructorSignature = 4, - InstantiatedNoFixedConstructorSignature = 8, - } - - [Flags] - internal enum ImplicitUseTargetFlags - { - Default = Itself, - Itself = 1, - Members = 2, - WithMembers = Itself | Members - } -} - -namespace Microsoft.EntityFrameworkCore.Relational.Utilities -{ - internal sealed class ValidatedNotNullAttribute : Attribute - { - } -} diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DataStoreErrorLogger.cs b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DataStoreErrorLogger.cs index d8b8fa2395..f0db3de1eb 100644 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DataStoreErrorLogger.cs +++ b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DataStoreErrorLogger.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using JetBrains.Annotations; -using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Utilities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -37,7 +36,8 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore _log.Value = new DataStoreErrorLog(); } - public virtual void Log(LogLevel logLevel, EventId eventId, [CanBeNull] TState state, [CanBeNull] Exception exception, [CanBeNull] Func formatter) + public virtual void Log( + LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { if (exception != null && LastError != null @@ -73,11 +73,8 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore private Type _contextType; private Exception _exception; - public virtual void SetError([NotNull] Type contextType, [NotNull] Exception exception) + public virtual void SetError(Type contextType, Exception exception) { - Check.NotNull(contextType, nameof(contextType)); - Check.NotNull(exception, nameof(exception)); - _contextType = contextType; _exception = exception; } diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageExtensions.cs b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageExtensions.cs index 6646407b11..6184c9f310 100644 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageExtensions.cs +++ b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageExtensions.cs @@ -5,6 +5,7 @@ using System; using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore; using Microsoft.Extensions.Options; +// ReSharper disable once CheckNamespace namespace Microsoft.AspNetCore.Builder { /// @@ -35,12 +36,14 @@ namespace Microsoft.AspNetCore.Builder /// The to register the middleware with. /// A that specifies options for the middleware. /// The same instance so that multiple calls can be chained. - public static IApplicationBuilder UseDatabaseErrorPage(this IApplicationBuilder app, DatabaseErrorPageOptions options) + 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)); @@ -56,4 +59,4 @@ namespace Microsoft.AspNetCore.Builder return app; } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageMiddleware.cs b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageMiddleware.cs index ec91ee863d..57d0b73823 100644 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageMiddleware.cs +++ b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/DatabaseErrorPageMiddleware.cs @@ -4,10 +4,8 @@ using System; using System.Linq; using System.Threading.Tasks; -using JetBrains.Annotations; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Utilities; -using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.RazorViews; +using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Views; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -26,7 +24,6 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore { private readonly RequestDelegate _next; private readonly DatabaseErrorPageOptions _options; - private readonly IServiceProvider _serviceProvider; private readonly ILogger _logger; private readonly DataStoreErrorLoggerProvider _loggerProvider; @@ -34,21 +31,32 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore /// Initializes a new instance of the class /// /// Delegate to execute the next piece of middleware in the request pipeline. - /// The to resolve services from. /// /// The for the application. This middleware both produces logging messages and /// consumes them to detect database related exception. /// /// The options to control what information is displayed on the error page. - public DatabaseErrorPageMiddleware([NotNull] RequestDelegate next, [NotNull] IServiceProvider serviceProvider, [NotNull] ILoggerFactory loggerFactory, [NotNull] IOptions options) + public DatabaseErrorPageMiddleware( + RequestDelegate next, + ILoggerFactory loggerFactory, + IOptions options) { - Check.NotNull(next, nameof(next)); - Check.NotNull(serviceProvider, nameof(serviceProvider)); - Check.NotNull(loggerFactory, nameof(loggerFactory)); - Check.NotNull(options, nameof(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; - _serviceProvider = serviceProvider; _options = options.Value; _logger = loggerFactory.CreateLogger(); @@ -63,9 +71,12 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore /// /// The context for the current request. /// A task that represents the asynchronous operation. - public virtual async Task Invoke([NotNull] HttpContext context) + public virtual async Task Invoke(HttpContext context) { - Check.NotNull(context, "context"); + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } try { @@ -80,14 +91,17 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore if (ShouldDisplayErrorPage(_loggerProvider.Logger.LastError, ex, _logger)) { var dbContextType = _loggerProvider.Logger.LastError.ContextType; - var dbContext = (DbContext)context.RequestServices.GetService(dbContextType); + var dbContext = (DbContext) context.RequestServices.GetService(dbContextType); + if (dbContext == null) { - _logger.LogError(Strings.FormatDatabaseErrorPageMiddleware_ContextNotRegistered(dbContextType.FullName)); + _logger.LogError( + Strings.FormatDatabaseErrorPageMiddleware_ContextNotRegistered(dbContextType.FullName)); } else { var creator = dbContext.GetService() as IRelationalDatabaseCreator; + if (creator == null) { _logger.LogDebug(Strings.DatabaseErrorPage_NotRelationalDatabase); @@ -101,25 +115,36 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore var modelDiffer = dbContext.GetService(); var appliedMigrations = historyRepository.GetAppliedMigrations(); - var pendingMigrations = ( - from m in migrationsAssembly.Migrations + + var pendingMigrations + = (from m in migrationsAssembly.Migrations where !appliedMigrations.Any( - r => string.Equals(r.MigrationId, m.Key, StringComparison.OrdinalIgnoreCase)) + r => string.Equals(r.MigrationId, m.Key, + StringComparison.OrdinalIgnoreCase)) select m.Key) .ToList(); // HasDifferences will return true if there is no model snapshot, but if there is an existing database // and no model snapshot then we don't want to show the error page since they are most likely targeting // and existing database and have just misconfigured their model - var pendingModelChanges = migrationsAssembly.ModelSnapshot == null && databaseExists - ? false - : modelDiffer.HasDifferences(migrationsAssembly.ModelSnapshot?.Model, dbContext.Model); + var pendingModelChanges + = (migrationsAssembly.ModelSnapshot != null || !databaseExists) + && modelDiffer.HasDifferences(migrationsAssembly.ModelSnapshot?.Model, + dbContext.Model); - if ((!databaseExists && pendingMigrations.Any()) || pendingMigrations.Any() || pendingModelChanges) + if (!databaseExists && pendingMigrations.Any() + || pendingMigrations.Any() + || pendingModelChanges) { - var page = new DatabaseErrorPage(); - page.Model = new DatabaseErrorPageModel(dbContextType, ex, databaseExists, pendingModelChanges, pendingMigrations, _options); + var page = new DatabaseErrorPage + { + Model = new DatabaseErrorPageModel( + dbContextType, ex, databaseExists, pendingModelChanges, pendingMigrations, + _options) + }; + await page.ExecuteAsync(context); + return; } } @@ -135,7 +160,8 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore } } - private static bool ShouldDisplayErrorPage(DataStoreErrorLogger.DataStoreErrorLog lastError, Exception exception, ILogger logger) + private static bool ShouldDisplayErrorPage(DataStoreErrorLogger.DataStoreErrorLog lastError, + Exception exception, ILogger logger) { logger.LogDebug(Strings.FormatDatabaseErrorPage_AttemptingToMatchException(exception.GetType())); @@ -145,7 +171,8 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore return false; } - bool match = false; + var match = false; + for (var e = exception; e != null && !match; e = e.InnerException) { match = lastError.Exception == e; @@ -154,11 +181,13 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore if (!match) { logger.LogDebug(Strings.DatabaseErrorPage_NoMatch); + return false; } logger.LogDebug(Strings.DatabaseErrorPage_Matched); + return true; } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/MigrationsEndPointMiddleware.cs b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/MigrationsEndPointMiddleware.cs index 794ebde88a..68166b3e90 100644 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/MigrationsEndPointMiddleware.cs +++ b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/MigrationsEndPointMiddleware.cs @@ -4,9 +4,7 @@ using System; using System.Net; using System.Threading.Tasks; -using JetBrains.Annotations; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Utilities; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -20,7 +18,6 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore public class MigrationsEndPointMiddleware { private readonly RequestDelegate _next; - private readonly IServiceProvider _serviceProvider; private readonly ILogger _logger; private readonly MigrationsEndPointOptions _options; @@ -28,22 +25,29 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore /// Initializes a new instance of the class /// /// Delegate to execute the next piece of middleware in the request pipeline. - /// The to resolve services from. /// The to write messages to. /// The options to control the behavior of the middleware. public MigrationsEndPointMiddleware( - [NotNull] RequestDelegate next, - [NotNull] IServiceProvider serviceProvider, - [NotNull] ILogger logger, - [NotNull] IOptions options) + RequestDelegate next, + ILogger logger, + IOptions options) { - Check.NotNull(next, "next"); - Check.NotNull(serviceProvider, "serviceProvider"); - Check.NotNull(logger, "logger"); - Check.NotNull(options, "options"); + if (next == null) + { + throw new ArgumentNullException(nameof(next)); + } + + if (logger == null) + { + throw new ArgumentNullException(nameof(logger)); + } + + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } _next = next; - _serviceProvider = serviceProvider; _logger = logger; _options = options.Value; } @@ -53,15 +57,19 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore /// /// The context for the current request. /// A task that represents the asynchronous operation. - public virtual async Task Invoke([NotNull] HttpContext context) + public virtual async Task Invoke(HttpContext context) { - Check.NotNull(context, "context"); + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } if (context.Request.Path.Equals(_options.Path)) { _logger.LogDebug(Strings.FormatMigrationsEndPointMiddleware_RequestPathMatched(context.Request.Path)); var db = await GetDbContext(context, _logger); + if (db != null) { try @@ -78,8 +86,10 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore } catch (Exception ex) { - var message = Strings.FormatMigrationsEndPointMiddleware_Exception(db.GetType().FullName) + ex.ToString(); + var message = Strings.FormatMigrationsEndPointMiddleware_Exception(db.GetType().FullName) + ex; + _logger.LogError(message); + throw new InvalidOperationException(message, ex); } } @@ -94,28 +104,39 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore { var form = await context.Request.ReadFormAsync(); var contextTypeName = form["context"]; + if (string.IsNullOrWhiteSpace(contextTypeName)) { logger.LogError(Strings.MigrationsEndPointMiddleware_NoContextType); + await WriteErrorToResponse(context.Response, Strings.MigrationsEndPointMiddleware_NoContextType); + return null; } var contextType = Type.GetType(contextTypeName); + if (contextType == null) { var message = Strings.FormatMigrationsEndPointMiddleware_InvalidContextType(contextTypeName); + logger.LogError(message); + await WriteErrorToResponse(context.Response, message); + return null; } var db = (DbContext)context.RequestServices.GetService(contextType); + if (db == null) { var message = Strings.FormatMigrationsEndPointMiddleware_ContextNotRegistered(contextType.FullName); + logger.LogError(message); + await WriteErrorToResponse(context.Response, message); + return null; } diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Properties/Strings.Designer.cs b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Properties/Strings.Designer.cs index 77fefd57c5..b076689f62 100644 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Properties/Strings.Designer.cs +++ b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Properties/Strings.Designer.cs @@ -10,38 +10,6 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore private static readonly ResourceManager _resourceManager = new ResourceManager("Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Strings", typeof(Strings).GetTypeInfo().Assembly); - /// - /// The string argument '{argumentName}' cannot be empty. - /// - internal static string ArgumentIsEmpty - { - get { return GetString("ArgumentIsEmpty"); } - } - - /// - /// The string argument '{argumentName}' cannot be empty. - /// - internal static string FormatArgumentIsEmpty(object argumentName) - { - return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentIsEmpty", "argumentName"), argumentName); - } - - /// - /// The collection argument '{argumentName}' must contain at least one element. - /// - internal static string CollectionArgumentIsEmpty - { - get { return GetString("CollectionArgumentIsEmpty"); } - } - - /// - /// The collection argument '{argumentName}' must contain at least one element. - /// - internal static string FormatCollectionArgumentIsEmpty(object argumentName) - { - return string.Format(CultureInfo.CurrentCulture, GetString("CollectionArgumentIsEmpty", "argumentName"), argumentName); - } - /// /// 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. /// @@ -298,22 +266,6 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore return GetString("DatabaseErrorPage_ApplyMigrationsCommandCLI"); } - /// - /// The value provided for argument '{argumentName}' must be a valid value of enum type '{enumType}'. - /// - internal static string InvalidEnumValue - { - get { return GetString("InvalidEnumValue"); } - } - - /// - /// The value provided for argument '{argumentName}' must be a valid value of enum type '{enumType}'. - /// - internal static string FormatInvalidEnumValue(object argumentName, object enumType) - { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidEnumValue", "argumentName", "enumType"), argumentName, enumType); - } - /// /// Migrations successfully applied for context '{0}'. /// diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Strings.resx b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Strings.resx index 92de6f0740..57dc98c9c4 100644 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Strings.resx +++ b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Strings.resx @@ -117,12 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - The string argument '{argumentName}' cannot be empty. - - - The collection argument '{argumentName}' must contain at least one element. - 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. @@ -171,9 +165,6 @@ > dotnet ef database update - - The value provided for argument '{argumentName}' must be a valid value of enum type '{enumType}'. - Migrations successfully applied for context '{0}'. diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Utilities/Check.cs b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Utilities/Check.cs deleted file mode 100644 index c293ab3637..0000000000 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Utilities/Check.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using JetBrains.Annotations; - -namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Utilities -{ - [DebuggerStepThrough] - internal static class Check - { - [ContractAnnotation("value:null => halt")] - public static T NotNull([NoEnumeration] T value, [InvokerParameterName] [NotNull] string parameterName) - { - NotEmpty(parameterName, nameof(parameterName)); - - if (ReferenceEquals(value, null)) - { - throw new ArgumentNullException(parameterName); - } - - return value; - } - - [ContractAnnotation("value:null => halt")] - public static IReadOnlyList NotEmpty(IReadOnlyList value, [InvokerParameterName] [NotNull] string parameterName) - { - NotEmpty(parameterName, nameof(parameterName)); - NotNull(value, parameterName); - - if (value.Count == 0) - { - throw new ArgumentException(Strings.FormatCollectionArgumentIsEmpty(parameterName)); - } - - return value; - } - - [ContractAnnotation("value:null => halt")] - public static string NotEmpty(string value, [InvokerParameterName] [NotNull] string parameterName) - { - if (ReferenceEquals(parameterName, null)) - { - throw new ArgumentNullException(nameof(parameterName)); - } - - if (parameterName.Length == 0) - { - throw new ArgumentException(Strings.FormatArgumentIsEmpty("parameterName")); - } - - if (ReferenceEquals(value, null)) - { - throw new ArgumentNullException(parameterName); - } - - if (value.Length == 0) - { - throw new ArgumentException(Strings.FormatArgumentIsEmpty(parameterName)); - } - - return value; - } - - public static T IsDefined(T value, [InvokerParameterName] [NotNull] string parameterName) - where T : struct - { - NotEmpty(parameterName, nameof(parameterName)); - - if (!Enum.IsDefined(typeof(T), value)) - { - throw new ArgumentException(Strings.FormatInvalidEnumValue(parameterName, typeof(T))); - } - - return value; - } - } -} diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPage.Designer.cs b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPage.Designer.cs index eb5626daa6..57fa3e8fac 100644 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPage.Designer.cs +++ b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPage.Designer.cs @@ -1,4 +1,4 @@ -namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.RazorViews +namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Views { #line 1 "DatabaseErrorPage.cshtml" using System @@ -19,7 +19,7 @@ using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore #line hidden ; #line 4 "DatabaseErrorPage.cshtml" -using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.RazorViews +using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Views #line default #line hidden diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPage.cshtml b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPage.cshtml index 81c7df9276..70711befb1 100644 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPage.cshtml +++ b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPage.cshtml @@ -1,7 +1,7 @@ @using System @using System.Linq @using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore -@using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.RazorViews +@using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Views @{ Response.StatusCode = 500; Response.ContentType = "text/html; charset=utf-8"; diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPageModel.cs b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPageModel.cs index 99280314a2..d6520c52ac 100644 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPageModel.cs +++ b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/Views/DatabaseErrorPageModel.cs @@ -1,72 +1,35 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using JetBrains.Annotations; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Utilities; using System; using System.Collections.Generic; +using Microsoft.AspNetCore.Builder; -namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.RazorViews +namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Views { internal class DatabaseErrorPageModel { - private readonly Type _contextType; - private readonly Exception _exception; - private readonly bool _databaseExists; - private readonly bool _pendingModelChanges; - private readonly IEnumerable _pendingMigrations; - private readonly DatabaseErrorPageOptions _options; - public DatabaseErrorPageModel( - [NotNull] Type contextType, - [NotNull] Exception exception, + Type contextType, + Exception exception, bool databaseExists, bool pendingModelChanges, - [NotNull] IEnumerable pendingMigrations, - [NotNull] DatabaseErrorPageOptions options) + IEnumerable pendingMigrations, + 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; + 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 PendingMigrations - { - get { return _pendingMigrations; } - } - - public virtual DatabaseErrorPageOptions Options - { - get { return _options; } - } + public virtual Type ContextType { get; } + public virtual Exception Exception { get; } + public virtual bool DatabaseExists { get; } + public virtual bool PendingModelChanges { get; } + public virtual IEnumerable PendingMigrations { get; } + public virtual DatabaseErrorPageOptions Options { get; } } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/breakingchanges.netcore.json b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/breakingchanges.netcore.json index 3c380e8acd..d8cfddf0aa 100644 --- a/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/breakingchanges.netcore.json +++ b/src/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore/breakingchanges.netcore.json @@ -6,5 +6,15 @@ { "TypeId": "public class Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Views.DatabaseErrorPageModel", "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware", + "MemberId": "public .ctor(Microsoft.AspNetCore.Http.RequestDelegate next, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILogger logger, Microsoft.Extensions.Options.IOptions options)", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware", + "MemberId": "public .ctor(Microsoft.AspNetCore.Http.RequestDelegate next, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.Extensions.Options.IOptions options)", + "Kind": "Removal" } ] \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests/ApiConsistencyTest.cs b/test/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests/ApiConsistencyTest.cs deleted file mode 100644 index 32f7f0750e..0000000000 --- a/test/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests/ApiConsistencyTest.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; -using System.Collections.Generic; -using System.Reflection; - -namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCoreTests -{ - public class ApiConsistencyTest : ApiConsistencyTestBase - { - protected override Assembly TargetAssembly => typeof(DatabaseErrorPageMiddleware).GetTypeInfo().Assembly; - - protected override IEnumerable GetCancellationTokenExceptions() - { - return new string[] - { - "DatabaseErrorPageMiddleware.Invoke", - "MigrationsEndPointMiddleware.Invoke", - "DatabaseErrorPage.ExecuteAsync", - "BaseView.ExecuteAsync" - }; - } - - protected override IEnumerable GetAsyncSuffixExceptions() - { - return new string[] - { - "DatabaseErrorPageMiddleware.Invoke", - "MigrationsEndPointMiddleware.Invoke" - }; - } - } -} diff --git a/test/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests/ApiConsistencyTestBase.cs b/test/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests/ApiConsistencyTestBase.cs deleted file mode 100644 index a838bdf397..0000000000 --- a/test/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests/ApiConsistencyTestBase.cs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.RazorViews; -using Microsoft.AspNetCore.Testing.xunit; -using Xunit; - -namespace Microsoft.EntityFrameworkCore -{ - public abstract class ApiConsistencyTestBase - { - private static readonly HashSet _typesToSkip = new HashSet - { - typeof(DatabaseErrorPage).GetTypeInfo() - }; - - protected const BindingFlags PublicInstance - = BindingFlags.Instance | BindingFlags.Public; - - protected const BindingFlags AnyInstance - = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; - - [ConditionalFact(Skip = "Skipping until we update to mono")] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - public void Public_inheritable_apis_should_be_virtual() - { - var nonVirtualMethods - = (from type in GetAllTypes(TargetAssembly.DefinedTypes) - where type.IsVisible - && !type.IsSealed - && type.DeclaredConstructors.Any(c => c.IsPublic || c.IsFamily || c.IsFamilyOrAssembly) - && type.Namespace != null - && !type.Namespace.EndsWith(".Compiled") - && !_typesToSkip.Contains(type) - from method in type.DeclaredMethods.Where(m => m.IsPublic && !m.IsStatic) - where method.DeclaringType.GetTypeInfo() == type - && !(method.IsVirtual && !method.IsFinal) - select type.FullName + "." + method.Name) - .ToList(); - - Assert.False( - nonVirtualMethods.Any(), - "\r\n-- Missing virtual APIs --\r\n" + string.Join("\r\n", nonVirtualMethods)); - } - - [ConditionalFact(Skip = "Skipping until we update to mono")] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - public void Public_api_arguments_should_have_not_null_annotation() - { - var parametersMissingAttribute - = (from type in GetAllTypes(TargetAssembly.DefinedTypes) - where type.IsVisible && !typeof(Delegate).GetTypeInfo().IsAssignableFrom(type) && !_typesToSkip.Contains(type) - let interfaceMappings = type.ImplementedInterfaces.Select(type.GetRuntimeInterfaceMap) - let events = type.DeclaredEvents - from method in type.DeclaredMethods.Where(m => m.IsPublic) - .Concat(type.DeclaredConstructors) - where method.DeclaringType.GetTypeInfo() == type - where type.IsInterface || !interfaceMappings.Any(im => im.TargetMethods.Contains(method)) - where !events.Any(e => e.AddMethod == method || e.RemoveMethod == method) - from parameter in method.GetParameters() - where !parameter.ParameterType.GetTypeInfo().IsValueType - && !parameter.GetCustomAttributes() - .Any( - a => a.GetType().Name == "NotNullAttribute" - || a.GetType().Name == "CanBeNullAttribute") - select type.FullName + "." + method.Name + "[" + parameter.Name + "]") - .ToList(); - - Assert.False( - parametersMissingAttribute.Any(), - "\r\n-- Missing NotNull annotations --\r\n" + string.Join("\r\n", parametersMissingAttribute)); - } - - [ConditionalFact(Skip = "Skipping until we update to mono")] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - public void Async_methods_should_have_overload_with_cancellation_token_and_end_with_async_suffix() - { - var asyncMethods - = (from type in GetAllTypes(TargetAssembly.DefinedTypes) - where type.IsVisible - from method in type.DeclaredMethods.Where(m => m.IsPublic) - where method.DeclaringType.GetTypeInfo() == type - where typeof(Task).IsAssignableFrom(method.ReturnType) - select method).ToList(); - - var asyncMethodsWithToken - = (from method in asyncMethods - where method.GetParameters().Any(pi => pi.ParameterType == typeof(CancellationToken)) - select method).ToList(); - - var asyncMethodsWithoutToken - = (from method in asyncMethods - where method.GetParameters().All(pi => pi.ParameterType != typeof(CancellationToken)) - select method).ToList(); - - var missingOverloads - = (from methodWithoutToken in asyncMethodsWithoutToken - where !asyncMethodsWithToken - .Any(methodWithToken => methodWithoutToken.Name == methodWithToken.Name - && methodWithoutToken.DeclaringType == methodWithToken.DeclaringType) - // ReSharper disable once PossibleNullReferenceException - select methodWithoutToken.DeclaringType.Name + "." + methodWithoutToken.Name) - .Except(GetCancellationTokenExceptions()) - .ToList(); - - Assert.False( - missingOverloads.Any(), - "\r\n-- Missing async overloads --\r\n" + string.Join("\r\n", missingOverloads)); - - var missingSuffixMethods - = asyncMethods - .Where(method => !method.Name.EndsWith("Async")) - .Select(method => method.DeclaringType.Name + "." + method.Name) - .Except(GetAsyncSuffixExceptions()) - .ToList(); - - Assert.False( - missingSuffixMethods.Any(), - "\r\n-- Missing async suffix --\r\n" + string.Join("\r\n", missingSuffixMethods)); - } - - protected virtual IEnumerable GetCancellationTokenExceptions() - { - return Enumerable.Empty(); - } - - protected virtual IEnumerable GetAsyncSuffixExceptions() - { - return Enumerable.Empty(); - } - - protected abstract Assembly TargetAssembly { get; } - - protected virtual IEnumerable GetAllTypes(IEnumerable typeInfos) - { - foreach (var typeInfo in typeInfos) - { - yield return typeInfo; - - foreach (var nestedType in GetAllTypes(typeInfo.DeclaredNestedTypes)) - { - yield return nestedType; - } - } - } - } -} diff --git a/test/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests/DatabaseErrorPageTest.cs b/test/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests/DatabaseErrorPageTest.cs index 1058b980e6..46ca2f2a96 100644 --- a/test/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests/DatabaseErrorPageTest.cs +++ b/test/Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests/DatabaseErrorPageTest.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests.Helpers; -using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.RazorViews; +using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Views; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Moq; @@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests exception: new Exception(), databaseExists: false, pendingModelChanges: false, - pendingMigrations: new string[] { "111_MigrationOne" }, + pendingMigrations: new[] { "111_MigrationOne" }, options: options); var content = await ExecutePage(options, model); @@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests exception: new Exception(), databaseExists: true, pendingModelChanges: false, - pendingMigrations: new string[] { "111_MigrationOne" }, + pendingMigrations: new[] { "111_MigrationOne" }, options: options); var content = await ExecutePage(options, model); @@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests exception: new Exception(), databaseExists: true, pendingModelChanges: true, - pendingMigrations: new string[] { "111_MigrationOne" }, + pendingMigrations: new[] { "111_MigrationOne" }, options: options); var content = await ExecutePage(options, model); @@ -165,7 +165,7 @@ namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.Tests exception: new Exception(), databaseExists: true, pendingModelChanges: false, - pendingMigrations: new string[] { "111_MigrationOne" }, + pendingMigrations: new[] { "111_MigrationOne" }, options: options); var content = await ExecutePage(options, model);