From 22f24c77308e21dd421a070c3d877e10c70f7df4 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 30 Aug 2021 15:32:41 +0800 Subject: [PATCH] Improved --- .../Volo/Abp/Cli/Commands/ProxyCommandBase.cs | 2 +- .../CSharp/CSharpServiceProxyGenerator.cs | 41 ++++++--- .../Volo/Abp/Http/Client/ClientProxyBase.cs | 90 +++++++++++++++++-- ...nyName.MyProjectName.HttpApi.Client.csproj | 6 ++ .../MyProjectNameHttpApiClientModule.cs | 6 ++ 5 files changed, 127 insertions(+), 18 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProxyCommandBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProxyCommandBase.cs index 594c3fb58e..58d8c04b95 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProxyCommandBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProxyCommandBase.cs @@ -68,7 +68,7 @@ namespace Volo.Abp.Cli.Commands var workDirectory = commandLineArgs.Options.GetOrNull(Options.WorkDirectory.Short, Options.WorkDirectory.Long) ?? Directory.GetCurrentDirectory(); var folder = commandLineArgs.Options.GetOrNull(Options.Folder.Long); - return new GenerateProxyArgs(CommandName, workDirectory, module.ToLower(), url, output, target, apiName, source, folder, commandLineArgs.Options); + return new GenerateProxyArgs(CommandName, workDirectory, module, url, output, target, apiName, source, folder, commandLineArgs.Options); } public virtual string GetUsageInfo() diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxy/CSharp/CSharpServiceProxyGenerator.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxy/CSharp/CSharpServiceProxyGenerator.cs index 810cbb0663..c3222985fa 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxy/CSharp/CSharpServiceProxyGenerator.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxy/CSharp/CSharpServiceProxyGenerator.cs @@ -33,7 +33,7 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp $"{Environment.NewLine}" + $"{Environment.NewLine}namespace " + $"{Environment.NewLine}{{" + - $"{Environment.NewLine} public partial class : ClientProxyBase<>, " + + $"{Environment.NewLine} public partial class : ClientProxyBase, " + $"{Environment.NewLine} {{" + $"{Environment.NewLine} " + $"{Environment.NewLine} }}" + @@ -65,6 +65,7 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp public override async Task GenerateProxyAsync(GenerateProxyArgs args) { + CheckFolder(args.Folder); var projectFilePath = CheckWorkDirectory(args.WorkDirectory); if (args.CommandName == RemoveProxyCommand.Name) @@ -90,6 +91,19 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp await GenerateClientProxyFileAsync(args, controller.Value, appServiceTypes, startupModule.Namespace); } } + + await CreateGenerateProxyJsonFile(args, applicationApiDescriptionModel); + } + + private async Task CreateGenerateProxyJsonFile(GenerateProxyArgs args, ApplicationApiDescriptionModel applicationApiDescriptionModel) + { + var folder = args.Folder.IsNullOrWhiteSpace()? DefaultNamespace : args.Folder; + var filePath = Path.Combine(args.WorkDirectory, folder, $"{args.Module}-generate-proxy.json"); + + using (var writer = new StreamWriter(filePath)) + { + await writer.WriteAsync(JsonSerializer.Serialize(applicationApiDescriptionModel, indented: true)); + } } private void RemoveClientProxyFile(GenerateProxyArgs args) @@ -140,7 +154,7 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp continue; } - GenerateMethod(actionApiDescription, method, clientProxyBuilder, usingNamespaceList); + GenerateMethod(actionApiDescription, appServiceType.Name, method, clientProxyBuilder, usingNamespaceList); } foreach (var usingNamespace in usingNamespaceList) @@ -184,6 +198,7 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp private void GenerateMethod( ActionApiDescriptionModel actionApiDescription, + string serviceName, MethodInfo method, StringBuilder clientProxyBuilder, List usingNamespaceList) @@ -199,7 +214,7 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp return; } - GenerateAsynchronousMethod(actionApiDescription, method, returnTypeName, methodBuilder, usingNamespaceList); + GenerateAsynchronousMethod(actionApiDescription, serviceName ,method, returnTypeName, methodBuilder, usingNamespaceList); clientProxyBuilder.Replace(MethodPlaceholder, $"{methodBuilder} {Environment.NewLine} {MethodPlaceholder}"); } @@ -223,6 +238,7 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp private void GenerateAsynchronousMethod( ActionApiDescriptionModel actionApiDescription, + string serviceName, MethodInfo method, string returnTypeName, StringBuilder methodBuilder, @@ -239,20 +255,14 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp methodBuilder.Replace(", )", ")"); methodBuilder.AppendLine(" {"); - methodBuilder.AppendLine(" #region ActionApiDescriptionModel JSON"); - methodBuilder.AppendLine($" var actionApiDescription = \"{JsonSerializer.Serialize(actionApiDescription).Replace("\"","\\\"")}\";"); - methodBuilder.AppendLine(" #endregion"); - methodBuilder.AppendLine(""); - methodBuilder.AppendLine(" var action = JsonSerializer.Deserialize(actionApiDescription);"); - methodBuilder.AppendLine(""); if (method.ReturnType.GenericTypeArguments.IsNullOrEmpty()) { - methodBuilder.AppendLine(" await MakeRequestAsync(action, );"); + methodBuilder.AppendLine($" await MakeRequestAsync<{serviceName}>(\"{method.Name}\", );"); } else { - methodBuilder.AppendLine($" return await MakeRequestAsync<{returnTypeName.Replace("Task<", string.Empty)}(action, );"); + methodBuilder.AppendLine($" return await MakeRequestAsync<{serviceName}, {returnTypeName.Replace("Task<", string.Empty)}(\"{method.Name}\", );"); } foreach (var parameter in method.GetParameters()) @@ -262,7 +272,6 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp methodBuilder.Replace(", ", string.Empty); methodBuilder.Replace(", )", ")"); - methodBuilder.AppendLine(""); methodBuilder.AppendLine(" }"); } @@ -371,6 +380,14 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp return projectFiles.First(); } + private static void CheckFolder(string folder) + { + if (!folder.IsNullOrWhiteSpace() && Path.HasExtension(folder)) + { + throw new CliUsageException("Option folder should be a directory."); + } + } + private Type GetStartupModule(string assemblyPath) { return Assembly diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxyBase.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxyBase.cs index a1a5b2e436..523310390c 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxyBase.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxyBase.cs @@ -1,27 +1,61 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; +using Microsoft.Extensions.FileProviders; using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Client.DynamicProxying; using Volo.Abp.Http.Modeling; using Volo.Abp.Json; +using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.Http.Client { - public class ClientProxyBase : ITransientDependency + public class ClientProxyBase : ITransientDependency { + public const string ApiDescriptionCacheKey = "client-proxy"; public IAbpLazyServiceProvider LazyServiceProvider { get; set; } protected IHttpProxyExecuter HttpProxyExecuter => LazyServiceProvider.LazyGetRequiredService(); protected IJsonSerializer JsonSerializer => LazyServiceProvider.LazyGetRequiredService(); + protected IApiDescriptionCache ApiDescriptionCache => LazyServiceProvider.LazyGetRequiredService(); + protected IVirtualFileProvider VirtualFileProvider => LazyServiceProvider.LazyGetRequiredService(); - protected virtual async Task MakeRequestAsync(ActionApiDescriptionModel action, params object[] arguments) + protected static readonly Dictionary ActionApiDescriptionModels = new Dictionary(); + + protected virtual async Task MakeRequestAsync(string methodName, params object[] arguments) { - await HttpProxyExecuter.MakeRequestAsync(new HttpProxyExecuterContext(action, BuildArguments(action, arguments), typeof(TService))); + await HttpProxyExecuter.MakeRequestAsync(await BuildHttpProxyExecuterContext(methodName, arguments)); } - protected virtual async Task MakeRequestAsync(ActionApiDescriptionModel action, params object[] arguments) + protected virtual async Task MakeRequestAsync(string methodName, params object[] arguments) { - return await HttpProxyExecuter.MakeRequestAndGetResultAsync(new HttpProxyExecuterContext(action, BuildArguments(action, arguments), typeof(TService))); + return await HttpProxyExecuter.MakeRequestAndGetResultAsync(await BuildHttpProxyExecuterContext(methodName, arguments)); + } + + protected virtual async Task BuildHttpProxyExecuterContext(string methodName, params object[] arguments) + { + var actionDescriptionKey = $"{typeof(TService).Name}.{methodName}"; + + if (!ActionApiDescriptionModels.ContainsKey(actionDescriptionKey)) + { + var apiDescription = await ApiDescriptionCache.GetAsync(ApiDescriptionCacheKey, GetApplicationApiDescriptionModel); + var controllers = apiDescription.Modules.Select(x=>x.Value).SelectMany(x => x.Controllers.Values).ToList(); + + foreach (var controller in controllers.Where(x => x.Interfaces.Any())) + { + var appServiceType = controller.Interfaces.Last().Type.Split('.').Last(); + + foreach (var actionItem in controller.Actions.Values) + { + ActionApiDescriptionModels.Add($"{appServiceType}.{actionItem.Name}", actionItem); + } + } + } + + var action = ActionApiDescriptionModels[actionDescriptionKey]; + + return new HttpProxyExecuterContext(action, BuildArguments(action, arguments), typeof(TService)); } protected virtual Dictionary BuildArguments(ActionApiDescriptionModel action, object[] arguments) @@ -36,5 +70,51 @@ namespace Volo.Abp.Http.Client return dict; } + + protected virtual async Task GetApplicationApiDescriptionModel() + { + var applicationApiDescription = ApplicationApiDescriptionModel.Create(); + + var fileInfoList = new List(); + GetGenerateProxyFileInfos(fileInfoList); + + foreach (var fileInfo in fileInfoList) + { + using (var streamReader = new StreamReader(fileInfo.CreateReadStream())) + { + var content = await streamReader.ReadToEndAsync(); + + var subApplicationApiDescription = JsonSerializer.Deserialize(content); + + foreach (var module in subApplicationApiDescription.Modules) + { + if (!applicationApiDescription.Modules.ContainsKey(module.Key)) + { + applicationApiDescription.AddModule(module.Value); + } + } + } + } + + return applicationApiDescription; + } + + private void GetGenerateProxyFileInfos(List fileInfoList, string path = "") + { + foreach (var directoryContent in VirtualFileProvider.GetDirectoryContents(path)) + { + if (directoryContent.IsDirectory) + { + GetGenerateProxyFileInfos(fileInfoList, directoryContent.PhysicalPath); + } + else + { + if (directoryContent.Name.EndsWith("generate-proxy.json")) + { + fileInfoList.Add(VirtualFileProvider.GetFileInfo(directoryContent.GetVirtualOrPhysicalPathOrNull())); + } + } + } + } } } diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj index 44023bac06..4faf7dcee3 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj @@ -5,12 +5,18 @@ netstandard2.0 MyCompanyName.MyProjectName + true + + + + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyProjectNameHttpApiClientModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyProjectNameHttpApiClientModule.cs index 67be0c087a..e54e6cf8c7 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyProjectNameHttpApiClientModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyProjectNameHttpApiClientModule.cs @@ -6,6 +6,7 @@ using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement; using Volo.Abp.TenantManagement; using Volo.Abp.SettingManagement; +using Volo.Abp.VirtualFileSystem; namespace MyCompanyName.MyProjectName { @@ -28,6 +29,11 @@ namespace MyCompanyName.MyProjectName typeof(MyProjectNameApplicationContractsModule).Assembly, RemoteServiceName ); + + Configure(options => + { + options.FileSets.AddEmbedded(); + }); } } }