diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ISingletonDependency.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ISingletonDependency.cs index 286648fde2..14a5332a29 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ISingletonDependency.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ISingletonDependency.cs @@ -2,5 +2,6 @@ { public interface ISingletonDependency { + } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs index a865dd7a48..aadb0415ab 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; using Nito.AsyncEx; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Modeling; @@ -12,55 +10,29 @@ namespace Volo.Abp.Http.Client.DynamicProxying { public class ApiDescriptionCache : IApiDescriptionCache, ISingletonDependency { - private readonly IDynamicProxyHttpClientFactory _httpClientFactory; - private readonly Dictionary _cache; - private readonly AsyncLock _asyncLock; + private readonly SemaphoreSlim _semaphoreSlim; - public ApiDescriptionCache(IDynamicProxyHttpClientFactory httpClientFactory) + public ApiDescriptionCache() { - _httpClientFactory = httpClientFactory; - _cache = new Dictionary(); - _asyncLock = new AsyncLock(); + _semaphoreSlim = new SemaphoreSlim(1, 1); } - public async Task GetAsync(string baseUrl, CancellationToken cancellationToken = default) + public async Task GetAsync( + string baseUrl, + Func> factory) { - using (await _asyncLock.LockAsync(cancellationToken)) + using (await _semaphoreSlim.LockAsync()) { var model = _cache.GetOrDefault(baseUrl); if (model == null) { - _cache[baseUrl] = model = await GetFromServerAsync(baseUrl); + _cache[baseUrl] = model = await factory(); } return model; } } - - private async Task GetFromServerAsync(string baseUrl) - { - using (var client = _httpClientFactory.Create()) - { - var response = await client.GetAsync(baseUrl.EnsureEndsWith('/') + "api/abp/api-definition"); - if (!response.IsSuccessStatusCode) - { - throw new AbpException("Remote service returns error!"); - } - - var content = await response.Content.ReadAsStringAsync(); - - var result = JsonConvert.DeserializeObject( - content, - typeof(ApplicationApiDescriptionModel), - new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver() - }); - - return (ApplicationApiDescriptionModel)result; - } - } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs index 34df0deecb..d65818bd41 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs @@ -2,23 +2,34 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Modeling; +using Volo.Abp.Threading; namespace Volo.Abp.Http.Client.DynamicProxying { public class ApiDescriptionFinder : IApiDescriptionFinder, ISingletonDependency { - private readonly IApiDescriptionCache _descriptionCache; + public ICancellationTokenProvider CancellationTokenProvider { get; set; } - public ApiDescriptionFinder(IApiDescriptionCache descriptionCache) + protected IDynamicProxyHttpClientFactory HttpClientFactory { get; } + + protected IApiDescriptionCache Cache { get; } + + public ApiDescriptionFinder( + IApiDescriptionCache cache, + IDynamicProxyHttpClientFactory httpClientFactory) { - _descriptionCache = descriptionCache; + Cache = cache; + HttpClientFactory = httpClientFactory; + CancellationTokenProvider = NullCancellationTokenProvider.Instance; } public async Task FindActionAsync(string baseUrl, Type serviceType, MethodInfo method) { - var apiDescription = await _descriptionCache.GetAsync(baseUrl); + var apiDescription = await GetApiDescriptionAsync(baseUrl); //TODO: Cache finding? @@ -57,7 +68,40 @@ namespace Volo.Abp.Http.Client.DynamicProxying } } - throw new AbpException("Could not found remote action for method: " + method); + throw new AbpException($"Could not found remote action for method: {method} on the URL: {baseUrl}"); + } + + public virtual async Task GetApiDescriptionAsync(string baseUrl) + { + return await Cache.GetAsync(baseUrl, () => GetApiDescriptionFromServerAsync(baseUrl)); + } + + protected virtual async Task GetApiDescriptionFromServerAsync(string baseUrl) + { + using (var client = HttpClientFactory.Create()) + { + var response = await client.GetAsync( + baseUrl.EnsureEndsWith('/') + "api/abp/api-definition", + CancellationTokenProvider.Token + ); + + if (!response.IsSuccessStatusCode) + { + throw new AbpException("Remote service returns error!"); + } + + var content = await response.Content.ReadAsStringAsync(); + + var result = JsonConvert.DeserializeObject( + content, + typeof(ApplicationApiDescriptionModel), + new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver() + }); + + return (ApplicationApiDescriptionModel)result; + } } } } diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionCache.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionCache.cs index aedaee8bd8..3eb334633f 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionCache.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionCache.cs @@ -1,4 +1,4 @@ -using System.Threading; +using System; using System.Threading.Tasks; using Volo.Abp.Http.Modeling; @@ -6,6 +6,9 @@ namespace Volo.Abp.Http.Client.DynamicProxying { public interface IApiDescriptionCache { - Task GetAsync(string baseUrl, CancellationToken cancellationToken = default); + Task GetAsync( + string baseUrl, + Func> factory + ); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionFinder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionFinder.cs index ede988b4b9..010d55706e 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionFinder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionFinder.cs @@ -8,5 +8,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying public interface IApiDescriptionFinder { Task FindActionAsync(string baseUrl, Type serviceType, MethodInfo invocationMethod); + + Task GetApiDescriptionAsync(string baseUrl); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs index 2293eecc44..b613ccec59 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs @@ -2,5 +2,6 @@ { public interface IAmbientUnitOfWork : IUnitOfWorkAccessor { + } } \ No newline at end of file