Browse Source

Merge pull request #3526 from abpframework/maliming/AbpRemoteServiceApiDescriptionProvider

Introducing AbpRemoteServiceApiDescriptionProvider
pull/3559/merge
Halil İbrahim Kalkan 7 years ago
committed by GitHub
parent
commit
ab7cf36cc7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 23
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  2. 94
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpRemoteServiceApiDescriptionProvider.cs
  3. 10
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpRemoteServiceApiDescriptionProviderOptions.cs
  4. 17
      framework/src/Volo.Abp.Core/Volo/Abp/Reflection/ReflectionHelper.cs

23
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

@ -11,18 +11,22 @@ using Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.Extensions.Hosting;
using Volo.Abp.ApiVersioning;
using Volo.Abp.AspNetCore.Mvc.ApiExploring;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.AspNetCore.Mvc.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.Json;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.VirtualFileSystem;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Localization;
@ -57,6 +61,25 @@ namespace Volo.Abp.AspNetCore.Mvc
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 =>
{
if (options.MinifyGeneratedScript == null)

94
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpRemoteServiceApiDescriptionProvider.cs

@ -0,0 +1,94 @@
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.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 => IsRemoteService(x.ActionDescriptor)))
{
var actionProducesResponseTypeAttributes =
ReflectionHelper.GetAttributesOfMemberOrDeclaringType<ProducesResponseTypeAttribute>(
result.ActionDescriptor.GetMethodInfo());
if (actionProducesResponseTypeAttributes.Any(x => x.StatusCode == apiResponseType.StatusCode))
{
continue;
}
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 IsRemoteService(ActionDescriptor actionDescriptor)
{
var remoteServiceAttr = ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<RemoteServiceAttribute>(actionDescriptor.GetMethodInfo());
return remoteServiceAttr != null && remoteServiceAttr.IsEnabled;
}
}
}

10
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpRemoteServiceApiDescriptionProviderOptions.cs

@ -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>();
}
}

17
framework/src/Volo.Abp.Core/Volo/Abp/Reflection/ReflectionHelper.cs

@ -108,6 +108,23 @@ namespace Volo.Abp.Reflection
?? defaultValue;
}
/// <summary>
/// Tries to gets attributes defined for a class member and it's declaring type including inherited attributes.
/// </summary>
/// <typeparam name="TAttribute">Type of the attribute</typeparam>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public static IEnumerable<TAttribute> GetAttributesOfMemberOrDeclaringType<TAttribute>(MemberInfo memberInfo, bool inherit = true)
where TAttribute : class
{
var customAttributes = memberInfo.GetCustomAttributes(true).OfType<TAttribute>();
var declaringTypeCustomAttributes =
memberInfo.DeclaringType?.GetTypeInfo().GetCustomAttributes(true).OfType<TAttribute>();
return declaringTypeCustomAttributes != null
? customAttributes.Concat(declaringTypeCustomAttributes).Distinct()
: customAttributes;
}
/// <summary>
/// Gets value of a property by it's full path from given object
/// </summary>

Loading…
Cancel
Save