Browse Source

Convert ClientProxy to controller.

pull/9905/head
maliming 5 years ago
parent
commit
b4bc92a893
  1. 14
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs
  2. 15
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention.cs
  3. 8
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyApiDescriptionFinder.cs
  4. 9
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs
  5. 5
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IClientProxyApiDescriptionFinder.cs
  6. 5
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs
  7. 4
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs
  8. 1
      framework/src/Volo.Abp.Swashbuckle/Volo.Abp.Swashbuckle.csproj
  9. 42
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleModule.cs
  10. 13
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyControllerFeatureProvider.cs
  11. 16
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyHelper.cs
  12. 12
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyOptions.cs
  13. 249
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyServiceConvention.cs

14
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs

@ -86,6 +86,7 @@ namespace Volo.Abp.AspNetCore.Mvc
var controllerModel = moduleModel.GetOrAddController(
_options.ControllerNameGenerator(controllerType, setting),
FindGroupName(controllerType) ?? apiDescription.GroupName,
controllerType,
_modelOptions.IgnoredInterfaces
);
@ -360,6 +361,19 @@ namespace Volo.Abp.AspNetCore.Mvc
return ModuleApiDescriptionModel.DefaultRemoteServiceName;
}
private string FindGroupName(Type controllerType)
{
var controllerNameAttribute =
controllerType.GetCustomAttributes().OfType<ControllerNameAttribute>().FirstOrDefault();
if (controllerNameAttribute?.Name != null)
{
return controllerNameAttribute.Name;
}
return null;
}
[CanBeNull]
private ConventionalControllerSetting FindSetting(Type controllerType)
{

15
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/AbpServiceConvention.cs

@ -45,7 +45,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
{
RemoveDuplicateControllers(application);
foreach (var controller in application.Controllers)
foreach (var controller in GetControllers(application))
{
var controllerType = controller.ControllerType.AsType();
@ -71,11 +71,16 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
}
}
protected virtual IList<ControllerModel> GetControllers(ApplicationModel application)
{
return application.Controllers;
}
protected virtual void RemoveDuplicateControllers(ApplicationModel application)
{
var controllerModelsToRemove = new List<ControllerModel>();
foreach (var controllerModel in application.Controllers)
foreach (var controllerModel in GetControllers(application))
{
if (!controllerModel.ControllerType.IsDefined(typeof(ExposeServicesAttribute), false))
{
@ -90,7 +95,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
var exposeServicesAttr = ReflectionHelper.GetSingleAttributeOrDefault<ExposeServicesAttribute>(controllerModel.ControllerType);
if (exposeServicesAttr.IncludeSelf)
{
var exposedControllerModels = application.Controllers
var exposedControllerModels = GetControllers(application)
.Where(cm => exposeServicesAttr.ServiceTypes.Contains(cm.ControllerType))
.ToArray();
@ -109,7 +114,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
continue;
}
var baseControllerModels = application.Controllers
var baseControllerModels = GetControllers(application)
.Where(cm => baseControllerTypes.Contains(cm.ControllerType))
.ToArray();
@ -122,7 +127,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Conventions
Logger.LogInformation($"Removing the controller {controllerModel.ControllerType.AssemblyQualifiedName} from the application model since it replaces the controller(s): {baseControllerTypes.Select(c => c.AssemblyQualifiedName).JoinAsString(", ")}");
}
application.Controllers.RemoveAll(controllerModelsToRemove);
GetControllers(application).RemoveAll(controllerModelsToRemove);
}
protected virtual void ConfigureRemoteService(ControllerModel controller, [CanBeNull] ConventionalControllerSetting configuration)

8
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyApiDescriptionFinder.cs

@ -28,14 +28,14 @@ namespace Volo.Abp.Http.Client.ClientProxying
Initialize();
}
public Task<ActionApiDescriptionModel> FindActionAsync(string methodName)
public ActionApiDescriptionModel FindAction(string methodName)
{
return Task.FromResult(ActionApiDescriptionModels[methodName]);
return ActionApiDescriptionModels.ContainsKey(methodName) ? ActionApiDescriptionModels[methodName] : null;
}
public Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync()
public ApplicationApiDescriptionModel GetApiDescription()
{
return Task.FromResult(ApplicationApiDescriptionModel);
return ApplicationApiDescriptionModel;
}
private void Initialize()

9
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs

@ -16,19 +16,18 @@ namespace Volo.Abp.Http.Client.ClientProxying
protected virtual async Task RequestAsync(string methodName, params object[] arguments)
{
await HttpProxyExecuter.MakeRequestAsync(await BuildHttpProxyExecuterContext(methodName, arguments));
await HttpProxyExecuter.MakeRequestAsync(BuildHttpProxyExecuterContext(methodName, arguments));
}
protected virtual async Task<T> RequestAsync<T>(string methodName, params object[] arguments)
{
return await HttpProxyExecuter.MakeRequestAndGetResultAsync<T>(await BuildHttpProxyExecuterContext(methodName, arguments));
return await HttpProxyExecuter.MakeRequestAndGetResultAsync<T>(BuildHttpProxyExecuterContext(methodName, arguments));
}
protected virtual async Task<HttpProxyExecuterContext> BuildHttpProxyExecuterContext(string methodName, params object[] arguments)
protected virtual HttpProxyExecuterContext BuildHttpProxyExecuterContext(string methodName, params object[] arguments)
{
var actionKey = GetActionKey(methodName, arguments);
var action = await ClientProxyApiDescriptionFinder.FindActionAsync(actionKey);
var action = ClientProxyApiDescriptionFinder.FindAction(actionKey);
return new HttpProxyExecuterContext(action, BuildArguments(action, arguments), typeof(TService));
}

5
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/IClientProxyApiDescriptionFinder.cs

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

5
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs

@ -10,6 +10,8 @@ namespace Volo.Abp.Http.Modeling
{
public string ControllerName { get; set; }
public string ControllerGroupName { get; set; }
public string Type { get; set; }
public List<ControllerInterfaceApiDescriptionModel> Interfaces { get; set; }
@ -21,11 +23,12 @@ namespace Volo.Abp.Http.Modeling
}
public static ControllerApiDescriptionModel Create(string controllerName, Type type, [CanBeNull] HashSet<Type> ignoredInterfaces = null)
public static ControllerApiDescriptionModel Create(string controllerName, string groupName, Type type, [CanBeNull] HashSet<Type> ignoredInterfaces = null)
{
return new ControllerApiDescriptionModel
{
ControllerName = controllerName,
ControllerGroupName = groupName,
Type = type.FullName,
Actions = new Dictionary<string, ActionApiDescriptionModel>(),
Interfaces = type

4
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs

@ -49,9 +49,9 @@ namespace Volo.Abp.Http.Modeling
return Controllers[controller.Type] = controller;
}
public ControllerApiDescriptionModel GetOrAddController(string name, Type type, [CanBeNull] HashSet<Type> ignoredInterfaces = null)
public ControllerApiDescriptionModel GetOrAddController(string name, string groupName, Type type, [CanBeNull] HashSet<Type> ignoredInterfaces = null)
{
return Controllers.GetOrAdd(type.FullName, () => ControllerApiDescriptionModel.Create(name, type, ignoredInterfaces));
return Controllers.GetOrAdd(type.FullName, () => ControllerApiDescriptionModel.Create(name, groupName, type, ignoredInterfaces));
}
public ModuleApiDescriptionModel CreateSubModel(string[] controllers, string[] actions)

1
framework/src/Volo.Abp.Swashbuckle/Volo.Abp.Swashbuckle.csproj

@ -20,6 +20,7 @@
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc\Volo.Abp.AspNetCore.Mvc.csproj" />
<ProjectReference Include="..\Volo.Abp.Http.Client\Volo.Abp.Http.Client.csproj" />
<ProjectReference Include="..\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" />
</ItemGroup>

42
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleModule.cs

@ -1,12 +1,21 @@
using Volo.Abp.AspNetCore.Mvc;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle.Conventions;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Swashbuckle
{
[DependsOn(
typeof(AbpVirtualFileSystemModule),
typeof(AbpAspNetCoreMvcModule))]
typeof(AbpAspNetCoreMvcModule),
typeof(AbpHttpClientModule))]
public class AbpSwashbuckleModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
@ -15,6 +24,35 @@ namespace Volo.Abp.Swashbuckle
{
options.FileSets.AddEmbedded<AbpSwashbuckleModule>();
});
var swaggerConventionOptions = context.Services.ExecutePreConfiguredActions<AbpSwaggerClientProxyOptions>();
if (swaggerConventionOptions.IsEnabled)
{
context.Services.Replace(ServiceDescriptor.Transient<IAbpServiceConvention, AbpSwaggerServiceConvention>());
context.Services.AddTransient<AbpSwaggerServiceConvention>();
var partManager = context.Services.GetSingletonInstance<ApplicationPartManager>();
partManager.FeatureProviders.Add(new AbpSwaggerClientProxyControllerFeatureProvider());
}
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var swaggerConventionOptions = context.ServiceProvider.GetRequiredService<IOptions<AbpSwaggerClientProxyOptions>>().Value;
if (swaggerConventionOptions.IsEnabled)
{
var partManager = context.ServiceProvider.GetRequiredService<ApplicationPartManager>();
foreach (var moduleAssembly in context
.ServiceProvider
.GetRequiredService<IModuleContainer>()
.Modules
.Select(m => m.Type.Assembly)
.Where(a => a.GetTypes().Any(AbpSwaggerClientProxyHelper.IsClientProxyService))
.Distinct())
{
partManager.ApplicationParts.AddIfNotContains(moduleAssembly);
}
}
}
}
}

13
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyControllerFeatureProvider.cs

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

16
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyHelper.cs

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

12
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyOptions.cs

@ -0,0 +1,12 @@
namespace Volo.Abp.Swashbuckle.Conventions
{
public class AbpSwaggerClientProxyOptions
{
public bool IsEnabled { get; set; }
public AbpSwaggerClientProxyOptions()
{
IsEnabled = true;
}
}
}

249
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/Conventions/AbpSwaggerClientProxyServiceConvention.cs

@ -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…
Cancel
Save