Browse Source

Improved

pull/9905/head
liangshiwei 5 years ago
parent
commit
22f24c7730
  1. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/ProxyCommandBase.cs
  2. 41
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ServiceProxy/CSharp/CSharpServiceProxyGenerator.cs
  3. 90
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxyBase.cs
  4. 6
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj
  5. 6
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyProjectNameHttpApiClientModule.cs

2
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 workDirectory = commandLineArgs.Options.GetOrNull(Options.WorkDirectory.Short, Options.WorkDirectory.Long) ?? Directory.GetCurrentDirectory();
var folder = commandLineArgs.Options.GetOrNull(Options.Folder.Long); 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() public virtual string GetUsageInfo()

41
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}" +
$"{Environment.NewLine}namespace <namespace>" + $"{Environment.NewLine}namespace <namespace>" +
$"{Environment.NewLine}{{" + $"{Environment.NewLine}{{" +
$"{Environment.NewLine} public partial class <className> : ClientProxyBase<<serviceInterface>>, <serviceInterface>" + $"{Environment.NewLine} public partial class <className> : ClientProxyBase, <serviceInterface>" +
$"{Environment.NewLine} {{" + $"{Environment.NewLine} {{" +
$"{Environment.NewLine} <method placeholder>" + $"{Environment.NewLine} <method placeholder>" +
$"{Environment.NewLine} }}" + $"{Environment.NewLine} }}" +
@ -65,6 +65,7 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp
public override async Task GenerateProxyAsync(GenerateProxyArgs args) public override async Task GenerateProxyAsync(GenerateProxyArgs args)
{ {
CheckFolder(args.Folder);
var projectFilePath = CheckWorkDirectory(args.WorkDirectory); var projectFilePath = CheckWorkDirectory(args.WorkDirectory);
if (args.CommandName == RemoveProxyCommand.Name) if (args.CommandName == RemoveProxyCommand.Name)
@ -90,6 +91,19 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp
await GenerateClientProxyFileAsync(args, controller.Value, appServiceTypes, startupModule.Namespace); 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) private void RemoveClientProxyFile(GenerateProxyArgs args)
@ -140,7 +154,7 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp
continue; continue;
} }
GenerateMethod(actionApiDescription, method, clientProxyBuilder, usingNamespaceList); GenerateMethod(actionApiDescription, appServiceType.Name, method, clientProxyBuilder, usingNamespaceList);
} }
foreach (var usingNamespace in usingNamespaceList) foreach (var usingNamespace in usingNamespaceList)
@ -184,6 +198,7 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp
private void GenerateMethod( private void GenerateMethod(
ActionApiDescriptionModel actionApiDescription, ActionApiDescriptionModel actionApiDescription,
string serviceName,
MethodInfo method, MethodInfo method,
StringBuilder clientProxyBuilder, StringBuilder clientProxyBuilder,
List<string> usingNamespaceList) List<string> usingNamespaceList)
@ -199,7 +214,7 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp
return; return;
} }
GenerateAsynchronousMethod(actionApiDescription, method, returnTypeName, methodBuilder, usingNamespaceList); GenerateAsynchronousMethod(actionApiDescription, serviceName ,method, returnTypeName, methodBuilder, usingNamespaceList);
clientProxyBuilder.Replace(MethodPlaceholder, $"{methodBuilder} {Environment.NewLine} {MethodPlaceholder}"); clientProxyBuilder.Replace(MethodPlaceholder, $"{methodBuilder} {Environment.NewLine} {MethodPlaceholder}");
} }
@ -223,6 +238,7 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp
private void GenerateAsynchronousMethod( private void GenerateAsynchronousMethod(
ActionApiDescriptionModel actionApiDescription, ActionApiDescriptionModel actionApiDescription,
string serviceName,
MethodInfo method, MethodInfo method,
string returnTypeName, string returnTypeName,
StringBuilder methodBuilder, StringBuilder methodBuilder,
@ -239,20 +255,14 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp
methodBuilder.Replace(", )", ")"); methodBuilder.Replace(", )", ")");
methodBuilder.AppendLine(" {"); 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<ActionApiDescriptionModel>(actionApiDescription);");
methodBuilder.AppendLine("");
if (method.ReturnType.GenericTypeArguments.IsNullOrEmpty()) if (method.ReturnType.GenericTypeArguments.IsNullOrEmpty())
{ {
methodBuilder.AppendLine(" await MakeRequestAsync(action, <args>);"); methodBuilder.AppendLine($" await MakeRequestAsync<{serviceName}>(\"{method.Name}\", <args>);");
} }
else else
{ {
methodBuilder.AppendLine($" return await MakeRequestAsync<{returnTypeName.Replace("Task<", string.Empty)}(action, <args>);"); methodBuilder.AppendLine($" return await MakeRequestAsync<{serviceName}, {returnTypeName.Replace("Task<", string.Empty)}(\"{method.Name}\", <args>);");
} }
foreach (var parameter in method.GetParameters()) foreach (var parameter in method.GetParameters())
@ -262,7 +272,6 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp
methodBuilder.Replace(", <args>", string.Empty); methodBuilder.Replace(", <args>", string.Empty);
methodBuilder.Replace(", )", ")"); methodBuilder.Replace(", )", ")");
methodBuilder.AppendLine("");
methodBuilder.AppendLine(" }"); methodBuilder.AppendLine(" }");
} }
@ -371,6 +380,14 @@ namespace Volo.Abp.Cli.ServiceProxy.CSharp
return projectFiles.First(); 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) private Type GetStartupModule(string assemblyPath)
{ {
return Assembly return Assembly

90
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxyBase.cs

@ -1,27 +1,61 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.FileProviders;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.Http.Modeling; using Volo.Abp.Http.Modeling;
using Volo.Abp.Json; using Volo.Abp.Json;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Http.Client namespace Volo.Abp.Http.Client
{ {
public class ClientProxyBase<TService> : ITransientDependency public class ClientProxyBase : ITransientDependency
{ {
public const string ApiDescriptionCacheKey = "client-proxy";
public IAbpLazyServiceProvider LazyServiceProvider { get; set; } public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
protected IHttpProxyExecuter HttpProxyExecuter => LazyServiceProvider.LazyGetRequiredService<IHttpProxyExecuter>(); protected IHttpProxyExecuter HttpProxyExecuter => LazyServiceProvider.LazyGetRequiredService<IHttpProxyExecuter>();
protected IJsonSerializer JsonSerializer => LazyServiceProvider.LazyGetRequiredService<IJsonSerializer>(); protected IJsonSerializer JsonSerializer => LazyServiceProvider.LazyGetRequiredService<IJsonSerializer>();
protected IApiDescriptionCache ApiDescriptionCache => LazyServiceProvider.LazyGetRequiredService<ApiDescriptionCache>();
protected IVirtualFileProvider VirtualFileProvider => LazyServiceProvider.LazyGetRequiredService<VirtualFileProvider>();
protected virtual async Task MakeRequestAsync(ActionApiDescriptionModel action, params object[] arguments) protected static readonly Dictionary<string, ActionApiDescriptionModel> ActionApiDescriptionModels = new Dictionary<string, ActionApiDescriptionModel>();
protected virtual async Task MakeRequestAsync<TService>(string methodName, params object[] arguments)
{ {
await HttpProxyExecuter.MakeRequestAsync(new HttpProxyExecuterContext(action, BuildArguments(action, arguments), typeof(TService))); await HttpProxyExecuter.MakeRequestAsync(await BuildHttpProxyExecuterContext<TService>(methodName, arguments));
} }
protected virtual async Task<T> MakeRequestAsync<T>(ActionApiDescriptionModel action, params object[] arguments) protected virtual async Task<T> MakeRequestAsync<TService,T>(string methodName, params object[] arguments)
{ {
return await HttpProxyExecuter.MakeRequestAndGetResultAsync<T>(new HttpProxyExecuterContext(action, BuildArguments(action, arguments), typeof(TService))); return await HttpProxyExecuter.MakeRequestAndGetResultAsync<T>(await BuildHttpProxyExecuterContext<TService>(methodName, arguments));
}
protected virtual async Task<HttpProxyExecuterContext> BuildHttpProxyExecuterContext<TService>(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<string, object> BuildArguments(ActionApiDescriptionModel action, object[] arguments) protected virtual Dictionary<string, object> BuildArguments(ActionApiDescriptionModel action, object[] arguments)
@ -36,5 +70,51 @@ namespace Volo.Abp.Http.Client
return dict; return dict;
} }
protected virtual async Task<ApplicationApiDescriptionModel> GetApplicationApiDescriptionModel()
{
var applicationApiDescription = ApplicationApiDescriptionModel.Create();
var fileInfoList = new List<IFileInfo>();
GetGenerateProxyFileInfos(fileInfoList);
foreach (var fileInfo in fileInfoList)
{
using (var streamReader = new StreamReader(fileInfo.CreateReadStream()))
{
var content = await streamReader.ReadToEndAsync();
var subApplicationApiDescription = JsonSerializer.Deserialize<ApplicationApiDescriptionModel>(content);
foreach (var module in subApplicationApiDescription.Modules)
{
if (!applicationApiDescription.Modules.ContainsKey(module.Key))
{
applicationApiDescription.AddModule(module.Value);
}
}
}
}
return applicationApiDescription;
}
private void GetGenerateProxyFileInfos(List<IFileInfo> 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()));
}
}
}
}
} }
} }

