Mutate API description parameter type from JsonPatchDocument to Operation[]
Addresses #5464
This commit is contained in:
parent
f95d49c870
commit
07c22f2b29
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
||||
|
|
@ -35,5 +36,10 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
|||
/// Gets or sets the parameter type.
|
||||
/// </summary>
|
||||
public Type Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the parameter descriptor.
|
||||
/// </summary>
|
||||
public ParameterDescriptor ParameterDescriptor { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
|||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Will be null if the action returns no response, or if the response type is unclear. Use
|
||||
/// <see cref="ProducesAttribute"/> or <see cref="ProducesResponseTypeAttribute"/> on an action method
|
||||
/// <c>Microsoft.AspNetCore.Mvc.ProducesAttribute</c> or <c>Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute</c> on an action method
|
||||
/// to specify a response type.
|
||||
/// </remarks>
|
||||
public Type Type { get; set; }
|
||||
|
|
@ -26,8 +26,16 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
|||
/// </remarks>
|
||||
int Order { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates or modifies <see cref="ApiDescription"/>s.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ApiDescriptionProviderContext"/>.</param>
|
||||
void OnProvidersExecuting(ApiDescriptionProviderContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Called after <see cref="IApiDescriptionProvider"/> implementations with higher <see cref="Order"/> values have been called.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ApiDescriptionProviderContext"/>.</param>
|
||||
void OnProvidersExecuted(ApiDescriptionProviderContext context);
|
||||
}
|
||||
}
|
||||
|
|
@ -688,6 +688,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
|||
Name = GetName(containerName, bindingContext),
|
||||
Source = source,
|
||||
Type = bindingContext.ModelMetadata.ModelType,
|
||||
ParameterDescriptor = Parameter,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,18 @@
|
|||
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyMetadata("Serviceable", "True")]
|
||||
[assembly: NeutralResourcesLanguage("en-us")]
|
||||
[assembly: AssemblyCompany("Microsoft Corporation.")]
|
||||
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
|
||||
[assembly: AssemblyProduct("Microsoft ASP.NET Core")]
|
||||
[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionProvider))]
|
||||
[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription))]
|
||||
[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescriptionProviderContext))]
|
||||
[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription))]
|
||||
[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterRouteInfo))]
|
||||
[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiRequestFormat))]
|
||||
[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiResponseFormat))]
|
||||
[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiResponseType))]
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
[
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescriptionProviderContext",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterRouteInfo",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiRequestFormat",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiResponseFormat",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiResponseType",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public interface Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionProvider",
|
||||
"Kind": "Removal"
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
[
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescriptionProviderContext",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterRouteInfo",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiRequestFormat",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiResponseFormat",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public class Microsoft.AspNetCore.Mvc.ApiExplorer.ApiResponseType",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"OldTypeId": "public interface Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionProvider",
|
||||
"Kind": "Removal"
|
||||
}
|
||||
]
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Json;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
|
@ -73,6 +75,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcJsonMvcOptionsSetup>());
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IApiDescriptionProvider, JsonPatchOperationsArrayProvider>());
|
||||
services.TryAddSingleton<JsonResultExecutor>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
// 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.Reflection;
|
||||
using Microsoft.AspNetCore.JsonPatch;
|
||||
using Microsoft.AspNetCore.JsonPatch.Operations;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a provider of <see cref="ApiDescription"/> to change parameters of
|
||||
/// type <see cref="IJsonPatchDocument"/> to an array of <see cref="Operation"/>.
|
||||
/// </summary>
|
||||
public class JsonPatchOperationsArrayProvider : IApiDescriptionProvider
|
||||
{
|
||||
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="JsonPatchOperationsArrayProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
||||
public JsonPatchOperationsArrayProvider(IModelMetadataProvider modelMetadataProvider)
|
||||
{
|
||||
_modelMetadataProvider = modelMetadataProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <remarks>
|
||||
/// The order -999 ensures that this provider is executed right after the <c>Microsoft.AspNetCore.Mvc.ApiExplorer.DefaultApiDescriptionProvider</c>.
|
||||
/// </remarks>
|
||||
public int Order
|
||||
{
|
||||
get { return -999; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnProvidersExecuting(ApiDescriptionProviderContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
foreach (var result in context.Results)
|
||||
{
|
||||
foreach (var parameterDescription in result.ParameterDescriptions)
|
||||
{
|
||||
if (typeof(IJsonPatchDocument).GetTypeInfo().IsAssignableFrom(parameterDescription.Type))
|
||||
{
|
||||
parameterDescription.Type = typeof(Operation[]);
|
||||
parameterDescription.ModelMetadata = _modelMetadataProvider.GetMetadataForType(typeof(Operation[]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnProvidersExecuted(ApiDescriptionProviderContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -216,6 +216,22 @@ namespace Microsoft.AspNetCore.Mvc.Description
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetApiDescription_ParameterDescription_IncludesParameterDescriptor()
|
||||
{
|
||||
// Arrange
|
||||
var action = CreateActionDescriptor(nameof(FromBody));
|
||||
|
||||
// Act
|
||||
var descriptions = GetApiDescriptions(action);
|
||||
|
||||
// Assert
|
||||
var description = Assert.Single(descriptions);
|
||||
var parameterDescription = Assert.Single(description.ParameterDescriptions);
|
||||
var actionParameterDescriptor = Assert.Single(action.Parameters);
|
||||
Assert.Equal(actionParameterDescriptor, parameterDescription.ParameterDescriptor);
|
||||
}
|
||||
|
||||
// Only a parameter which comes from a route or model binding or unknown should
|
||||
// include route info.
|
||||
[Theory]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
// 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 Microsoft.AspNetCore.JsonPatch;
|
||||
using Microsoft.AspNetCore.JsonPatch.Operations;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Json
|
||||
{
|
||||
public class JsonPatchOperationsArrayProviderTests
|
||||
{
|
||||
[Fact]
|
||||
public void OnProvidersExecuting_FindsJsonPatchDocuments_ProvidesOperationsArray()
|
||||
{
|
||||
// Arrange
|
||||
var metadataprovider = new TestModelMetadataProvider();
|
||||
var provider = new JsonPatchOperationsArrayProvider(metadataprovider);
|
||||
var jsonPatchParameterDescription = new ApiParameterDescription
|
||||
{
|
||||
Type = typeof(JsonPatchDocument)
|
||||
};
|
||||
|
||||
var stringParameterDescription = new ApiParameterDescription
|
||||
{
|
||||
Type = typeof(string),
|
||||
};
|
||||
|
||||
var apiDescription = new ApiDescription();
|
||||
apiDescription.ParameterDescriptions.Add(jsonPatchParameterDescription);
|
||||
apiDescription.ParameterDescriptions.Add(stringParameterDescription);
|
||||
|
||||
var actionDescriptorList = new List<ActionDescriptor>();
|
||||
var apiDescriptionProviderContext = new ApiDescriptionProviderContext(actionDescriptorList);
|
||||
apiDescriptionProviderContext.Results.Add(apiDescription);
|
||||
|
||||
// Act
|
||||
provider.OnProvidersExecuting(apiDescriptionProviderContext);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(apiDescription.ParameterDescriptions,
|
||||
description =>
|
||||
{
|
||||
Assert.Equal(typeof(Operation[]), description.Type);
|
||||
Assert.Equal(typeof(Operation[]), description.ModelMetadata.ModelType);
|
||||
},
|
||||
description =>
|
||||
{
|
||||
Assert.Equal(typeof(string), description.Type);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Mvc.Controllers;
|
|||
using Microsoft.AspNetCore.Mvc.Cors.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Json;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
|
|
@ -411,6 +412,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
new Type[]
|
||||
{
|
||||
typeof(DefaultApiDescriptionProvider),
|
||||
typeof(JsonPatchOperationsArrayProvider),
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue