32 changed files with 1194 additions and 0 deletions
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
|
||||
|
namespace Dapr.Actors.Runtime |
||||
|
{ |
||||
|
public static class ActorRegistrationExtensions |
||||
|
{ |
||||
|
public static bool Contains( |
||||
|
this ICollection<ActorRegistration> registrations, |
||||
|
Type implementationType) |
||||
|
{ |
||||
|
return registrations.Any(x => x.Type.ImplementationType == implementationType); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Dapr.Actors.AspNetCore" Version="1.1.0" /> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore" Version="4.2.1" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,54 @@ |
|||||
|
using Dapr.Actors; |
||||
|
using Dapr.Actors.Runtime; |
||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.AspNetCore.Routing; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.AspNetCore; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors.AspNetCore |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAspNetCoreModule))] |
||||
|
public class AbpDaprActorsAspNetCoreModule : AbpModule |
||||
|
{ |
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
AddDefinitionActor(context.Services); |
||||
|
} |
||||
|
|
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpEndpointRouterOptions>(options => |
||||
|
{ |
||||
|
options.EndpointConfigureActions.Add(endpointContext => |
||||
|
{ |
||||
|
endpointContext.Endpoints.MapActorsHandlers(); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private static void AddDefinitionActor(IServiceCollection services) |
||||
|
{ |
||||
|
var actorRegistrations = new List<ActorRegistration>(); |
||||
|
|
||||
|
services.OnRegistred(context => |
||||
|
{ |
||||
|
if (typeof(IActor).IsAssignableFrom(context.ImplementationType) && |
||||
|
!actorRegistrations.Contains(context.ImplementationType)) |
||||
|
{ |
||||
|
var actorRegistration = new ActorRegistration(context.ImplementationType.GetActorTypeInfo()); |
||||
|
|
||||
|
actorRegistrations.Add(actorRegistration); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
services.AddActors(options => |
||||
|
{ |
||||
|
options.Actors.AddIfNotContains(actorRegistrations); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
# LINGYUN.Abp.Dapr.Actors.AspNetCore |
||||
|
|
||||
|
Dapr.Asp.NetCore的Abp框架集成,扫描程序集内部实现的Actor服务列表,批量注册为Dapr.Actors |
||||
|
|
||||
|
## 配置使用 |
||||
|
|
||||
|
模块按需引用 |
||||
|
|
||||
|
```csharp |
||||
|
[DependsOn(typeof(AbpDaprActorsAspNetCoreModule))] |
||||
|
public class YouProjectModule : AbpModule |
||||
|
{ |
||||
|
// other |
||||
|
} |
||||
|
``` |
||||
|
## 配置项说明 |
||||
|
|
||||
|
|
||||
|
## 其他 |
||||
@ -0,0 +1,100 @@ |
|||||
|
using Dapr.Actors; |
||||
|
using Dapr.Actors.Runtime; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace System |
||||
|
{ |
||||
|
internal static class TypeExtensions |
||||
|
{ |
||||
|
public static bool IsActor(this Type actorType) |
||||
|
{ |
||||
|
Type baseType = actorType.GetTypeInfo().BaseType; |
||||
|
while (baseType != null) |
||||
|
{ |
||||
|
if (baseType == typeof(Actor)) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
actorType = baseType; |
||||
|
baseType = actorType.GetTypeInfo().BaseType; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public static Type[] GetActorInterfaces(this Type type) |
||||
|
{ |
||||
|
List<Type> list = new List<Type>(from t in type.GetInterfaces() |
||||
|
where typeof(IActor).IsAssignableFrom(t) |
||||
|
select t); |
||||
|
list.RemoveAll((Type t) => t.GetNonActorParentType() != null); |
||||
|
return list.ToArray(); |
||||
|
} |
||||
|
|
||||
|
public static RemoteServiceAttribute GetRemoteServiceAttribute(this Type type) |
||||
|
{ |
||||
|
return type.GetInterfaces() |
||||
|
.Where(t => t.IsDefined(typeof(RemoteServiceAttribute), false)) |
||||
|
.Select(t => t.GetCustomAttribute<RemoteServiceAttribute>()) |
||||
|
.FirstOrDefault(); |
||||
|
} |
||||
|
|
||||
|
public static Type GetNonActorParentType(this Type type) |
||||
|
{ |
||||
|
List<Type> list = new List<Type>(type.GetInterfaces()); |
||||
|
if (list.RemoveAll((Type t) => t == typeof(IActor)) == 0) |
||||
|
{ |
||||
|
return type; |
||||
|
} |
||||
|
|
||||
|
foreach (Type item in list) |
||||
|
{ |
||||
|
Type nonActorParentType = item.GetNonActorParentType(); |
||||
|
if (nonActorParentType != null) |
||||
|
{ |
||||
|
return nonActorParentType; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public static ActorTypeInformation GetActorTypeInfo( |
||||
|
this Type actorType) |
||||
|
{ |
||||
|
if (!actorType.IsActor()) |
||||
|
{ |
||||
|
throw new ArgumentException( |
||||
|
string.Format("The type '{0}' is not an Actor. An actor type must derive from '{1}'.", actorType.FullName, typeof(Actor).FullName), |
||||
|
nameof(actorType)); |
||||
|
} |
||||
|
|
||||
|
Type[] actorInterfaces = actorType.GetActorInterfaces(); |
||||
|
if (actorInterfaces.Length == 0 && !actorType.GetTypeInfo().IsAbstract) |
||||
|
{ |
||||
|
throw new ArgumentException( |
||||
|
string.Format("The actor type '{0}' does not implement any actor interfaces or one of the interfaces implemented is not an actor interface." + |
||||
|
" All interfaces(including its parent interface) implemented by actor type must be actor interface. " + |
||||
|
"An actor interface is the one that ultimately derives from '{1}' type.", actorType.FullName, typeof(IActor).FullName), |
||||
|
nameof(actorType)); |
||||
|
} |
||||
|
|
||||
|
var actorTypeInfo = ActorTypeInformation.Get(actorType); |
||||
|
|
||||
|
var remoteServiceAttr = actorType.GetRemoteServiceAttribute(); |
||||
|
if (remoteServiceAttr != null && |
||||
|
!string.Equals(actorTypeInfo.ActorTypeName, remoteServiceAttr.Name)) |
||||
|
{ |
||||
|
typeof(ActorTypeInformation) |
||||
|
.GetProperty(nameof(ActorTypeInformation.ActorTypeName), BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) |
||||
|
?.SetValue(actorTypeInfo, remoteServiceAttr.Name); |
||||
|
} |
||||
|
|
||||
|
return actorTypeInfo; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk.Web"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<IsPackable>true</IsPackable> |
||||
|
<OutputType>Library</OutputType> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.Dapr.Actors.IdentityModel\LINGYUN.Abp.Dapr.Actors.IdentityModel.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,6 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
|
<PropertyGroup> |
||||
|
<ActiveDebugProfile>IIS Express</ActiveDebugProfile> |
||||
|
</PropertyGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,10 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors.IdentityModel.Web |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpDaprActorsIdentityModelModule))] |
||||
|
public class AbpDaprActorsIdentityModelWebModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
using LINGYUN.Abp.Dapr.Actors.Authentication; |
||||
|
using Microsoft.AspNetCore.Authentication; |
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
using System.Net.Http.Headers; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.IdentityModel; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors.IdentityModel |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class HttpContextIdentityModelDaprActorProxyAuthenticator : IdentityModelDaprActorProxyAuthenticator |
||||
|
{ |
||||
|
public IHttpContextAccessor HttpContextAccessor { get; set; } |
||||
|
|
||||
|
public HttpContextIdentityModelDaprActorProxyAuthenticator( |
||||
|
IIdentityModelAuthenticationService identityModelAuthenticationService) |
||||
|
: base(identityModelAuthenticationService) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override async Task AuthenticateAsync(DaprActorProxyAuthenticateContext context) |
||||
|
{ |
||||
|
if (context.RemoteService.GetUseCurrentAccessToken() != false) |
||||
|
{ |
||||
|
var accessToken = await GetAccessTokenFromHttpContextOrNullAsync(); |
||||
|
if (accessToken != null) |
||||
|
{ |
||||
|
context.Handler.PreConfigure(request => |
||||
|
{ |
||||
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
await base.AuthenticateAsync(context); |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<string> GetAccessTokenFromHttpContextOrNullAsync() |
||||
|
{ |
||||
|
var httpContext = HttpContextAccessor?.HttpContext; |
||||
|
if (httpContext == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return await httpContext.GetTokenAsync("access_token"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
{ |
||||
|
"iisSettings": { |
||||
|
"windowsAuthentication": false, |
||||
|
"anonymousAuthentication": true, |
||||
|
"iisExpress": { |
||||
|
"applicationUrl": "http://localhost:51684/", |
||||
|
"sslPort": 44331 |
||||
|
} |
||||
|
}, |
||||
|
"profiles": { |
||||
|
"IIS Express": { |
||||
|
"commandName": "IISExpress", |
||||
|
"launchBrowser": true, |
||||
|
"environmentVariables": { |
||||
|
"ASPNETCORE_ENVIRONMENT": "Development" |
||||
|
} |
||||
|
}, |
||||
|
"LINGYUN.Abp.Dapr.Actors.IdentityModel.Web": { |
||||
|
"commandName": "Project", |
||||
|
"launchBrowser": true, |
||||
|
"environmentVariables": { |
||||
|
"ASPNETCORE_ENVIRONMENT": "Development" |
||||
|
}, |
||||
|
"applicationUrl": "https://localhost:5001;http://localhost:5000" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
# LINGYUN.Abp.Dapr.Actors.IdentityModel.Web |
||||
|
|
||||
|
Dapr.Actors内部使用Http进行服务间调用,此模块用于获取应用当前状态中的身份令牌并传递到远程Actor服务 |
||||
|
|
||||
|
## 配置使用 |
||||
|
|
||||
|
模块按需引用 |
||||
|
|
||||
|
```csharp |
||||
|
[DependsOn(typeof(AbpDaprActorsIdentityModelWebModule))] |
||||
|
public class YouProjectModule : AbpModule |
||||
|
{ |
||||
|
// other |
||||
|
} |
||||
|
``` |
||||
|
## 配置项说明 |
||||
|
|
||||
|
|
||||
|
## 其他 |
||||
@ -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.IdentityModel" Version="4.2.1" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.Dapr.Actors\LINGYUN.Abp.Dapr.Actors.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,54 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors |
||||
|
{ |
||||
|
public static class DaprActorConfigurationExtensions |
||||
|
{ |
||||
|
public const string IdentityClientName = "IdentityClient"; |
||||
|
public const string UseCurrentAccessTokenName = "UseCurrentAccessToken"; |
||||
|
|
||||
|
[CanBeNull] |
||||
|
public static string GetIdentityClient([NotNull] this DaprActorConfiguration configuration) |
||||
|
{ |
||||
|
Check.NotNullOrEmpty(configuration, nameof(configuration)); |
||||
|
|
||||
|
return configuration.GetOrDefault(IdentityClientName); |
||||
|
} |
||||
|
|
||||
|
public static DaprActorConfiguration SetIdentityClient([NotNull] this DaprActorConfiguration configuration, [CanBeNull] string value) |
||||
|
{ |
||||
|
configuration[IdentityClientName] = value; |
||||
|
return configuration; |
||||
|
} |
||||
|
|
||||
|
[CanBeNull] |
||||
|
public static bool? GetUseCurrentAccessToken([NotNull] this DaprActorConfiguration configuration) |
||||
|
{ |
||||
|
Check.NotNullOrEmpty(configuration, nameof(configuration)); |
||||
|
|
||||
|
var value = configuration.GetOrDefault(UseCurrentAccessTokenName); |
||||
|
if (value == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return bool.Parse(value); |
||||
|
} |
||||
|
|
||||
|
public static DaprActorConfiguration SetUseCurrentAccessToken([NotNull] this DaprActorConfiguration configuration, [CanBeNull] bool? value) |
||||
|
{ |
||||
|
if (value == null) |
||||
|
{ |
||||
|
configuration.Remove(UseCurrentAccessTokenName); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
configuration[UseCurrentAccessTokenName] = value.Value.ToString().ToLowerInvariant(); |
||||
|
} |
||||
|
|
||||
|
return configuration; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using Volo.Abp.IdentityModel; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors.IdentityModel |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpDaprActorsModule), |
||||
|
typeof(AbpIdentityModelModule) |
||||
|
)] |
||||
|
public class AbpDaprActorsIdentityModelModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,66 @@ |
|||||
|
using LINGYUN.Abp.Dapr.Actors.Authentication; |
||||
|
using LINGYUN.Abp.Dapr.Actors.DynamicProxying; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Net.Http.Headers; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.IdentityModel; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors.IdentityModel |
||||
|
{ |
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class IdentityModelDaprActorProxyAuthenticator : IDaprActorProxyAuthenticator, ITransientDependency |
||||
|
{ |
||||
|
protected AbpIdentityClientOptions ClientOptions { get; } |
||||
|
protected IIdentityModelAuthenticationService IdentityModelAuthenticationService { get; } |
||||
|
|
||||
|
public ILogger<IdentityModelDaprActorProxyAuthenticator> Logger { get; set; } |
||||
|
|
||||
|
public IdentityModelDaprActorProxyAuthenticator( |
||||
|
IIdentityModelAuthenticationService identityModelAuthenticationService) |
||||
|
{ |
||||
|
IdentityModelAuthenticationService = identityModelAuthenticationService; |
||||
|
Logger = NullLogger<IdentityModelDaprActorProxyAuthenticator>.Instance; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task AuthenticateAsync(DaprActorProxyAuthenticateContext context) |
||||
|
{ |
||||
|
var identityClientName = context.RemoteService.GetIdentityClient(); |
||||
|
var configuration = GetClientConfiguration(identityClientName); |
||||
|
if (configuration == null) |
||||
|
{ |
||||
|
Logger.LogWarning($"Could not find {nameof(IdentityClientConfiguration)} for {identityClientName}. Either define a configuration for {identityClientName} or set a default configuration."); |
||||
|
return; |
||||
|
} |
||||
|
var accessToken = await IdentityModelAuthenticationService.GetAccessTokenAsync(configuration); |
||||
|
if (accessToken == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
SetAccessToken(context.Handler, accessToken); |
||||
|
} |
||||
|
|
||||
|
protected virtual void SetAccessToken(DaprHttpClientHandler handler, string accessToken) |
||||
|
{ |
||||
|
handler.PreConfigure(request => |
||||
|
{ |
||||
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private IdentityClientConfiguration GetClientConfiguration(string identityClientName = null) |
||||
|
{ |
||||
|
if (identityClientName.IsNullOrEmpty()) |
||||
|
{ |
||||
|
return ClientOptions.IdentityClients.Default; |
||||
|
} |
||||
|
|
||||
|
return ClientOptions.IdentityClients.GetOrDefault(identityClientName) ?? |
||||
|
ClientOptions.IdentityClients.Default; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
# LINGYUN.Abp.Dapr.Actors.IdentityModel |
||||
|
|
||||
|
Dapr.Actors内部使用Http进行服务间调用,此模块用于传递服务间调用令牌 |
||||
|
|
||||
|
## 配置使用 |
||||
|
|
||||
|
模块按需引用 |
||||
|
|
||||
|
```csharp |
||||
|
[DependsOn(typeof(AbpDaprActorsIdentityModelModule))] |
||||
|
public class YouProjectModule : AbpModule |
||||
|
{ |
||||
|
// other |
||||
|
} |
||||
|
``` |
||||
|
## 配置项说明 |
||||
|
|
||||
|
|
||||
|
## 其他 |
||||
@ -0,0 +1,17 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Dapr.Actors" Version="1.1.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Castle.Core" Version="4.2.1" /> |
||||
|
<PackageReference Include="Volo.Abp.ExceptionHandling" Version="4.2.1" /> |
||||
|
<PackageReference Include="Volo.Abp.MultiTenancy" Version="4.2.1" /> |
||||
|
<PackageReference Include="Volo.Abp.Validation" Version="4.2.1" /> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,41 @@ |
|||||
|
using System.Runtime.Serialization; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.ExceptionHandling; |
||||
|
using Volo.Abp.Http; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors |
||||
|
{ |
||||
|
public class AbpDaprActorCallException : AbpException, IHasErrorCode, IHasErrorDetails |
||||
|
{ |
||||
|
public string Code => Error?.Code; |
||||
|
|
||||
|
public string Details => Error?.Details; |
||||
|
|
||||
|
public RemoteServiceErrorInfo Error { get; set; } |
||||
|
|
||||
|
public AbpDaprActorCallException() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public AbpDaprActorCallException(SerializationInfo serializationInfo, StreamingContext context) |
||||
|
: base(serializationInfo, context) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public AbpDaprActorCallException(RemoteServiceErrorInfo error) |
||||
|
: base(error.Message) |
||||
|
{ |
||||
|
Error = error; |
||||
|
|
||||
|
if (error.Data != null) |
||||
|
{ |
||||
|
foreach (var dataKey in error.Data.Keys) |
||||
|
{ |
||||
|
Data[dataKey] = error.Data[dataKey]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
namespace LINGYUN.Abp.Dapr.Actors |
||||
|
{ |
||||
|
public class AbpDaprActorOptions |
||||
|
{ |
||||
|
public DaprActorConfigurationDictionary RemoteActors { get; set; } |
||||
|
|
||||
|
public AbpDaprActorOptions() |
||||
|
{ |
||||
|
RemoteActors = new DaprActorConfigurationDictionary(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using LINGYUN.Abp.Dapr.Actors.DynamicProxying; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors |
||||
|
{ |
||||
|
public class AbpDaprActorProxyOptions |
||||
|
{ |
||||
|
public Dictionary<Type, DynamicDaprActorProxyConfig> ActorProxies { get; set; } |
||||
|
|
||||
|
public AbpDaprActorProxyOptions() |
||||
|
{ |
||||
|
ActorProxies = new Dictionary<Type, DynamicDaprActorProxyConfig>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Castle; |
||||
|
using Volo.Abp.ExceptionHandling; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpCastleCoreModule), |
||||
|
typeof(AbpMultiTenancyModule), |
||||
|
typeof(AbpValidationModule), |
||||
|
typeof(AbpExceptionHandlingModule) |
||||
|
)] |
||||
|
public class AbpDaprActorsModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
Configure<AbpDaprActorOptions>(configuration); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using LINGYUN.Abp.Dapr.Actors.DynamicProxying; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors.Authentication |
||||
|
{ |
||||
|
public class DaprActorProxyAuthenticateContext |
||||
|
{ |
||||
|
public DaprHttpClientHandler Handler { get; } |
||||
|
public DaprActorConfiguration RemoteService { get; } |
||||
|
|
||||
|
public string RemoteServiceName { get; } |
||||
|
public DaprActorProxyAuthenticateContext( |
||||
|
DaprHttpClientHandler handler, |
||||
|
DaprActorConfiguration remoteService, |
||||
|
string remoteServiceName) |
||||
|
{ |
||||
|
Handler = handler; |
||||
|
RemoteService = remoteService; |
||||
|
RemoteServiceName = remoteServiceName; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors.Authentication |
||||
|
{ |
||||
|
public interface IDaprActorProxyAuthenticator |
||||
|
{ |
||||
|
Task AuthenticateAsync(DaprActorProxyAuthenticateContext context); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors.Authentication |
||||
|
{ |
||||
|
[Dependency(TryRegister = true)] |
||||
|
public class NullDaprActorProxyAuthenticator : IDaprActorProxyAuthenticator, ISingletonDependency |
||||
|
{ |
||||
|
public Task AuthenticateAsync(DaprActorProxyAuthenticateContext context) |
||||
|
{ |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors |
||||
|
{ |
||||
|
public class DaprActorConfiguration : Dictionary<string, string> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Base ActorId.
|
||||
|
/// </summary>
|
||||
|
public string ActorId |
||||
|
{ |
||||
|
get => this.GetOrDefault(nameof(ActorId)); |
||||
|
set => this[nameof(ActorId)] = value; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Base Url.
|
||||
|
/// </summary>
|
||||
|
public string BaseUrl |
||||
|
{ |
||||
|
get => this.GetOrDefault(nameof(BaseUrl)); |
||||
|
set => this[nameof(BaseUrl)] = value; |
||||
|
} |
||||
|
|
||||
|
public DaprActorConfiguration() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public DaprActorConfiguration( |
||||
|
string actorId, |
||||
|
string baseUrl) |
||||
|
{ |
||||
|
this[nameof(ActorId)] = actorId; |
||||
|
this[nameof(BaseUrl)] = baseUrl; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors |
||||
|
{ |
||||
|
public class DaprActorConfigurationDictionary : Dictionary<string, DaprActorConfiguration> |
||||
|
{ |
||||
|
public const string DefaultName = "Default"; |
||||
|
|
||||
|
public DaprActorConfiguration Default |
||||
|
{ |
||||
|
get => this.GetOrDefault(DefaultName); |
||||
|
set => this[DefaultName] = value; |
||||
|
} |
||||
|
|
||||
|
public DaprActorConfiguration GetConfigurationOrDefault(string name) |
||||
|
{ |
||||
|
return this.GetOrDefault(name) |
||||
|
?? Default |
||||
|
?? throw new AbpException($"Dapr service '{name}' was not found and there is no default configuration."); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
using System; |
||||
|
using System.Net.Http; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors.DynamicProxying |
||||
|
{ |
||||
|
public class DaprHttpClientHandler : HttpClientHandler |
||||
|
{ |
||||
|
private Action<HttpRequestMessage> _preConfigureInvoke; |
||||
|
protected Action<HttpRequestMessage> PreConfigureInvoke => _preConfigureInvoke; |
||||
|
|
||||
|
public virtual void PreConfigure(Action<HttpRequestMessage> config) |
||||
|
{ |
||||
|
if (_preConfigureInvoke == null) |
||||
|
{ |
||||
|
_preConfigureInvoke = config; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_preConfigureInvoke += config; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void AddHeader(string key, string value) |
||||
|
{ |
||||
|
PreConfigure(request => |
||||
|
{ |
||||
|
request.Headers.Add(key, value); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) |
||||
|
{ |
||||
|
PreConfigureInvoke?.Invoke(request); |
||||
|
|
||||
|
return await base.SendAsync(request, cancellationToken); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors.DynamicProxying |
||||
|
{ |
||||
|
public class DynamicDaprActorProxyConfig |
||||
|
{ |
||||
|
public Type Type { get; } |
||||
|
|
||||
|
public string RemoteServiceName { get; } |
||||
|
|
||||
|
public DynamicDaprActorProxyConfig(Type type, string remoteServiceName) |
||||
|
{ |
||||
|
Type = type; |
||||
|
RemoteServiceName = remoteServiceName; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,153 @@ |
|||||
|
using Dapr.Actors; |
||||
|
using Dapr.Actors.Client; |
||||
|
using LINGYUN.Abp.Dapr.Actors.Authentication; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Globalization; |
||||
|
using System.Net.Http; |
||||
|
using System.Net.Http.Headers; |
||||
|
using System.Reflection; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.DynamicProxy; |
||||
|
using Volo.Abp.Http; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Volo.Abp.Threading; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dapr.Actors.DynamicProxying |
||||
|
{ |
||||
|
public class DynamicDaprActorProxyInterceptor<TService> : AbpInterceptor, ITransientDependency |
||||
|
where TService: IActor |
||||
|
{ |
||||
|
protected ICurrentTenant CurrentTenant { get; } |
||||
|
protected AbpDaprActorOptions DaprActorOptions { get; } |
||||
|
protected AbpDaprActorProxyOptions DaprActorProxyOptions { get; } |
||||
|
protected IDaprActorProxyAuthenticator ActoryProxyAuthenticator { get; } |
||||
|
|
||||
|
public ILogger<DynamicDaprActorProxyInterceptor<TService>> Logger { get; set; } |
||||
|
|
||||
|
public DynamicDaprActorProxyInterceptor( |
||||
|
IOptions<AbpDaprActorProxyOptions> daprActorProxyOptions, |
||||
|
IOptionsSnapshot<AbpDaprActorOptions> daprActorOptions, |
||||
|
IDaprActorProxyAuthenticator actorProxyAuthenticator, |
||||
|
ICurrentTenant currentTenant) |
||||
|
{ |
||||
|
CurrentTenant = currentTenant; |
||||
|
ActoryProxyAuthenticator = actorProxyAuthenticator; |
||||
|
DaprActorProxyOptions = daprActorProxyOptions.Value; |
||||
|
DaprActorOptions = daprActorOptions.Value; |
||||
|
|
||||
|
Logger = NullLogger<DynamicDaprActorProxyInterceptor<TService>>.Instance; |
||||
|
} |
||||
|
|
||||
|
public override async Task InterceptAsync(IAbpMethodInvocation invocation) |
||||
|
{ |
||||
|
await MakeRequestAsync(invocation); |
||||
|
} |
||||
|
|
||||
|
private async Task MakeRequestAsync(IAbpMethodInvocation invocation) |
||||
|
{ |
||||
|
// 获取Actor配置
|
||||
|
var actorProxyConfig = DaprActorProxyOptions.ActorProxies.GetOrDefault(typeof(TService)) ?? throw new AbpException($"Could not get DynamicDaprActorProxyConfig for {typeof(TService).FullName}."); |
||||
|
var remoteServiceConfig = DaprActorOptions.RemoteActors.GetConfigurationOrDefault(actorProxyConfig.RemoteServiceName); |
||||
|
|
||||
|
var actorProxyOptions = new ActorProxyOptions |
||||
|
{ |
||||
|
HttpEndpoint = remoteServiceConfig.BaseUrl |
||||
|
}; |
||||
|
|
||||
|
// 自定义请求处理器
|
||||
|
// 可添加请求头
|
||||
|
var httpClientHandler = new DaprHttpClientHandler(); |
||||
|
|
||||
|
// 身份认证处理
|
||||
|
await ActoryProxyAuthenticator.AuthenticateAsync( |
||||
|
new DaprActorProxyAuthenticateContext( |
||||
|
httpClientHandler, remoteServiceConfig, actorProxyConfig.RemoteServiceName)); |
||||
|
|
||||
|
AddHeaders(httpClientHandler); |
||||
|
|
||||
|
// 构建代理服务
|
||||
|
var proxyFactory = new ActorProxyFactory(actorProxyOptions, (HttpMessageHandler)httpClientHandler); |
||||
|
|
||||
|
await MakeRequestAsync(invocation, proxyFactory, remoteServiceConfig); |
||||
|
} |
||||
|
|
||||
|
private async Task MakeRequestAsync( |
||||
|
IAbpMethodInvocation invocation, |
||||
|
ActorProxyFactory proxyFactory, |
||||
|
DaprActorConfiguration configuration |
||||
|
) |
||||
|
{ |
||||
|
var actorId = new ActorId(configuration.ActorId); |
||||
|
|
||||
|
var invokeType = typeof(TService); |
||||
|
var remoteServiceAttr = invokeType.GetTypeInfo().GetCustomAttribute<RemoteServiceAttribute>(); |
||||
|
var actorType = remoteServiceAttr != null |
||||
|
? remoteServiceAttr.Name |
||||
|
: invokeType.Name; |
||||
|
var isAsyncMethod = invocation.Method.IsAsync(); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
var actorProxy = proxyFactory.CreateActorProxy<TService>(actorId, actorType); |
||||
|
if (isAsyncMethod) |
||||
|
{ |
||||
|
// 调用异步Actor
|
||||
|
var task = (Task)invocation.Method.Invoke(actorProxy, invocation.Arguments); |
||||
|
await task; |
||||
|
|
||||
|
if (!invocation.Method.ReturnType.GenericTypeArguments.IsNullOrEmpty()) |
||||
|
{ |
||||
|
// 处理返回值
|
||||
|
invocation.ReturnValue = typeof(Task<>) |
||||
|
.MakeGenericType(invocation.Method.ReturnType.GenericTypeArguments[0]) |
||||
|
.GetProperty(nameof(Task<object>.Result), BindingFlags.Public | BindingFlags.Instance) |
||||
|
.GetValue(task); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// 调用同步Actor
|
||||
|
invocation.ReturnValue = invocation.Method.Invoke(actorProxy, invocation.Arguments); |
||||
|
} |
||||
|
} |
||||
|
catch (ActorMethodInvocationException amie) // 其他异常忽略交给框架处理
|
||||
|
{ |
||||
|
if (amie.InnerException != null && amie.InnerException is ActorInvokeException aie) |
||||
|
{ |
||||
|
// Dapr 包装了远程服务异常
|
||||
|
throw new AbpDaprActorCallException( |
||||
|
new RemoteServiceErrorInfo |
||||
|
{ |
||||
|
Message = aie.Message, |
||||
|
Code = aie.ActualExceptionType |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void AddHeaders(DaprHttpClientHandler handler) |
||||
|
{ |
||||
|
//TenantId
|
||||
|
if (CurrentTenant.Id.HasValue) |
||||
|
{ |
||||
|
//TODO: Use AbpAspNetCoreMultiTenancyOptions to get the key
|
||||
|
handler.AddHeader(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString()); |
||||
|
} |
||||
|
//Culture
|
||||
|
//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()) |
||||
|
{ |
||||
|
handler.PreConfigure(request => request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(currentCulture))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,104 @@ |
|||||
|
using Castle.DynamicProxy; |
||||
|
using Dapr.Actors; |
||||
|
using JetBrains.Annotations; |
||||
|
using LINGYUN.Abp.Dapr.Actors; |
||||
|
using LINGYUN.Abp.Dapr.Actors.DynamicProxying; |
||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Castle.DynamicProxy; |
||||
|
using Volo.Abp.Validation; |
||||
|
|
||||
|
namespace Microsoft.Extensions.DependencyInjection |
||||
|
{ |
||||
|
public static class ServiceCollectionDynamicDaprActorProxyExtensions |
||||
|
{ |
||||
|
private static readonly ProxyGenerator ProxyGeneratorInstance = new ProxyGenerator(); |
||||
|
|
||||
|
public static IServiceCollection AddDaprActorProxies( |
||||
|
[NotNull] this IServiceCollection services, |
||||
|
[NotNull] Assembly assembly, |
||||
|
[NotNull] string remoteServiceConfigurationName = DaprActorConfigurationDictionary.DefaultName, |
||||
|
bool asDefaultServices = true) |
||||
|
{ |
||||
|
Check.NotNull(services, nameof(assembly)); |
||||
|
|
||||
|
var serviceTypes = assembly.GetTypes().Where(IsSuitableForDynamicActorProxying).ToArray(); |
||||
|
|
||||
|
foreach (var serviceType in serviceTypes) |
||||
|
{ |
||||
|
services.AddDaprActorProxy( |
||||
|
serviceType, |
||||
|
remoteServiceConfigurationName, |
||||
|
asDefaultServices |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
return services; |
||||
|
} |
||||
|
|
||||
|
public static IServiceCollection AddDaprActorProxy<T>( |
||||
|
[NotNull] this IServiceCollection services, |
||||
|
[NotNull] string remoteServiceConfigurationName = DaprActorConfigurationDictionary.DefaultName, |
||||
|
bool asDefaultService = true) |
||||
|
{ |
||||
|
return services.AddDaprActorProxy( |
||||
|
typeof(T), |
||||
|
remoteServiceConfigurationName, |
||||
|
asDefaultService |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public static IServiceCollection AddDaprActorProxy( |
||||
|
[NotNull] this IServiceCollection services, |
||||
|
[NotNull] Type type, |
||||
|
[NotNull] string remoteServiceConfigurationName = DaprActorConfigurationDictionary.DefaultName, |
||||
|
bool asDefaultService = true) |
||||
|
{ |
||||
|
Check.NotNull(services, nameof(services)); |
||||
|
Check.NotNull(type, nameof(type)); |
||||
|
Check.NotNullOrWhiteSpace(remoteServiceConfigurationName, nameof(remoteServiceConfigurationName)); |
||||
|
|
||||
|
// AddHttpClientFactory(services, remoteServiceConfigurationName);
|
||||
|
|
||||
|
services.Configure<AbpDaprActorProxyOptions>(options => |
||||
|
{ |
||||
|
options.ActorProxies[type] = new DynamicDaprActorProxyConfig(type, remoteServiceConfigurationName); |
||||
|
}); |
||||
|
|
||||
|
var interceptorType = typeof(DynamicDaprActorProxyInterceptor<>).MakeGenericType(type); |
||||
|
services.AddTransient(interceptorType); |
||||
|
|
||||
|
var interceptorAdapterType = typeof(AbpAsyncDeterminationInterceptor<>).MakeGenericType(interceptorType); |
||||
|
|
||||
|
var validationInterceptorAdapterType = |
||||
|
typeof(AbpAsyncDeterminationInterceptor<>).MakeGenericType(typeof(ValidationInterceptor)); |
||||
|
|
||||
|
if (asDefaultService) |
||||
|
{ |
||||
|
services.AddTransient( |
||||
|
type, |
||||
|
serviceProvider => ProxyGeneratorInstance |
||||
|
.CreateInterfaceProxyWithoutTarget( |
||||
|
type, |
||||
|
(IInterceptor)serviceProvider.GetRequiredService(validationInterceptorAdapterType), |
||||
|
(IInterceptor)serviceProvider.GetRequiredService(interceptorAdapterType) |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
return services; |
||||
|
} |
||||
|
|
||||
|
private static bool IsSuitableForDynamicActorProxying(Type type) |
||||
|
{ |
||||
|
//TODO: Add option to change type filter
|
||||
|
|
||||
|
return type.IsInterface |
||||
|
&& type.IsPublic |
||||
|
&& !type.IsGenericType |
||||
|
&& typeof(IActor).IsAssignableFrom(type); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,125 @@ |
|||||
|
# LINGYUN.Abp.Dapr.Actors |
||||
|
|
||||
|
Abp Dapr.Actors 集成 |
||||
|
|
||||
|
## 配置使用 |
||||
|
|
||||
|
项目设计与 **Volo.Abp.Http.Client** 类似 |
||||
|
|
||||
|
### 1、接口定义 |
||||
|
|
||||
|
```c# |
||||
|
|
||||
|
// 定义在接口上的RemoteService.Name会被作为Actor的名称注册到Dapr |
||||
|
[RemoteService(Name = "System")] |
||||
|
public interface ISystemActor : IActor |
||||
|
{ |
||||
|
Task<string> GetAsync(); |
||||
|
} |
||||
|
|
||||
|
public class SystemActorInterfaceModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
### 2、服务端 |
||||
|
|
||||
|
引用 LINGYUN.Abp.Dapr.Actors.AspNetCore |
||||
|
|
||||
|
* 实现接口 |
||||
|
|
||||
|
```c# |
||||
|
|
||||
|
public class SystemActor : Actor |
||||
|
{ |
||||
|
public Task<string> GetAsync() |
||||
|
{ |
||||
|
retuen Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
* 创建模块 |
||||
|
|
||||
|
```c# |
||||
|
|
||||
|
// 模块会自动搜索实现了IActor的服务,注册为Dapr的Actors |
||||
|
[DependsOn( |
||||
|
typeof(AbpDaprActorsAspNetCoreModule))] |
||||
|
public class SystemActorServerModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
* 发布到Dapr |
||||
|
|
||||
|
```shell |
||||
|
# --app-port .net程序映射端口 |
||||
|
# -H 对外暴露 http 监听端口 |
||||
|
# -G 对外暴露 grpc 监听端口 |
||||
|
dapr run --app-id ufsoft --app-port 5000 -H 50000 -G 40001 -- dotnet run |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
### 3、客户端 |
||||
|
|
||||
|
引用 LINGYUN.Abp.Dapr.Actors |
||||
|
|
||||
|
* 配置文件 **appsettings.json** |
||||
|
|
||||
|
```json |
||||
|
|
||||
|
{ |
||||
|
"RemoteActors": { |
||||
|
"System": { |
||||
|
"ActorId": "1", |
||||
|
"BaseUrl": "http://127.0.0.1:50000" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
* 客户端代码 |
||||
|
|
||||
|
```c# |
||||
|
|
||||
|
// 模块依赖 |
||||
|
[DependsOn( |
||||
|
typeof(AbpDaprActorsModule))] |
||||
|
public class SystemActorClientModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
// 注册代理类似于 Volo.Abp.Http.Client 模块 |
||||
|
context.Services.AddDaprActorProxies( |
||||
|
typeof(SystemActorInterfaceModule).Assembly, // 搜索 SystemActorInterfaceModule 模块下的IActor定义 |
||||
|
RemoteServiceName |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 调用方法,直接依赖注入即可 |
||||
|
public class InvokeClass |
||||
|
{ |
||||
|
private readonly ISystemActor _systemActor; |
||||
|
|
||||
|
public InvokeClass(ISystemActor systemActor) |
||||
|
{ |
||||
|
_systemActor = systemActor; |
||||
|
} |
||||
|
|
||||
|
public async Task InvokeAsync() |
||||
|
{ |
||||
|
await _systemActor.GetAsync(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
## 其他 |
||||
Loading…
Reference in new issue