Browse Source

Created IApplicationApiDescriptionModelCache

pull/96/head
Halil İbrahim Kalkan 9 years ago
parent
commit
819eb7f0a4
  1. 4
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/AbpApiDefinitionController.cs
  2. 41
      src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs
  3. 32
      src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpProxyExtensions.cs
  4. 16
      src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpOptions.cs
  5. 66
      src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelCache.cs
  6. 17
      src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpClientProxyConfig.cs
  7. 30
      src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs
  8. 13
      src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelCache.cs
  9. 2
      src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs
  10. 1
      src/Volo.Abp/Volo.Abp.csproj

4
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs → src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/AbpApiDefinitionController.cs

@ -4,11 +4,11 @@ using Volo.Abp.Http.Modeling;
namespace Volo.Abp.AspNetCore.Mvc.Controllers
{
[Area("abp")]
public class ApiDefinitionController : AbpController
public class AbpApiDefinitionController : AbpController
{
private readonly IApiDescriptionModelProvider _modelProvider;
public ApiDefinitionController(IApiDescriptionModelProvider modelProvider)
public AbpApiDefinitionController(IApiDescriptionModelProvider modelProvider)
{
_modelProvider = modelProvider;
}

41
src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs

@ -0,0 +1,41 @@
using System;
using Castle.DynamicProxy;
using Volo.Abp.Castle.DynamicProxy;
using Volo.Abp.Http;
using Volo.Abp.Http.DynamicProxying;
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionDynamicHttpClientProxyExtensions
{
private static readonly ProxyGenerator ProxyGeneratorInstance = new ProxyGenerator();
//TODO: AddHttpClientProxies for adding all services from single assembly!
public static IServiceCollection AddHttpClientProxy<T>(this IServiceCollection services, string baseUrl)
{
return services.AddHttpClientProxy(typeof(T), baseUrl);
}
public static IServiceCollection AddHttpClientProxy(this IServiceCollection services, Type type, string baseUrl)
{
services.Configure<AbpHttpOptions>(options =>
{
options.HttpClientProxies[type] = new DynamicHttpClientProxyConfig(type, baseUrl);
});
var interceptorType = typeof(DynamicHttpProxyInterceptor<>).MakeGenericType(type);
services.AddTransient(interceptorType);
var interceptorAdapterType = typeof(CastleAbpInterceptorAdapter<>).MakeGenericType(interceptorType);
return services.AddTransient(
type,
serviceProvider => ProxyGeneratorInstance
.CreateInterfaceProxyWithoutTarget(
type,
(IInterceptor) serviceProvider.GetRequiredService(interceptorAdapterType)
)
);
}
}
}

32
src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpProxyExtensions.cs

@ -1,32 +0,0 @@
using System;
using Castle.DynamicProxy;
using Volo.Abp.Castle.DynamicProxy;
using Volo.Abp.Http;
using Volo.Abp.Http.DynamicProxying;
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionHttpProxyExtensions
{
private static readonly ProxyGenerator ProxyGeneratorInstance = new ProxyGenerator();
public static IServiceCollection AddHttpClientProxy<T>(this IServiceCollection services, string baseUrl)
{
return services.AddHttpClientProxy(typeof(T), baseUrl);
}
public static IServiceCollection AddHttpClientProxy(this IServiceCollection services, Type type, string baseUrl)
{
services.AddTransient(type, serviceProvider =>
{
return ProxyGeneratorInstance
.CreateInterfaceProxyWithoutTarget(
type,
serviceProvider.GetRequiredService<CastleAbpInterceptorAdapter<DynamicHttpProxyInterceptor>>()
);
});
return services;
}
}
}

16
src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpOptions.cs

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Http.DynamicProxying;
namespace Volo.Abp.Http
{
public class AbpHttpOptions
{
public Dictionary<Type, DynamicHttpClientProxyConfig> HttpClientProxies { get; set; }
public AbpHttpOptions()
{
HttpClientProxies = new Dictionary<Type, DynamicHttpClientProxyConfig>();
}
}
}

66
src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelCache.cs

