30 changed files with 900 additions and 622 deletions
@ -0,0 +1,18 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Http.Client" Version="5.0.0-rc.1" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.Wrapper\LINGYUN.Abp.Wrapper.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,13 @@ |
|||||
|
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 |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,153 @@ |
|||||
|
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<TService> |
||||
|
: DynamicHttpProxyInterceptorClientProxy<TService>, ITransientDependency |
||||
|
{ |
||||
|
protected IOptions<AbpWrapperOptions> WrapperOptions => LazyServiceProvider.LazyGetRequiredService<IOptions<AbpWrapperOptions>>(); |
||||
|
|
||||
|
protected override async Task<T> RequestAsync<T>(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<WrapResult<T>>(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<T>(stringContent); |
||||
|
} |
||||
|
|
||||
|
public override async Task<HttpContent> CallRequestAsync(ClientProxyRequestContext requestContext) |
||||
|
{ |
||||
|
var response = await RequestAndGetResponseAsync(requestContext); |
||||
|
// 对于包装后的结果需要处理
|
||||
|
if (response.Headers.Contains(AbpHttpWrapConsts.AbpWrapResult)) |
||||
|
{ |
||||
|
var stringContent = await response.Content.ReadAsStringAsync(); |
||||
|
var wrapResult = JsonSerializer.Deserialize<WrapResult>(stringContent); |
||||
|
|
||||
|
ThrowExceptionForResponse(wrapResult); |
||||
|
} |
||||
|
|
||||
|
return response.Content; |
||||
|
} |
||||
|
|
||||
|
protected virtual void ThrowExceptionForResponse<T>(WrapResult<T> 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<HttpResponseMessage> 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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,4 +1,4 @@ |
|||||
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper |
namespace LINGYUN.Abp.Wrapper |
||||
{ |
{ |
||||
public static class AbpHttpWrapConsts |
public static class AbpHttpWrapConsts |
||||
{ |
{ |
||||
@ -1,54 +1,61 @@ |
|||||
using Dapr.Actors; |
using Dapr.Actors; |
||||
using Dapr.Actors.Runtime; |
using Dapr.Actors.Runtime; |
||||
using Microsoft.AspNetCore.Builder; |
using LINGYUN.Abp.Wrapper; |
||||
using Microsoft.AspNetCore.Routing; |
using Microsoft.AspNetCore.Builder; |
||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.AspNetCore.Routing; |
||||
using System; |
using Microsoft.Extensions.DependencyInjection; |
||||
using System.Collections.Generic; |
using System; |
||||
using Volo.Abp.AspNetCore; |
using System.Collections.Generic; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.AspNetCore; |
||||
|
using Volo.Abp.Modularity; |
||||
namespace LINGYUN.Abp.Dapr.Actors.AspNetCore |
|
||||
{ |
namespace LINGYUN.Abp.Dapr.Actors.AspNetCore |
||||
[DependsOn( |
{ |
||||
typeof(AbpAspNetCoreModule))] |
[DependsOn( |
||||
public class AbpDaprActorsAspNetCoreModule : AbpModule |
typeof(AbpAspNetCoreModule), |
||||
{ |
typeof(AbpWrapperModule))] |
||||
public override void PreConfigureServices(ServiceConfigurationContext context) |
public class AbpDaprActorsAspNetCoreModule : AbpModule |
||||
{ |
{ |
||||
AddDefinitionActor(context.Services); |
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
} |
{ |
||||
|
AddDefinitionActor(context.Services); |
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
} |
||||
{ |
|
||||
Configure<AbpEndpointRouterOptions>(options => |
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
{ |
||||
options.EndpointConfigureActions.Add(endpointContext => |
Configure<AbpEndpointRouterOptions>(options => |
||||
{ |
{ |
||||
endpointContext.Endpoints.MapActorsHandlers(); |
options.EndpointConfigureActions.Add(endpointContext => |
||||
}); |
{ |
||||
}); |
endpointContext.Endpoints.MapActorsHandlers(); |
||||
} |
}); |
||||
|
}); |
||||
private static void AddDefinitionActor(IServiceCollection services) |
|
||||
{ |
Configure<AbpWrapperOptions>(options => |
||||
var actorRegistrations = new List<ActorRegistration>(); |
{ |
||||
|
options.IgnoreBaseTypes.TryAdd<IActor>(); |
||||
services.OnRegistred(context => |
}); |
||||
{ |
} |
||||
if (typeof(IActor).IsAssignableFrom(context.ImplementationType) && |
|
||||
!actorRegistrations.Contains(context.ImplementationType)) |
private static void AddDefinitionActor(IServiceCollection services) |
||||
{ |
{ |
||||
var actorRegistration = new ActorRegistration(context.ImplementationType.GetActorTypeInfo()); |
var actorRegistrations = new List<ActorRegistration>(); |
||||
|
|
||||
actorRegistrations.Add(actorRegistration); |
services.OnRegistred(context => |
||||
} |
{ |
||||
}); |
if (typeof(IActor).IsAssignableFrom(context.ImplementationType) && |
||||
|
!actorRegistrations.Contains(context.ImplementationType)) |
||||
services.AddActors(options => |
{ |
||||
{ |
var actorRegistration = new ActorRegistration(context.ImplementationType.GetActorTypeInfo()); |
||||
options.Actors.AddIfNotContains(actorRegistrations); |
|
||||
}); |
actorRegistrations.Add(actorRegistration); |
||||
} |
} |
||||
} |
}); |
||||
} |
|
||||
|
services.AddActors(options => |
||||
|
{ |
||||
|
options.Actors.AddIfNotContains(actorRegistrations); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|||||
@ -1,24 +1,24 @@ |
|||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.Extensions.DependencyInjection; |
||||
using Volo.Abp.Http.Client; |
using Volo.Abp.Http.Client; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.Modularity; |
||||
|
|
||||
namespace LINGYUN.Abp.Dapr.Actors |
namespace LINGYUN.Abp.Dapr.Actors |
||||
{ |
{ |
||||
[DependsOn( |
[DependsOn( |
||||
typeof(AbpHttpClientModule) |
typeof(AbpHttpClientModule) |
||||
)] |
)] |
||||
public class AbpDaprActorsModule : AbpModule |
public class AbpDaprActorsModule : AbpModule |
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// 与AbpHttpClient集成,创建一个命名HttpClient
|
/// 与AbpHttpClient集成,创建一个命名HttpClient
|
||||
/// </summary>
|
/// </summary>
|
||||
internal const string DaprHttpClient = "_AbpDaprActorsClient"; |
internal const string DaprHttpClient = "_AbpDaprActorsClient"; |
||||
|
|
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
{ |
||||
var configuration = context.Services.GetConfiguration(); |
var configuration = context.Services.GetConfiguration(); |
||||
Configure<AbpDaprRemoteServiceOptions>(configuration); |
Configure<AbpDaprRemoteServiceOptions>(configuration); |
||||
context.Services.AddHttpClient(DaprHttpClient); |
context.Services.AddHttpClient(DaprHttpClient); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,312 +1,342 @@ |
|||||
using Dapr.Client; |
using Dapr.Client; |
||||
using Microsoft.Extensions.Logging; |
using LINGYUN.Abp.Wrapper; |
||||
using Microsoft.Extensions.Logging.Abstractions; |
using Microsoft.Extensions.Logging; |
||||
using Microsoft.Extensions.Options; |
using Microsoft.Extensions.Logging.Abstractions; |
||||
using System; |
using Microsoft.Extensions.Options; |
||||
using System.Collections.Generic; |
using System; |
||||
using System.Globalization; |
using System.Collections.Generic; |
||||
using System.Linq; |
using System.Globalization; |
||||
using System.Net.Http; |
using System.Linq; |
||||
using System.Net.Http.Headers; |
using System.Net.Http; |
||||
using System.Reflection; |
using System.Net.Http.Headers; |
||||
using System.Threading; |
using System.Reflection; |
||||
using System.Threading.Tasks; |
using System.Threading; |
||||
using Volo.Abp; |
using System.Threading.Tasks; |
||||
using Volo.Abp.Content; |
using Volo.Abp; |
||||
using Volo.Abp.DependencyInjection; |
using Volo.Abp.Content; |
||||
using Volo.Abp.DynamicProxy; |
using Volo.Abp.DependencyInjection; |
||||
using Volo.Abp.Http; |
using Volo.Abp.DynamicProxy; |
||||
using Volo.Abp.Http.Client; |
using Volo.Abp.Http; |
||||
using Volo.Abp.Http.Client.Authentication; |
using Volo.Abp.Http.Client; |
||||
using Volo.Abp.Http.Client.DynamicProxying; |
using Volo.Abp.Http.Client.Authentication; |
||||
using Volo.Abp.Http.Modeling; |
using Volo.Abp.Http.Client.DynamicProxying; |
||||
using Volo.Abp.Http.ProxyScripting.Generators; |
using Volo.Abp.Http.Modeling; |
||||
using Volo.Abp.Json; |
using Volo.Abp.Http.ProxyScripting.Generators; |
||||
using Volo.Abp.MultiTenancy; |
using Volo.Abp.Json; |
||||
using Volo.Abp.Threading; |
using Volo.Abp.MultiTenancy; |
||||
using Volo.Abp.Tracing; |
using Volo.Abp.Threading; |
||||
|
using Volo.Abp.Tracing; |
||||
namespace LINGYUN.Abp.Dapr.Client.DynamicProxying |
|
||||
{ |
namespace LINGYUN.Abp.Dapr.Client.DynamicProxying |
||||
public class DynamicDaprClientProxyInterceptor<TService> : AbpInterceptor, ITransientDependency |
{ |
||||
{ |
public class DynamicDaprClientProxyInterceptor<TService> : AbpInterceptor, ITransientDependency |
||||
protected static MethodInfo MakeRequestAndGetResultAsyncMethod { get; } |
{ |
||||
|
protected static MethodInfo MakeRequestAndGetResultAsyncMethod { get; } |
||||
protected IDaprClientFactory DaprClientFactory { get; } |
|
||||
protected ICancellationTokenProvider CancellationTokenProvider { get; } |
protected IDaprClientFactory DaprClientFactory { get; } |
||||
protected ICorrelationIdProvider CorrelationIdProvider { get; } |
protected ICancellationTokenProvider CancellationTokenProvider { get; } |
||||
protected ICurrentTenant CurrentTenant { get; } |
protected ICorrelationIdProvider CorrelationIdProvider { get; } |
||||
protected AbpCorrelationIdOptions AbpCorrelationIdOptions { get; } |
protected ICurrentTenant CurrentTenant { get; } |
||||
protected IDynamicProxyHttpClientFactory HttpClientFactory { get; } |
protected AbpCorrelationIdOptions AbpCorrelationIdOptions { get; } |
||||
protected IDaprApiDescriptionFinder ApiDescriptionFinder { get; } |
protected IDynamicProxyHttpClientFactory HttpClientFactory { get; } |
||||
protected AbpDaprRemoteServiceOptions AbpRemoteServiceOptions { get; } |
protected IDaprApiDescriptionFinder ApiDescriptionFinder { get; } |
||||
protected AbpDaprClientProxyOptions ClientProxyOptions { get; } |
protected AbpDaprRemoteServiceOptions AbpRemoteServiceOptions { get; } |
||||
protected IJsonSerializer JsonSerializer { get; } |
protected AbpDaprClientProxyOptions ClientProxyOptions { get; } |
||||
protected IRemoteServiceHttpClientAuthenticator ClientAuthenticator { get; } |
protected AbpWrapperOptions WrapperOptions { get; } |
||||
|
protected IJsonSerializer JsonSerializer { get; } |
||||
public ILogger<DynamicDaprClientProxyInterceptor<TService>> Logger { get; set; } |
protected IRemoteServiceHttpClientAuthenticator ClientAuthenticator { get; } |
||||
|
|
||||
static DynamicDaprClientProxyInterceptor() |
public ILogger<DynamicDaprClientProxyInterceptor<TService>> Logger { get; set; } |
||||
{ |
|
||||
MakeRequestAndGetResultAsyncMethod = typeof(DynamicDaprClientProxyInterceptor<TService>) |
static DynamicDaprClientProxyInterceptor() |
||||
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) |
{ |
||||
.First(m => m.Name == nameof(MakeRequestAndGetResultAsync) && m.IsGenericMethodDefinition); |
MakeRequestAndGetResultAsyncMethod = typeof(DynamicDaprClientProxyInterceptor<TService>) |
||||
} |
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) |
||||
|
.First(m => m.Name == nameof(MakeRequestAndGetResultAsync) && m.IsGenericMethodDefinition); |
||||
public DynamicDaprClientProxyInterceptor( |
} |
||||
IDaprClientFactory daprClientFactory, |
|
||||
IOptions<AbpDaprClientProxyOptions> clientProxyOptions, |
public DynamicDaprClientProxyInterceptor( |
||||
IOptionsSnapshot<AbpDaprRemoteServiceOptions> remoteServiceOptions, |
IDaprClientFactory daprClientFactory, |
||||
IDaprApiDescriptionFinder apiDescriptionFinder, |
IOptions<AbpDaprClientProxyOptions> clientProxyOptions, |
||||
IJsonSerializer jsonSerializer, |
IOptionsSnapshot<AbpDaprRemoteServiceOptions> remoteServiceOptions, |
||||
IDynamicProxyHttpClientFactory dynamicProxyHttpClientFactory, |
IDaprApiDescriptionFinder apiDescriptionFinder, |
||||
IRemoteServiceHttpClientAuthenticator clientAuthenticator, |
IJsonSerializer jsonSerializer, |
||||
ICancellationTokenProvider cancellationTokenProvider, |
IDynamicProxyHttpClientFactory dynamicProxyHttpClientFactory, |
||||
ICorrelationIdProvider correlationIdProvider, |
IRemoteServiceHttpClientAuthenticator clientAuthenticator, |
||||
IOptions<AbpCorrelationIdOptions> correlationIdOptions, |
ICancellationTokenProvider cancellationTokenProvider, |
||||
ICurrentTenant currentTenant) |
ICorrelationIdProvider correlationIdProvider, |
||||
{ |
IOptions<AbpCorrelationIdOptions> correlationIdOptions, |
||||
DaprClientFactory = daprClientFactory; |
IOptions<AbpWrapperOptions> wrapperOptions, |
||||
CancellationTokenProvider = cancellationTokenProvider; |
ICurrentTenant currentTenant) |
||||
CorrelationIdProvider = correlationIdProvider; |
{ |
||||
CurrentTenant = currentTenant; |
DaprClientFactory = daprClientFactory; |
||||
HttpClientFactory = dynamicProxyHttpClientFactory; |
CancellationTokenProvider = cancellationTokenProvider; |
||||
AbpCorrelationIdOptions = correlationIdOptions.Value; |
CorrelationIdProvider = correlationIdProvider; |
||||
ApiDescriptionFinder = apiDescriptionFinder; |
CurrentTenant = currentTenant; |
||||
JsonSerializer = jsonSerializer; |
HttpClientFactory = dynamicProxyHttpClientFactory; |
||||
ClientAuthenticator = clientAuthenticator; |
AbpCorrelationIdOptions = correlationIdOptions.Value; |
||||
ClientProxyOptions = clientProxyOptions.Value; |
ApiDescriptionFinder = apiDescriptionFinder; |
||||
AbpRemoteServiceOptions = remoteServiceOptions.Value; |
JsonSerializer = jsonSerializer; |
||||
|
ClientAuthenticator = clientAuthenticator; |
||||
Logger = NullLogger<DynamicDaprClientProxyInterceptor<TService>>.Instance; |
ClientProxyOptions = clientProxyOptions.Value; |
||||
} |
AbpRemoteServiceOptions = remoteServiceOptions.Value; |
||||
|
WrapperOptions = wrapperOptions.Value; |
||||
public override async Task InterceptAsync(IAbpMethodInvocation invocation) |
|
||||
{ |
Logger = NullLogger<DynamicDaprClientProxyInterceptor<TService>>.Instance; |
||||
if (invocation.Method.ReturnType.GenericTypeArguments.IsNullOrEmpty()) |
} |
||||
{ |
|
||||
await MakeRequestAsync(invocation); |
public override async Task InterceptAsync(IAbpMethodInvocation invocation) |
||||
} |
{ |
||||
else |
if (invocation.Method.ReturnType.GenericTypeArguments.IsNullOrEmpty()) |
||||
{ |
{ |
||||
var result = (Task)MakeRequestAndGetResultAsyncMethod |
await MakeRequestAsync(invocation); |
||||
.MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0]) |
} |
||||
.Invoke(this, new object[] { invocation }); |
else |
||||
|
{ |
||||
invocation.ReturnValue = await GetResultAsync( |
var result = (Task)MakeRequestAndGetResultAsyncMethod |
||||
result, |
.MakeGenericMethod(invocation.Method.ReturnType.GenericTypeArguments[0]) |
||||
invocation.Method.ReturnType.GetGenericArguments()[0] |
.Invoke(this, new object[] { invocation }); |
||||
); |
|
||||
} |
invocation.ReturnValue = await GetResultAsync( |
||||
} |
result, |
||||
|
invocation.Method.ReturnType.GetGenericArguments()[0] |
||||
private async Task<object> GetResultAsync(Task task, Type resultType) |
); |
||||
{ |
} |
||||
await task; |
} |
||||
return typeof(Task<>) |
|
||||
.MakeGenericType(resultType) |
private async Task<object> GetResultAsync(Task task, Type resultType) |
||||
.GetProperty(nameof(Task<object>.Result), BindingFlags.Instance | BindingFlags.Public) |
{ |
||||
.GetValue(task); |
await task; |
||||
} |
return typeof(Task<>) |
||||
|
.MakeGenericType(resultType) |
||||
private async Task<T> MakeRequestAndGetResultAsync<T>(IAbpMethodInvocation invocation) |
.GetProperty(nameof(Task<object>.Result), BindingFlags.Instance | BindingFlags.Public) |
||||
{ |
.GetValue(task); |
||||
var responseContent = await MakeRequestAsync(invocation); |
} |
||||
|
|
||||
if (typeof(T) == typeof(IRemoteStreamContent)) |
private async Task<T> MakeRequestAndGetResultAsync<T>(IAbpMethodInvocation invocation) |
||||
{ |
{ |
||||
/* returning a class that holds a reference to response |
var response = await MakeRequestAsync(invocation); |
||||
* content just to be sure that GC does not dispose of |
var responseContent = response.Content; |
||||
* it before we finish doing our work with the stream */ |
|
||||
return (T)(object)new RemoteStreamContent(await responseContent.ReadAsStreamAsync()) |
if (typeof(T) == typeof(IRemoteStreamContent)) |
||||
{ |
{ |
||||
ContentType = responseContent.Headers.ContentType?.ToString() |
/* 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()) |
||||
var stringContent = await responseContent.ReadAsStringAsync(); |
{ |
||||
if (typeof(T) == typeof(string)) |
ContentType = responseContent.Headers.ContentType?.ToString() |
||||
{ |
}; |
||||
return (T)(object)stringContent; |
} |
||||
} |
var stringContent = await responseContent.ReadAsStringAsync(); |
||||
|
|
||||
if (stringContent.IsNullOrWhiteSpace()) |
if (stringContent.IsNullOrWhiteSpace()) |
||||
{ |
{ |
||||
return default; |
return default; |
||||
} |
} |
||||
|
|
||||
return JsonSerializer.Deserialize<T>(stringContent); |
// 对于包装后的结果需要处理
|
||||
} |
if (response.Headers.Contains(AbpHttpWrapConsts.AbpWrapResult)) |
||||
|
{ |
||||
private async Task<HttpContent> MakeRequestAsync(IAbpMethodInvocation invocation) |
var wrapResult = JsonSerializer.Deserialize<WrapResult<T>>(stringContent); |
||||
{ |
|
||||
var clientConfig = ClientProxyOptions.DaprClientProxies.GetOrDefault(typeof(TService)) ?? throw new AbpException($"Could not get DynamicDaprClientProxyConfig for {typeof(TService).FullName}."); |
if (!string.Equals(wrapResult.Code, WrapperOptions.CodeWithSuccess)) |
||||
var remoteServiceConfig = AbpRemoteServiceOptions.RemoteServices.GetConfigurationOrDefault(clientConfig.RemoteServiceName); |
{ |
||||
|
var errorInfo = new RemoteServiceErrorInfo( |
||||
// 遵循远端 api/abp/api-definition
|
wrapResult.Message, |
||||
var action = await ApiDescriptionFinder.FindActionAsync( |
wrapResult.Details, |
||||
clientConfig.RemoteServiceName, |
wrapResult.Code); |
||||
remoteServiceConfig.AppId, |
throw new AbpRemoteCallException(errorInfo) |
||||
typeof(TService), |
{ |
||||
invocation.Method |
HttpStatusCode = (int)WrapperOptions.HttpStatusCode |
||||
); |
}; |
||||
|
} |
||||
var apiVersion = GetApiVersionInfo(action); |
|
||||
|
if (typeof(T) == typeof(string)) |
||||
// See: https://docs.dapr.io/reference/api/service_invocation_api/#examples
|
{ |
||||
// 需要合并端点作为dapr远程调用的方法名称
|
return (T)(object)wrapResult.Result; |
||||
var methodName = UrlBuilder.GenerateUrlWithParameters(action, invocation.ArgumentsDictionary, apiVersion); |
} |
||||
|
|
||||
var daprClient = DaprClientFactory.CreateClient(clientConfig.RemoteServiceName); |
return wrapResult.Result; |
||||
var requestMessage = daprClient.CreateInvokeMethodRequest( |
} |
||||
action.GetHttpMethod(), |
|
||||
remoteServiceConfig.AppId, |
if (typeof(T) == typeof(string)) |
||||
methodName); |
{ |
||||
|
return (T)(object)stringContent; |
||||
requestMessage.Content = RequestPayloadBuilder.BuildContent(action, invocation.ArgumentsDictionary, JsonSerializer, apiVersion); |
} |
||||
|
|
||||
AddHeaders(invocation, action, requestMessage, apiVersion); |
return JsonSerializer.Deserialize<T>(stringContent); |
||||
|
} |
||||
var httpClient = HttpClientFactory.Create(AbpDaprClientModule.DaprHttpClient); |
|
||||
await ClientAuthenticator.Authenticate( |
private async Task<HttpResponseMessage> MakeRequestAsync(IAbpMethodInvocation invocation) |
||||
new RemoteServiceHttpClientAuthenticateContext( |
{ |
||||
httpClient, |
var clientConfig = ClientProxyOptions.DaprClientProxies.GetOrDefault(typeof(TService)) ?? throw new AbpException($"Could not get DynamicDaprClientProxyConfig for {typeof(TService).FullName}."); |
||||
requestMessage, |
var remoteServiceConfig = AbpRemoteServiceOptions.RemoteServices.GetConfigurationOrDefault(clientConfig.RemoteServiceName); |
||||
remoteServiceConfig, |
|
||||
clientConfig.RemoteServiceName |
// 遵循远端 api/abp/api-definition
|
||||
) |
var action = await ApiDescriptionFinder.FindActionAsync( |
||||
); |
clientConfig.RemoteServiceName, |
||||
// 其他库可能将授权标头写入到HttpClient中
|
remoteServiceConfig.AppId, |
||||
if (requestMessage.Headers.Authorization == null && |
typeof(TService), |
||||
httpClient.DefaultRequestHeaders.Authorization != null) |
invocation.Method |
||||
{ |
); |
||||
requestMessage.Headers.Authorization = httpClient.DefaultRequestHeaders.Authorization; |
|
||||
} |
var apiVersion = GetApiVersionInfo(action); |
||||
|
|
||||
var response = await daprClient.InvokeMethodWithResponseAsync(requestMessage, GetCancellationToken()); |
// See: https://docs.dapr.io/reference/api/service_invocation_api/#examples
|
||||
|
// 需要合并端点作为dapr远程调用的方法名称
|
||||
if (!response.IsSuccessStatusCode) |
var methodName = UrlBuilder.GenerateUrlWithParameters(action, invocation.ArgumentsDictionary, apiVersion); |
||||
{ |
|
||||
await ThrowExceptionForResponseAsync(response); |
var daprClient = DaprClientFactory.CreateClient(clientConfig.RemoteServiceName); |
||||
} |
var requestMessage = daprClient.CreateInvokeMethodRequest( |
||||
|
action.GetHttpMethod(), |
||||
return response.Content; |
remoteServiceConfig.AppId, |
||||
} |
methodName); |
||||
|
|
||||
private ApiVersionInfo GetApiVersionInfo(ActionApiDescriptionModel action) |
requestMessage.Content = RequestPayloadBuilder.BuildContent(action, invocation.ArgumentsDictionary, JsonSerializer, apiVersion); |
||||
{ |
|
||||
var apiVersion = FindBestApiVersion(action); |
AddHeaders(invocation, action, requestMessage, apiVersion); |
||||
|
|
||||
//TODO: Make names configurable?
|
var httpClient = HttpClientFactory.Create(AbpDaprClientModule.DaprHttpClient); |
||||
var versionParam = action.Parameters.FirstOrDefault(p => p.Name == "apiVersion" && p.BindingSourceId == ParameterBindingSources.Path) ?? |
await ClientAuthenticator.Authenticate( |
||||
action.Parameters.FirstOrDefault(p => p.Name == "api-version" && p.BindingSourceId == ParameterBindingSources.Query); |
new RemoteServiceHttpClientAuthenticateContext( |
||||
|
httpClient, |
||||
return new ApiVersionInfo(versionParam?.BindingSourceId, apiVersion); |
requestMessage, |
||||
} |
remoteServiceConfig, |
||||
|
clientConfig.RemoteServiceName |
||||
private string FindBestApiVersion(ActionApiDescriptionModel action) |
) |
||||
{ |
); |
||||
var configuredVersion = GetConfiguredApiVersion(); |
// 其他库可能将授权标头写入到HttpClient中
|
||||
|
if (requestMessage.Headers.Authorization == null && |
||||
if (action.SupportedVersions.IsNullOrEmpty()) |
httpClient.DefaultRequestHeaders.Authorization != null) |
||||
{ |
{ |
||||
return configuredVersion ?? "1.0"; |
requestMessage.Headers.Authorization = httpClient.DefaultRequestHeaders.Authorization; |
||||
} |
} |
||||
|
|
||||
if (action.SupportedVersions.Contains(configuredVersion)) |
var response = await daprClient.InvokeMethodWithResponseAsync(requestMessage, GetCancellationToken()); |
||||
{ |
|
||||
return configuredVersion; |
if (!response.IsSuccessStatusCode) |
||||
} |
{ |
||||
|
await ThrowExceptionForResponseAsync(response); |
||||
return action.SupportedVersions.Last(); //TODO: Ensure to get the latest version!
|
} |
||||
} |
|
||||
|
return response; |
||||
protected virtual void AddHeaders( |
} |
||||
IAbpMethodInvocation invocation, |
|
||||
ActionApiDescriptionModel action, |
private ApiVersionInfo GetApiVersionInfo(ActionApiDescriptionModel action) |
||||
HttpRequestMessage requestMessage, |
{ |
||||
ApiVersionInfo apiVersion) |
var apiVersion = FindBestApiVersion(action); |
||||
{ |
|
||||
//API Version
|
//TODO: Make names configurable?
|
||||
if (!apiVersion.Version.IsNullOrEmpty()) |
var versionParam = action.Parameters.FirstOrDefault(p => p.Name == "apiVersion" && p.BindingSourceId == ParameterBindingSources.Path) ?? |
||||
{ |
action.Parameters.FirstOrDefault(p => p.Name == "api-version" && p.BindingSourceId == ParameterBindingSources.Query); |
||||
//TODO: What about other media types?
|
|
||||
requestMessage.Headers.Add("accept", $"{MimeTypes.Text.Plain}; v={apiVersion.Version}"); |
return new ApiVersionInfo(versionParam?.BindingSourceId, apiVersion); |
||||
requestMessage.Headers.Add("accept", $"{MimeTypes.Application.Json}; v={apiVersion.Version}"); |
} |
||||
requestMessage.Headers.Add("api-version", apiVersion.Version); |
|
||||
} |
private string FindBestApiVersion(ActionApiDescriptionModel action) |
||||
|
{ |
||||
//Header parameters
|
var configuredVersion = GetConfiguredApiVersion(); |
||||
var headers = action.Parameters.Where(p => p.BindingSourceId == ParameterBindingSources.Header).ToArray(); |
|
||||
foreach (var headerParameter in headers) |
if (action.SupportedVersions.IsNullOrEmpty()) |
||||
{ |
{ |
||||
var value = HttpActionParameterHelper.FindParameterValue(invocation.ArgumentsDictionary, headerParameter); |
return configuredVersion ?? "1.0"; |
||||
if (value != null) |
} |
||||
{ |
|
||||
requestMessage.Headers.Add(headerParameter.Name, value.ToString()); |
if (action.SupportedVersions.Contains(configuredVersion)) |
||||
} |
{ |
||||
} |
return configuredVersion; |
||||
|
} |
||||
//CorrelationId
|
|
||||
requestMessage.Headers.Add(AbpCorrelationIdOptions.HttpHeaderName, CorrelationIdProvider.Get()); |
return action.SupportedVersions.Last(); //TODO: Ensure to get the latest version!
|
||||
|
} |
||||
//TenantId
|
|
||||
if (CurrentTenant.Id.HasValue) |
protected virtual void AddHeaders( |
||||
{ |
IAbpMethodInvocation invocation, |
||||
//TODO: Use AbpAspNetCoreMultiTenancyOptions to get the key
|
ActionApiDescriptionModel action, |
||||
requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString()); |
HttpRequestMessage requestMessage, |
||||
} |
ApiVersionInfo apiVersion) |
||||
|
{ |
||||
//Culture
|
//API Version
|
||||
//TODO: Is that the way we want? Couldn't send the culture (not ui culture)
|
if (!apiVersion.Version.IsNullOrEmpty()) |
||||
var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name; |
{ |
||||
if (!currentCulture.IsNullOrEmpty()) |
//TODO: What about other media types?
|
||||
{ |
requestMessage.Headers.Add("accept", $"{MimeTypes.Text.Plain}; v={apiVersion.Version}"); |
||||
requestMessage.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(currentCulture)); |
requestMessage.Headers.Add("accept", $"{MimeTypes.Application.Json}; v={apiVersion.Version}"); |
||||
} |
requestMessage.Headers.Add("api-version", apiVersion.Version); |
||||
|
} |
||||
//X-Requested-With
|
|
||||
requestMessage.Headers.Add("X-Requested-With", "XMLHttpRequest"); |
//Header parameters
|
||||
} |
var headers = action.Parameters.Where(p => p.BindingSourceId == ParameterBindingSources.Header).ToArray(); |
||||
|
foreach (var headerParameter in headers) |
||||
private string GetConfiguredApiVersion() |
{ |
||||
{ |
var value = HttpActionParameterHelper.FindParameterValue(invocation.ArgumentsDictionary, headerParameter); |
||||
var clientConfig = ClientProxyOptions.DaprClientProxies.GetOrDefault(typeof(TService)) |
if (value != null) |
||||
?? throw new AbpException($"Could not get DynamicDaprClientProxyConfig for {typeof(TService).FullName}."); |
{ |
||||
|
requestMessage.Headers.Add(headerParameter.Name, value.ToString()); |
||||
return AbpRemoteServiceOptions.RemoteServices.GetOrDefault(clientConfig.RemoteServiceName)?.Version |
} |
||||
?? AbpRemoteServiceOptions.RemoteServices.Default?.Version; |
} |
||||
} |
|
||||
|
//CorrelationId
|
||||
private async Task ThrowExceptionForResponseAsync(HttpResponseMessage response) |
requestMessage.Headers.Add(AbpCorrelationIdOptions.HttpHeaderName, CorrelationIdProvider.Get()); |
||||
{ |
|
||||
if (response.Headers.Contains(AbpHttpConsts.AbpErrorFormat)) |
//TenantId
|
||||
{ |
if (CurrentTenant.Id.HasValue) |
||||
var errorResponse = JsonSerializer.Deserialize<RemoteServiceErrorResponse>( |
{ |
||||
await response.Content.ReadAsStringAsync() |
//TODO: Use AbpAspNetCoreMultiTenancyOptions to get the key
|
||||
); |
requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString()); |
||||
|
} |
||||
throw new AbpRemoteCallException(errorResponse.Error) |
|
||||
{ |
//Culture
|
||||
HttpStatusCode = (int)response.StatusCode |
//TODO: Is that the way we want? Couldn't send the culture (not ui culture)
|
||||
}; |
var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name; |
||||
} |
if (!currentCulture.IsNullOrEmpty()) |
||||
|
{ |
||||
throw new AbpRemoteCallException( |
requestMessage.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(currentCulture)); |
||||
new RemoteServiceErrorInfo |
} |
||||
{ |
|
||||
Message = response.ReasonPhrase, |
//X-Requested-With
|
||||
Code = response.StatusCode.ToString() |
requestMessage.Headers.Add("X-Requested-With", "XMLHttpRequest"); |
||||
} |
} |
||||
) |
|
||||
{ |
private string GetConfiguredApiVersion() |
||||
HttpStatusCode = (int)response.StatusCode |
{ |
||||
}; |
var clientConfig = ClientProxyOptions.DaprClientProxies.GetOrDefault(typeof(TService)) |
||||
} |
?? throw new AbpException($"Could not get DynamicDaprClientProxyConfig for {typeof(TService).FullName}."); |
||||
|
|
||||
protected virtual CancellationToken GetCancellationToken() |
return AbpRemoteServiceOptions.RemoteServices.GetOrDefault(clientConfig.RemoteServiceName)?.Version |
||||
{ |
?? AbpRemoteServiceOptions.RemoteServices.Default?.Version; |
||||
return CancellationTokenProvider.Token; |
} |
||||
} |
|
||||
} |
private async Task ThrowExceptionForResponseAsync(HttpResponseMessage response) |
||||
} |
{ |
||||
|
if (response.Headers.Contains(AbpHttpConsts.AbpErrorFormat)) |
||||
|
{ |
||||
|
var errorResponse = JsonSerializer.Deserialize<RemoteServiceErrorResponse>( |
||||
|
await response.Content.ReadAsStringAsync() |
||||
|
); |
||||
|
|
||||
|
throw new AbpRemoteCallException(errorResponse.Error) |
||||
|
{ |
||||
|
HttpStatusCode = (int)response.StatusCode |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
throw new AbpRemoteCallException( |
||||
|
new RemoteServiceErrorInfo |
||||
|
{ |
||||
|
Message = response.ReasonPhrase, |
||||
|
Code = response.StatusCode.ToString() |
||||
|
} |
||||
|
) |
||||
|
{ |
||||
|
HttpStatusCode = (int)response.StatusCode |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
protected virtual CancellationToken GetCancellationToken() |
||||
|
{ |
||||
|
return CancellationTokenProvider.Token; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|||||
@ -1,70 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Net; |
|
||||
using Volo.Abp.Collections; |
|
||||
|
|
||||
namespace LINGYUN.Abp.AspNetCore.Mvc.Wrapper |
|
||||
{ |
|
||||
public class AbpAspNetCoreMvcWrapperOptions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 是否启用包装器
|
|
||||
/// </summary>
|
|
||||
public bool IsEnabled { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 资源有效时返回代码
|
|
||||
/// 默认:0
|
|
||||
/// </summary>
|
|
||||
public string CodeWithFound { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 资源为空时返回代码
|
|
||||
/// 默认:404
|
|
||||
/// </summary>
|
|
||||
public Func<IServiceProvider, string> CodeWithEmptyResult { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 资源为空时返回错误消息
|
|
||||
/// </summary>
|
|
||||
public Func<IServiceProvider, string> MessageWithEmptyResult { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 包装后的返回状态码
|
|
||||
/// 默认:200 HttpStatusCode.OK
|
|
||||
/// </summary>
|
|
||||
public HttpStatusCode HttpStatusCode { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 忽略Url开头类型
|
|
||||
/// </summary>
|
|
||||
public IList<string> IgnorePrefixUrls { get; } |
|
||||
/// <summary>
|
|
||||
/// 忽略指定命名空间
|
|
||||
/// </summary>
|
|
||||
public IList<string> IgnoreNamespaces { get; } |
|
||||
/// <summary>
|
|
||||
/// 忽略控制器
|
|
||||
/// </summary>
|
|
||||
public ITypeList IgnoreControllers { get; } |
|
||||
/// <summary>
|
|
||||
/// 忽略返回值
|
|
||||
/// </summary>
|
|
||||
public ITypeList IgnoreReturnTypes { get; } |
|
||||
/// <summary>
|
|
||||
/// 忽略异常
|
|
||||
/// </summary>
|
|
||||
public ITypeList<Exception> IgnoreExceptions { get; } |
|
||||
|
|
||||
public AbpAspNetCoreMvcWrapperOptions() |
|
||||
{ |
|
||||
CodeWithFound = "0"; |
|
||||
HttpStatusCode = HttpStatusCode.OK; |
|
||||
|
|
||||
IgnorePrefixUrls = new List<string>(); |
|
||||
IgnoreNamespaces = new List<string>(); |
|
||||
|
|
||||
IgnoreControllers = new TypeList(); |
|
||||
IgnoreReturnTypes = new TypeList(); |
|
||||
IgnoreExceptions = new TypeList<Exception>(); |
|
||||
|
|
||||
CodeWithEmptyResult = (_) => "404"; |
|
||||
MessageWithEmptyResult = (_) => "Not Found"; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,39 +1,51 @@ |
|||||
using LINGYUN.Abp.Dapr.Actors.AspNetCore; |
using LINGYUN.Abp.AspNetCore.Mvc.Wrapper; |
||||
using Microsoft.AspNetCore.Builder; |
using LINGYUN.Abp.Dapr.Actors.AspNetCore; |
||||
using Microsoft.Extensions.DependencyInjection; |
using LINGYUN.Abp.Dapr.ServiceInvocation; |
||||
using Volo.Abp; |
using LINGYUN.Abp.Wrapper; |
||||
using Volo.Abp.AspNetCore.Mvc; |
using Microsoft.AspNetCore.Builder; |
||||
using Volo.Abp.Modularity; |
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp; |
||||
namespace LINGYUN.Abp.Dapr |
using Volo.Abp.Application.Dtos; |
||||
{ |
using Volo.Abp.AspNetCore.Mvc; |
||||
[DependsOn( |
using Volo.Abp.Modularity; |
||||
typeof(AbpAspNetCoreMvcModule), |
|
||||
typeof(AbpDaprActorsAspNetCoreModule) |
namespace LINGYUN.Abp.Dapr |
||||
)] |
{ |
||||
public class AbpDaprAspNetCoreTestHostModule : AbpModule |
[DependsOn( |
||||
{ |
typeof(AbpDaprActorsAspNetCoreModule), |
||||
public override void PreConfigureServices(ServiceConfigurationContext context) |
typeof(AbpAspNetCoreMvcWrapperModule) |
||||
{ |
)] |
||||
Configure<IMvcBuilder>(builder => |
public class AbpDaprAspNetCoreTestHostModule : AbpModule |
||||
{ |
{ |
||||
builder.AddApplicationPart(typeof(AbpDaprAspNetCoreTestHostModule).Assembly); |
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
}); |
{ |
||||
} |
Configure<IMvcBuilder>(builder => |
||||
|
{ |
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
builder.AddApplicationPart(typeof(AbpDaprAspNetCoreTestHostModule).Assembly); |
||||
{ |
}); |
||||
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
} |
||||
var configuration = context.Services.GetConfiguration(); |
|
||||
} |
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
||||
{ |
var configuration = context.Services.GetConfiguration(); |
||||
var app = context.GetApplicationBuilder(); |
|
||||
|
Configure<AbpWrapperOptions>(options => |
||||
app.UseRouting(); |
{ |
||||
app.UseAuditing(); |
options.IsEnabled = true; |
||||
app.UseConfiguredEndpoints(); |
|
||||
} |
options.IgnoreReturnTypes.TryAdd<NameValue>(); |
||||
} |
options.IgnoreReturnTypes.TryAdd<ListResultDto<NameValue>>(); |
||||
} |
}); |
||||
|
} |
||||
|
|
||||
|
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
var app = context.GetApplicationBuilder(); |
||||
|
|
||||
|
app.UseRouting(); |
||||
|
app.UseAuditing(); |
||||
|
app.UseConfiguredEndpoints(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|||||
@ -1,41 +1,53 @@ |
|||||
using Microsoft.AspNetCore.Mvc; |
using Microsoft.AspNetCore.Mvc; |
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
using System.Threading; |
using System.Threading; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using Volo.Abp; |
using Volo.Abp; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.AspNetCore.Mvc; |
using Volo.Abp.AspNetCore.Mvc; |
||||
|
|
||||
namespace LINGYUN.Abp.Dapr.ServiceInvocation |
namespace LINGYUN.Abp.Dapr.ServiceInvocation |
||||
{ |
{ |
||||
[RemoteService(Name = "TestDapr")] |
[RemoteService(Name = "TestDapr")] |
||||
[Route("api/dapr/test")] |
[Route("api/dapr/test")] |
||||
public class TestAppService : AbpController, ITestAppService |
public class TestAppService : AbpController, ITestAppService |
||||
{ |
{ |
||||
private static int _inctement; |
private static int _inctement; |
||||
private readonly List<NameValue> _cache = new List<NameValue> |
private readonly List<NameValue> _cache = new List<NameValue> |
||||
{ |
{ |
||||
new NameValue("name1", "value1"), |
new NameValue("name1", "value1"), |
||||
new NameValue("name2", "value2"), |
new NameValue("name2", "value2"), |
||||
new NameValue("name3", "value3"), |
new NameValue("name3", "value3"), |
||||
new NameValue("name4", "value4"), |
new NameValue("name4", "value4"), |
||||
new NameValue("name5", "value5") |
new NameValue("name5", "value5") |
||||
}; |
}; |
||||
|
|
||||
[HttpGet] |
[HttpGet] |
||||
public Task<ListResultDto<NameValue>> GetAsync() |
public Task<ListResultDto<NameValue>> GetAsync() |
||||
{ |
{ |
||||
return Task.FromResult(new ListResultDto<NameValue>(_cache)); |
return Task.FromResult(new ListResultDto<NameValue>(_cache)); |
||||
} |
} |
||||
|
|
||||
[HttpPut] |
[HttpPut] |
||||
public Task<NameValue> UpdateAsync() |
public Task<NameValue> UpdateAsync() |
||||
{ |
{ |
||||
Interlocked.Increment(ref _inctement); |
Interlocked.Increment(ref _inctement); |
||||
|
|
||||
_cache[0].Value = $"value:updated:{_inctement}"; |
_cache[0].Value = $"value:updated:{_inctement}"; |
||||
|
|
||||
return Task.FromResult(_cache[0]); |
return Task.FromResult(_cache[0]); |
||||
} |
} |
||||
} |
|
||||
} |
[HttpGet] |
||||
|
[Route("{name}")] |
||||
|
public Task<TestNeedWrapObject> GetWrapedAsync(string name) |
||||
|
{ |
||||
|
var obj = new TestNeedWrapObject |
||||
|
{ |
||||
|
Name = name |
||||
|
}; |
||||
|
|
||||
|
return Task.FromResult(obj); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|||||
@ -1,33 +1,41 @@ |
|||||
using LINGYUN.Abp.Dapr.ServiceInvocation; |
using LINGYUN.Abp.Dapr.ServiceInvocation; |
||||
using Shouldly; |
using Shouldly; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using Xunit; |
using Xunit; |
||||
|
|
||||
namespace LINGYUN.Abp.Dapr.Client.Tests |
namespace LINGYUN.Abp.Dapr.Client.Tests |
||||
{ |
{ |
||||
public class TestAppServiceTests : AbpDaptClientTestBase |
public class TestAppServiceTests : AbpDaptClientTestBase |
||||
{ |
{ |
||||
private readonly ITestAppService _service; |
private readonly ITestAppService _service; |
||||
|
|
||||
public TestAppServiceTests() |
public TestAppServiceTests() |
||||
{ |
{ |
||||
_service = GetRequiredService<ITestAppService>(); |
_service = GetRequiredService<ITestAppService>(); |
||||
} |
} |
||||
|
|
||||
[Fact] |
[Fact] |
||||
public async Task Get_Result_Items_Count_Should_5() |
public async Task Get_Result_Items_Count_Should_5() |
||||
{ |
{ |
||||
var result = await _service.GetAsync(); |
var result = await _service.GetAsync(); |
||||
|
|
||||
result.Items.Count.ShouldBe(5); |
result.Items.Count.ShouldBe(5); |
||||
} |
} |
||||
|
|
||||
[Fact] |
[Fact] |
||||
public async Task Update_Result_Value_Should_Value_Updated_1() |
public async Task Should_Get_Wraped_Object() |
||||
{ |
{ |
||||
var result = await _service.UpdateAsync(); |
var result = await _service.GetWrapedAsync("Test"); |
||||
|
|
||||
result.Value.ShouldBe("value:updated:1"); |
result.Name.ShouldBe("Test"); |
||||
} |
} |
||||
} |
|
||||
} |
[Fact] |
||||
|
public async Task Update_Result_Value_Should_Value_Updated_1() |
||||
|
{ |
||||
|
var result = await _service.UpdateAsync(); |
||||
|
|
||||
|
result.Value.ShouldBe("value:updated:1"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|||||
@ -1,11 +1,12 @@ |
|||||
using Volo.Abp.Application; |
using Volo.Abp.Application; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.Modularity; |
||||
|
|
||||
namespace LINGYUN.Abp.Dapr |
namespace LINGYUN.Abp.Dapr |
||||
{ |
{ |
||||
[DependsOn( |
[DependsOn( |
||||
typeof(AbpDddApplicationContractsModule))] |
typeof(AbpDddApplicationContractsModule))] |
||||
public class AbpDaprTestModule : AbpModule |
public class AbpDaprTestModule : AbpModule |
||||
{ |
{ |
||||
} |
|
||||
} |
} |
||||
|
} |
||||
|
|||||
@ -1,14 +1,16 @@ |
|||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using Volo.Abp; |
using Volo.Abp; |
||||
using Volo.Abp.Application.Dtos; |
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.Application.Services; |
using Volo.Abp.Application.Services; |
||||
|
|
||||
namespace LINGYUN.Abp.Dapr.ServiceInvocation |
namespace LINGYUN.Abp.Dapr.ServiceInvocation |
||||
{ |
{ |
||||
public interface ITestAppService : IApplicationService |
public interface ITestAppService : IApplicationService |
||||
{ |
{ |
||||
Task<ListResultDto<NameValue>> GetAsync(); |
Task<ListResultDto<NameValue>> GetAsync(); |
||||
|
|
||||
Task<NameValue> UpdateAsync(); |
Task<NameValue> UpdateAsync(); |
||||
} |
|
||||
} |
Task<TestNeedWrapObject> GetWrapedAsync(string name); |
||||
|
} |
||||
|
} |
||||
|
|||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Abp.Dapr |
||||
|
{ |
||||
|
public class TestNeedWrapObject |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue