diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ApiExplorer/ApiResponseType.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ApiExplorer/ApiResponseType.cs
index 4e3307c0b5..6ed9644931 100644
--- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ApiExplorer/ApiResponseType.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ApiExplorer/ApiResponseType.cs
@@ -39,5 +39,15 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
/// Gets or sets the HTTP response status code.
///
public int StatusCode { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the response type represents a default response.
+ ///
+ ///
+ /// If an has a default response, then the property should be ignored. This response
+ /// will be used when a more specific response format does not apply. The common use of a default response is to specify the format
+ /// for communicating error conditions.
+ ///
+ public bool IsDefaultResponse { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Mvc.ApiExplorer/ApiBehaviorApiDescriptionProvider.cs b/src/Microsoft.AspNetCore.Mvc.ApiExplorer/ApiBehaviorApiDescriptionProvider.cs
new file mode 100644
index 0000000000..83874b6733
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Mvc.ApiExplorer/ApiBehaviorApiDescriptionProvider.cs
@@ -0,0 +1,116 @@
+// 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 Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Abstractions;
+using Microsoft.AspNetCore.Mvc.Internal;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+
+namespace Microsoft.AspNetCore.Mvc.ApiExplorer
+{
+ public class ApiBehaviorApiDescriptionProvider : IApiDescriptionProvider
+ {
+ private readonly IModelMetadataProvider _modelMetadaProvider;
+
+ public ApiBehaviorApiDescriptionProvider(IModelMetadataProvider modelMetadataProvider)
+ {
+ _modelMetadaProvider = modelMetadataProvider;
+ }
+
+ ///
+ /// The order is set to execute after the default provider.
+ ///
+ public int Order => -1000 + 10;
+
+ public void OnProvidersExecuted(ApiDescriptionProviderContext context)
+ {
+ }
+
+ public void OnProvidersExecuting(ApiDescriptionProviderContext context)
+ {
+ foreach (var description in context.Results)
+ {
+ if (!AppliesTo(description))
+ {
+ continue;
+ }
+
+ foreach (var responseType in CreateProblemResponseTypes(description))
+ {
+ description.SupportedResponseTypes.Add(responseType);
+ }
+ }
+ }
+
+ public bool AppliesTo(ApiDescription description)
+ {
+ return description.ActionDescriptor.FilterDescriptors.Any(f => f.Filter is IApiBehaviorMetadata);
+ }
+
+ // Check if the parameter is named "id" (e.g. int id) or ends in Id (e.g. personId)
+ public bool IsIdParameter(ParameterDescriptor parameter)
+ {
+ if (parameter.Name == null)
+ {
+ return false;
+ }
+
+ if (string.Equals("id", parameter.Name, StringComparison.Ordinal))
+ {
+ return true;
+ }
+
+ // We're looking for a name ending with Id, but preceded by a lower case letter. This should match
+ // the normal PascalCase naming conventions.
+ if (parameter.Name.Length >= 3 &&
+ parameter.Name.EndsWith("Id", StringComparison.Ordinal) &&
+ char.IsLower(parameter.Name, parameter.Name.Length - 3))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public IEnumerable CreateProblemResponseTypes(ApiDescription description)
+ {
+ if (description.ActionDescriptor.Parameters.Any() || description.ActionDescriptor.BoundProperties.Any())
+ {
+ // For validation errors.
+ yield return CreateProblemResponse(StatusCodes.Status400BadRequest);
+
+ if (description.ActionDescriptor.Parameters.Any(p => IsIdParameter(p)))
+ {
+ yield return CreateProblemResponse(StatusCodes.Status404NotFound);
+ }
+ }
+
+ yield return CreateProblemResponse(statusCode: 0, isDefaultResponse: true);
+ }
+
+ private ApiResponseType CreateProblemResponse(int statusCode, bool isDefaultResponse = false)
+ {
+ return new ApiResponseType
+ {
+ ApiResponseFormats = new List
+ {
+ new ApiResponseFormat
+ {
+ MediaType = "application/problem+json",
+ },
+ new ApiResponseFormat
+ {
+ MediaType = "application/problem+xml",
+ },
+ },
+ IsDefaultResponse = isDefaultResponse,
+ ModelMetadata = _modelMetadaProvider.GetMetadataForType(typeof(ProblemDetails)),
+ StatusCode = statusCode,
+ Type = typeof(ProblemDetails),
+ };
+ }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.Mvc.ApiExplorer/ApiControllerApiDescriptionProvider.cs b/src/Microsoft.AspNetCore.Mvc.ApiExplorer/ApiControllerApiDescriptionProvider.cs
deleted file mode 100644
index 4856b19cbd..0000000000
--- a/src/Microsoft.AspNetCore.Mvc.ApiExplorer/ApiControllerApiDescriptionProvider.cs
+++ /dev/null
@@ -1,78 +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 Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc.Internal;
-using Microsoft.AspNetCore.Mvc.ModelBinding;
-
-namespace Microsoft.AspNetCore.Mvc.ApiExplorer
-{
- public class ApiControllerApiDescriptionProvider : IApiDescriptionProvider
- {
- private readonly IModelMetadataProvider _modelMetadaProvider;
-
- public ApiControllerApiDescriptionProvider(IModelMetadataProvider modelMetadataProvider)
- {
- _modelMetadaProvider = modelMetadataProvider;
- }
-
- ///
- /// The order is set to execute after the .
- ///
- public int Order => -1000 + 10;
-
- public void OnProvidersExecuted(ApiDescriptionProviderContext context)
- {
- }
-
- public void OnProvidersExecuting(ApiDescriptionProviderContext context)
- {
- foreach (var apiDescription in context.Results)
- {
- if (!apiDescription.ActionDescriptor.FilterDescriptors.Any(f => f.Filter is IApiBehaviorMetadata))
- {
- continue;
- }
-
- var parameters = apiDescription.ActionDescriptor.Parameters.Concat(apiDescription.ActionDescriptor.BoundProperties);
- if (parameters.Any())
- {
- apiDescription.SupportedResponseTypes.Add(CreateProblemResponse(StatusCodes.Status400BadRequest));
-
- if (parameters.Any(p => p.Name.EndsWith("id", StringComparison.OrdinalIgnoreCase)))
- {
- apiDescription.SupportedResponseTypes.Add(CreateProblemResponse(StatusCodes.Status404NotFound));
- }
- }
-
- // We don't have a good way to signal a "default" response type. We'll use 0 to indicate this until we come up
- // with something better.
- apiDescription.SupportedResponseTypes.Add(CreateProblemResponse(statusCode: 0));
- }
- }
-
- private ApiResponseType CreateProblemResponse(int statusCode)
- {
- return new ApiResponseType
- {
- ApiResponseFormats = new List
- {
- new ApiResponseFormat
- {
- MediaType = "application/problem+json",
- },
- new ApiResponseFormat
- {
- MediaType = "application/problem+xml",
- },
- },
- ModelMetadata = _modelMetadaProvider.GetMetadataForType(typeof(ProblemDetails)),
- StatusCode = statusCode,
- Type = typeof(ProblemDetails),
- };
- }
- }
-}
diff --git a/src/Microsoft.AspNetCore.Mvc.ApiExplorer/DependencyInjection/MvcApiExplorerMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.ApiExplorer/DependencyInjection/MvcApiExplorerMvcCoreBuilderExtensions.cs
index bb823c3ecb..bcf71e8642 100644
--- a/src/Microsoft.AspNetCore.Mvc.ApiExplorer/DependencyInjection/MvcApiExplorerMvcCoreBuilderExtensions.cs
+++ b/src/Microsoft.AspNetCore.Mvc.ApiExplorer/DependencyInjection/MvcApiExplorerMvcCoreBuilderExtensions.cs
@@ -27,7 +27,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddEnumerable(
ServiceDescriptor.Transient());
services.TryAddEnumerable(
- ServiceDescriptor.Transient());
+ ServiceDescriptor.Transient());
}
}
}
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs
index bc2a5c992d..15549963e6 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs
@@ -160,7 +160,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddEnumerable(
ServiceDescriptor.Transient());
services.TryAddEnumerable(
- ServiceDescriptor.Transient());
+ ServiceDescriptor.Transient());
services.TryAddEnumerable(
ServiceDescriptor.Transient());
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ApiControllerApplicationModelProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ApiBehaviorApplicationModelProvider.cs
similarity index 93%
rename from src/Microsoft.AspNetCore.Mvc.Core/Internal/ApiControllerApplicationModelProvider.cs
rename to src/Microsoft.AspNetCore.Mvc.Core/Internal/ApiBehaviorApplicationModelProvider.cs
index a8ddde6528..968eeef334 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ApiControllerApplicationModelProvider.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ApiBehaviorApplicationModelProvider.cs
@@ -12,12 +12,12 @@ using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.Internal
{
- public class ApiControllerApplicationModelProvider : IApplicationModelProvider
+ public class ApiBehaviorApplicationModelProvider : IApplicationModelProvider
{
private readonly ApiBehaviorOptions _apiBehaviorOptions;
private readonly ModelStateInvalidFilter _modelStateInvalidFilter;
- public ApiControllerApplicationModelProvider(IOptions apiBehaviorOptions, ILoggerFactory loggerFactory)
+ public ApiBehaviorApplicationModelProvider(IOptions apiBehaviorOptions, ILoggerFactory loggerFactory)
{
_apiBehaviorOptions = apiBehaviorOptions.Value;
if (_apiBehaviorOptions.EnableModelStateInvalidFilter && _apiBehaviorOptions.InvalidModelStateResponseFactory == null)
diff --git a/test/Microsoft.AspNetCore.Mvc.ApiExplorer.Test/ApiBehaviorApiDescriptionProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.ApiExplorer.Test/ApiBehaviorApiDescriptionProviderTest.cs
new file mode 100644
index 0000000000..f5b22d0527
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Mvc.ApiExplorer.Test/ApiBehaviorApiDescriptionProviderTest.cs
@@ -0,0 +1,241 @@
+// 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.Collections.Generic;
+using System.Linq;
+using Microsoft.AspNetCore.Mvc.Abstractions;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Mvc.Internal;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Moq;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Mvc.ApiExplorer
+{
+ public class ApiBehaviorApiDescriptionProviderTest
+ {
+ [Fact]
+ public void AppliesTo_ActionWithoutApiBehavior_ReturnsFalse()
+ {
+ // Arrange
+ var action = new ActionDescriptor()
+ {
+ FilterDescriptors = new List(),
+ };
+ var description = new ApiDescription()
+ {
+ ActionDescriptor = action,
+ };
+
+ var provider = new ApiBehaviorApiDescriptionProvider(new EmptyModelMetadataProvider());
+
+ // Act
+ var result = provider.AppliesTo(description);
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void AppliesTo_ActionWithApiBehavior_ReturnsTrue()
+ {
+ // Arrange
+ var action = new ActionDescriptor()
+ {
+ FilterDescriptors = new List()
+ {
+ new FilterDescriptor(Mock.Of(), FilterScope.Global),
+ }
+ };
+ var description = new ApiDescription()
+ {
+ ActionDescriptor = action,
+ };
+
+ var provider = new ApiBehaviorApiDescriptionProvider(new EmptyModelMetadataProvider());
+
+ // Act
+ var result = provider.AppliesTo(description);
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Theory]
+ [InlineData("id")]
+ [InlineData("personId")]
+ [InlineData("üId")]
+ public void IsIdParameter_ParameterNameMatchesConvention_ReturnsTrue(string name)
+ {
+ var parameter = new ParameterDescriptor()
+ {
+ Name = name,
+ };
+
+ var provider = new ApiBehaviorApiDescriptionProvider(new EmptyModelMetadataProvider());
+
+ // Act
+ var result = provider.IsIdParameter(parameter);
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData("i")]
+ [InlineData("Id")]
+ [InlineData("iD")]
+ [InlineData("persoNId")]
+ [InlineData("personid")]
+ [InlineData("ü Id")]
+ [InlineData("ÜId")]
+ public void IsIdParameter_ParameterNameDoesNotMatchConvention_ReturnsFalse(string name)
+ {
+ var parameter = new ParameterDescriptor()
+ {
+ Name = name,
+ };
+
+ var provider = new ApiBehaviorApiDescriptionProvider(new EmptyModelMetadataProvider());
+
+ // Act
+ var result = provider.IsIdParameter(parameter);
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void CreateProblemResponseTypes_NoParameters_IncludesDefaultResponse()
+ {
+ // Arrange
+ var action = new ActionDescriptor()
+ {
+ FilterDescriptors = new List()
+ {
+ new FilterDescriptor(Mock.Of(), FilterScope.Global),
+ },
+ BoundProperties = new List(),
+ Parameters = new List(),
+ };
+ var description = new ApiDescription()
+ {
+ ActionDescriptor = action,
+ };
+
+ var provider = new ApiBehaviorApiDescriptionProvider(new EmptyModelMetadataProvider());
+
+ // Act
+ var results = provider.CreateProblemResponseTypes(description);
+
+ // Assert
+ Assert.Collection(
+ results.OrderBy(r => r.StatusCode),
+ r =>
+ {
+ Assert.Equal(typeof(ProblemDetails), r.Type);
+ Assert.Equal(0, r.StatusCode);
+ Assert.True(r.IsDefaultResponse);
+ });
+ }
+
+ [Fact]
+ public void CreateProblemResponseTypes_WithBoundProperty_Includes400Response()
+ {
+ // Arrange
+ var action = new ActionDescriptor()
+ {
+ FilterDescriptors = new List()
+ {
+ new FilterDescriptor(Mock.Of(), FilterScope.Global),
+ },
+ BoundProperties = new List()
+ {
+ new ParameterDescriptor()
+ },
+ Parameters = new List(),
+ };
+ var description = new ApiDescription()
+ {
+ ActionDescriptor = action,
+ };
+
+ var provider = new ApiBehaviorApiDescriptionProvider(new EmptyModelMetadataProvider());
+
+ // Act
+ var results = provider.CreateProblemResponseTypes(description);
+
+ // Assert
+ Assert.Collection(
+ results.OrderBy(r => r.StatusCode),
+ r =>
+ {
+ Assert.Equal(typeof(ProblemDetails), r.Type);
+ Assert.Equal(0, r.StatusCode);
+ Assert.True(r.IsDefaultResponse);
+ },
+ r =>
+ {
+ Assert.Equal(typeof(ProblemDetails), r.Type);
+ Assert.Equal(400, r.StatusCode);
+ Assert.False(r.IsDefaultResponse);
+ });
+ }
+
+ [Fact]
+ public void CreateProblemResponseTypes_WithIdParameter_Includes404Response()
+ {
+ // Arrange
+ var action = new ActionDescriptor()
+ {
+ FilterDescriptors = new List()
+ {
+ new FilterDescriptor(Mock.Of(), FilterScope.Global),
+ },
+ BoundProperties = new List()
+ {
+ },
+ Parameters = new List()
+ {
+ new ParameterDescriptor()
+ {
+ Name = "customerId",
+ }
+ },
+ };
+ var description = new ApiDescription()
+ {
+ ActionDescriptor = action,
+ };
+
+ var provider = new ApiBehaviorApiDescriptionProvider(new EmptyModelMetadataProvider());
+
+ // Act
+ var results = provider.CreateProblemResponseTypes(description);
+
+ // Assert
+ Assert.Collection(
+ results.OrderBy(r => r.StatusCode),
+ r =>
+ {
+ Assert.Equal(typeof(ProblemDetails), r.Type);
+ Assert.Equal(0, r.StatusCode);
+ Assert.True(r.IsDefaultResponse);
+ },
+ r =>
+ {
+ Assert.Equal(typeof(ProblemDetails), r.Type);
+ Assert.Equal(400, r.StatusCode);
+ Assert.False(r.IsDefaultResponse);
+ },
+ r =>
+ {
+ Assert.Equal(typeof(ProblemDetails), r.Type);
+ Assert.Equal(404, r.StatusCode);
+ Assert.False(r.IsDefaultResponse);
+ });
+ }
+ }
+}
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/DependencyInjection/MvcCoreServiceCollectionExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/DependencyInjection/MvcCoreServiceCollectionExtensionsTest.cs
index 5340478ff7..59ddee1789 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/DependencyInjection/MvcCoreServiceCollectionExtensionsTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/DependencyInjection/MvcCoreServiceCollectionExtensionsTest.cs
@@ -295,7 +295,7 @@ namespace Microsoft.AspNetCore.Mvc
new Type[]
{
typeof(DefaultApplicationModelProvider),
- typeof(ApiControllerApplicationModelProvider),
+ typeof(ApiBehaviorApplicationModelProvider),
}
},
};
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ApiControllerApplicationModelProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ApiBehaviorApplicationModelProviderTest.cs
similarity index 90%
rename from test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ApiControllerApplicationModelProviderTest.cs
rename to test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ApiBehaviorApplicationModelProviderTest.cs
index 15a00e5445..0f10c182c6 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ApiControllerApplicationModelProviderTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ApiBehaviorApplicationModelProviderTest.cs
@@ -11,7 +11,7 @@ using Xunit;
namespace Microsoft.AspNetCore.Mvc.Internal
{
- public class ApiControllerApplicationModelProviderTest
+ public class ApiBehaviorApplicationModelProviderTest
{
[Fact]
public void OnProvidersExecuting_AddsModelStateInvalidFilter_IfTypeIsAnnotatedWithAttribute()
@@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
InvalidModelStateResponseFactory = _ => null,
});
- var provider = new ApiControllerApplicationModelProvider(options, NullLoggerFactory.Instance);
+ var provider = new ApiBehaviorApplicationModelProvider(options, NullLoggerFactory.Instance);
// Act
provider.OnProvidersExecuting(context);
@@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
EnableModelStateInvalidFilter = false,
});
- var provider = new ApiControllerApplicationModelProvider(options, NullLoggerFactory.Instance);
+ var provider = new ApiBehaviorApplicationModelProvider(options, NullLoggerFactory.Instance);
// Act
provider.OnProvidersExecuting(context);
@@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
InvalidModelStateResponseFactory = _ => null,
});
- var provider = new ApiControllerApplicationModelProvider(options, NullLoggerFactory.Instance);
+ var provider = new ApiBehaviorApplicationModelProvider(options, NullLoggerFactory.Instance);
// Act
provider.OnProvidersExecuting(context);
@@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
EnableModelStateInvalidFilter = false,
});
- var provider = new ApiControllerApplicationModelProvider(options, NullLoggerFactory.Instance);
+ var provider = new ApiBehaviorApplicationModelProvider(options, NullLoggerFactory.Instance);
// Act
provider.OnProvidersExecuting(context);
@@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
InvalidModelStateResponseFactory = _ => null,
});
- var provider = new ApiControllerApplicationModelProvider(options, NullLoggerFactory.Instance);
+ var provider = new ApiBehaviorApplicationModelProvider(options, NullLoggerFactory.Instance);
// Act & Assert
var ex = Assert.Throws(() => provider.OnProvidersExecuting(context));
diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApiExplorerTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApiExplorerTest.cs
index 3d969234b6..c7a3f034a0 100644
--- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApiExplorerTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApiExplorerTest.cs
@@ -1079,6 +1079,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
response =>
{
Assert.Equal(0, response.StatusCode);
+ Assert.True(response.IsDefaultResponse);
AssertProblemDetails(response);
});
}
@@ -1097,12 +1098,14 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
response =>
{
Assert.Equal(0, response.StatusCode);
+ Assert.True(response.IsDefaultResponse);
AssertProblemDetails(response);
},
response => Assert.Equal(200, response.StatusCode),
response =>
{
Assert.Equal(400, response.StatusCode);
+ Assert.False(response.IsDefaultResponse);
AssertProblemDetails(response);
});
}
@@ -1123,17 +1126,20 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
response =>
{
Assert.Equal(0, response.StatusCode);
+ Assert.True(response.IsDefaultResponse);
AssertProblemDetails(response);
},
response => Assert.Equal(200, response.StatusCode),
response =>
{
Assert.Equal(400, response.StatusCode);
+ Assert.False(response.IsDefaultResponse);
AssertProblemDetails(response);
},
response =>
{
Assert.Equal(404, response.StatusCode);
+ Assert.False(response.IsDefaultResponse);
AssertProblemDetails(response);
});
}
@@ -1199,6 +1205,8 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public string ResponseType { get; set; }
public int StatusCode { get; set; }
+
+ public bool IsDefaultResponse { get; set; }
}
private class ApiExplorerResponseFormat
diff --git a/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs
index c71cb03802..87a3a1b95a 100644
--- a/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs
@@ -417,7 +417,7 @@ namespace Microsoft.AspNetCore.Mvc
typeof(CorsApplicationModelProvider),
typeof(AuthorizationApplicationModelProvider),
typeof(TempDataApplicationModelProvider),
- typeof(ApiControllerApplicationModelProvider),
+ typeof(ApiBehaviorApplicationModelProvider),
}
},
{
@@ -425,7 +425,7 @@ namespace Microsoft.AspNetCore.Mvc
new Type[]
{
typeof(DefaultApiDescriptionProvider),
- typeof(ApiControllerApiDescriptionProvider),
+ typeof(ApiBehaviorApiDescriptionProvider),
typeof(JsonPatchOperationsArrayProvider),
}
},
diff --git a/test/WebSites/ApiExplorerWebSite/ApiExplorerDataFilter.cs b/test/WebSites/ApiExplorerWebSite/ApiExplorerDataFilter.cs
index a028cf3a0d..dbe476a3dd 100644
--- a/test/WebSites/ApiExplorerWebSite/ApiExplorerDataFilter.cs
+++ b/test/WebSites/ApiExplorerWebSite/ApiExplorerDataFilter.cs
@@ -89,7 +89,8 @@ namespace ApiExplorerWebSite
var responseType = new ApiExplorerResponseType()
{
StatusCode = response.StatusCode,
- ResponseType = response.Type?.FullName
+ ResponseType = response.Type?.FullName,
+ IsDefaultResponse = response.IsDefaultResponse,
};
foreach(var responseFormat in response.ApiResponseFormats)
@@ -152,6 +153,8 @@ namespace ApiExplorerWebSite
public string ResponseType { get; set; }
public int StatusCode { get; set; }
+
+ public bool IsDefaultResponse { get; set; }
}
private class ApiExplorerResponseFormat