6
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Client/MyCompanyName.MyProjectName.HttpApi.Client.csproj

@ -5,12 +5,18 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>MyCompanyName.MyProjectName</RootNamespace> <RootNamespace>MyCompanyName.MyProjectName</RootNamespace>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\MyCompanyName.MyProjectName.Application.Contracts\MyCompanyName.MyProjectName.Application.Contracts.csproj" /> <ProjectReference Include="..\MyCompanyName.MyProjectName.Application.Contracts\MyCompanyName.MyProjectName.Application.Contracts.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="**\*generate-proxy.json" />
<Content Remove="**\*generate-proxy.json" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\..\modules\account\src\Volo.Abp.Account.HttpApi.Client\Volo.Abp.Account.HttpApi.Client.csproj" /> <ProjectReference Include="..\..\..\..\..\modules\account\src\Volo.Abp.Account.HttpApi.Client\Volo.Abp.Account.HttpApi.Client.csproj" />
<ProjectReference Include="..\..\..\..\..\modules\identity\src\Volo.Abp.Identity.HttpApi.Client\Volo.Abp.Identity.HttpApi.Client.csproj" /> <ProjectReference Include="..\..\..\..\..\modules\identity\src\Volo.Abp.Identity.HttpApi.Client\Volo.Abp.Identity.HttpApi.Client.csproj" />

6
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.PermissionManagement;
using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement;
using Volo.Abp.SettingManagement; using Volo.Abp.SettingManagement;
using Volo.Abp.VirtualFileSystem;
namespace MyCompanyName.MyProjectName namespace MyCompanyName.MyProjectName
{ {
@ -28,6 +29,11 @@ namespace MyCompanyName.MyProjectName
typeof(MyProjectNameApplicationContractsModule).Assembly, typeof(MyProjectNameApplicationContractsModule).Assembly,
RemoteServiceName RemoteServiceName
); );
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<MyProjectNameHttpApiClientModule>();
});
} }
} }
} }

Loading…
Cancel
Save