@ -0,0 +1,66 @@
using System;
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;
namespace Volo.Abp.Http.DynamicProxying
{
public class ApplicationApiDescriptionModelCache : IApplicationApiDescriptionModelCache, ISingletonDependency
{
private readonly IDynamicProxyHttpClientFactory _httpClientFactory;
private readonly Dictionary<string, ApplicationApiDescriptionModel> _cache;
private readonly AsyncLock _asyncLock;
public ApplicationApiDescriptionModelCache(IDynamicProxyHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
_cache = new Dictionary<string, ApplicationApiDescriptionModel>();
_asyncLock = new AsyncLock();
}
public async Task<ApplicationApiDescriptionModel> GetAsync(string baseUrl, CancellationToken cancellationToken = default(CancellationToken))
{
using (await _asyncLock.LockAsync(cancellationToken))
{
var model = _cache.GetOrDefault(baseUrl);
if (model == null)
{
_cache[baseUrl] = model = await GetModelFromRemoteServer(baseUrl);
}
return model;
}
}
private async Task<ApplicationApiDescriptionModel> GetModelFromRemoteServer(string baseUrl)
{
using (var client = _httpClientFactory.Create())
{
var response = await client.GetAsync(baseUrl + "api/abp/api-description");
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;
}
}
}
}

17
src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpClientProxyConfig.cs

@ -0,0 +1,17 @@
using System;
namespace Volo.Abp.Http.DynamicProxying
{
public class DynamicHttpClientProxyConfig
{
public Type Type { get; }
public string BaseUrl { get; }
public DynamicHttpClientProxyConfig(Type type, string baseUrl)
{
Type = type;
BaseUrl = baseUrl;
}
}
}

30
src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs

@ -1,36 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Threading;
namespace Volo.Abp.Http.DynamicProxying
{
public class DynamicHttpProxyInterceptor : AbpInterceptor, ITransientDependency
public class DynamicHttpProxyInterceptor<TService> : AbpInterceptor, ITransientDependency
{
private readonly IDynamicProxyHttpClientFactory _httpClientFactory;
private static readonly MethodInfo GenericInterceptAsyncMethod;
private readonly IDynamicProxyHttpClientFactory _httpClientFactory;
private readonly IApplicationApiDescriptionModelCache _discoverManager;
private readonly AbpHttpOptions _options;
static DynamicHttpProxyInterceptor()
{
GenericInterceptAsyncMethod = typeof(DynamicHttpProxyInterceptor)
GenericInterceptAsyncMethod = typeof(DynamicHttpProxyInterceptor<TService>)
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.First(m => m.Name == nameof(InterceptAsync) && m.IsGenericMethodDefinition);
}
public DynamicHttpProxyInterceptor(IDynamicProxyHttpClientFactory httpClientFactory)
public DynamicHttpProxyInterceptor(
IDynamicProxyHttpClientFactory httpClientFactory,
IOptions<AbpHttpOptions> options,
IApplicationApiDescriptionModelCache discoverManager)
{
_httpClientFactory = httpClientFactory;
_discoverManager = discoverManager;
_options = options.Value;
}
public override void Intercept(IAbpMethodInvocation invocation)
{
throw new System.NotImplementedException();
AsyncHelper.RunSync(() => InterceptAsync(invocation));
}
public override Task InterceptAsync(IAbpMethodInvocation invocation)
@ -44,6 +54,14 @@ namespace Volo.Abp.Http.DynamicProxying
private async Task<T> InterceptAsync<T>(IAbpMethodInvocation invocation)
{
var config = _options.HttpClientProxies.GetOrDefault(typeof(TService));
if (config == null)
{
throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(T).FullName}.");
}
var apiDescriptionModel = await _discoverManager.GetAsync(config.BaseUrl);
using (var client = _httpClientFactory.Create())
{
var response = await client.GetAsync("/api/app/people");

13
src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelCache.cs

@ -0,0 +1,13 @@
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Http.Modeling;
namespace Volo.Abp.Http.DynamicProxying
{
public interface IApplicationApiDescriptionModelCache
{
Task<ApplicationApiDescriptionModel> GetAsync(string baseUrl, CancellationToken cancellationToken = default(CancellationToken));
}
}

2
src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs

@ -43,7 +43,7 @@ namespace Volo.Abp.Http.Modeling
public ControllerApiDescriptionModel CreateSubModel(string[] actions)
{
var subModel = new ControllerApiDescriptionModel(Name);
var subModel = new ControllerApiDescriptionModel(Name, Type);
foreach (var action in Actions.Values)
{

1
src/Volo.Abp/Volo.Abp.csproj

@ -16,6 +16,7 @@
<PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Nito.AsyncEx.Coordination" Version="1.0.2" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.4.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.4.0" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />

Loading…
Cancel
Save