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; |
using Volo.Abp.Http.Modeling; |
||||
|
|
||||
namespace Volo.Abp.Http.Client.ClientProxying |
namespace Volo.Abp.Http.Client.ClientProxying |
||||
{ |
{ |
||||
public interface IClientProxyApiDescriptionFinder |
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