diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln index 64f8b664f..d7c8a7fa4 100644 --- a/aspnet-core/LINGYUN.MicroService.All.sln +++ b/aspnet-core/LINGYUN.MicroService.All.sln @@ -468,6 +468,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Notifications.C EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Notifications.Jobs", "modules\common\LINGYUN.Abp.Notifications.Jobs\LINGYUN.Abp.Notifications.Jobs.csproj", "{3E9D07D8-963C-4A61-B720-BD47593BE752}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Http.Client.Wrapper", "modules\common\LINGYUN.Abp.Http.Client.Wrapper\LINGYUN.Abp.Http.Client.Wrapper.csproj", "{942816E3-B270-40DC-9532-C1077FF59A32}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Actors.AspNetCore.Wrapper", "modules\dapr\LINGYUN.Abp.Dapr.Actors.AspNetCore.Wrapper\LINGYUN.Abp.Dapr.Actors.AspNetCore.Wrapper.csproj", "{FBB50072-33BE-4B4A-8908-E98BC0C80B92}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1214,6 +1218,14 @@ Global {3E9D07D8-963C-4A61-B720-BD47593BE752}.Debug|Any CPU.Build.0 = Debug|Any CPU {3E9D07D8-963C-4A61-B720-BD47593BE752}.Release|Any CPU.ActiveCfg = Release|Any CPU {3E9D07D8-963C-4A61-B720-BD47593BE752}.Release|Any CPU.Build.0 = Release|Any CPU + {942816E3-B270-40DC-9532-C1077FF59A32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {942816E3-B270-40DC-9532-C1077FF59A32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {942816E3-B270-40DC-9532-C1077FF59A32}.Release|Any CPU.ActiveCfg = Release|Any CPU + {942816E3-B270-40DC-9532-C1077FF59A32}.Release|Any CPU.Build.0 = Release|Any CPU + {FBB50072-33BE-4B4A-8908-E98BC0C80B92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FBB50072-33BE-4B4A-8908-E98BC0C80B92}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FBB50072-33BE-4B4A-8908-E98BC0C80B92}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FBB50072-33BE-4B4A-8908-E98BC0C80B92}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1443,6 +1455,8 @@ Global {ECC8B9A9-9E92-4493-984D-2E350A49189D} = {C5CAD011-DF84-4914-939C-0C029DCEF26F} {62971DAE-CE71-4E9C-B6F5-514C8E2B915C} = {ECC8B9A9-9E92-4493-984D-2E350A49189D} {3E9D07D8-963C-4A61-B720-BD47593BE752} = {ECC8B9A9-9E92-4493-984D-2E350A49189D} + {942816E3-B270-40DC-9532-C1077FF59A32} = {8AC72641-30D3-4ACF-89FA-808FADC55C2E} + {FBB50072-33BE-4B4A-8908-E98BC0C80B92} = {DC33925B-264D-421B-96CC-46F853CBCC70} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/FodyWeavers.xml b/aspnet-core/modules/common/LINGYUN.Abp.Http.Client.Wrapper/FodyWeavers.xml similarity index 100% rename from aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/FodyWeavers.xml rename to aspnet-core/modules/common/LINGYUN.Abp.Http.Client.Wrapper/FodyWeavers.xml diff --git a/aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/FodyWeavers.xsd b/aspnet-core/modules/common/LINGYUN.Abp.Http.Client.Wrapper/FodyWeavers.xsd similarity index 100% rename from aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/FodyWeavers.xsd rename to aspnet-core/modules/common/LINGYUN.Abp.Http.Client.Wrapper/FodyWeavers.xsd diff --git a/aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/LINGYUN.Abp.HttpClient.Wrapper.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Http.Client.Wrapper/LINGYUN.Abp.Http.Client.Wrapper.csproj similarity index 63% rename from aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/LINGYUN.Abp.HttpClient.Wrapper.csproj rename to aspnet-core/modules/common/LINGYUN.Abp.Http.Client.Wrapper/LINGYUN.Abp.Http.Client.Wrapper.csproj index 40f24499c..8ac196841 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/LINGYUN.Abp.HttpClient.Wrapper.csproj +++ b/aspnet-core/modules/common/LINGYUN.Abp.Http.Client.Wrapper/LINGYUN.Abp.Http.Client.Wrapper.csproj @@ -4,7 +4,7 @@ - net6.0 + netstandard2.0 @@ -12,8 +12,8 @@ - - - + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Http.Client.Wrapper/LINGYUN/Abp/Http/Client/Wrapper/AbpHttpClientWrapperModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Http.Client.Wrapper/LINGYUN/Abp/Http/Client/Wrapper/AbpHttpClientWrapperModule.cs new file mode 100644 index 000000000..723d010bc --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Http.Client.Wrapper/LINGYUN/Abp/Http/Client/Wrapper/AbpHttpClientWrapperModule.cs @@ -0,0 +1,33 @@ +using LINGYUN.Abp.Wrapper; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Http.Client; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Http.Client.Wrapper; + +[DependsOn( + typeof(AbpHttpClientModule), + typeof(AbpWrapperModule))] +public class AbpHttpClientWrapperModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(options => + { + options.ProxyClientBuildActions.Add( + (_, builder) => + { + builder.ConfigureHttpClient((provider, client) => + { + var wrapperOptions = provider.GetRequiredService>(); + var wrapperHeader = wrapperOptions.Value.IsEnabled + ? AbpHttpWrapConsts.AbpWrapResult + : AbpHttpWrapConsts.AbpDontWrapResult; + + client.DefaultRequestHeaders.TryAddWithoutValidation(wrapperHeader, "true"); + }); + }); + }); + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/LINGYUN/Abp/HttpClient/Wrapper/AbpHttpClientWrapperModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/LINGYUN/Abp/HttpClient/Wrapper/AbpHttpClientWrapperModule.cs deleted file mode 100644 index 9f7aa9db9..000000000 --- a/aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/LINGYUN/Abp/HttpClient/Wrapper/AbpHttpClientWrapperModule.cs +++ /dev/null @@ -1,13 +0,0 @@ -using LINGYUN.Abp.Wrapper; -using Volo.Abp.Http.Client; -using Volo.Abp.Modularity; - -namespace LINGYUN.Abp.HttpClient.Wrapper -{ - [DependsOn( - typeof(AbpHttpClientModule), - typeof(AbpWrapperModule))] - public class AbpHttpClientWrapperModule : AbpModule - { - } -} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/LINGYUN/Abp/HttpClient/Wrapper/DynamicHttpProxyInterceptorWrapClientProxy.cs b/aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/LINGYUN/Abp/HttpClient/Wrapper/DynamicHttpProxyInterceptorWrapClientProxy.cs deleted file mode 100644 index b568c0da6..000000000 --- a/aspnet-core/modules/common/LINGYUN.Abp.HttpClient.Wrapper/LINGYUN/Abp/HttpClient/Wrapper/DynamicHttpProxyInterceptorWrapClientProxy.cs +++ /dev/null @@ -1,153 +0,0 @@ -using LINGYUN.Abp.Wrapper; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.Content; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Http; -using Volo.Abp.Http.Client; -using Volo.Abp.Http.Client.Authentication; -using Volo.Abp.Http.Client.ClientProxying; -using Volo.Abp.Http.Client.DynamicProxying; - -namespace LINGYUN.Abp.HttpClient.Wrapper -{ - [Dependency(ReplaceServices = true)] - [ExposeServices(typeof(DynamicHttpProxyInterceptorClientProxy<>))] - public class DynamicHttpProxyInterceptorWrapClientProxy - : DynamicHttpProxyInterceptorClientProxy, ITransientDependency - { - protected IOptions WrapperOptions => LazyServiceProvider.LazyGetRequiredService>(); - - protected override async Task RequestAsync(ClientProxyRequestContext requestContext) - { - var response = await RequestAndGetResponseAsync(requestContext); - - var responseContent = response.Content; - - if (typeof(T) == typeof(IRemoteStreamContent) || - typeof(T) == typeof(RemoteStreamContent)) - { - /* returning a class that holds a reference to response - * content just to be sure that GC does not dispose of - * it before we finish doing our work with the stream */ - return (T)(object)new RemoteStreamContent( - await responseContent.ReadAsStreamAsync(), - responseContent.Headers?.ContentDisposition?.FileNameStar ?? - RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString(), - responseContent.Headers?.ContentType?.ToString(), - responseContent.Headers?.ContentLength); - } - - var stringContent = await responseContent.ReadAsStringAsync(); - - if (stringContent.IsNullOrWhiteSpace()) - { - return default; - } - - // 对于包装后的结果需要处理 - if (response.Headers.Contains(AbpHttpWrapConsts.AbpWrapResult)) - { - var wrapResult = JsonSerializer.Deserialize>(stringContent); - - ThrowExceptionForResponse(wrapResult); - - if (typeof(T) == typeof(string)) - { - return (T)(object)wrapResult.Result; - } - - return wrapResult.Result; - } - - if (typeof(T) == typeof(string)) - { - return (T)(object)stringContent; - } - - if (stringContent.IsNullOrWhiteSpace()) - { - return default; - } - - return JsonSerializer.Deserialize(stringContent); - } - - public override async Task CallRequestAsync(ClientProxyRequestContext requestContext) - { - var response = await RequestAndGetResponseAsync(requestContext); - // 对于包装后的结果需要处理 - if (response.Headers.Contains(AbpHttpWrapConsts.AbpWrapResult)) - { - var stringContent = await response.Content.ReadAsStringAsync(); - var wrapResult = JsonSerializer.Deserialize(stringContent); - - ThrowExceptionForResponse(wrapResult); - } - - return response.Content; - } - - protected virtual void ThrowExceptionForResponse(WrapResult wrapResult) - { - if (!string.Equals(wrapResult.Code, WrapperOptions.Value.CodeWithSuccess)) - { - var errorInfo = new RemoteServiceErrorInfo( - wrapResult.Message, - wrapResult.Details, - wrapResult.Code); - throw new AbpRemoteCallException(errorInfo) - { - HttpStatusCode = (int)WrapperOptions.Value.HttpStatusCode - }; - } - } - - protected virtual async Task RequestAndGetResponseAsync(ClientProxyRequestContext requestContext) - { - var clientConfig = ClientOptions.Value.HttpClientProxies.GetOrDefault(requestContext.ServiceType) ?? throw new AbpException($"Could not get HttpClientProxyConfig for {requestContext.ServiceType.FullName}."); - var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(clientConfig.RemoteServiceName); - - var client = HttpClientFactory.Create(clientConfig.RemoteServiceName); - - var apiVersion = await GetApiVersionInfoAsync(requestContext); - var url = remoteServiceConfig.BaseUrl.EnsureEndsWith('/') + await GetUrlWithParametersAsync(requestContext, apiVersion); - - var requestMessage = new HttpRequestMessage(requestContext.Action.GetHttpMethod(), url) - { - Content = await ClientProxyRequestPayloadBuilder.BuildContentAsync(requestContext.Action, requestContext.Arguments, JsonSerializer, apiVersion) - }; - - AddHeaders(requestContext.Arguments, requestContext.Action, requestMessage, apiVersion); - - if (requestContext.Action.AllowAnonymous != true) - { - await ClientAuthenticator.Authenticate( - new RemoteServiceHttpClientAuthenticateContext( - client, - requestMessage, - remoteServiceConfig, - clientConfig.RemoteServiceName - ) - ); - } - - var response = await client.SendAsync( - requestMessage, - HttpCompletionOption.ResponseHeadersRead /*this will buffer only the headers, the content will be used as a stream*/, - GetCancellationToken(requestContext.Arguments) - ); - - if (!response.IsSuccessStatusCode) - { - await ThrowExceptionForResponseAsync(response); - } - - return response; - } - } -} diff --git a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client.Wrapper/LINGYUN/Abp/Dapr/Client/Wrapper/AbpDaprClientWrapperModule.cs b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client.Wrapper/LINGYUN/Abp/Dapr/Client/Wrapper/AbpDaprClientWrapperModule.cs index 9b17166bf..2766623bb 100644 --- a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client.Wrapper/LINGYUN/Abp/Dapr/Client/Wrapper/AbpDaprClientWrapperModule.cs +++ b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client.Wrapper/LINGYUN/Abp/Dapr/Client/Wrapper/AbpDaprClientWrapperModule.cs @@ -1,10 +1,11 @@ -using LINGYUN.Abp.Dapr.Client.DynamicProxying; -using LINGYUN.Abp.Wrapper; +using LINGYUN.Abp.Wrapper; using Microsoft.Extensions.Options; using Volo.Abp.Http; using Volo.Abp.Http.Client; using Volo.Abp.Json; using Volo.Abp.Modularity; +using Microsoft.Extensions.DependencyInjection; +using LINGYUN.Abp.Dapr.Client.ClientProxying; namespace LINGYUN.Abp.Dapr.Client.Wrapper { @@ -14,8 +15,20 @@ namespace LINGYUN.Abp.Dapr.Client.Wrapper { public override void ConfigureServices(ServiceConfigurationContext context) { + var wrapperOptions = context.Services.ExecutePreConfiguredActions(); + Configure(options => { + options.ProxyRequestActions.Add( + (_, request) => + { + var wrapperHeader = wrapperOptions.IsEnabled + ? AbpHttpWrapConsts.AbpWrapResult + : AbpHttpWrapConsts.AbpDontWrapResult; + + request.Headers.TryAddWithoutValidation(wrapperHeader, "true"); + }); + options.OnResponse(async (response, serviceProvider) => { var stringContent = await response.Content.ReadAsStringAsync(); diff --git a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/AbpDaprClientProxyOptions.cs b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/ClientProxying/AbpDaprClientProxyOptions.cs similarity index 90% rename from aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/AbpDaprClientProxyOptions.cs rename to aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/ClientProxying/AbpDaprClientProxyOptions.cs index 9aa24063e..d359469c9 100644 --- a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/AbpDaprClientProxyOptions.cs +++ b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/ClientProxying/AbpDaprClientProxyOptions.cs @@ -1,10 +1,11 @@ -using System; +using LINGYUN.Abp.Dapr.Client.DynamicProxying; +using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; -namespace LINGYUN.Abp.Dapr.Client.DynamicProxying +namespace LINGYUN.Abp.Dapr.Client.ClientProxying { public class AbpDaprClientProxyOptions { diff --git a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/ClientProxying/DaprClientProxyBase.cs b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/ClientProxying/DaprClientProxyBase.cs new file mode 100644 index 000000000..dca292e43 --- /dev/null +++ b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/ClientProxying/DaprClientProxyBase.cs @@ -0,0 +1,124 @@ +using Dapr.Client; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Content; +using Volo.Abp.Http.Client.Authentication; +using Volo.Abp.Http.Client.ClientProxying; + +namespace LINGYUN.Abp.Dapr.Client.ClientProxying +{ + public abstract class DaprClientProxyBase : ClientProxyBase + { + protected IOptions DaprClientProxyOptions => LazyServiceProvider.LazyGetRequiredService>(); + protected IDaprClientFactory DaprClientFactory => LazyServiceProvider.LazyGetRequiredService(); + + protected async override Task RequestAsync(ClientProxyRequestContext requestContext) + { + var response = await MakeRequestAsync(requestContext); + + var responseContent = response.Content; + + if (typeof(T) == typeof(IRemoteStreamContent) || + typeof(T) == typeof(RemoteStreamContent)) + { + /* returning a class that holds a reference to response + * content just to be sure that GC does not dispose of + * it before we finish doing our work with the stream */ + return (T)(object)new RemoteStreamContent( + await responseContent.ReadAsStreamAsync(), + responseContent.Headers?.ContentDisposition?.FileNameStar ?? + RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString(), + responseContent.Headers?.ContentType?.ToString(), + responseContent.Headers?.ContentLength); + } + + var stringContent = await DaprClientProxyOptions + .Value + .ProxyResponseContent(response, LazyServiceProvider); + + if (stringContent.IsNullOrWhiteSpace()) + { + return default; + } + + if (typeof(T) == typeof(string)) + { + return (T)(object)stringContent; + } + + return JsonSerializer.Deserialize(stringContent); + } + + protected async override Task GetConfiguredApiVersionAsync(ClientProxyRequestContext requestContext) + { + var clientConfig = DaprClientProxyOptions.Value.DaprClientProxies.GetOrDefault(requestContext.ServiceType) + ?? throw new AbpException($"Could not get DynamicDaprClientProxyConfig for {requestContext.ServiceType.FullName}."); + var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(clientConfig.RemoteServiceName); + + return remoteServiceConfig?.Version; + } + + private async Task MakeRequestAsync(ClientProxyRequestContext requestContext) + { + var clientConfig = DaprClientProxyOptions.Value.DaprClientProxies.GetOrDefault(requestContext.ServiceType) ?? throw new AbpException($"Could not get DaprClientProxyConfig for {requestContext.ServiceType.FullName}."); + var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(clientConfig.RemoteServiceName); + + var appId = remoteServiceConfig.GetAppId(); + var apiVersion = await GetApiVersionInfoAsync(requestContext); + var methodName = await GetUrlWithParametersAsync(requestContext, apiVersion); + // See: https://docs.dapr.io/reference/api/service_invocation_api/#examples + var daprClient = DaprClientFactory.CreateClient(clientConfig.RemoteServiceName); + var requestMessage = daprClient.CreateInvokeMethodRequest( + requestContext.Action.GetHttpMethod(), + appId, + methodName); + requestMessage.Content = await ClientProxyRequestPayloadBuilder.BuildContentAsync( + requestContext.Action, + requestContext.Arguments, + JsonSerializer, + apiVersion); + + AddHeaders(requestContext.Arguments, requestContext.Action, requestMessage, apiVersion); + + if (requestContext.Action.AllowAnonymous != true) + { + var httpClient = HttpClientFactory.Create(AbpDaprClientModule.DaprHttpClient); + + await ClientAuthenticator.Authenticate( + new RemoteServiceHttpClientAuthenticateContext( + httpClient, + requestMessage, + remoteServiceConfig, + clientConfig.RemoteServiceName + ) + ); + + // 其他库可能将授权标头写入到HttpClient中 + if (requestMessage.Headers.Authorization == null && + httpClient.DefaultRequestHeaders.Authorization != null) + { + requestMessage.Headers.Authorization = httpClient.DefaultRequestHeaders.Authorization; + } + } + + // 增加一个可配置的请求消息 + foreach (var clientRequestAction in DaprClientProxyOptions.Value.ProxyRequestActions) + { + clientRequestAction(appId, requestMessage); + } + + var response = await daprClient.InvokeMethodWithResponseAsync(requestMessage, GetCancellationToken(requestContext.Arguments)); + + if (!response.IsSuccessStatusCode) + { + await ThrowExceptionForResponseAsync(response); + } + + return response; + } + } +} diff --git a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/DynamicDaprClientProxyInterceptor.cs b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/DynamicDaprClientProxyInterceptor.cs index baea6e563..2344d9892 100644 --- a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/DynamicDaprClientProxyInterceptor.cs +++ b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/DynamicDaprClientProxyInterceptor.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Logging; +using LINGYUN.Abp.Dapr.Client.ClientProxying; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using System; diff --git a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/DynamicDaprProxyInterceptorClientProxy.cs b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/DynamicDaprProxyInterceptorClientProxy.cs index 80d7e550f..489dec591 100644 --- a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/DynamicDaprProxyInterceptorClientProxy.cs +++ b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/DynamicDaprProxyInterceptorClientProxy.cs @@ -1,134 +1,20 @@ -using Dapr.Client; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; +using LINGYUN.Abp.Dapr.Client.ClientProxying; using System.Net.Http; using System.Threading.Tasks; -using Volo.Abp; -using Volo.Abp.Content; -using Volo.Abp.Http.Client.Authentication; using Volo.Abp.Http.Client.ClientProxying; namespace LINGYUN.Abp.Dapr.Client.DynamicProxying { - public class DynamicDaprProxyInterceptorClientProxy : ClientProxyBase + public class DynamicDaprProxyInterceptorClientProxy : DaprClientProxyBase { - protected IOptions DaprClientProxyOptions => LazyServiceProvider.LazyGetRequiredService>(); - protected IDaprClientFactory DaprClientFactory => LazyServiceProvider.LazyGetRequiredService(); - - public virtual async Task CallRequestAsync(ClientProxyRequestContext requestContext) + public async virtual Task CallRequestAsync(ClientProxyRequestContext requestContext) { return await RequestAsync(requestContext); } - public virtual async Task CallRequestAsync(ClientProxyRequestContext requestContext) + public async virtual Task CallRequestAsync(ClientProxyRequestContext requestContext) { return await RequestAsync(requestContext); } - - protected override async Task RequestAsync(ClientProxyRequestContext requestContext) - { - var response = await MakeRequestAsync(requestContext); - - var responseContent = response.Content; - - if (typeof(T) == typeof(IRemoteStreamContent) || - typeof(T) == typeof(RemoteStreamContent)) - { - /* returning a class that holds a reference to response - * content just to be sure that GC does not dispose of - * it before we finish doing our work with the stream */ - return (T)(object)new RemoteStreamContent( - await responseContent.ReadAsStreamAsync(), - responseContent.Headers?.ContentDisposition?.FileNameStar ?? - RemoveQuotes(responseContent.Headers?.ContentDisposition?.FileName).ToString(), - responseContent.Headers?.ContentType?.ToString(), - responseContent.Headers?.ContentLength); - } - - var stringContent = await DaprClientProxyOptions - .Value - .ProxyResponseContent(response, LazyServiceProvider); - - if (stringContent.IsNullOrWhiteSpace()) - { - return default; - } - - if (typeof(T) == typeof(string)) - { - return (T)(object)stringContent; - } - - return JsonSerializer.Deserialize(stringContent); - } - - protected override async Task GetConfiguredApiVersionAsync(ClientProxyRequestContext requestContext) - { - var clientConfig = DaprClientProxyOptions.Value.DaprClientProxies.GetOrDefault(requestContext.ServiceType) - ?? throw new AbpException($"Could not get DynamicDaprClientProxyConfig for {requestContext.ServiceType.FullName}."); - var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(clientConfig.RemoteServiceName); - - return remoteServiceConfig?.Version; - } - - private async Task MakeRequestAsync(ClientProxyRequestContext requestContext) - { - var clientConfig = DaprClientProxyOptions.Value.DaprClientProxies.GetOrDefault(requestContext.ServiceType) ?? throw new AbpException($"Could not get DaprClientProxyConfig for {requestContext.ServiceType.FullName}."); - var remoteServiceConfig = await RemoteServiceConfigurationProvider.GetConfigurationOrDefaultAsync(clientConfig.RemoteServiceName); - - var appId = remoteServiceConfig.GetAppId(); - var apiVersion = await GetApiVersionInfoAsync(requestContext); - var methodName = await GetUrlWithParametersAsync(requestContext, apiVersion); - // See: https://docs.dapr.io/reference/api/service_invocation_api/#examples - var daprClient = DaprClientFactory.CreateClient(clientConfig.RemoteServiceName); - var requestMessage = daprClient.CreateInvokeMethodRequest( - requestContext.Action.GetHttpMethod(), - appId, - methodName); - requestMessage.Content = await ClientProxyRequestPayloadBuilder.BuildContentAsync( - requestContext.Action, - requestContext.Arguments, - JsonSerializer, - apiVersion); - - AddHeaders(requestContext.Arguments, requestContext.Action, requestMessage, apiVersion); - - if (requestContext.Action.AllowAnonymous != true) - { - var httpClient = HttpClientFactory.Create(AbpDaprClientModule.DaprHttpClient); - - await ClientAuthenticator.Authenticate( - new RemoteServiceHttpClientAuthenticateContext( - httpClient, - requestMessage, - remoteServiceConfig, - clientConfig.RemoteServiceName - ) - ); - - // 其他库可能将授权标头写入到HttpClient中 - if (requestMessage.Headers.Authorization == null && - httpClient.DefaultRequestHeaders.Authorization != null) - { - requestMessage.Headers.Authorization = httpClient.DefaultRequestHeaders.Authorization; - } - } - - // 增加一个可配置的请求消息 - foreach (var clientRequestAction in DaprClientProxyOptions.Value.ProxyRequestActions) - { - clientRequestAction(appId, requestMessage); - } - - var response = await daprClient.InvokeMethodWithResponseAsync(requestMessage, GetCancellationToken(requestContext.Arguments)); - - if (!response.IsSuccessStatusCode) - { - await ThrowExceptionForResponseAsync(response); - } - - return response; - } } } diff --git a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicDaprClientProxyExtensions.cs b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDaprClientProxyExtensions.cs similarity index 81% rename from aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicDaprClientProxyExtensions.cs rename to aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDaprClientProxyExtensions.cs index c5d34a9c4..27e81105a 100644 --- a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicDaprClientProxyExtensions.cs +++ b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDaprClientProxyExtensions.cs @@ -2,6 +2,7 @@ using Dapr.Client; using JetBrains.Annotations; using LINGYUN.Abp.Dapr.Client; +using LINGYUN.Abp.Dapr.Client.ClientProxying; using LINGYUN.Abp.Dapr.Client.DynamicProxying; using Microsoft.Extensions.Options; using System; @@ -14,11 +15,37 @@ using Volo.Abp.Validation; namespace Microsoft.Extensions.DependencyInjection { - public static class ServiceCollectionDynamicDaprClientProxyExtensions + public static class ServiceCollectionDaprClientProxyExtensions { private static readonly ProxyGenerator ProxyGeneratorInstance = new ProxyGenerator(); - #region Add DaprClient Proxies + #region Add Static DaprClient Proxies + + public static IServiceCollection AddStaticDaprClientProxies( + [NotNull] this IServiceCollection services, + [NotNull] Assembly assembly, + [NotNull] string remoteServiceConfigurationName = RemoteServiceConfigurationDictionary.DefaultName) + { + Check.NotNull(services, nameof(assembly)); + + var serviceTypes = assembly.GetTypes().Where(IsSuitableForClientProxying).ToArray(); + + foreach (var serviceType in serviceTypes) + { + AddDaprClientFactory(services, remoteServiceConfigurationName); + + services.Configure(options => + { + options.DaprClientProxies[serviceType] = new DynamicDaprClientProxyConfig(serviceType, remoteServiceConfigurationName); + }); + } + + return services; + } + + #endregion + + #region Add Dynamic DaprClient Proxies public static IServiceCollection AddDaprClientProxies( [NotNull] this IServiceCollection services, @@ -28,7 +55,7 @@ namespace Microsoft.Extensions.DependencyInjection { Check.NotNull(services, nameof(assembly)); - var serviceTypes = assembly.GetTypes().Where(IsSuitableForDynamicActorProxying).ToArray(); + var serviceTypes = assembly.GetTypes().Where(IsSuitableForClientProxying).ToArray(); foreach (var serviceType in serviceTypes) { @@ -153,7 +180,7 @@ namespace Microsoft.Extensions.DependencyInjection return services; } - private static bool IsSuitableForDynamicActorProxying(Type type) + private static bool IsSuitableForClientProxying(Type type) { //TODO: Add option to change type filter diff --git a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/README.md b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/README.md index 5b59dca79..23b9f7489 100644 --- a/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/README.md +++ b/aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/README.md @@ -152,7 +152,7 @@ public class InvokeClass ## 配置项说明 -* AbpDaprRemoteServiceOptions.RemoteServices 配置Dapr.AppId +* AbpRemoteServiceOptions.RemoteServices 配置Dapr.AppId ```json diff --git a/aspnet-core/tests/LINGYUN.Abp.Dapr.AspNetCore.TestHost/LINGYUN/Abp/Dapr/ServiceInvocation/TestAppService.cs b/aspnet-core/tests/LINGYUN.Abp.Dapr.AspNetCore.TestHost/LINGYUN/Abp/Dapr/ServiceInvocation/TestAppService.cs index 01373762e..16bcec150 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Dapr.AspNetCore.TestHost/LINGYUN/Abp/Dapr/ServiceInvocation/TestAppService.cs +++ b/aspnet-core/tests/LINGYUN.Abp.Dapr.AspNetCore.TestHost/LINGYUN/Abp/Dapr/ServiceInvocation/TestAppService.cs @@ -12,7 +12,6 @@ namespace LINGYUN.Abp.Dapr.ServiceInvocation [Route("api/dapr/test")] public class TestAppService : AbpController, ITestAppService { - private static int _inctement; private readonly List _cache = new List { new NameValue("name1", "value1"), @@ -29,11 +28,9 @@ namespace LINGYUN.Abp.Dapr.ServiceInvocation } [HttpPut] - public Task UpdateAsync() + public Task UpdateAsync(int inctement) { - Interlocked.Increment(ref _inctement); - - _cache[0].Value = $"value:updated:{_inctement}"; + _cache[0].Value = $"value:updated:{inctement}"; return Task.FromResult(_cache[0]); } diff --git a/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/ClientProxies/TestClientProxy.Generated.cs b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/ClientProxies/TestClientProxy.Generated.cs new file mode 100644 index 000000000..1e9d70f80 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/ClientProxies/TestClientProxy.Generated.cs @@ -0,0 +1,45 @@ +// This file is automatically generated by ABP framework to use MVC Controllers from CSharp +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Http.Client; +using Volo.Abp.Http.Modeling; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Client.ClientProxying; +using LINGYUN.Abp.Dapr.ServiceInvocation; +using LINGYUN.Abp.Dapr; +using System.Linq; +using Volo.Abp; +using System.Collections.Generic; +using Volo.Abp.Reflection; +using System.Net.Http; +using LINGYUN.Abp.Dapr.Client.ClientProxying; + +// ReSharper disable once CheckNamespace +namespace LINGYUN.Abp.Dapr.ServiceInvocation.ClientProxies; + +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(ITestAppService), typeof(TestClientProxy))] +public partial class TestClientProxy : DaprClientProxyBase, ITestAppService +{ + public virtual async Task> GetAsync() + { + return await RequestAsync>(nameof(GetAsync)); + } + + public virtual async Task UpdateAsync(int inctement) + { + return await RequestAsync(nameof(UpdateAsync), new ClientProxyRequestTypeValue + { + { typeof(int), inctement } + }); + } + + public virtual async Task GetWrapedAsync(string name) + { + return await RequestAsync(nameof(GetWrapedAsync), new ClientProxyRequestTypeValue + { + { typeof(string), name } + }); + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/ClientProxies/TestClientProxy.cs b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/ClientProxies/TestClientProxy.cs new file mode 100644 index 000000000..8727dae3b --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/ClientProxies/TestClientProxy.cs @@ -0,0 +1,7 @@ +// This file is part of TestClientProxy, you can customize it here +// ReSharper disable once CheckNamespace +namespace LINGYUN.Abp.Dapr.ServiceInvocation.ClientProxies; + +public partial class TestClientProxy +{ +} diff --git a/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/ClientProxies/app-generate-proxy.json b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/ClientProxies/app-generate-proxy.json new file mode 100644 index 000000000..227944676 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/ClientProxies/app-generate-proxy.json @@ -0,0 +1,114 @@ +{ + "modules": { + "app": { + "rootPath": "app", + "remoteServiceName": "TestDapr", + "controllers": { + "LINGYUN.Abp.Dapr.ServiceInvocation.TestAppService": { + "controllerName": "Test", + "controllerGroupName": "Test", + "isRemoteService": true, + "apiVersion": null, + "type": "LINGYUN.Abp.Dapr.ServiceInvocation.TestAppService", + "interfaces": [ + { + "type": "LINGYUN.Abp.Dapr.ServiceInvocation.ITestAppService" + } + ], + "actions": { + "GetAsync": { + "uniqueName": "GetAsync", + "name": "GetAsync", + "httpMethod": "GET", + "url": "api/dapr/test", + "supportedVersions": [], + "parametersOnMethod": [], + "parameters": [], + "returnValue": { + "type": "Volo.Abp.Application.Dtos.ListResultDto", + "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" + }, + "allowAnonymous": null, + "implementFrom": "LINGYUN.Abp.Dapr.ServiceInvocation.ITestAppService" + }, + "UpdateAsyncByInctement": { + "uniqueName": "UpdateAsyncByInctement", + "name": "UpdateAsync", + "httpMethod": "PUT", + "url": "api/dapr/test", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "inctement", + "typeAsString": "System.Int32, System.Private.CoreLib", + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "inctement", + "name": "inctement", + "jsonName": null, + "type": "System.Int32", + "typeSimple": "number", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "LINGYUN.Abp.Dapr.NameValue", + "typeSimple": "LINGYUN.Abp.Dapr.NameValue" + }, + "allowAnonymous": null, + "implementFrom": "LINGYUN.Abp.Dapr.ServiceInvocation.ITestAppService" + }, + "GetWrapedAsyncByName": { + "uniqueName": "GetWrapedAsyncByName", + "name": "GetWrapedAsync", + "httpMethod": "GET", + "url": "api/dapr/test/{name}", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "name", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "name", + "name": "name", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + } + ], + "returnValue": { + "type": "LINGYUN.Abp.Dapr.TestNeedWrapObject", + "typeSimple": "LINGYUN.Abp.Dapr.TestNeedWrapObject" + }, + "allowAnonymous": null, + "implementFrom": "LINGYUN.Abp.Dapr.ServiceInvocation.ITestAppService" + } + } + } + } + } + }, + "types": {} +} \ No newline at end of file diff --git a/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN.Abp.Dapr.Client.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN.Abp.Dapr.Client.Tests.csproj index 012ccc756..f137662a1 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN.Abp.Dapr.Client.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN.Abp.Dapr.Client.Tests.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -6,6 +6,14 @@ false + + + + + + + + diff --git a/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN/Abp/Dapr/Client/Tests/AbpDaptClientTestModule.cs b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN/Abp/Dapr/Client/Tests/AbpDaptClientTestModule.cs index c14f7599d..ac39f5d84 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN/Abp/Dapr/Client/Tests/AbpDaptClientTestModule.cs +++ b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN/Abp/Dapr/Client/Tests/AbpDaptClientTestModule.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration; using System.IO; using LINGYUN.Abp.Dapr.Client.Wrapper; +using Volo.Abp.VirtualFileSystem; namespace LINGYUN.Abp.Dapr.Client.Tests { @@ -23,13 +24,11 @@ namespace LINGYUN.Abp.Dapr.Client.Tests EnvironmentName = "Testing", BasePath = Directory.GetCurrentDirectory() })); - } - public override void ConfigureServices(ServiceConfigurationContext context) - { - context.Services.AddDaprClientProxies( - typeof(AbpDaprTestModule).Assembly, - "TestDapr"); + Configure(options => + { + options.FileSets.AddEmbedded(); + }); } } } diff --git a/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN/Abp/Dapr/Client/Tests/TestAppServiceStaticProxyTests.cs b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN/Abp/Dapr/Client/Tests/TestAppServiceStaticProxyTests.cs new file mode 100644 index 000000000..cfe68d82f --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN/Abp/Dapr/Client/Tests/TestAppServiceStaticProxyTests.cs @@ -0,0 +1,53 @@ +using LINGYUN.Abp.Dapr.ServiceInvocation; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace LINGYUN.Abp.Dapr.Client.Tests +{ + public class TestAppServiceStaticProxyTests : AbpDaptClientTestBase + { + private readonly ITestAppService _service; + + public TestAppServiceStaticProxyTests() + { + _service = GetRequiredService(); + } + + protected override void BeforeAddApplication(IServiceCollection services) + { + services.AddStaticDaprClientProxies( + typeof(AbpDaprTestModule).Assembly, + "TestDapr"); + } + + [Fact] + public async Task Get_Result_Items_Count_Should_5() + { + var result = await _service.GetAsync(); + + result.Items.Count.ShouldBe(5); + } + + [Fact] + public async Task Should_Get_Wraped_Object() + { + var result = await _service.GetWrapedAsync("Test"); + + result.Name.ShouldBe("Test"); + } + + [Fact] + public async Task Update_Result_Value_Should_Value_Updated_1() + { + var result = await _service.UpdateAsync(1); + + result.Value.ShouldBe("value:updated:1"); + } + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN/Abp/Dapr/Client/Tests/TestAppServiceTests.cs b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN/Abp/Dapr/Client/Tests/TestAppServiceTests.cs index 40329a2f0..4e3980cbf 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN/Abp/Dapr/Client/Tests/TestAppServiceTests.cs +++ b/aspnet-core/tests/LINGYUN.Abp.Dapr.Client.Tests/LINGYUN/Abp/Dapr/Client/Tests/TestAppServiceTests.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.Dapr.ServiceInvocation; +using Microsoft.Extensions.DependencyInjection; using Shouldly; using System.Threading.Tasks; using Xunit; @@ -14,6 +15,13 @@ namespace LINGYUN.Abp.Dapr.Client.Tests _service = GetRequiredService(); } + protected override void BeforeAddApplication(IServiceCollection services) + { + services.AddDaprClientProxies( + typeof(AbpDaprTestModule).Assembly, + "TestDapr"); + } + [Fact] public async Task Get_Result_Items_Count_Should_5() { @@ -33,7 +41,7 @@ namespace LINGYUN.Abp.Dapr.Client.Tests [Fact] public async Task Update_Result_Value_Should_Value_Updated_1() { - var result = await _service.UpdateAsync(); + var result = await _service.UpdateAsync(1); result.Value.ShouldBe("value:updated:1"); } diff --git a/aspnet-core/tests/LINGYUN.Abp.Dapr.Tests/LINGYUN/Abp/Dapr/ServiceInvocation/ITestAppService.cs b/aspnet-core/tests/LINGYUN.Abp.Dapr.Tests/LINGYUN/Abp/Dapr/ServiceInvocation/ITestAppService.cs index c543aa5b3..4c453c2e1 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Dapr.Tests/LINGYUN/Abp/Dapr/ServiceInvocation/ITestAppService.cs +++ b/aspnet-core/tests/LINGYUN.Abp.Dapr.Tests/LINGYUN/Abp/Dapr/ServiceInvocation/ITestAppService.cs @@ -9,7 +9,7 @@ namespace LINGYUN.Abp.Dapr.ServiceInvocation { Task> GetAsync(); - Task UpdateAsync(); + Task UpdateAsync(int inctement); Task GetWrapedAsync(string name); }