Introducing AbpRemoteServiceApiDescriptionProvider

Resolve #3458
pull/3526/head
maliming 5 years ago
parent ebdb8abecd
commit c3f38382d0

@ -11,15 +11,19 @@ using Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Reflection; using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Volo.Abp.ApiVersioning; using Volo.Abp.ApiVersioning;
using Volo.Abp.AspNetCore.Mvc.ApiExploring;
using Volo.Abp.AspNetCore.Mvc.Conventions; using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.AspNetCore.Mvc.DependencyInjection; using Volo.Abp.AspNetCore.Mvc.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.Json; using Volo.Abp.AspNetCore.Mvc.Json;
using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.VirtualFileSystem; using Volo.Abp.AspNetCore.VirtualFileSystem;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Http;
using Volo.Abp.Http.Modeling; using Volo.Abp.Http.Modeling;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
@ -50,6 +54,25 @@ namespace Volo.Abp.AspNetCore.Mvc
options.IgnoredInterfaces.AddIfNotContains(typeof(IActionFilter)); options.IgnoredInterfaces.AddIfNotContains(typeof(IActionFilter));
}); });
Configure<AbpRemoteServiceApiDescriptionProviderOptions>(options =>
{
var statusCodes = new List<int>
{
(int) HttpStatusCode.Forbidden,
(int) HttpStatusCode.Unauthorized,
(int) HttpStatusCode.BadRequest,
(int) HttpStatusCode.NotFound,
(int) HttpStatusCode.NotImplemented,
(int) HttpStatusCode.InternalServerError
};
options.SupportedResponseTypes.AddIfNotContains(statusCodes.Select(statusCode => new ApiResponseType
{
Type = typeof(RemoteServiceErrorResponse),
StatusCode = statusCode
}));
});
context.Services.PostConfigure<AbpAspNetCoreMvcOptions>(options => context.Services.PostConfigure<AbpAspNetCoreMvcOptions>(options =>
{ {
if (options.MinifyGeneratedScript == null) if (options.MinifyGeneratedScript == null)

@ -0,0 +1,92 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Reflection;
namespace Volo.Abp.AspNetCore.Mvc.ApiExploring
{
public class AbpRemoteServiceApiDescriptionProvider : IApiDescriptionProvider, ITransientDependency
{
private readonly IModelMetadataProvider _modelMetadataProvider;
private readonly MvcOptions _mvcOptions;
private readonly AbpRemoteServiceApiDescriptionProviderOptions _options;
public AbpRemoteServiceApiDescriptionProvider(
IModelMetadataProvider modelMetadataProvider,
IOptions<MvcOptions> mvcOptionsAccessor,
IOptions<AbpRemoteServiceApiDescriptionProviderOptions> optionsAccessor)
{
_modelMetadataProvider = modelMetadataProvider;
_mvcOptions = mvcOptionsAccessor.Value;
_options = optionsAccessor.Value;
}
public void OnProvidersExecuted(ApiDescriptionProviderContext context)
{
}
/// <summary>
/// The order -999 ensures that this provider is executed right after the
/// Microsoft.AspNetCore.Mvc.ApiExplorer.DefaultApiDescriptionProvider.
/// </summary>
public int Order => -999;
public void OnProvidersExecuting(ApiDescriptionProviderContext context)
{
foreach (var apiResponseType in GetApiResponseTypes())
{
foreach (var result in context.Results.Where(x => ShouldAddResponseTypes(x.ActionDescriptor)))
{
result.SupportedResponseTypes.AddIfNotContains(x => x.StatusCode == apiResponseType.StatusCode, () => apiResponseType);
}
}
}
protected virtual IEnumerable<ApiResponseType> GetApiResponseTypes()
{
foreach (var apiResponse in _options.SupportedResponseTypes)
{
apiResponse.ModelMetadata = _modelMetadataProvider.GetMetadataForType(apiResponse.Type);
foreach (var responseTypeMetadataProvider in _mvcOptions.OutputFormatters.OfType<IApiResponseTypeMetadataProvider>())
{
var formatterSupportedContentTypes = responseTypeMetadataProvider.GetSupportedContentTypes(null, apiResponse.Type);
if (formatterSupportedContentTypes == null)
{
continue;
}
foreach (var formatterSupportedContentType in formatterSupportedContentTypes)
{
apiResponse.ApiResponseFormats.Add(new ApiResponseFormat
{
Formatter = (IOutputFormatter) responseTypeMetadataProvider,
MediaType = formatterSupportedContentType
});
}
}
}
return _options.SupportedResponseTypes;
}
protected virtual bool ShouldAddResponseTypes(ActionDescriptor actionDescriptor)
{
if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<ProducesResponseTypeAttribute>(actionDescriptor.GetMethodInfo()) != null ||
ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<ProducesErrorResponseTypeAttribute>(actionDescriptor.GetMethodInfo()) != null)
{
return false;
}
var remoteServiceAttr = ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<RemoteServiceAttribute>(actionDescriptor.GetMethodInfo());
return remoteServiceAttr != null && remoteServiceAttr.IsEnabled;
}
}
}

@ -0,0 +1,10 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
namespace Volo.Abp.AspNetCore.Mvc.ApiExploring
{
public class AbpRemoteServiceApiDescriptionProviderOptions
{
public HashSet<ApiResponseType> SupportedResponseTypes { get; set; } = new HashSet<ApiResponseType>();
}
}
Loading…
Cancel
Save