Browse Source

#1403: Simplify ApiDescriptionCache

pull/1406/head
Halil İbrahim Kalkan 7 years ago
parent
commit
5636dd4fb5
  1. 1
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ISingletonDependency.cs
  2. 44
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs
  3. 54
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs
  4. 7
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionCache.cs
  5. 2
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApiDescriptionFinder.cs
  6. 1
      framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs

1
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ISingletonDependency.cs

@ -2,5 +2,6 @@
{ {
public interface ISingletonDependency public interface ISingletonDependency
{ {
} }
} }

44
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs

@ -2,8 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Nito.AsyncEx; using Nito.AsyncEx;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Modeling; using Volo.Abp.Http.Modeling;
@ -12,55 +10,29 @@ namespace Volo.Abp.Http.Client.DynamicProxying
{ {
public class ApiDescriptionCache : IApiDescriptionCache, ISingletonDependency public class ApiDescriptionCache : IApiDescriptionCache, ISingletonDependency
{ {
private readonly IDynamicProxyHttpClientFactory _httpClientFactory;
private readonly Dictionary<string, ApplicationApiDescriptionModel> _cache; private readonly Dictionary<string, ApplicationApiDescriptionModel> _cache;
private readonly AsyncLock _asyncLock; private readonly SemaphoreSlim _semaphoreSlim;
public ApiDescriptionCache(IDynamicProxyHttpClientFactory httpClientFactory) public ApiDescriptionCache()
{ {
_httpClientFactory = httpClientFactory;
_cache = new Dictionary<string, ApplicationApiDescriptionModel>(); _cache = new Dictionary<string, ApplicationApiDescriptionModel>();
_asyncLock = new AsyncLock(); _semaphoreSlim = new SemaphoreSlim(1, 1);
} }
public async Task<ApplicationApiDescriptionModel> GetAsync(string baseUrl, CancellationToken cancellationToken = default) public async Task<ApplicationApiDescriptionModel> GetAsync(
string baseUrl,
Func<Task<ApplicationApiDescriptionModel>> factory)
{ {
using (await _asyncLock.LockAsync(cancellationToken)) using (await _semaphoreSlim.LockAsync())
{ {
var model = _cache.GetOrDefault(baseUrl); var model = _cache.GetOrDefault(baseUrl);
if (model == null) if (model == null)
{ {
_cache[baseUrl] = model = await GetFromServerAsync(baseUrl); _cache[baseUrl] = model = await factory();
} }
return model; return model;
} }
} }
private async Task<ApplicationApiDescriptionModel> 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;
}
}
} }
} }

54
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs

@ -2,23 +2,34 @@
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Modeling; using Volo.Abp.Http.Modeling;
using Volo.Abp.Threading;
namespace Volo.Abp.Http.Client.DynamicProxying namespace Volo.Abp.Http.Client.DynamicProxying
{ {
public class ApiDescriptionFinder : IApiDescriptionFinder, ISingletonDependency 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<ActionApiDescriptionModel> FindActionAsync(string baseUrl, Type serviceType, MethodInfo method) public async Task<ActionApiDescriptionModel> FindActionAsync(string baseUrl, Type serviceType, MethodInfo method)
{ {
var apiDescription = await _descriptionCache.GetAsync(baseUrl); var apiDescription = await GetApiDescriptionAsync(baseUrl);
//TODO: Cache finding? //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<ApplicationApiDescriptionModel> GetApiDescriptionAsync(string baseUrl)
{
return await Cache.GetAsync(baseUrl, () => GetApiDescriptionFromServerAsync(baseUrl));
}
protected virtual async Task<ApplicationApiDescriptionModel> 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;
}
} }
} }
} }

7
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 System.Threading.Tasks;
using Volo.Abp.Http.Modeling; using Volo.Abp.Http.Modeling;
@ -6,6 +6,9 @@ namespace Volo.Abp.Http.Client.DynamicProxying
{ {
public interface IApiDescriptionCache public interface IApiDescriptionCache
{ {
Task<ApplicationApiDescriptionModel> GetAsync(string baseUrl, CancellationToken cancellationToken = default); Task<ApplicationApiDescriptionModel> GetAsync(
string baseUrl,
Func<Task<ApplicationApiDescriptionModel>> factory
);
} }
} }

2
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 public interface IApiDescriptionFinder
{ {
Task<ActionApiDescriptionModel> FindActionAsync(string baseUrl, Type serviceType, MethodInfo invocationMethod); Task<ActionApiDescriptionModel> FindActionAsync(string baseUrl, Type serviceType, MethodInfo invocationMethod);
Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync(string baseUrl);
} }
} }

1
framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs

@ -2,5 +2,6 @@
{ {
public interface IAmbientUnitOfWork : IUnitOfWorkAccessor public interface IAmbientUnitOfWork : IUnitOfWorkAccessor
{ {
} }
} }
Loading…
Cancel
Save