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(); }