mirror of https://github.com/abpframework/abp.git
13 changed files with 371 additions and 22 deletions
@ -1,12 +1,11 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Http.Modeling; |
|||
|
|||
namespace Volo.Abp.Http.Client.ClientProxying |
|||
{ |
|||
public interface IClientProxyApiDescriptionFinder |
|||
{ |
|||
Task<ActionApiDescriptionModel> FindActionAsync(string methodName); |
|||
ActionApiDescriptionModel FindAction(string methodName); |
|||
|
|||
Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync(); |
|||
ApplicationApiDescriptionModel GetApiDescription(); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,13 @@ |
|||
using System.Reflection; |
|||
using Microsoft.AspNetCore.Mvc.Controllers; |
|||
|
|||
namespace Volo.Abp.Swashbuckle.Conventions |
|||
{ |
|||
public class AbpSwaggerClientProxyControllerFeatureProvider : ControllerFeatureProvider |
|||
{ |
|||
protected override bool IsController(TypeInfo typeInfo) |
|||
{ |
|||
return AbpSwaggerClientProxyHelper.IsClientProxyService(typeInfo); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using Volo.Abp.Application.Services; |
|||
using Volo.Abp.Http.Client.ClientProxying; |
|||
|
|||
namespace Volo.Abp.Swashbuckle.Conventions |
|||
{ |
|||
public static class AbpSwaggerClientProxyHelper |
|||
{ |
|||
public static bool IsClientProxyService(Type type) |
|||
{ |
|||
return typeof(IApplicationService).IsAssignableFrom(type) && |
|||
type.GetBaseClasses().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ClientProxyBase<>)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
namespace Volo.Abp.Swashbuckle.Conventions |
|||
{ |
|||
public class AbpSwaggerClientProxyOptions |
|||
{ |
|||
public bool IsEnabled { get; set; } |
|||
|
|||
public AbpSwaggerClientProxyOptions() |
|||
{ |
|||
IsEnabled = true; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,249 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.ActionConstraints; |
|||
using Microsoft.AspNetCore.Mvc.ApplicationModels; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.Application.Services; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.Conventions; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Http.Client.ClientProxying; |
|||
using Volo.Abp.Http.Modeling; |
|||
using Volo.Abp.Reflection; |
|||
|
|||
namespace Volo.Abp.Swashbuckle.Conventions |
|||
{ |
|||
[DisableConventionalRegistration] |
|||
public class AbpSwaggerServiceConvention : AbpServiceConvention |
|||
{ |
|||
protected readonly IClientProxyApiDescriptionFinder ClientProxyApiDescriptionFinder; |
|||
protected readonly List<ActionModel> ActionWithAttributeRoute; |
|||
|
|||
public AbpSwaggerServiceConvention( |
|||
IOptions<AbpAspNetCoreMvcOptions> options, |
|||
IConventionalRouteBuilder conventionalRouteBuilder, |
|||
IClientProxyApiDescriptionFinder clientProxyApiDescriptionFinder) |
|||
: base(options, conventionalRouteBuilder) |
|||
{ |
|||
ClientProxyApiDescriptionFinder = clientProxyApiDescriptionFinder; |
|||
ActionWithAttributeRoute = new List<ActionModel>(); |
|||
} |
|||
|
|||
protected override IList<ControllerModel> GetControllers(ApplicationModel application) |
|||
{ |
|||
return application.Controllers.Where(c => !AbpSwaggerClientProxyHelper.IsClientProxyService(c.ControllerType)).ToList(); |
|||
} |
|||
|
|||
protected virtual IList<ControllerModel> GetClientProxyControllers(ApplicationModel application) |
|||
{ |
|||
return application.Controllers.Where(c => AbpSwaggerClientProxyHelper.IsClientProxyService(c.ControllerType)).ToList(); |
|||
} |
|||
|
|||
protected override void ApplyForControllers(ApplicationModel application) |
|||
{ |
|||
base.ApplyForControllers(application); |
|||
|
|||
foreach (var controller in GetClientProxyControllers(application)) |
|||
{ |
|||
controller.ControllerName = controller.ControllerName.RemovePostFix("ClientProxy"); |
|||
|
|||
var controllerApiDescription = FindControllerApiDescriptionModel(controller); |
|||
if (controllerApiDescription != null && |
|||
!controllerApiDescription.ControllerGroupName.IsNullOrWhiteSpace()) |
|||
{ |
|||
controller.ControllerName = controllerApiDescription.ControllerGroupName; |
|||
} |
|||
|
|||
ConfigureClientProxySelector(controller); |
|||
ConfigureClientProxyApiExplorer(controller); |
|||
ConfigureParameters(controller); |
|||
} |
|||
} |
|||
|
|||
protected virtual void ConfigureClientProxySelector(ControllerModel controller) |
|||
{ |
|||
RemoveEmptySelectors(controller.Selectors); |
|||
|
|||
var controllerType = controller.ControllerType.AsType(); |
|||
var remoteServiceAtt = ReflectionHelper.GetSingleAttributeOrDefault<RemoteServiceAttribute>(controllerType.GetTypeInfo()); |
|||
if (remoteServiceAtt != null && !remoteServiceAtt.IsEnabledFor(controllerType)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (controller.Selectors.Any(selector => selector.AttributeRouteModel != null)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
foreach (var action in controller.Actions) |
|||
{ |
|||
ConfigureClientProxySelector(controller, action); |
|||
} |
|||
} |
|||
|
|||
protected virtual void ConfigureClientProxySelector(ControllerModel controller, ActionModel action) |
|||
{ |
|||
RemoveEmptySelectors(action.Selectors); |
|||
|
|||
var remoteServiceAtt = ReflectionHelper.GetSingleAttributeOrDefault<RemoteServiceAttribute>(action.ActionMethod); |
|||
if (remoteServiceAtt != null && !remoteServiceAtt.IsEnabledFor(action.ActionMethod)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var actionApiDescriptionModel = FindActionApiDescriptionModel(controller, action); |
|||
if (actionApiDescriptionModel == null) |
|||
{ |
|||
return;; |
|||
} |
|||
|
|||
ActionWithAttributeRoute.Add(action); |
|||
|
|||
if (!action.Selectors.Any()) |
|||
{ |
|||
var abpServiceSelectorModel = new SelectorModel |
|||
{ |
|||
AttributeRouteModel = new AttributeRouteModel( |
|||
new RouteAttribute(template: actionApiDescriptionModel.Url) |
|||
), |
|||
ActionConstraints = { new HttpMethodActionConstraint(new[] { actionApiDescriptionModel.HttpMethod }) } |
|||
}; |
|||
|
|||
action.Selectors.Add(abpServiceSelectorModel); |
|||
} |
|||
else |
|||
{ |
|||
foreach (var selector in action.Selectors) |
|||
{ |
|||
var httpMethod = selector.ActionConstraints |
|||
.OfType<HttpMethodActionConstraint>() |
|||
.FirstOrDefault()? |
|||
.HttpMethods? |
|||
.FirstOrDefault(); |
|||
|
|||
if (httpMethod == null) |
|||
{ |
|||
httpMethod = actionApiDescriptionModel.HttpMethod; |
|||
} |
|||
|
|||
if (selector.AttributeRouteModel == null) |
|||
{ |
|||
selector.AttributeRouteModel = new AttributeRouteModel( |
|||
new RouteAttribute(template: actionApiDescriptionModel.Url) |
|||
); |
|||
} |
|||
|
|||
if (!selector.ActionConstraints.OfType<HttpMethodActionConstraint>().Any()) |
|||
{ |
|||
selector.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMethod })); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected virtual void ConfigureClientProxyApiExplorer(ControllerModel controller) |
|||
{ |
|||
if (controller.ApiExplorer.GroupName.IsNullOrEmpty()) |
|||
{ |
|||
controller.ApiExplorer.GroupName = controller.ControllerName; |
|||
} |
|||
|
|||
if (controller.ApiExplorer.IsVisible == null) |
|||
{ |
|||
controller.ApiExplorer.IsVisible = IsVisibleRemoteService(controller.ControllerType); |
|||
} |
|||
|
|||
foreach (var action in controller.Actions) |
|||
{ |
|||
if (ActionWithAttributeRoute.Contains(action)) |
|||
{ |
|||
ConfigureApiExplorer(action); |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected virtual ModuleApiDescriptionModel FindModuleApiDescriptionModel(ControllerModel controller) |
|||
{ |
|||
var appServiceType = FindAppServiceInterfaceType(controller); |
|||
if (appServiceType == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
var applicationApiDescriptionModel = ClientProxyApiDescriptionFinder.GetApiDescription(); |
|||
foreach (var moduleApiDescription in applicationApiDescriptionModel.Modules.Values) |
|||
{ |
|||
if (moduleApiDescription.Controllers.Values.Any(x => x.Interfaces.Any(t => t.Type == appServiceType.FullName))) |
|||
{ |
|||
return moduleApiDescription; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
protected virtual ControllerApiDescriptionModel FindControllerApiDescriptionModel(ControllerModel controller) |
|||
{ |
|||
var appServiceType = FindAppServiceInterfaceType(controller); |
|||
if (appServiceType == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
var applicationApiDescriptionModel = ClientProxyApiDescriptionFinder.GetApiDescription(); |
|||
foreach (var controllerApiDescription in applicationApiDescriptionModel.Modules.Values.SelectMany(x => x.Controllers.Values)) |
|||
{ |
|||
if (controllerApiDescription.Interfaces.Any(t => t.Type == appServiceType.FullName)) |
|||
{ |
|||
return controllerApiDescription; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
protected virtual ActionApiDescriptionModel FindActionApiDescriptionModel(ControllerModel controller, ActionModel action) |
|||
{ |
|||
var appServiceType = FindAppServiceInterfaceType(controller); |
|||
if (appServiceType == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
var key = |
|||
$"{appServiceType.FullName}." + |
|||
$"{action.ActionMethod.Name}." + |
|||
$"{string.Join("-", action.Parameters.Select(x => x.ParameterType.FullName))}"; |
|||
|
|||
var actionApiDescriptionModel = ClientProxyApiDescriptionFinder.FindAction(key); |
|||
if (actionApiDescriptionModel == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
if (actionApiDescriptionModel.ImplementFrom.StartsWith("Volo.Abp.Application.Services")) |
|||
{ |
|||
return actionApiDescriptionModel; |
|||
} |
|||
|
|||
if (appServiceType.FullName != null && actionApiDescriptionModel.ImplementFrom.StartsWith(appServiceType.FullName)) |
|||
{ |
|||
return actionApiDescriptionModel; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
protected virtual Type FindAppServiceInterfaceType(ControllerModel controller) |
|||
{ |
|||
return controller.ControllerType.GetInterfaces() |
|||
.FirstOrDefault(type => !type.IsGenericType && |
|||
type != typeof(IApplicationService) && |
|||
typeof(IApplicationService).IsAssignableFrom(type)); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue