mirror of https://github.com/abpframework/abp.git
11 changed files with 286 additions and 244 deletions
@ -1,128 +0,0 @@ |
|||||
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 const string ApiDescriptionCacheKey = "client-proxy"; |
|
||||
public IAbpLazyServiceProvider LazyServiceProvider { get; set; } |
|
||||
|
|
||||
protected IHttpProxyExecuter HttpProxyExecuter => LazyServiceProvider.LazyGetRequiredService<IHttpProxyExecuter>(); |
|
||||
protected IJsonSerializer JsonSerializer => LazyServiceProvider.LazyGetRequiredService<IJsonSerializer>(); |
|
||||
protected IApiDescriptionCache ApiDescriptionCache => LazyServiceProvider.LazyGetRequiredService<ApiDescriptionCache>(); |
|
||||
protected IVirtualFileProvider VirtualFileProvider => LazyServiceProvider.LazyGetRequiredService<VirtualFileProvider>(); |
|
||||
|
|
||||
protected static readonly Dictionary<string, ActionApiDescriptionModel> ActionApiDescriptionModels = new Dictionary<string, ActionApiDescriptionModel>(); |
|
||||
|
|
||||
private static object SyncLock = new object(); |
|
||||
|
|
||||
protected virtual async Task MakeRequestAsync<TService>(string methodName, params object[] arguments) |
|
||||
{ |
|
||||
await HttpProxyExecuter.MakeRequestAsync(await BuildHttpProxyExecuterContext<TService>(methodName, arguments)); |
|
||||
} |
|
||||
|
|
||||
protected virtual async Task<T> MakeRequestAsync<TService,T>(string methodName, params object[] arguments) |
|
||||
{ |
|
||||
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(); |
|
||||
|
|
||||
lock (SyncLock) |
|
||||
{ |
|
||||
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) |
|
||||
{ |
|
||||
if (!ActionApiDescriptionModels.ContainsKey($"{appServiceType}.{actionItem.Name}")) |
|
||||
{ |
|
||||
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) |
|
||||
{ |
|
||||
var parameters = action.Parameters.GroupBy(x => x.NameOnMethod).Select(x => x.Key).ToList(); |
|
||||
var dict = new Dictionary<string, object>(); |
|
||||
|
|
||||
for (var i = 0; i < parameters.Count; i++) |
|
||||
{ |
|
||||
dict[parameters[i]] = arguments[i]; |
|
||||
} |
|
||||
|
|
||||
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())); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,105 @@ |
|||||
|
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.Modeling; |
||||
|
using Volo.Abp.Json; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace Volo.Abp.Http.Client.ClientProxying |
||||
|
{ |
||||
|
public class ClientProxyApiDescriptionFinder : IClientProxyApiDescriptionFinder, ISingletonDependency |
||||
|
{ |
||||
|
protected IVirtualFileProvider VirtualFileProvider { get; } |
||||
|
protected IJsonSerializer JsonSerializer { get; } |
||||
|
protected Dictionary<string, ActionApiDescriptionModel> ActionApiDescriptionModels { get; } |
||||
|
protected ApplicationApiDescriptionModel ApplicationApiDescriptionModel { get; set; } |
||||
|
|
||||
|
public ClientProxyApiDescriptionFinder( |
||||
|
IVirtualFileProvider virtualFileProvider, |
||||
|
IJsonSerializer jsonSerializer) |
||||
|
{ |
||||
|
VirtualFileProvider = virtualFileProvider; |
||||
|
JsonSerializer = jsonSerializer; |
||||
|
ActionApiDescriptionModels = new Dictionary<string, ActionApiDescriptionModel>(); |
||||
|
|
||||
|
Initial(); |
||||
|
} |
||||
|
|
||||
|
public Task<ActionApiDescriptionModel> FindActionAsync(string action) |
||||
|
{ |
||||
|
return Task.FromResult(ActionApiDescriptionModels[action]); |
||||
|
} |
||||
|
|
||||
|
public Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync() |
||||
|
{ |
||||
|
return Task.FromResult(ApplicationApiDescriptionModel); |
||||
|
} |
||||
|
|
||||
|
private void Initial() |
||||
|
{ |
||||
|
ApplicationApiDescriptionModel = GetApplicationApiDescriptionModel(); |
||||
|
var controllers = ApplicationApiDescriptionModel.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; |
||||
|
|
||||
|
foreach (var actionItem in controller.Actions.Values) |
||||
|
{ |
||||
|
if (!ActionApiDescriptionModels.ContainsKey($"{appServiceType}.{actionItem.Name}")) |
||||
|
{ |
||||
|
ActionApiDescriptionModels.Add($"{appServiceType}.{actionItem.Name}", actionItem); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private 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 = streamReader.ReadToEnd(); |
||||
|
|
||||
|
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())); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Http.Modeling; |
||||
|
|
||||
|
namespace Volo.Abp.Http.Client.ClientProxying |
||||
|
{ |
||||
|
public class ClientProxyBase<TService> : ITransientDependency |
||||
|
{ |
||||
|
public IAbpLazyServiceProvider LazyServiceProvider { get; set; } |
||||
|
|
||||
|
protected IHttpProxyExecuter HttpProxyExecuter => LazyServiceProvider.LazyGetRequiredService<IHttpProxyExecuter>(); |
||||
|
protected IClientProxyApiDescriptionFinder ClientProxyApiDescriptionFinder => LazyServiceProvider.LazyGetRequiredService<IClientProxyApiDescriptionFinder>(); |
||||
|
|
||||
|
protected virtual async Task RequestAsync(string methodName, params object[] arguments) |
||||
|
{ |
||||
|
await HttpProxyExecuter.MakeRequestAsync(await BuildHttpProxyExecuterContext(methodName, arguments)); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<T> RequestAsync<T>(string methodName, params object[] arguments) |
||||
|
{ |
||||
|
return await HttpProxyExecuter.MakeRequestAndGetResultAsync<T>(await BuildHttpProxyExecuterContext(methodName, arguments)); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<HttpProxyExecuterContext> BuildHttpProxyExecuterContext(string methodName, params object[] arguments) |
||||
|
{ |
||||
|
var actionDescriptionKey = $"{typeof(TService).FullName}.{methodName}"; |
||||
|
var action = await ClientProxyApiDescriptionFinder.FindActionAsync(actionDescriptionKey); |
||||
|
|
||||
|
return new HttpProxyExecuterContext(action, BuildArguments(action, arguments), typeof(TService)); |
||||
|
} |
||||
|
|
||||
|
protected virtual Dictionary<string, object> BuildArguments(ActionApiDescriptionModel action, object[] arguments) |
||||
|
{ |
||||
|
var parameters = action.Parameters.GroupBy(x => x.NameOnMethod).Select(x => x.Key).ToList(); |
||||
|
var dict = new Dictionary<string, object>(); |
||||
|
|
||||
|
for (var i = 0; i < parameters.Count; i++) |
||||
|
{ |
||||
|
dict[parameters[i]] = arguments[i]; |
||||
|
} |
||||
|
|
||||
|
return dict; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Http.Modeling; |
||||
|
|
||||
|
namespace Volo.Abp.Http.Client.ClientProxying |
||||
|
{ |
||||
|
public interface IClientProxyApiDescriptionFinder |
||||
|
{ |
||||
|
Task<ActionApiDescriptionModel> FindActionAsync(string action); |
||||
|
|
||||
|
Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync(); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue