From c3efe16f98139d7c01c9908ae68a26219eac10a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 13 Sep 2017 16:36:51 +0300 Subject: [PATCH 01/12] Worked on dynamic http proxying --- .../Volo.Abp.AspNetCore.TestBase.csproj | 1 + .../AbpAspNetCoreIntegratedTestBase.cs | 4 +- .../TestBase/AbpAspNetCoreTestBaseModule.cs | 2 + ...etCoreTestDynamicProxyHttpClientFactory.cs | 22 +++++++ .../TestBase/ITestServerAccessor.cs | 9 +++ .../AspNetCore/TestBase/TestServerAccessor.cs | 10 +++ .../CastleAbpInterceptorAdapter.cs | 4 +- .../CastleAbpMethodInvocationAdapter.cs | 2 +- .../ServiceCollectionHttpProxyExtensions.cs | 32 +++++++++ src/Volo.Abp.Http/Volo.Abp.Http.csproj | 1 + .../DefaultDynamicProxyHttpClientFactory.cs | 13 ++++ .../DynamicHttpProxyInterceptor.cs | 66 +++++++++++++++++++ .../IDynamicProxyHttpClientFactory.cs | 9 +++ .../Volo/Abp/AspNetCore/AppTestBase.cs | 2 +- .../Volo/Abp/Http/AbpHttpTestBase.cs | 1 + .../Volo/Abp/Http/AbpHttpTestModule.cs | 8 ++- .../PersonAppServiceClientProxy_Tests.cs | 1 - 17 files changed, 180 insertions(+), 7 deletions(-) create mode 100644 src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestDynamicProxyHttpClientFactory.cs create mode 100644 src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/ITestServerAccessor.cs create mode 100644 src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/TestServerAccessor.cs create mode 100644 src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpProxyExtensions.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IDynamicProxyHttpClientFactory.cs diff --git a/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj b/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj index c6ff8966ba..49b7547607 100644 --- a/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj +++ b/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj @@ -13,6 +13,7 @@ + diff --git a/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs index 4f9da35c91..81c85197b1 100644 --- a/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs +++ b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreIntegratedTestBase.cs @@ -5,6 +5,7 @@ using System.Net.Http; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; namespace Volo.Abp.AspNetCore.TestBase { @@ -22,8 +23,9 @@ namespace Volo.Abp.AspNetCore.TestBase var builder = CreateWebHostBuilder(); Server = CreateTestServer(builder); Client = Server.CreateClient(); - ServiceProvider = Server.Host.Services; + + ServiceProvider.GetRequiredService().Server = Server; } protected virtual IWebHostBuilder CreateWebHostBuilder() diff --git a/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreTestBaseModule.cs b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreTestBaseModule.cs index 6f98ab1614..ddd6324780 100644 --- a/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreTestBaseModule.cs +++ b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreTestBaseModule.cs @@ -1,8 +1,10 @@ using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Http; using Volo.Abp.Modularity; namespace Volo.Abp.AspNetCore.TestBase { + [DependsOn(typeof(AbpHttpModule))] [DependsOn(typeof(AbpAspNetCoreModule))] public class AbpAspNetCoreTestBaseModule : AbpModule { diff --git a/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestDynamicProxyHttpClientFactory.cs b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestDynamicProxyHttpClientFactory.cs new file mode 100644 index 0000000000..8830c34c20 --- /dev/null +++ b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestDynamicProxyHttpClientFactory.cs @@ -0,0 +1,22 @@ +using System.Net.Http; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.DynamicProxying; + +namespace Volo.Abp.AspNetCore.TestBase.DynamicProxying +{ + [Dependency(ReplaceServices = true)] + public class AspNetCoreTestDynamicProxyHttpClientFactory : IDynamicProxyHttpClientFactory, ITransientDependency + { + private readonly ITestServerAccessor _testServerAccessor; + + public AspNetCoreTestDynamicProxyHttpClientFactory(ITestServerAccessor testServerAccessor) + { + _testServerAccessor = testServerAccessor; + } + + public HttpClient Create() + { + return _testServerAccessor.Server.CreateClient(); + } + } +} diff --git a/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/ITestServerAccessor.cs b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/ITestServerAccessor.cs new file mode 100644 index 0000000000..86247877cb --- /dev/null +++ b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/ITestServerAccessor.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.TestHost; + +namespace Volo.Abp.AspNetCore.TestBase +{ + public interface ITestServerAccessor + { + TestServer Server { get; set; } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/TestServerAccessor.cs b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/TestServerAccessor.cs new file mode 100644 index 0000000000..f848529536 --- /dev/null +++ b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/TestServerAccessor.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.TestHost; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.TestBase +{ + public class TestServerAccessor : ITestServerAccessor, ISingletonDependency + { + public TestServer Server { get; set; } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs b/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs index 56675ec73f..1b1b958ff1 100644 --- a/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs +++ b/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpInterceptorAdapter.cs @@ -17,7 +17,9 @@ namespace Volo.Abp.Castle.DynamicProxy public void Intercept(IInvocation invocation) { - if (invocation.MethodInvocationTarget.IsAsync()) + var method = invocation.MethodInvocationTarget ?? invocation.Method; + + if (method.IsAsync()) { InterceptAsyncMethod(invocation); } diff --git a/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs b/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs index 2ce330ec66..6758f138b0 100644 --- a/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs +++ b/src/Volo.Abp.Castle.Core/Volo/Abp/Castle/DynamicProxy/CastleAbpMethodInvocationAdapter.cs @@ -15,7 +15,7 @@ namespace Volo.Abp.Castle.DynamicProxy public object TargetObject => Invocation.InvocationTarget; - public MethodInfo Method => Invocation.MethodInvocationTarget; + public MethodInfo Method => Invocation.MethodInvocationTarget ?? Invocation.Method; public object ReturnValue { diff --git a/src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpProxyExtensions.cs b/src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpProxyExtensions.cs new file mode 100644 index 0000000000..0470a4bffd --- /dev/null +++ b/src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpProxyExtensions.cs @@ -0,0 +1,32 @@ +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(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>() + ); + }); + + return services; + } + } +} diff --git a/src/Volo.Abp.Http/Volo.Abp.Http.csproj b/src/Volo.Abp.Http/Volo.Abp.Http.csproj index 475e1a8af2..181e749dfc 100644 --- a/src/Volo.Abp.Http/Volo.Abp.Http.csproj +++ b/src/Volo.Abp.Http/Volo.Abp.Http.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs new file mode 100644 index 0000000000..ccdafae17e --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs @@ -0,0 +1,13 @@ +using System.Net.Http; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Http.DynamicProxying +{ + public class DefaultDynamicProxyHttpClientFactory : IDynamicProxyHttpClientFactory, ITransientDependency + { + public HttpClient Create() + { + return new HttpClient(); + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs new file mode 100644 index 0000000000..924f8bc8c5 --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs @@ -0,0 +1,66 @@ +using System; +using System.Linq; +using System.Net.Http; +using System.Reflection; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Volo.Abp.DependencyInjection; +using Volo.Abp.DynamicProxy; + +namespace Volo.Abp.Http.DynamicProxying +{ + public class DynamicHttpProxyInterceptor : AbpInterceptor, ITransientDependency + { + private readonly IDynamicProxyHttpClientFactory _httpClientFactory; + + public DynamicHttpProxyInterceptor(IDynamicProxyHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; + } + + public override void Intercept(IAbpMethodInvocation invocation) + { + throw new System.NotImplementedException(); + } + + public override async Task InterceptAsync(IAbpMethodInvocation invocation) + { + var returnTypeWithoutTask = invocation.Method.ReturnType.GenericTypeArguments[0]; + + //var result = await GetResult(client, returnTypeWithoutTask); + + var methods = typeof(DynamicHttpProxyInterceptor).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance); + var getResultMethod = methods + .Where(m => m.Name == nameof(GetResult)) + .First() + .MakeGenericMethod(returnTypeWithoutTask); + + invocation.ReturnValue = getResultMethod.Invoke(this, new object[] { returnTypeWithoutTask }); + } + + private async Task GetResult(Type returnTypeWithoutTask) + { + using (var client = _httpClientFactory.Create()) + { + var response = await client.GetAsync("/api/app/people"); + if (!response.IsSuccessStatusCode) + { + throw new AbpException("Remote service returns error!"); + } + + var content = await response.Content.ReadAsStringAsync(); + + var result = JsonConvert.DeserializeObject( + content, + returnTypeWithoutTask, + new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver() + }); + + return (T)result; + } + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IDynamicProxyHttpClientFactory.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IDynamicProxyHttpClientFactory.cs new file mode 100644 index 0000000000..99691ccc2f --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IDynamicProxyHttpClientFactory.cs @@ -0,0 +1,9 @@ +using System.Net.Http; + +namespace Volo.Abp.Http.DynamicProxying +{ + public interface IDynamicProxyHttpClientFactory + { + HttpClient Create(); + } +} \ No newline at end of file diff --git a/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AppTestBase.cs b/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AppTestBase.cs index d13cb810bf..6bb82c3656 100644 --- a/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AppTestBase.cs +++ b/test/Volo.Abp.AspNetCore.Tests/Volo/Abp/AspNetCore/AppTestBase.cs @@ -6,7 +6,7 @@ using Newtonsoft.Json.Serialization; using Shouldly; using Volo.Abp.AspNetCore.TestBase; -namespace Volo.Abp.AspNetCore.App +namespace Volo.Abp.AspNetCore { public abstract class AbpAspNetCoreTestBase : AbpAspNetCoreIntegratedTestBase where TStartup : class diff --git a/test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestBase.cs b/test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestBase.cs index 35db320555..f950193109 100644 --- a/test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestBase.cs +++ b/test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestBase.cs @@ -1,3 +1,4 @@ +using Volo.Abp.AspNetCore; using Volo.Abp.AspNetCore.App; namespace Volo.Abp.Http diff --git a/test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestModule.cs b/test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestModule.cs index ae2cb91658..8348e729a5 100644 --- a/test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestModule.cs +++ b/test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestModule.cs @@ -1,6 +1,9 @@ -using Microsoft.Extensions.DependencyInjection; +using Castle.DynamicProxy; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.App; +using Volo.Abp.Castle.DynamicProxy; using Volo.Abp.Modularity; +using Volo.Abp.TestApp.Application; namespace Volo.Abp.Http { @@ -9,7 +12,8 @@ namespace Volo.Abp.Http { public override void ConfigureServices(IServiceCollection services) { - services.AddAssemblyOf(); + services.AddAssemblyOf(); + services.AddHttpClientProxy("/"); } } } diff --git a/test/Volo.Abp.Http.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs b/test/Volo.Abp.Http.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs index abd73531c2..4d6c18ceca 100644 --- a/test/Volo.Abp.Http.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs +++ b/test/Volo.Abp.Http.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs @@ -13,7 +13,6 @@ namespace Volo.Abp.Http.DynamicProxying public PersonAppServiceClientProxy_Tests() { - //TODO: Should actually test the proxy! _peopleAppService = ServiceProvider.GetRequiredService(); } From 0bbe78f25eb0fb67d23f5e1691a577d484b10ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 13 Sep 2017 17:03:40 +0300 Subject: [PATCH 02/12] Refactored. --- .../DynamicHttpProxyInterceptor.cs | 27 ++++++++++--------- .../Volo/Abp/Uow/UnitOfWorkInterceptor.cs | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs index 924f8bc8c5..d65c54f866 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs @@ -14,6 +14,16 @@ namespace Volo.Abp.Http.DynamicProxying { private readonly IDynamicProxyHttpClientFactory _httpClientFactory; + private static readonly MethodInfo GenericInterceptAsyncMethod; + private static readonly object[] EmptyObjectArray = new object[0]; + + static DynamicHttpProxyInterceptor() + { + GenericInterceptAsyncMethod = typeof(DynamicHttpProxyInterceptor) + .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) + .First(m => m.Name == nameof(InterceptAsync) && m.IsGenericMethodDefinition); + } + public DynamicHttpProxyInterceptor(IDynamicProxyHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; @@ -27,19 +37,12 @@ namespace Volo.Abp.Http.DynamicProxying public override async Task InterceptAsync(IAbpMethodInvocation invocation) { var returnTypeWithoutTask = invocation.Method.ReturnType.GenericTypeArguments[0]; - - //var result = await GetResult(client, returnTypeWithoutTask); - - var methods = typeof(DynamicHttpProxyInterceptor).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance); - var getResultMethod = methods - .Where(m => m.Name == nameof(GetResult)) - .First() - .MakeGenericMethod(returnTypeWithoutTask); - - invocation.ReturnValue = getResultMethod.Invoke(this, new object[] { returnTypeWithoutTask }); + invocation.ReturnValue = GenericInterceptAsyncMethod + .MakeGenericMethod(returnTypeWithoutTask) + .Invoke(this, EmptyObjectArray); } - private async Task GetResult(Type returnTypeWithoutTask) + private async Task InterceptAsync() { using (var client = _httpClientFactory.Create()) { @@ -53,7 +56,7 @@ namespace Volo.Abp.Http.DynamicProxying var result = JsonConvert.DeserializeObject( content, - returnTypeWithoutTask, + typeof(T), new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() diff --git a/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInterceptor.cs b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInterceptor.cs index 53b6efb2fa..1bf813905a 100644 --- a/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInterceptor.cs +++ b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInterceptor.cs @@ -32,7 +32,7 @@ namespace Volo.Abp.Uow { if (!UnitOfWorkHelper.IsUnitOfWorkMethod(invocation.Method)) { - invocation.Proceed(); + await invocation.ProceedAsync(); return; } From 3714afa33f1268feee97cb80f8662e92dd4d39a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 13 Sep 2017 17:10:09 +0300 Subject: [PATCH 03/12] Minor refactor. --- .../DynamicProxying/DynamicHttpProxyInterceptor.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs index d65c54f866..933c58c9e7 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs @@ -15,7 +15,6 @@ namespace Volo.Abp.Http.DynamicProxying private readonly IDynamicProxyHttpClientFactory _httpClientFactory; private static readonly MethodInfo GenericInterceptAsyncMethod; - private static readonly object[] EmptyObjectArray = new object[0]; static DynamicHttpProxyInterceptor() { @@ -34,15 +33,16 @@ namespace Volo.Abp.Http.DynamicProxying throw new System.NotImplementedException(); } - public override async Task InterceptAsync(IAbpMethodInvocation invocation) + public override Task InterceptAsync(IAbpMethodInvocation invocation) { - var returnTypeWithoutTask = invocation.Method.ReturnType.GenericTypeArguments[0]; invocation.ReturnValue = GenericInterceptAsyncMethod - .MakeGenericMethod(returnTypeWithoutTask) - .Invoke(this, EmptyObjectArray); + .MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0]) + .Invoke(this, new object[]{ invocation }); + + return Task.CompletedTask; } - private async Task InterceptAsync() + private async Task InterceptAsync(IAbpMethodInvocation invocation) { using (var client = _httpClientFactory.Create()) { From d96adba2777fa6031e6f4fdd7af9af8e17df2615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 13 Sep 2017 21:18:50 +0300 Subject: [PATCH 04/12] Added api models and aspnet core model provider. --- .../Properties/AssemblyInfo.cs | 3 + .../Volo.Abp.AspNetCore.Mvc.csproj | 1 + .../Mvc/ActionDescriptorExtensions.cs | 29 ++++ .../AspNetCoreApiDescriptionModelProvider.cs | 149 ++++++++++++++++++ .../Mvc/ControllerAssemblySettingList.cs | 2 +- .../Abp/AspNetCore/Mvc/Utils/ArrayMatcher.cs | 42 +++++ src/Volo.Abp.Http/Volo.Abp.Http.csproj | 4 - .../Modeling/ActionApiDescriptionModel.cs | 40 +++++ .../ApplicationApiDescriptionModel.cs | 47 ++++++ .../Modeling/ControllerApiDescriptionModel.cs | 53 +++++++ .../Modeling/IApiDescriptionModelProvider.cs | 7 + .../Modeling/ModuleApiDescriptionModel.cs | 56 +++++++ .../Modeling/ParameterApiDescriptionModel.cs | 41 +++++ .../ReturnValueApiDescriptionModel.cs | 17 ++ src/Volo.Abp/System/AbpTypeExtensions.cs | 13 -- .../Abp/Modularity/AbpModuleDescriptor.cs | 2 +- .../Volo/Abp/Reflection/AssemblyFinder.cs | 2 +- .../Mvc/Utils/ArrayMacther_Tests.cs | 19 +++ .../Abp/Reflection/AssemblyFinder_Tests.cs | 2 +- .../Volo/Abp/Reflection/TypeFinder_Tests.cs | 4 +- 20 files changed, 510 insertions(+), 23 deletions(-) create mode 100644 src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ActionDescriptorExtensions.cs create mode 100644 src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs create mode 100644 src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Utils/ArrayMatcher.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/Modeling/IApiDescriptionModelProvider.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs delete mode 100644 src/Volo.Abp/System/AbpTypeExtensions.cs create mode 100644 test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Utils/ArrayMacther_Tests.cs diff --git a/src/Volo.Abp.AspNetCore.Mvc/Properties/AssemblyInfo.cs b/src/Volo.Abp.AspNetCore.Mvc/Properties/AssemblyInfo.cs index 214a7fbd4f..61be6f3536 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Properties/AssemblyInfo.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Properties/AssemblyInfo.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -9,6 +10,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyProduct("Volo.Abp.AspNetCore.Mvc")] [assembly: AssemblyTrademark("")] +[assembly:InternalsVisibleTo("Volo.Abp.AspNetCore.Mvc.Tests")] + // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj b/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj index 828bdfbb27..da9a2c3a86 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj @@ -13,6 +13,7 @@ + diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ActionDescriptorExtensions.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ActionDescriptorExtensions.cs new file mode 100644 index 0000000000..e12fae5152 --- /dev/null +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ActionDescriptorExtensions.cs @@ -0,0 +1,29 @@ +using System.Reflection; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Controllers; + +namespace Volo.Abp.AspNetCore.Mvc +{ + public static class ActionDescriptorExtensions + { + public static ControllerActionDescriptor AsControllerActionDescriptor(this ActionDescriptor actionDescriptor) + { + if (!actionDescriptor.IsControllerAction()) + { + throw new AbpException($"{nameof(actionDescriptor)} should be type of {typeof(ControllerActionDescriptor).AssemblyQualifiedName}"); + } + + return actionDescriptor as ControllerActionDescriptor; + } + + public static MethodInfo GetMethodInfo(this ActionDescriptor actionDescriptor) + { + return actionDescriptor.AsControllerActionDescriptor().MethodInfo; + } + + public static bool IsControllerAction(this ActionDescriptor actionDescriptor) + { + return actionDescriptor is ControllerActionDescriptor; + } + } +} diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs new file mode 100644 index 0000000000..cffb5c6f24 --- /dev/null +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs @@ -0,0 +1,149 @@ +using System; +using System.Linq; +using System.Reflection; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Volo.Abp.Application.Services; +using Volo.Abp.AspNetCore.Mvc.Utils; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Modeling; + +namespace Volo.Abp.AspNetCore.Mvc +{ + public class AspNetCoreApiDescriptionModelProvider : IApiDescriptionModelProvider, ISingletonDependency + { + public ILogger Logger { get; set; } + + private readonly IApiDescriptionGroupCollectionProvider _descriptionProvider; + private readonly AbpAspNetCoreMvcOptions _options; + + public AspNetCoreApiDescriptionModelProvider( + IApiDescriptionGroupCollectionProvider descriptionProvider, + IOptions options) + { + _descriptionProvider = descriptionProvider; + _options = options.Value; + + Logger = NullLogger.Instance; + } + + public ApplicationApiDescriptionModel CreateModel() + { + var model = new ApplicationApiDescriptionModel(); + + foreach (var descriptionGroupItem in _descriptionProvider.ApiDescriptionGroups.Items) + { + foreach (var apiDescription in descriptionGroupItem.Items) + { + if (!apiDescription.ActionDescriptor.IsControllerAction()) + { + continue; + } + + AddApiDescriptionToModel(apiDescription, model); + } + } + + return model; + } + + private void AddApiDescriptionToModel(ApiDescription apiDescription, ApplicationApiDescriptionModel model) + { + var moduleModel = model.GetOrAddModule(GetModuleName(apiDescription)); + var controllerModel = moduleModel.GetOrAddController(GetControllerName(apiDescription)); + + var method = apiDescription.ActionDescriptor.GetMethodInfo(); + + if (controllerModel.Actions.ContainsKey(method.Name)) + { + Logger.LogWarning($"Controller '{controllerModel.Name}' contains more than one action with name '{method.Name}' for module '{moduleModel.Name}'. Ignored: " + apiDescription.ActionDescriptor.GetMethodInfo()); + return; + } + + var returnValue = new ReturnValueApiDescriptionModel(method.ReturnType); + + var actionModel = controllerModel.AddAction(new ActionApiDescriptionModel( + method.Name, + returnValue, + apiDescription.RelativePath, + apiDescription.HttpMethod + )); + + AddParameterDescriptionsToModel(actionModel, method, apiDescription); + } + + private static string GetControllerName(ApiDescription apiDescription) + { + return apiDescription.GroupName?.RemovePostFix(ApplicationService.CommonPostfixes) + ?? apiDescription.ActionDescriptor.AsControllerActionDescriptor().ControllerName; + } + + private void AddParameterDescriptionsToModel(ActionApiDescriptionModel actionModel, MethodInfo method, ApiDescription apiDescription) + { + if (!apiDescription.ParameterDescriptions.Any()) + { + return; + } + + var matchedMethodParamNames = ArrayMatcher.Match( + apiDescription.ParameterDescriptions.Select(p => p.Name).ToArray(), + method.GetParameters().Select(GetMethodParamName).ToArray() + ); + + for (var i = 0; i < apiDescription.ParameterDescriptions.Count; i++) + { + var parameterDescription = apiDescription.ParameterDescriptions[i]; + var matchedMethodParamName = matchedMethodParamNames.Length > i + ? matchedMethodParamNames[i] + : parameterDescription.Name; + + actionModel.AddParameter(new ParameterApiDescriptionModel( + parameterDescription.Name, + matchedMethodParamName, + parameterDescription.Type, + parameterDescription.RouteInfo?.IsOptional ?? false, + parameterDescription.RouteInfo?.DefaultValue, + parameterDescription.RouteInfo?.Constraints?.Select(c => c.GetType().Name).ToArray(), + parameterDescription.Source.Id + ) + ); + } + } + + public string GetMethodParamName(ParameterInfo parameterInfo) + { + var modelNameProvider = parameterInfo.GetCustomAttributes() + .OfType() + .FirstOrDefault(); + + if (modelNameProvider == null) + { + return parameterInfo.Name; + } + + return modelNameProvider.Name; + } + + private string GetModuleName(ApiDescription apiDescription) + { + var controllerType = apiDescription.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(); + if (controllerType == null) + { + return AbpControllerAssemblySetting.DefaultServiceModuleName; + } + + foreach (var controllerSetting in _options.AppServiceControllers.ControllerAssemblySettings) + { + if (Equals(controllerType.Assembly, controllerSetting.Assembly)) + { + return controllerSetting.ModuleName; + } + } + + return AbpControllerAssemblySetting.DefaultServiceModuleName; + } + } +} diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ControllerAssemblySettingList.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ControllerAssemblySettingList.cs index 36112a9ccc..c7701994bc 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ControllerAssemblySettingList.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ControllerAssemblySettingList.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.AspNetCore.Mvc [CanBeNull] public AbpControllerAssemblySetting GetSettingOrNull(Type controllerType) { - return this.FirstOrDefault(controllerSetting => controllerSetting.Assembly == controllerType.GetAssembly()); + return this.FirstOrDefault(controllerSetting => controllerSetting.Assembly == controllerType.Assembly); } } } \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Utils/ArrayMatcher.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Utils/ArrayMatcher.cs new file mode 100644 index 0000000000..f1b5b2b8e6 --- /dev/null +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Utils/ArrayMatcher.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.Utils +{ + internal static class ArrayMatcher + { + public static T[] Match(T[] sourceArray, T[] destinationArray) + { + var result = new List(); + + var currentMethodParamIndex = 0; + var parentItem = default(T); + + foreach (var sourceItem in sourceArray) + { + if (currentMethodParamIndex < destinationArray.Length) + { + var destinationItem = destinationArray[currentMethodParamIndex]; + + if (EqualityComparer.Default.Equals(sourceItem, destinationItem)) + { + parentItem = default(T); + currentMethodParamIndex++; + } + else + { + if (parentItem == null) + { + parentItem = destinationItem; + currentMethodParamIndex++; + } + } + } + + var resultItem = EqualityComparer.Default.Equals(parentItem, default(T)) ? sourceItem : parentItem; + result.Add(resultItem); + } + + return result.ToArray(); + } + } +} diff --git a/src/Volo.Abp.Http/Volo.Abp.Http.csproj b/src/Volo.Abp.Http/Volo.Abp.Http.csproj index 181e749dfc..d4031e3399 100644 --- a/src/Volo.Abp.Http/Volo.Abp.Http.csproj +++ b/src/Volo.Abp.Http/Volo.Abp.Http.csproj @@ -16,8 +16,4 @@ - - - - \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs new file mode 100644 index 0000000000..b897d8a900 --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.Http.Modeling +{ + [Serializable] + public class ActionApiDescriptionModel + { + public string Name { get; } + + public string HttpMethod { get; } + + public string Url { get; } + + public IList Parameters { get; } + + public ReturnValueApiDescriptionModel ReturnValue { get; } + + private ActionApiDescriptionModel() + { + + } + + public ActionApiDescriptionModel(string name, ReturnValueApiDescriptionModel returnValue, string url, string httpMethod = null) + { + Name = name; + ReturnValue = returnValue; + Url = url; + HttpMethod = httpMethod; + + Parameters = new List(); + } + + public ParameterApiDescriptionModel AddParameter(ParameterApiDescriptionModel parameter) + { + Parameters.Add(parameter); + return parameter; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs new file mode 100644 index 0000000000..6438c5e9b8 --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Volo.Abp.Http.Modeling +{ + [Serializable] + public class ApplicationApiDescriptionModel + { + public IDictionary Modules { get; } + + public ApplicationApiDescriptionModel() + { + Modules = new Dictionary(); + } + + public ModuleApiDescriptionModel AddModule(ModuleApiDescriptionModel module) + { + if (Modules.ContainsKey(module.Name)) + { + throw new AbpException("There is already a module with same name: " + module.Name); + } + + return Modules[module.Name] = module; + } + + public ModuleApiDescriptionModel GetOrAddModule(string name) + { + return Modules.GetOrAdd(name, () => new ModuleApiDescriptionModel(name)); + } + + public ApplicationApiDescriptionModel CreateSubModel(string[] modules = null, string[] controllers = null, string[] actions = null) + { + var subModel = new ApplicationApiDescriptionModel(); + + foreach (var module in Modules.Values) + { + if (modules == null || modules.Contains(module.Name)) + { + subModel.AddModule(module.CreateSubModel(controllers, actions)); + } + } + + return subModel; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs new file mode 100644 index 0000000000..ee30fb82ce --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Volo.Abp.Http.Modeling +{ + [Serializable] + public class ControllerApiDescriptionModel + { + public string Name { get; } + + public IDictionary Actions { get; } + + private ControllerApiDescriptionModel() + { + + } + + public ControllerApiDescriptionModel(string name) + { + Name = name; + + Actions = new Dictionary(); + } + + public ActionApiDescriptionModel AddAction(ActionApiDescriptionModel action) + { + if (Actions.ContainsKey(action.Name)) + { + throw new AbpException( + $"Can not add more than one action with same name to the same controller. Controller: {Name}, Action: {action.Name}." + ); + } + + return Actions[action.Name] = action; + } + + public ControllerApiDescriptionModel CreateSubModel(string[] actions) + { + var subModel = new ControllerApiDescriptionModel(Name); + + foreach (var action in Actions.Values) + { + if (actions == null || actions.Contains(action.Name)) + { + subModel.AddAction(action); + } + } + + return subModel; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/IApiDescriptionModelProvider.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/IApiDescriptionModelProvider.cs new file mode 100644 index 0000000000..35334fae33 --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/IApiDescriptionModelProvider.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.Http.Modeling +{ + public interface IApiDescriptionModelProvider + { + ApplicationApiDescriptionModel CreateModel(); + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs new file mode 100644 index 0000000000..f87db87693 --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Volo.Abp.Http.Modeling +{ + [Serializable] + public class ModuleApiDescriptionModel + { + public string Name { get; set; } + + public IDictionary Controllers { get; } + + private ModuleApiDescriptionModel() + { + + } + + public ModuleApiDescriptionModel(string name) + { + Name = name; + + Controllers = new Dictionary(); + } + + public ControllerApiDescriptionModel AddController(ControllerApiDescriptionModel controller) + { + if (Controllers.ContainsKey(controller.Name)) + { + throw new AbpException($"There is already a controller with name: {controller.Name} in module: {Name}"); + } + + return Controllers[controller.Name] = controller; + } + + public ControllerApiDescriptionModel GetOrAddController(string name) + { + return Controllers.GetOrAdd(name, () => new ControllerApiDescriptionModel(name)); + } + + public ModuleApiDescriptionModel CreateSubModel(string[] controllers, string[] actions) + { + var subModel = new ModuleApiDescriptionModel(Name); + + foreach (var controller in Controllers.Values) + { + if (controllers == null || controllers.Contains(controller.Name)) + { + subModel.AddController(controller.CreateSubModel(actions)); + } + } + + return subModel; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs new file mode 100644 index 0000000000..a5d0dde0a1 --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs @@ -0,0 +1,41 @@ +using System; + +namespace Volo.Abp.Http.Modeling +{ + [Serializable] + public class ParameterApiDescriptionModel + { + public string NameOnMethod { get; } + + public string Name { get; } + + public Type Type { get; } + + public string TypeAsString { get; } + + public bool IsOptional { get; } + + public object DefaultValue { get; } + + public string[] ConstraintTypes { get; } + + public string BindingSourceId { get; } + + private ParameterApiDescriptionModel() + { + + } + + public ParameterApiDescriptionModel(string name, string nameOnMethod, Type type, bool isOptional = false, object defaultValue = null, string[] constraintTypes = null, string bindingSourceId = null) + { + Name = name; + NameOnMethod = nameOnMethod; + Type = type; + TypeAsString = type.FullName; + IsOptional = isOptional; + DefaultValue = defaultValue; + ConstraintTypes = constraintTypes; + BindingSourceId = bindingSourceId; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs new file mode 100644 index 0000000000..83b4cba346 --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs @@ -0,0 +1,17 @@ +using System; + +namespace Volo.Abp.Http.Modeling +{ + [Serializable] + public class ReturnValueApiDescriptionModel + { + public Type Type { get; } + public string TypeAsString { get; } + + public ReturnValueApiDescriptionModel(Type type) + { + Type = type; + TypeAsString = type.FullName; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp/System/AbpTypeExtensions.cs b/src/Volo.Abp/System/AbpTypeExtensions.cs deleted file mode 100644 index 2cbd8dea77..0000000000 --- a/src/Volo.Abp/System/AbpTypeExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Reflection; - -namespace System -{ - public static class AbpTypeExtensions - { - //TODO: This method can be removed because not needed anymore! - public static Assembly GetAssembly(this Type type) - { - return type.GetTypeInfo().Assembly; - } - } -} diff --git a/src/Volo.Abp/Volo/Abp/Modularity/AbpModuleDescriptor.cs b/src/Volo.Abp/Volo/Abp/Modularity/AbpModuleDescriptor.cs index 69fada953c..7413e1154f 100644 --- a/src/Volo.Abp/Volo/Abp/Modularity/AbpModuleDescriptor.cs +++ b/src/Volo.Abp/Volo/Abp/Modularity/AbpModuleDescriptor.cs @@ -33,7 +33,7 @@ namespace Volo.Abp.Modularity } Type = type; - Assembly = type.GetAssembly(); + Assembly = type.Assembly; Instance = instance; IsLoadedAsPlugIn = isLoadedAsPlugIn; diff --git a/src/Volo.Abp/Volo/Abp/Reflection/AssemblyFinder.cs b/src/Volo.Abp/Volo/Abp/Reflection/AssemblyFinder.cs index 6d90a8fb5c..8178f1046b 100644 --- a/src/Volo.Abp/Volo/Abp/Reflection/AssemblyFinder.cs +++ b/src/Volo.Abp/Volo/Abp/Reflection/AssemblyFinder.cs @@ -30,7 +30,7 @@ namespace Volo.Abp.Reflection foreach (var module in _moduleContainer.Modules) { - assemblies.Add(module.Type.GetAssembly()); + assemblies.Add(module.Type.Assembly); } return assemblies.Distinct().ToImmutableList(); diff --git a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Utils/ArrayMacther_Tests.cs b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Utils/ArrayMacther_Tests.cs new file mode 100644 index 0000000000..a066622748 --- /dev/null +++ b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Utils/ArrayMacther_Tests.cs @@ -0,0 +1,19 @@ +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.Utils +{ + public class ArrayMacther_Tests + { + [Theory] + [InlineData( + new[] { "p1", "p2.a1", "p2.a2.b1", "p2.a2.b2", "p3", "p4", "p5.c1", "p5.c2" }, + new[] { "p1", "p2", "p3", "p4", "p5" }, + new[] { "p1", "p2", "p2", "p2", "p3", "p4", "p5", "p5" }) + ] + public void Should_Find_Correct_Items(string[] sourceArray, string[] destinationArray, string[] expectedArray) + { + var result = ArrayMatcher.Match(sourceArray, destinationArray); + Assert.Equal(expectedArray, result); + } + } +} diff --git a/test/Volo.Abp.Tests/Volo/Abp/Reflection/AssemblyFinder_Tests.cs b/test/Volo.Abp.Tests/Volo/Abp/Reflection/AssemblyFinder_Tests.cs index 92cd5aaf64..37c5b01518 100644 --- a/test/Volo.Abp.Tests/Volo/Abp/Reflection/AssemblyFinder_Tests.cs +++ b/test/Volo.Abp.Tests/Volo/Abp/Reflection/AssemblyFinder_Tests.cs @@ -30,7 +30,7 @@ namespace Volo.Abp.Reflection foreach (var moduleType in moduleTypes) { - assemblyFinder.Assemblies.ShouldContain(moduleType.GetAssembly()); + assemblyFinder.Assemblies.ShouldContain(moduleType.Assembly); } } diff --git a/test/Volo.Abp.Tests/Volo/Abp/Reflection/TypeFinder_Tests.cs b/test/Volo.Abp.Tests/Volo/Abp/Reflection/TypeFinder_Tests.cs index 4bbaf34400..c9876875ed 100644 --- a/test/Volo.Abp.Tests/Volo/Abp/Reflection/TypeFinder_Tests.cs +++ b/test/Volo.Abp.Tests/Volo/Abp/Reflection/TypeFinder_Tests.cs @@ -18,8 +18,8 @@ namespace Volo.Abp.Reflection var fakeAssemblyFinder = Substitute.For(); fakeAssemblyFinder.Assemblies.Returns(new List { - typeof(AbpKernelModule).GetAssembly(), - typeof(TypeFinder_Tests).GetAssembly() + typeof(AbpKernelModule).Assembly, + typeof(TypeFinder_Tests).Assembly }); //Act From bd55cc97bc8924d59575ed6d7b898bbaf24671b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 13 Sep 2017 21:32:02 +0300 Subject: [PATCH 05/12] Added todo --- .../Controllers/ApiDefinitionController.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs new file mode 100644 index 0000000000..7c1a913ffd --- /dev/null +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Http.Modeling; + +namespace Volo.Abp.AspNetCore.Mvc.Controllers +{ + public class ApiDefinitionController : AbpController + { + private readonly IApiDescriptionModelProvider _modelProvider; + + public ApiDefinitionController(IApiDescriptionModelProvider modelProvider) + { + _modelProvider = modelProvider; + } + + [HttpGet] + [Route("api/abp/api-description")] + public ApplicationApiDescriptionModel Get() + { + //TODO: It can not create methods if there are overloads of same action in a controller! + + return _modelProvider.CreateModel(); + } + } +} From bc68b01bc586462d892b3053deb81a11525a22a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 14 Sep 2017 09:37:13 +0300 Subject: [PATCH 06/12] Allow to user same method name in same application service for API model. --- .../AspNetCoreApiDescriptionModelProvider.cs | 38 +++++++++++++++++-- .../Controllers/ApiDefinitionController.cs | 3 +- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs index cffb5c6f24..49eb9ebd43 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs @@ -1,6 +1,8 @@ using System; using System.Linq; using System.Reflection; +using System.Text; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Logging; @@ -57,16 +59,17 @@ namespace Volo.Abp.AspNetCore.Mvc var method = apiDescription.ActionDescriptor.GetMethodInfo(); - if (controllerModel.Actions.ContainsKey(method.Name)) + var uniqueMethodName = GetUniqueActionName(method); + if (controllerModel.Actions.ContainsKey(uniqueMethodName)) { - Logger.LogWarning($"Controller '{controllerModel.Name}' contains more than one action with name '{method.Name}' for module '{moduleModel.Name}'. Ignored: " + apiDescription.ActionDescriptor.GetMethodInfo()); + Logger.LogWarning($"Controller '{controllerModel.Name}' contains more than one action with name '{uniqueMethodName}' for module '{moduleModel.Name}'. Ignored: " + method); return; } var returnValue = new ReturnValueApiDescriptionModel(method.ReturnType); var actionModel = controllerModel.AddAction(new ActionApiDescriptionModel( - method.Name, + uniqueMethodName, returnValue, apiDescription.RelativePath, apiDescription.HttpMethod @@ -81,6 +84,29 @@ namespace Volo.Abp.AspNetCore.Mvc ?? apiDescription.ActionDescriptor.AsControllerActionDescriptor().ControllerName; } + private static string GetUniqueActionName(MethodInfo method) + { + var methodNameBuilder = new StringBuilder(method.Name); + + var parameters = method.GetParameters(); + if (parameters.Any()) + { + methodNameBuilder.Append("By"); + + for (var i = 0; i < parameters.Length; i++) + { + if (i > 0) + { + methodNameBuilder.Append("And"); + } + + methodNameBuilder.Append(parameters[i].Name.ToPascalCase()); + } + } + + return methodNameBuilder.ToString(); + } + private void AddParameterDescriptionsToModel(ActionApiDescriptionModel actionModel, MethodInfo method, ApiDescription apiDescription) { if (!apiDescription.ParameterDescriptions.Any()) @@ -143,6 +169,12 @@ namespace Volo.Abp.AspNetCore.Mvc } } + var areaAttr = controllerType.GetCustomAttributes().OfType().FirstOrDefault(); + if (areaAttr != null) + { + return areaAttr.RouteValue; + } + return AbpControllerAssemblySetting.DefaultServiceModuleName; } } diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs index 7c1a913ffd..f2bb05ba74 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs @@ -3,6 +3,7 @@ using Volo.Abp.Http.Modeling; namespace Volo.Abp.AspNetCore.Mvc.Controllers { + [Area("abp")] public class ApiDefinitionController : AbpController { private readonly IApiDescriptionModelProvider _modelProvider; @@ -16,8 +17,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Controllers [Route("api/abp/api-description")] public ApplicationApiDescriptionModel Get() { - //TODO: It can not create methods if there are overloads of same action in a controller! - return _modelProvider.CreateModel(); } } From d5e69a623f5522bcc2b99304d1dba09ffd32fe73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 14 Sep 2017 09:52:26 +0300 Subject: [PATCH 07/12] Add controller type to ApplicationApiDescriptionModel --- .../Mvc/AspNetCoreApiDescriptionModelProvider.cs | 10 ++++++---- .../Abp/Http/Modeling/ControllerApiDescriptionModel.cs | 8 +++++++- .../Abp/Http/Modeling/ModuleApiDescriptionModel.cs | 4 ++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs index 49eb9ebd43..6b400796a1 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs @@ -54,8 +54,11 @@ namespace Volo.Abp.AspNetCore.Mvc private void AddApiDescriptionToModel(ApiDescription apiDescription, ApplicationApiDescriptionModel model) { - var moduleModel = model.GetOrAddModule(GetModuleName(apiDescription)); - var controllerModel = moduleModel.GetOrAddController(GetControllerName(apiDescription)); + var controllerType = apiDescription.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(); + + var moduleModel = model.GetOrAddModule(GetModuleName(controllerType)); + + var controllerModel = moduleModel.GetOrAddController(GetControllerName(apiDescription), controllerType); var method = apiDescription.ActionDescriptor.GetMethodInfo(); @@ -153,9 +156,8 @@ namespace Volo.Abp.AspNetCore.Mvc return modelNameProvider.Name; } - private string GetModuleName(ApiDescription apiDescription) + private string GetModuleName(Type controllerType) { - var controllerType = apiDescription.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(); if (controllerType == null) { return AbpControllerAssemblySetting.DefaultServiceModuleName; diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs index ee30fb82ce..b261c62416 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs @@ -9,6 +9,10 @@ namespace Volo.Abp.Http.Modeling { public string Name { get; } + public Type Type { get; } + + public string TypeAsString { get; } + public IDictionary Actions { get; } private ControllerApiDescriptionModel() @@ -16,9 +20,11 @@ namespace Volo.Abp.Http.Modeling } - public ControllerApiDescriptionModel(string name) + public ControllerApiDescriptionModel(string name, Type type) { Name = name; + Type = type; + TypeAsString = type.FullName; Actions = new Dictionary(); } diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs index f87db87693..a390550157 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs @@ -33,9 +33,9 @@ namespace Volo.Abp.Http.Modeling return Controllers[controller.Name] = controller; } - public ControllerApiDescriptionModel GetOrAddController(string name) + public ControllerApiDescriptionModel GetOrAddController(string name, Type type) { - return Controllers.GetOrAdd(name, () => new ControllerApiDescriptionModel(name)); + return Controllers.GetOrAdd(name, () => new ControllerApiDescriptionModel(name, type)); } public ModuleApiDescriptionModel CreateSubModel(string[] controllers, string[] actions) From 819eb7f0a47127672e218b6da54c939513fa7455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 14 Sep 2017 11:52:51 +0300 Subject: [PATCH 08/12] Created IApplicationApiDescriptionModelCache --- ...oller.cs => AbpApiDefinitionController.cs} | 4 +- ...lectionDynamicHttpClientProxyExtensions.cs | 41 ++++++++++++ .../ServiceCollectionHttpProxyExtensions.cs | 32 --------- .../Volo/Abp/Http/AbpHttpOptions.cs | 16 +++++ .../ApplicationApiDescriptionModelCache.cs | 66 +++++++++++++++++++ .../DynamicHttpClientProxyConfig.cs | 17 +++++ .../DynamicHttpProxyInterceptor.cs | 30 +++++++-- .../IApplicationApiDescriptionModelCache.cs | 13 ++++ .../Modeling/ControllerApiDescriptionModel.cs | 2 +- src/Volo.Abp/Volo.Abp.csproj | 1 + 10 files changed, 181 insertions(+), 41 deletions(-) rename src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/{ApiDefinitionController.cs => AbpApiDefinitionController.cs} (76%) create mode 100644 src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs delete mode 100644 src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpProxyExtensions.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpOptions.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelCache.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpClientProxyConfig.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelCache.cs diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/AbpApiDefinitionController.cs similarity index 76% rename from src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs rename to src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/AbpApiDefinitionController.cs index f2bb05ba74..0a8c6fb8ef 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Controllers/ApiDefinitionController.cs +++ b/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; } diff --git a/src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs b/src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs new file mode 100644 index 0000000000..91ac82c21a --- /dev/null +++ b/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(this IServiceCollection services, string baseUrl) + { + return services.AddHttpClientProxy(typeof(T), baseUrl); + } + + public static IServiceCollection AddHttpClientProxy(this IServiceCollection services, Type type, string baseUrl) + { + services.Configure(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) + ) + ); + } + } +} diff --git a/src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpProxyExtensions.cs b/src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpProxyExtensions.cs deleted file mode 100644 index 0470a4bffd..0000000000 --- a/src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpProxyExtensions.cs +++ /dev/null @@ -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(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>() - ); - }); - - return services; - } - } -} diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpOptions.cs b/src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpOptions.cs new file mode 100644 index 0000000000..692702c405 --- /dev/null +++ b/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 HttpClientProxies { get; set; } + + public AbpHttpOptions() + { + HttpClientProxies = new Dictionary(); + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelCache.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelCache.cs new file mode 100644 index 0000000000..d1f5b48985 --- /dev/null +++ b/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 _cache; + private readonly AsyncLock _asyncLock; + + public ApplicationApiDescriptionModelCache(IDynamicProxyHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; + + _cache = new Dictionary(); + _asyncLock = new AsyncLock(); + } + + public async Task 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 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; + } + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpClientProxyConfig.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpClientProxyConfig.cs new file mode 100644 index 0000000000..e818d46f0c --- /dev/null +++ b/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; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs index 933c58c9e7..e0fdd8dd09 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs +++ b/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 : 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) .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) .First(m => m.Name == nameof(InterceptAsync) && m.IsGenericMethodDefinition); } - public DynamicHttpProxyInterceptor(IDynamicProxyHttpClientFactory httpClientFactory) + public DynamicHttpProxyInterceptor( + IDynamicProxyHttpClientFactory httpClientFactory, + IOptions 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 InterceptAsync(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"); diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelCache.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelCache.cs new file mode 100644 index 0000000000..2d6ccc5d5b --- /dev/null +++ b/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 GetAsync(string baseUrl, CancellationToken cancellationToken = default(CancellationToken)); + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs index b261c62416..d89a093988 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs +++ b/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) { diff --git a/src/Volo.Abp/Volo.Abp.csproj b/src/Volo.Abp/Volo.Abp.csproj index d02cb6b1b3..be558fc887 100644 --- a/src/Volo.Abp/Volo.Abp.csproj +++ b/src/Volo.Abp/Volo.Abp.csproj @@ -16,6 +16,7 @@ + From b7adb82418e08547fb47e7d1807d69786309fe3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 14 Sep 2017 13:33:47 +0300 Subject: [PATCH 09/12] Refactored. --- .../Mvc/AspNetCoreApiDescriptionModelProvider.cs | 1 + ....cs => ApplicationApiDescriptionModelManager.cs} | 13 +++++++------ .../DynamicProxying/DynamicHttpProxyInterceptor.cs | 5 +++-- ...cs => IApplicationApiDescriptionModelManager.cs} | 6 ++---- .../Abp/Http/Modeling/ActionApiDescriptionModel.cs | 5 ++++- 5 files changed, 17 insertions(+), 13 deletions(-) rename src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/{ApplicationApiDescriptionModelCache.cs => ApplicationApiDescriptionModelManager.cs} (79%) rename src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/{IApplicationApiDescriptionModelCache.cs => IApplicationApiDescriptionModelManager.cs} (64%) diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs index 6b400796a1..e2dec4fff3 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs @@ -73,6 +73,7 @@ namespace Volo.Abp.AspNetCore.Mvc var actionModel = controllerModel.AddAction(new ActionApiDescriptionModel( uniqueMethodName, + method.Name, returnValue, apiDescription.RelativePath, apiDescription.HttpMethod diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelCache.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelManager.cs similarity index 79% rename from src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelCache.cs rename to src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelManager.cs index d1f5b48985..cca45ab21d 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelCache.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelManager.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; @@ -10,14 +9,16 @@ using Volo.Abp.Http.Modeling; namespace Volo.Abp.Http.DynamicProxying { - public class ApplicationApiDescriptionModelCache : IApplicationApiDescriptionModelCache, ISingletonDependency + //TODO: Move DynamicProxying to Volo.Abp.Http.Client module + + public class ApplicationApiDescriptionModelManager : IApplicationApiDescriptionModelManager, ISingletonDependency { private readonly IDynamicProxyHttpClientFactory _httpClientFactory; private readonly Dictionary _cache; private readonly AsyncLock _asyncLock; - public ApplicationApiDescriptionModelCache(IDynamicProxyHttpClientFactory httpClientFactory) + public ApplicationApiDescriptionModelManager(IDynamicProxyHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; @@ -32,14 +33,14 @@ namespace Volo.Abp.Http.DynamicProxying var model = _cache.GetOrDefault(baseUrl); if (model == null) { - _cache[baseUrl] = model = await GetModelFromRemoteServer(baseUrl); + _cache[baseUrl] = model = await GetFromServerAsync(baseUrl); } return model; } } - private async Task GetModelFromRemoteServer(string baseUrl) + private async Task GetFromServerAsync(string baseUrl) { using (var client = _httpClientFactory.Create()) { diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs index e0fdd8dd09..37a64f3643 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs @@ -18,7 +18,7 @@ namespace Volo.Abp.Http.DynamicProxying private static readonly MethodInfo GenericInterceptAsyncMethod; private readonly IDynamicProxyHttpClientFactory _httpClientFactory; - private readonly IApplicationApiDescriptionModelCache _discoverManager; + private readonly IApplicationApiDescriptionModelManager _discoverManager; private readonly AbpHttpOptions _options; static DynamicHttpProxyInterceptor() @@ -31,7 +31,7 @@ namespace Volo.Abp.Http.DynamicProxying public DynamicHttpProxyInterceptor( IDynamicProxyHttpClientFactory httpClientFactory, IOptions options, - IApplicationApiDescriptionModelCache discoverManager) + IApplicationApiDescriptionModelManager discoverManager) { _httpClientFactory = httpClientFactory; _discoverManager = discoverManager; @@ -61,6 +61,7 @@ namespace Volo.Abp.Http.DynamicProxying } var apiDescriptionModel = await _discoverManager.GetAsync(config.BaseUrl); + using (var client = _httpClientFactory.Create()) { diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelCache.cs b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelManager.cs similarity index 64% rename from src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelCache.cs rename to src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelManager.cs index 2d6ccc5d5b..0adff97a3e 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelCache.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelManager.cs @@ -1,12 +1,10 @@ -using System; -using System.Collections.Concurrent; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.Http.Modeling; namespace Volo.Abp.Http.DynamicProxying { - public interface IApplicationApiDescriptionModelCache + public interface IApplicationApiDescriptionModelManager { Task GetAsync(string baseUrl, CancellationToken cancellationToken = default(CancellationToken)); } diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs index b897d8a900..a20d52b72b 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs @@ -8,6 +8,8 @@ namespace Volo.Abp.Http.Modeling { public string Name { get; } + public string NameOnClass { get; } + public string HttpMethod { get; } public string Url { get; } @@ -21,9 +23,10 @@ namespace Volo.Abp.Http.Modeling } - public ActionApiDescriptionModel(string name, ReturnValueApiDescriptionModel returnValue, string url, string httpMethod = null) + public ActionApiDescriptionModel(string name, string nameOnClass, ReturnValueApiDescriptionModel returnValue, string url, string httpMethod = null) { Name = name; + NameOnClass = nameOnClass; ReturnValue = returnValue; Url = url; HttpMethod = httpMethod; From 849eed0b54093e5767288f846b1c550d657f1f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 14 Sep 2017 21:56:05 +0300 Subject: [PATCH 10/12] Created Abp.Http.Client package. --- Volo.Abp.sln | 21 ++++--- .../Volo.Abp.AspNetCore.TestBase.csproj | 2 +- .../TestBase/AbpAspNetCoreTestBaseModule.cs | 4 +- ...etCoreTestDynamicProxyHttpClientFactory.cs | 2 +- ...lectionDynamicHttpClientProxyExtensions.cs | 5 +- .../Volo.Abp.Http.Client.csproj | 19 ++++++ .../Abp/Http/Client/AbpHttpClientOptions.cs} | 8 +-- .../Volo/Abp/Http/Client/AbpHttpModule.cs | 14 +++++ .../ApplicationApiDescriptionModelManager.cs | 4 +- .../DefaultDynamicProxyHttpClientFactory.cs | 2 +- .../DynamicHttpClientProxyConfig.cs | 2 +- .../DynamicHttpProxyInterceptor.cs | 59 +++++++++++++++---- .../IApplicationApiDescriptionModelManager.cs | 2 +- .../IDynamicProxyHttpClientFactory.cs | 2 +- .../Volo.Abp.Http.Client.Tests.csproj} | 4 +- .../Volo/Abp/Http/AbpHttpTestBase.cs | 0 .../Volo/Abp/Http/AbpHttpTestModule.cs | 7 +-- .../PersonAppServiceClientProxy_Tests.cs | 0 .../Volo/Abp/Http/Startup.cs | 0 19 files changed, 117 insertions(+), 40 deletions(-) rename src/{Volo.Abp.Http => Volo.Abp.Http.Client}/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs (91%) create mode 100644 src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj rename src/{Volo.Abp.Http/Volo/Abp/Http/AbpHttpOptions.cs => Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientOptions.cs} (63%) create mode 100644 src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpModule.cs rename src/{Volo.Abp.Http/Volo/Abp/Http => Volo.Abp.Http.Client/Volo/Abp/Http/Client}/DynamicProxying/ApplicationApiDescriptionModelManager.cs (95%) rename src/{Volo.Abp.Http/Volo/Abp/Http => Volo.Abp.Http.Client/Volo/Abp/Http/Client}/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs (85%) rename src/{Volo.Abp.Http/Volo/Abp/Http => Volo.Abp.Http.Client/Volo/Abp/Http/Client}/DynamicProxying/DynamicHttpClientProxyConfig.cs (86%) rename src/{Volo.Abp.Http/Volo/Abp/Http => Volo.Abp.Http.Client/Volo/Abp/Http/Client}/DynamicProxying/DynamicHttpProxyInterceptor.cs (57%) rename src/{Volo.Abp.Http/Volo/Abp/Http => Volo.Abp.Http.Client/Volo/Abp/Http/Client}/DynamicProxying/IApplicationApiDescriptionModelManager.cs (86%) rename src/{Volo.Abp.Http/Volo/Abp/Http => Volo.Abp.Http.Client/Volo/Abp/Http/Client}/DynamicProxying/IDynamicProxyHttpClientFactory.cs (71%) rename test/{Volo.Abp.Http.Tests/Volo.Abp.Http.Tests.csproj => Volo.Abp.Http.Client.Tests/Volo.Abp.Http.Client.Tests.csproj} (84%) rename test/{Volo.Abp.Http.Tests => Volo.Abp.Http.Client.Tests}/Volo/Abp/Http/AbpHttpTestBase.cs (100%) rename test/{Volo.Abp.Http.Tests => Volo.Abp.Http.Client.Tests}/Volo/Abp/Http/AbpHttpTestModule.cs (78%) rename test/{Volo.Abp.Http.Tests => Volo.Abp.Http.Client.Tests}/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs (100%) rename test/{Volo.Abp.Http.Tests => Volo.Abp.Http.Client.Tests}/Volo/Abp/Http/Startup.cs (100%) diff --git a/Volo.Abp.sln b/Volo.Abp.sln index d6e55fe8f7..4c62a97e82 100644 --- a/Volo.Abp.sln +++ b/Volo.Abp.sln @@ -128,9 +128,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.MemoryDb.Tests", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.TestApp.Tests", "test\Volo.Abp.TestApp.Tests\Volo.Abp.TestApp.Tests.csproj", "{4C2F7B03-C598-4432-A43A-B065D9D0712F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Http", "src\Volo.Abp.Http\Volo.Abp.Http.csproj", "{01A70034-D353-4BF9-821D-F2B6F7641532}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Http", "src\Volo.Abp.Http\Volo.Abp.Http.csproj", "{01A70034-D353-4BF9-821D-F2B6F7641532}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Http.Tests", "test\Volo.Abp.Http.Tests\Volo.Abp.Http.Tests.csproj", "{5B86E837-0C89-4058-A84B-0B51F2F573D4}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Http.Client", "src\Volo.Abp.Http.Client\Volo.Abp.Http.Client.csproj", "{D5E2FB37-0194-480A-B952-5FFECC1200EB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Http.Client.Tests", "test\Volo.Abp.Http.Client.Tests\Volo.Abp.Http.Client.Tests.csproj", "{703BD43C-02B9-413F-854C-9CBA0C963196}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -326,10 +328,14 @@ Global {01A70034-D353-4BF9-821D-F2B6F7641532}.Debug|Any CPU.Build.0 = Debug|Any CPU {01A70034-D353-4BF9-821D-F2B6F7641532}.Release|Any CPU.ActiveCfg = Release|Any CPU {01A70034-D353-4BF9-821D-F2B6F7641532}.Release|Any CPU.Build.0 = Release|Any CPU - {5B86E837-0C89-4058-A84B-0B51F2F573D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5B86E837-0C89-4058-A84B-0B51F2F573D4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5B86E837-0C89-4058-A84B-0B51F2F573D4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5B86E837-0C89-4058-A84B-0B51F2F573D4}.Release|Any CPU.Build.0 = Release|Any CPU + {D5E2FB37-0194-480A-B952-5FFECC1200EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5E2FB37-0194-480A-B952-5FFECC1200EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5E2FB37-0194-480A-B952-5FFECC1200EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5E2FB37-0194-480A-B952-5FFECC1200EB}.Release|Any CPU.Build.0 = Release|Any CPU + {703BD43C-02B9-413F-854C-9CBA0C963196}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {703BD43C-02B9-413F-854C-9CBA0C963196}.Debug|Any CPU.Build.0 = Debug|Any CPU + {703BD43C-02B9-413F-854C-9CBA0C963196}.Release|Any CPU.ActiveCfg = Release|Any CPU + {703BD43C-02B9-413F-854C-9CBA0C963196}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -391,7 +397,8 @@ Global {D0279C94-E9A3-4A1B-968B-D3BBF3E06FD8} = {37087D1B-3693-4E96-983D-A69F210BDE53} {4C2F7B03-C598-4432-A43A-B065D9D0712F} = {37087D1B-3693-4E96-983D-A69F210BDE53} {01A70034-D353-4BF9-821D-F2B6F7641532} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8} - {5B86E837-0C89-4058-A84B-0B51F2F573D4} = {37087D1B-3693-4E96-983D-A69F210BDE53} + {D5E2FB37-0194-480A-B952-5FFECC1200EB} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8} + {703BD43C-02B9-413F-854C-9CBA0C963196} = {37087D1B-3693-4E96-983D-A69F210BDE53} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj b/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj index 49b7547607..7090e4bf39 100644 --- a/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj +++ b/src/Volo.Abp.AspNetCore.TestBase/Volo.Abp.AspNetCore.TestBase.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreTestBaseModule.cs b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreTestBaseModule.cs index ddd6324780..c6828feea5 100644 --- a/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreTestBaseModule.cs +++ b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/AbpAspNetCoreTestBaseModule.cs @@ -1,10 +1,10 @@ using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Http; +using Volo.Abp.Http.Client; using Volo.Abp.Modularity; namespace Volo.Abp.AspNetCore.TestBase { - [DependsOn(typeof(AbpHttpModule))] + [DependsOn(typeof(AbpHttpClientModule))] [DependsOn(typeof(AbpAspNetCoreModule))] public class AbpAspNetCoreTestBaseModule : AbpModule { diff --git a/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestDynamicProxyHttpClientFactory.cs b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestDynamicProxyHttpClientFactory.cs index 8830c34c20..e0253f8f8b 100644 --- a/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestDynamicProxyHttpClientFactory.cs +++ b/src/Volo.Abp.AspNetCore.TestBase/Volo/Abp/AspNetCore/TestBase/DynamicProxying/AspNetCoreTestDynamicProxyHttpClientFactory.cs @@ -1,6 +1,6 @@ using System.Net.Http; using Volo.Abp.DependencyInjection; -using Volo.Abp.Http.DynamicProxying; +using Volo.Abp.Http.Client.DynamicProxying; namespace Volo.Abp.AspNetCore.TestBase.DynamicProxying { diff --git a/src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs b/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs similarity index 91% rename from src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs rename to src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs index 91ac82c21a..fa77c9584d 100644 --- a/src/Volo.Abp.Http/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs +++ b/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs @@ -2,7 +2,8 @@ using Castle.DynamicProxy; using Volo.Abp.Castle.DynamicProxy; using Volo.Abp.Http; -using Volo.Abp.Http.DynamicProxying; +using Volo.Abp.Http.Client; +using Volo.Abp.Http.Client.DynamicProxying; namespace Microsoft.Extensions.DependencyInjection { @@ -19,7 +20,7 @@ namespace Microsoft.Extensions.DependencyInjection public static IServiceCollection AddHttpClientProxy(this IServiceCollection services, Type type, string baseUrl) { - services.Configure(options => + services.Configure(options => { options.HttpClientProxies[type] = new DynamicHttpClientProxyConfig(type, baseUrl); }); diff --git a/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj b/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj new file mode 100644 index 0000000000..ff4dd91623 --- /dev/null +++ b/src/Volo.Abp.Http.Client/Volo.Abp.Http.Client.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.0 + Volo.Abp.Http.Client + Volo.Abp.Http.Client + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + + \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpOptions.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientOptions.cs similarity index 63% rename from src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpOptions.cs rename to src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientOptions.cs index 692702c405..5adcd7525f 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/AbpHttpOptions.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientOptions.cs @@ -1,14 +1,14 @@ using System; using System.Collections.Generic; -using Volo.Abp.Http.DynamicProxying; +using Volo.Abp.Http.Client.DynamicProxying; -namespace Volo.Abp.Http +namespace Volo.Abp.Http.Client { - public class AbpHttpOptions + public class AbpHttpClientOptions { public Dictionary HttpClientProxies { get; set; } - public AbpHttpOptions() + public AbpHttpClientOptions() { HttpClientProxies = new Dictionary(); } diff --git a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpModule.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpModule.cs new file mode 100644 index 0000000000..37ddfe2755 --- /dev/null +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpModule.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace Volo.Abp.Http.Client +{ + [DependsOn(typeof(AbpHttpModule))] + public class AbpHttpClientModule : AbpModule + { + public override void ConfigureServices(IServiceCollection services) + { + services.AddAssemblyOf(); + } + } +} diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelManager.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApplicationApiDescriptionModelManager.cs similarity index 95% rename from src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelManager.cs rename to src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApplicationApiDescriptionModelManager.cs index cca45ab21d..79cac746e5 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/ApplicationApiDescriptionModelManager.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApplicationApiDescriptionModelManager.cs @@ -7,10 +7,8 @@ using Nito.AsyncEx; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Modeling; -namespace Volo.Abp.Http.DynamicProxying +namespace Volo.Abp.Http.Client.DynamicProxying { - //TODO: Move DynamicProxying to Volo.Abp.Http.Client module - public class ApplicationApiDescriptionModelManager : IApplicationApiDescriptionModelManager, ISingletonDependency { private readonly IDynamicProxyHttpClientFactory _httpClientFactory; diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs similarity index 85% rename from src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs rename to src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs index ccdafae17e..6c827f5237 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DefaultDynamicProxyHttpClientFactory.cs @@ -1,7 +1,7 @@ using System.Net.Http; using Volo.Abp.DependencyInjection; -namespace Volo.Abp.Http.DynamicProxying +namespace Volo.Abp.Http.Client.DynamicProxying { public class DefaultDynamicProxyHttpClientFactory : IDynamicProxyHttpClientFactory, ITransientDependency { diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpClientProxyConfig.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpClientProxyConfig.cs similarity index 86% rename from src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpClientProxyConfig.cs rename to src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpClientProxyConfig.cs index e818d46f0c..1286db09cc 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpClientProxyConfig.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpClientProxyConfig.cs @@ -1,6 +1,6 @@ using System; -namespace Volo.Abp.Http.DynamicProxying +namespace Volo.Abp.Http.Client.DynamicProxying { public class DynamicHttpClientProxyConfig { diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs similarity index 57% rename from src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs rename to src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs index 37a64f3643..e27b6007cb 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/DynamicHttpProxyInterceptor.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Net.Http; using System.Reflection; using System.Threading.Tasks; using Microsoft.Extensions.Options; @@ -9,9 +7,10 @@ using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Volo.Abp.DependencyInjection; using Volo.Abp.DynamicProxy; +using Volo.Abp.Http.Modeling; using Volo.Abp.Threading; -namespace Volo.Abp.Http.DynamicProxying +namespace Volo.Abp.Http.Client.DynamicProxying { public class DynamicHttpProxyInterceptor : AbpInterceptor, ITransientDependency { @@ -19,7 +18,7 @@ namespace Volo.Abp.Http.DynamicProxying private readonly IDynamicProxyHttpClientFactory _httpClientFactory; private readonly IApplicationApiDescriptionModelManager _discoverManager; - private readonly AbpHttpOptions _options; + private readonly AbpHttpClientOptions _options; static DynamicHttpProxyInterceptor() { @@ -29,8 +28,8 @@ namespace Volo.Abp.Http.DynamicProxying } public DynamicHttpProxyInterceptor( - IDynamicProxyHttpClientFactory httpClientFactory, - IOptions options, + IDynamicProxyHttpClientFactory httpClientFactory, + IOptions options, IApplicationApiDescriptionModelManager discoverManager) { _httpClientFactory = httpClientFactory; @@ -47,7 +46,7 @@ namespace Volo.Abp.Http.DynamicProxying { invocation.ReturnValue = GenericInterceptAsyncMethod .MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0]) - .Invoke(this, new object[]{ invocation }); + .Invoke(this, new object[] { invocation }); return Task.CompletedTask; } @@ -62,10 +61,11 @@ namespace Volo.Abp.Http.DynamicProxying var apiDescriptionModel = await _discoverManager.GetAsync(config.BaseUrl); - + var action = FindAction(apiDescriptionModel, invocation.Method); + using (var client = _httpClientFactory.Create()) { - var response = await client.GetAsync("/api/app/people"); + var response = await client.GetAsync(config.BaseUrl + action.Url); if (!response.IsSuccessStatusCode) { throw new AbpException("Remote service returns error!"); @@ -84,5 +84,44 @@ namespace Volo.Abp.Http.DynamicProxying return (T)result; } } + + private ActionApiDescriptionModel FindAction(ApplicationApiDescriptionModel apiDescriptionModel, MethodInfo method) + { + var methodParameters = method.GetParameters().ToArray(); + + foreach (var module in apiDescriptionModel.Modules.Values) + { + //TODO: Check module type too + + foreach (var controller in module.Controllers.Values) + { + //TODO: Check controller type too + + foreach (var action in controller.Actions.Values) + { + if (action.NameOnClass == method.Name && action.Parameters.Count == methodParameters.Length) + { + var found = true; + + for (int i = 0; i < methodParameters.Length; i++) + { + if (action.Parameters[i].TypeAsString != methodParameters[i].ParameterType.FullName) + { + found = false; + break; + } + } + + if (found) + { + return action; + } + } + } + } + } + + throw new AbpException("Could not found remote action for method: " + method); + } } } \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelManager.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApplicationApiDescriptionModelManager.cs similarity index 86% rename from src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelManager.cs rename to src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApplicationApiDescriptionModelManager.cs index 0adff97a3e..bdc7f3d6af 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IApplicationApiDescriptionModelManager.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IApplicationApiDescriptionModelManager.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Volo.Abp.Http.Modeling; -namespace Volo.Abp.Http.DynamicProxying +namespace Volo.Abp.Http.Client.DynamicProxying { public interface IApplicationApiDescriptionModelManager { diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IDynamicProxyHttpClientFactory.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IDynamicProxyHttpClientFactory.cs similarity index 71% rename from src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IDynamicProxyHttpClientFactory.cs rename to src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IDynamicProxyHttpClientFactory.cs index 99691ccc2f..aaf821d0f9 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/DynamicProxying/IDynamicProxyHttpClientFactory.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/IDynamicProxyHttpClientFactory.cs @@ -1,6 +1,6 @@ using System.Net.Http; -namespace Volo.Abp.Http.DynamicProxying +namespace Volo.Abp.Http.Client.DynamicProxying { public interface IDynamicProxyHttpClientFactory { diff --git a/test/Volo.Abp.Http.Tests/Volo.Abp.Http.Tests.csproj b/test/Volo.Abp.Http.Client.Tests/Volo.Abp.Http.Client.Tests.csproj similarity index 84% rename from test/Volo.Abp.Http.Tests/Volo.Abp.Http.Tests.csproj rename to test/Volo.Abp.Http.Client.Tests/Volo.Abp.Http.Client.Tests.csproj index fd4ae111e2..6593fa5d39 100644 --- a/test/Volo.Abp.Http.Tests/Volo.Abp.Http.Tests.csproj +++ b/test/Volo.Abp.Http.Client.Tests/Volo.Abp.Http.Client.Tests.csproj @@ -3,7 +3,7 @@ netcoreapp2.0 Volo.Abp.Http.Tests - Volo.Abp.Http.Tests + Volo.Abp.Http.Client.Tests true false false @@ -12,7 +12,7 @@ - + diff --git a/test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestBase.cs b/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpTestBase.cs similarity index 100% rename from test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestBase.cs rename to test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpTestBase.cs diff --git a/test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestModule.cs b/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpTestModule.cs similarity index 78% rename from test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestModule.cs rename to test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpTestModule.cs index 8348e729a5..4a150a2c19 100644 --- a/test/Volo.Abp.Http.Tests/Volo/Abp/Http/AbpHttpTestModule.cs +++ b/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/AbpHttpTestModule.cs @@ -1,13 +1,12 @@ -using Castle.DynamicProxy; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.App; -using Volo.Abp.Castle.DynamicProxy; +using Volo.Abp.Http.Client; using Volo.Abp.Modularity; using Volo.Abp.TestApp.Application; namespace Volo.Abp.Http { - [DependsOn(typeof(AbpAspNetCoreMvcTestModule), typeof(AbpHttpModule))] + [DependsOn(typeof(AbpAspNetCoreMvcTestModule), typeof(AbpHttpClientModule))] public class AbpHttpTestModule : AbpModule { public override void ConfigureServices(IServiceCollection services) diff --git a/test/Volo.Abp.Http.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs b/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs similarity index 100% rename from test/Volo.Abp.Http.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs rename to test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs diff --git a/test/Volo.Abp.Http.Tests/Volo/Abp/Http/Startup.cs b/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/Startup.cs similarity index 100% rename from test/Volo.Abp.Http.Tests/Volo/Abp/Http/Startup.cs rename to test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/Startup.cs From 1446775be35334944445cf469bf86a80646b6885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 14 Sep 2017 23:21:31 +0300 Subject: [PATCH 11/12] Added todos. --- .../Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs | 2 ++ .../Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs index a20d52b72b..a2c37fc324 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs @@ -14,6 +14,8 @@ namespace Volo.Abp.Http.Modeling public string Url { get; } + //TODO: Add actual parameters on method + public IList Parameters { get; } public ReturnValueApiDescriptionModel ReturnValue { get; } diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs index d89a093988..ad5c53fbe2 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs @@ -13,6 +13,8 @@ namespace Volo.Abp.Http.Modeling public string TypeAsString { get; } + //TODO: Add interfaces implemented by this service. + public IDictionary Actions { get; } private ControllerApiDescriptionModel() From bbd7339672b369e1764cae1c3a87f9ee1939e5c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 15 Sep 2017 14:41:47 +0300 Subject: [PATCH 12/12] Improved Http dynamic API. --- .../AspNetCore/Mvc/AbpAppServiceConvention.cs | 3 +- .../Mvc/AbpControllerAssemblySetting.cs | 5 --- .../Mvc/AppServiceControllerOptions.cs | 3 +- .../AspNetCoreApiDescriptionModelProvider.cs | 17 +++----- ...lectionDynamicHttpClientProxyExtensions.cs | 10 ++--- .../DynamicHttpClientProxyConfig.cs | 11 +++-- .../DynamicHttpProxyInterceptor.cs | 18 +++++--- .../Modeling/ActionApiDescriptionModel.cs | 38 +++++++++------- .../ApplicationApiDescriptionModel.cs | 18 ++++++-- .../Modeling/ControllerApiDescriptionModel.cs | 43 +++++++++++-------- .../ControllerInterfaceApiDescriptionModel.cs | 23 ++++++++++ .../MethodParameterApiDescriptionModel.cs | 33 ++++++++++++++ .../Modeling/ModuleApiDescriptionModel.cs | 29 ++++++++----- .../Modeling/ParameterApiDescriptionModel.cs | 37 ++++++++-------- 14 files changed, 192 insertions(+), 96 deletions(-) create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs index c04e563097..25e9265ab1 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.Options; using Volo.Abp.Application.Services; using Volo.Abp.DependencyInjection; using Volo.Abp.Http; +using Volo.Abp.Http.Modeling; using Volo.Abp.Reflection; namespace Volo.Abp.AspNetCore.Mvc @@ -245,7 +246,7 @@ namespace Volo.Abp.AspNetCore.Mvc protected virtual string GetModuleNameOrDefault(Type controllerType) { return GetControllerSettingOrNull(controllerType)?.ModuleName ?? - AbpControllerAssemblySetting.DefaultServiceModuleName; + ModuleApiDescriptionModel.DefaultServiceModuleName; } [CanBeNull] diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs index ed89e7ae9b..56f4fa0142 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs @@ -6,11 +6,6 @@ namespace Volo.Abp.AspNetCore.Mvc { public class AbpControllerAssemblySetting { - /// - /// "app". - /// - public const string DefaultServiceModuleName = "app"; - public string ModuleName { get; } public Assembly Assembly { get; } diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AppServiceControllerOptions.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AppServiceControllerOptions.cs index dd1944b3f8..659b939e3c 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AppServiceControllerOptions.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AppServiceControllerOptions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Reflection; using Microsoft.AspNetCore.Http; +using Volo.Abp.Http.Modeling; namespace Volo.Abp.AspNetCore.Mvc { @@ -30,7 +31,7 @@ namespace Volo.Abp.AspNetCore.Mvc public AbpControllerAssemblySettingBuilder CreateFor( Assembly assembly, - string moduleName = AbpControllerAssemblySetting.DefaultServiceModuleName, + string moduleName = ModuleApiDescriptionModel.DefaultServiceModuleName, bool useConventionalHttpVerbs = true) { var setting = new AbpControllerAssemblySetting(moduleName, assembly, useConventionalHttpVerbs); diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs index e2dec4fff3..799b65ac6e 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs @@ -34,7 +34,7 @@ namespace Volo.Abp.AspNetCore.Mvc public ApplicationApiDescriptionModel CreateModel() { - var model = new ApplicationApiDescriptionModel(); + var model = ApplicationApiDescriptionModel.Create(); foreach (var descriptionGroupItem in _descriptionProvider.ApiDescriptionGroups.Items) { @@ -65,16 +65,13 @@ namespace Volo.Abp.AspNetCore.Mvc var uniqueMethodName = GetUniqueActionName(method); if (controllerModel.Actions.ContainsKey(uniqueMethodName)) { - Logger.LogWarning($"Controller '{controllerModel.Name}' contains more than one action with name '{uniqueMethodName}' for module '{moduleModel.Name}'. Ignored: " + method); + Logger.LogWarning($"Controller '{controllerModel.ControllerName}' contains more than one action with name '{uniqueMethodName}' for module '{moduleModel.Name}'. Ignored: " + method); return; } - var returnValue = new ReturnValueApiDescriptionModel(method.ReturnType); - - var actionModel = controllerModel.AddAction(new ActionApiDescriptionModel( + var actionModel = controllerModel.AddAction(ActionApiDescriptionModel.Create( + method, uniqueMethodName, - method.Name, - returnValue, apiDescription.RelativePath, apiDescription.HttpMethod )); @@ -130,7 +127,7 @@ namespace Volo.Abp.AspNetCore.Mvc ? matchedMethodParamNames[i] : parameterDescription.Name; - actionModel.AddParameter(new ParameterApiDescriptionModel( + actionModel.AddParameter(ParameterApiDescriptionModel.Create( parameterDescription.Name, matchedMethodParamName, parameterDescription.Type, @@ -161,7 +158,7 @@ namespace Volo.Abp.AspNetCore.Mvc { if (controllerType == null) { - return AbpControllerAssemblySetting.DefaultServiceModuleName; + return ModuleApiDescriptionModel.DefaultServiceModuleName; } foreach (var controllerSetting in _options.AppServiceControllers.ControllerAssemblySettings) @@ -178,7 +175,7 @@ namespace Volo.Abp.AspNetCore.Mvc return areaAttr.RouteValue; } - return AbpControllerAssemblySetting.DefaultServiceModuleName; + return ModuleApiDescriptionModel.DefaultServiceModuleName; } } } diff --git a/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs b/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs index fa77c9584d..17f5d51f7a 100644 --- a/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs +++ b/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs @@ -1,9 +1,9 @@ using System; using Castle.DynamicProxy; using Volo.Abp.Castle.DynamicProxy; -using Volo.Abp.Http; using Volo.Abp.Http.Client; using Volo.Abp.Http.Client.DynamicProxying; +using Volo.Abp.Http.Modeling; namespace Microsoft.Extensions.DependencyInjection { @@ -13,16 +13,16 @@ namespace Microsoft.Extensions.DependencyInjection //TODO: AddHttpClientProxies for adding all services from single assembly! - public static IServiceCollection AddHttpClientProxy(this IServiceCollection services, string baseUrl) + public static IServiceCollection AddHttpClientProxy(this IServiceCollection services, string baseUrl, string moduleName = ModuleApiDescriptionModel.DefaultServiceModuleName) { - return services.AddHttpClientProxy(typeof(T), baseUrl); + return services.AddHttpClientProxy(typeof(T), baseUrl, moduleName); } - public static IServiceCollection AddHttpClientProxy(this IServiceCollection services, Type type, string baseUrl) + public static IServiceCollection AddHttpClientProxy(this IServiceCollection services, Type type, string baseUrl, string moduleName = ModuleApiDescriptionModel.DefaultServiceModuleName) { services.Configure(options => { - options.HttpClientProxies[type] = new DynamicHttpClientProxyConfig(type, baseUrl); + options.HttpClientProxies[type] = new DynamicHttpClientProxyConfig(moduleName, baseUrl, type); }); var interceptorType = typeof(DynamicHttpProxyInterceptor<>).MakeGenericType(type); diff --git a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpClientProxyConfig.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpClientProxyConfig.cs index 1286db09cc..20df2dfd7e 100644 --- a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpClientProxyConfig.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpClientProxyConfig.cs @@ -4,14 +4,17 @@ namespace Volo.Abp.Http.Client.DynamicProxying { public class DynamicHttpClientProxyConfig { - public Type Type { get; } - public string BaseUrl { get; } - public DynamicHttpClientProxyConfig(Type type, string baseUrl) + public string ModuleName { get; } + + public Type Type { get; } + + public DynamicHttpClientProxyConfig(string moduleName, string baseUrl, Type type) { - Type = type; BaseUrl = baseUrl; + ModuleName = moduleName; + Type = type; } } } \ No newline at end of file diff --git a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs index e27b6007cb..b19d901bda 100644 --- a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs @@ -61,7 +61,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying var apiDescriptionModel = await _discoverManager.GetAsync(config.BaseUrl); - var action = FindAction(apiDescriptionModel, invocation.Method); + var action = FindAction(apiDescriptionModel, invocation.Method, config); using (var client = _httpClientFactory.Create()) { @@ -85,27 +85,33 @@ namespace Volo.Abp.Http.Client.DynamicProxying } } - private ActionApiDescriptionModel FindAction(ApplicationApiDescriptionModel apiDescriptionModel, MethodInfo method) + private ActionApiDescriptionModel FindAction(ApplicationApiDescriptionModel apiDescriptionModel, MethodInfo method, DynamicHttpClientProxyConfig config) { var methodParameters = method.GetParameters().ToArray(); foreach (var module in apiDescriptionModel.Modules.Values) { - //TODO: Check module type too + if (module.Name != config.ModuleName) + { + continue; + } foreach (var controller in module.Controllers.Values) { - //TODO: Check controller type too + if (controller.Interfaces.All(i => i.TypeAsString != typeof(TService).FullName)) + { + continue; + } foreach (var action in controller.Actions.Values) { - if (action.NameOnClass == method.Name && action.Parameters.Count == methodParameters.Length) + if (action.NameOnClass == method.Name && action.ParametersOnMethod.Count == methodParameters.Length) { var found = true; for (int i = 0; i < methodParameters.Length; i++) { - if (action.Parameters[i].TypeAsString != methodParameters[i].ParameterType.FullName) + if (action.ParametersOnMethod[i].TypeAsString != methodParameters[i].ParameterType.FullName) { found = false; break; diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs index a2c37fc324..aaac0bfba9 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs @@ -1,39 +1,47 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Reflection; namespace Volo.Abp.Http.Modeling { [Serializable] public class ActionApiDescriptionModel { - public string Name { get; } + public string UniqueName { get; set; } - public string NameOnClass { get; } + public string NameOnClass { get; set; } - public string HttpMethod { get; } + public string HttpMethod { get; set; } - public string Url { get; } + public string Url { get; set; } - //TODO: Add actual parameters on method + public IList ParametersOnMethod { get; set; } - public IList Parameters { get; } + public IList Parameters { get; set; } - public ReturnValueApiDescriptionModel ReturnValue { get; } + public ReturnValueApiDescriptionModel ReturnValue { get; set; } private ActionApiDescriptionModel() { } - public ActionApiDescriptionModel(string name, string nameOnClass, ReturnValueApiDescriptionModel returnValue, string url, string httpMethod = null) + public static ActionApiDescriptionModel Create(MethodInfo method, string uniqueName, string url, string httpMethod = null) { - Name = name; - NameOnClass = nameOnClass; - ReturnValue = returnValue; - Url = url; - HttpMethod = httpMethod; - - Parameters = new List(); + return new ActionApiDescriptionModel + { + UniqueName = uniqueName, + NameOnClass = method.Name, + Url = url, + HttpMethod = httpMethod, + ReturnValue = new ReturnValueApiDescriptionModel(method.ReturnType), + Parameters = new List(), + ParametersOnMethod = method + .GetParameters() + .Select(MethodParameterApiDescriptionModel.Create) + .ToList() + }; } public ParameterApiDescriptionModel AddParameter(ParameterApiDescriptionModel parameter) diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs index 6438c5e9b8..63f9aef716 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -7,11 +8,20 @@ namespace Volo.Abp.Http.Modeling [Serializable] public class ApplicationApiDescriptionModel { - public IDictionary Modules { get; } + public IDictionary Modules { get; set; } - public ApplicationApiDescriptionModel() + private ApplicationApiDescriptionModel() { - Modules = new Dictionary(); + + } + + public static ApplicationApiDescriptionModel Create() + { + return new ApplicationApiDescriptionModel + { + //TODO: Why ConcurrentDictionary? + Modules = new ConcurrentDictionary() + }; } public ModuleApiDescriptionModel AddModule(ModuleApiDescriptionModel module) @@ -26,7 +36,7 @@ namespace Volo.Abp.Http.Modeling public ModuleApiDescriptionModel GetOrAddModule(string name) { - return Modules.GetOrAdd(name, () => new ModuleApiDescriptionModel(name)); + return Modules.GetOrAdd(name, () => ModuleApiDescriptionModel.Create(name)); } public ApplicationApiDescriptionModel CreateSubModel(string[] modules = null, string[] controllers = null, string[] actions = null) diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs index ad5c53fbe2..b4bd4df80e 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs @@ -7,49 +7,58 @@ namespace Volo.Abp.Http.Modeling [Serializable] public class ControllerApiDescriptionModel { - public string Name { get; } + public string ControllerName { get; set; } - public Type Type { get; } + public string TypeAsString { get; set; } - public string TypeAsString { get; } + public List Interfaces { get; set; } - //TODO: Add interfaces implemented by this service. - - public IDictionary Actions { get; } + public Dictionary Actions { get; set; } private ControllerApiDescriptionModel() { } - public ControllerApiDescriptionModel(string name, Type type) + public static ControllerApiDescriptionModel Create(string controllerName, Type type) { - Name = name; - Type = type; - TypeAsString = type.FullName; - - Actions = new Dictionary(); + return new ControllerApiDescriptionModel + { + ControllerName = controllerName, + TypeAsString = type.FullName, + Actions = new Dictionary(), + Interfaces = type + .GetInterfaces() + .Select(ControllerInterfaceApiDescriptionModel.Create) + .ToList() + }; } public ActionApiDescriptionModel AddAction(ActionApiDescriptionModel action) { - if (Actions.ContainsKey(action.Name)) + if (Actions.ContainsKey(action.UniqueName)) { throw new AbpException( - $"Can not add more than one action with same name to the same controller. Controller: {Name}, Action: {action.Name}." + $"Can not add more than one action with same name to the same controller. Controller: {ControllerName}, Action: {action.UniqueName}." ); } - return Actions[action.Name] = action; + return Actions[action.UniqueName] = action; } public ControllerApiDescriptionModel CreateSubModel(string[] actions) { - var subModel = new ControllerApiDescriptionModel(Name, Type); + var subModel = new ControllerApiDescriptionModel + { + TypeAsString = TypeAsString, + Interfaces = Interfaces, + ControllerName = ControllerName, + Actions = new Dictionary() + }; foreach (var action in Actions.Values) { - if (actions == null || actions.Contains(action.Name)) + if (actions == null || actions.Contains(action.UniqueName)) { subModel.AddAction(action); } diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs new file mode 100644 index 0000000000..3868ec94f9 --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs @@ -0,0 +1,23 @@ +using System; + +namespace Volo.Abp.Http.Modeling +{ + [Serializable] + public class ControllerInterfaceApiDescriptionModel + { + public string TypeAsString { get; set; } + + private ControllerInterfaceApiDescriptionModel() + { + + } + + public static ControllerInterfaceApiDescriptionModel Create(Type type) + { + return new ControllerInterfaceApiDescriptionModel + { + TypeAsString = type.FullName + }; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs new file mode 100644 index 0000000000..fdc50090d2 --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs @@ -0,0 +1,33 @@ +using System; +using System.Reflection; + +namespace Volo.Abp.Http.Modeling +{ + [Serializable] + public class MethodParameterApiDescriptionModel + { + public string Name { get; set; } + + public string TypeAsString { get; set; } + + public bool IsOptional { get; set; } + + public object DefaultValue { get; set; } + + private MethodParameterApiDescriptionModel() + { + + } + + public static MethodParameterApiDescriptionModel Create(ParameterInfo parameterInfo) + { + return new MethodParameterApiDescriptionModel + { + Name = parameterInfo.Name, + TypeAsString = parameterInfo.ParameterType.FullName, + IsOptional = parameterInfo.IsOptional, + DefaultValue = parameterInfo.HasDefaultValue ? parameterInfo.DefaultValue : null + }; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs index a390550157..20ce707dff 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs @@ -7,44 +7,51 @@ namespace Volo.Abp.Http.Modeling [Serializable] public class ModuleApiDescriptionModel { + /// + /// "app". + /// + public const string DefaultServiceModuleName = "app"; + public string Name { get; set; } - public IDictionary Controllers { get; } + public IDictionary Controllers { get; set; } private ModuleApiDescriptionModel() { } - public ModuleApiDescriptionModel(string name) + public static ModuleApiDescriptionModel Create(string name) { - Name = name; - - Controllers = new Dictionary(); + return new ModuleApiDescriptionModel + { + Name = name, + Controllers = new Dictionary() + }; } public ControllerApiDescriptionModel AddController(ControllerApiDescriptionModel controller) { - if (Controllers.ContainsKey(controller.Name)) + if (Controllers.ContainsKey(controller.ControllerName)) { - throw new AbpException($"There is already a controller with name: {controller.Name} in module: {Name}"); + throw new AbpException($"There is already a controller with name: {controller.ControllerName} in module: {Name}"); } - return Controllers[controller.Name] = controller; + return Controllers[controller.ControllerName] = controller; } public ControllerApiDescriptionModel GetOrAddController(string name, Type type) { - return Controllers.GetOrAdd(name, () => new ControllerApiDescriptionModel(name, type)); + return Controllers.GetOrAdd(name, () => ControllerApiDescriptionModel.Create(name, type)); } public ModuleApiDescriptionModel CreateSubModel(string[] controllers, string[] actions) { - var subModel = new ModuleApiDescriptionModel(Name); + var subModel = ModuleApiDescriptionModel.Create(Name); foreach (var controller in Controllers.Values) { - if (controllers == null || controllers.Contains(controller.Name)) + if (controllers == null || controllers.Contains(controller.ControllerName)) { subModel.AddController(controller.CreateSubModel(actions)); } diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs index a5d0dde0a1..d3e9a5fbab 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs @@ -5,37 +5,40 @@ namespace Volo.Abp.Http.Modeling [Serializable] public class ParameterApiDescriptionModel { - public string NameOnMethod { get; } + public string NameOnMethod { get; set; } - public string Name { get; } + public string Name { get; set; } - public Type Type { get; } + public Type Type { get; set; } - public string TypeAsString { get; } + public string TypeAsString { get; set; } - public bool IsOptional { get; } + public bool IsOptional { get; set; } - public object DefaultValue { get; } + public object DefaultValue { get; set; } - public string[] ConstraintTypes { get; } + public string[] ConstraintTypes { get; set; } - public string BindingSourceId { get; } + public string BindingSourceId { get; set; } private ParameterApiDescriptionModel() { } - public ParameterApiDescriptionModel(string name, string nameOnMethod, Type type, bool isOptional = false, object defaultValue = null, string[] constraintTypes = null, string bindingSourceId = null) + public static ParameterApiDescriptionModel Create(string name, string nameOnMethod, Type type, bool isOptional = false, object defaultValue = null, string[] constraintTypes = null, string bindingSourceId = null) { - Name = name; - NameOnMethod = nameOnMethod; - Type = type; - TypeAsString = type.FullName; - IsOptional = isOptional; - DefaultValue = defaultValue; - ConstraintTypes = constraintTypes; - BindingSourceId = bindingSourceId; + return new ParameterApiDescriptionModel + { + Name = name, + NameOnMethod = nameOnMethod, + Type = type, + TypeAsString = type.FullName, + IsOptional = isOptional, + DefaultValue = defaultValue, + ConstraintTypes = constraintTypes, + BindingSourceId = bindingSourceId + }; } } } \ No newline at end of file