Browse Source

Merge pull request #257 from colinin/4.3

Improved DaprActors to accommodate multiple RemoteServices
pull/274/head
cKey 5 years ago
committed by GitHub
parent
commit
c546182aac
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      aspnet-core/LINGYUN.MicroService.Common.sln
  2. 1
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN.Abp.Dapr.Actors.csproj
  3. 12
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/AbpDaprActorOptions.cs
  4. 24
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/AbpDaprActorsModule.cs
  5. 14
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/AbpDaprRemoteServiceOptions.cs
  6. 21
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/Authentication/DaprActorProxyAuthenticateContext.cs
  7. 9
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/Authentication/IDaprActorProxyAuthenticator.cs
  8. 14
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/Authentication/NullDaprActorProxyAuthenticator.cs
  9. 37
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/DaprActorConfiguration.cs
  10. 23
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/DaprActorConfigurationDictionary.cs
  11. 24
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/DynamicProxying/DaprHttpClientHandler.cs
  12. 63
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/DynamicProxying/DynamicDaprActorProxyInterceptor.cs
  13. 7
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicDaprActorProxyExtensions.cs
  14. 6
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/AbpDaprClientModule.cs
  15. 4
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/DynamicDaprClientProxyInterceptor.cs
  16. 7
      aspnet-core/modules/dapr/README.md
  17. 34
      aspnet-core/tests/LINGYUN.Abp.Dapr.Actors.Tests/LINGYUN.Abp.Dapr.Actors.Tests.csproj
  18. 34
      aspnet-core/tests/LINGYUN.Abp.Dapr.Actors.Tests/LINGYUN/Abp/Dapr/Actors/Tests/AbpDaprActorsTestBase.cs
  19. 33
      aspnet-core/tests/LINGYUN.Abp.Dapr.Actors.Tests/LINGYUN/Abp/Dapr/Actors/Tests/AbpDaprActorsTestModule.cs
  20. 39
      aspnet-core/tests/LINGYUN.Abp.Dapr.Actors.Tests/LINGYUN/Abp/Dapr/Actors/Tests/TestActorsTests.cs
  21. 4
      aspnet-core/tests/LINGYUN.Abp.Dapr.AspNetCore.TestHost/LINGYUN/Abp/Dapr/Actors/TestActor.cs
  22. 4
      aspnet-core/tests/LINGYUN.Abp.Dapr.Tests/LINGYUN/Abp/Dapr/Actors/ITestActor.cs
  23. 17
      aspnet-core/tests/LINGYUN.Abp.Dapr.Tests/LINGYUN/Abp/Dapr/NameValue.cs

27
aspnet-core/LINGYUN.MicroService.Common.sln

@ -134,10 +134,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dapr", "dapr", "{7FDFB22F-1
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Actors", "modules\dapr\LINGYUN.Abp.Dapr.Actors\LINGYUN.Abp.Dapr.Actors.csproj", "{C72E0407-06FE-4CAA-86E5-30FF216A7B82}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Actors", "modules\dapr\LINGYUN.Abp.Dapr.Actors\LINGYUN.Abp.Dapr.Actors.csproj", "{C72E0407-06FE-4CAA-86E5-30FF216A7B82}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Actors.IdentityModel", "modules\dapr\LINGYUN.Abp.Dapr.Actors.IdentityModel\LINGYUN.Abp.Dapr.Actors.IdentityModel.csproj", "{A5DC8C25-6504-4C35-A657-7A1BF051570F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Actors.IdentityModel.Web", "modules\dapr\LINGYUN.Abp.Dapr.Actors.IdentityModel.Web\LINGYUN.Abp.Dapr.Actors.IdentityModel.Web.csproj", "{E263A9ED-D5DB-4495-A0C7-6268ED92EB92}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Actors.AspNetCore", "modules\dapr\LINGYUN.Abp.Dapr.Actors.AspNetCore\LINGYUN.Abp.Dapr.Actors.AspNetCore.csproj", "{E74FF671-6E5E-430C-9211-ED910634DDBE}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Actors.AspNetCore", "modules\dapr\LINGYUN.Abp.Dapr.Actors.AspNetCore\LINGYUN.Abp.Dapr.Actors.AspNetCore.csproj", "{E74FF671-6E5E-430C-9211-ED910634DDBE}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Client", "modules\dapr\LINGYUN.Abp.Dapr.Client\LINGYUN.Abp.Dapr.Client.csproj", "{879791A3-BD69-42E4-A3BC-9878EFAADDD1}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Client", "modules\dapr\LINGYUN.Abp.Dapr.Client\LINGYUN.Abp.Dapr.Client.csproj", "{879791A3-BD69-42E4-A3BC-9878EFAADDD1}"
@ -154,11 +150,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Rules.RulesEngi
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Rules.NRules.Tests", "tests\LINGYUN.Abp.Rules.NRules.Tests\LINGYUN.Abp.Rules.NRules.Tests.csproj", "{EF03A0A7-A93E-4DEF-A33E-F5A82E995FBF}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Rules.NRules.Tests", "tests\LINGYUN.Abp.Rules.NRules.Tests\LINGYUN.Abp.Rules.NRules.Tests.csproj", "{EF03A0A7-A93E-4DEF-A33E-F5A82E995FBF}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Dapr.Client.Tests", "tests\LINGYUN.Abp.Dapr.Client.Tests\LINGYUN.Abp.Dapr.Client.Tests.csproj", "{9403FC1F-9677-489F-A03A-0B456153EE86}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Client.Tests", "tests\LINGYUN.Abp.Dapr.Client.Tests\LINGYUN.Abp.Dapr.Client.Tests.csproj", "{9403FC1F-9677-489F-A03A-0B456153EE86}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Tests", "tests\LINGYUN.Abp.Dapr.Tests\LINGYUN.Abp.Dapr.Tests.csproj", "{26E87199-F0AD-4B30-B0E4-080B12E6F8FC}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Dapr.Tests", "tests\LINGYUN.Abp.Dapr.Tests\LINGYUN.Abp.Dapr.Tests.csproj", "{26E87199-F0AD-4B30-B0E4-080B12E6F8FC}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.AspNetCore.TestHost", "tests\LINGYUN.Abp.Dapr.AspNetCore.TestHost\LINGYUN.Abp.Dapr.AspNetCore.TestHost.csproj", "{8968EDAF-9F5C-4786-AF2A-D3928B70C3EC}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Dapr.AspNetCore.TestHost", "tests\LINGYUN.Abp.Dapr.AspNetCore.TestHost\LINGYUN.Abp.Dapr.AspNetCore.TestHost.csproj", "{8968EDAF-9F5C-4786-AF2A-D3928B70C3EC}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Dapr.Actors.Tests", "tests\LINGYUN.Abp.Dapr.Actors.Tests\LINGYUN.Abp.Dapr.Actors.Tests.csproj", "{CF30221B-CA7A-42CD-B91A-B7224AB2F38B}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -370,14 +368,6 @@ Global
{C72E0407-06FE-4CAA-86E5-30FF216A7B82}.Debug|Any CPU.Build.0 = Debug|Any CPU {C72E0407-06FE-4CAA-86E5-30FF216A7B82}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C72E0407-06FE-4CAA-86E5-30FF216A7B82}.Release|Any CPU.ActiveCfg = Release|Any CPU {C72E0407-06FE-4CAA-86E5-30FF216A7B82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C72E0407-06FE-4CAA-86E5-30FF216A7B82}.Release|Any CPU.Build.0 = Release|Any CPU {C72E0407-06FE-4CAA-86E5-30FF216A7B82}.Release|Any CPU.Build.0 = Release|Any CPU
{A5DC8C25-6504-4C35-A657-7A1BF051570F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5DC8C25-6504-4C35-A657-7A1BF051570F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5DC8C25-6504-4C35-A657-7A1BF051570F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5DC8C25-6504-4C35-A657-7A1BF051570F}.Release|Any CPU.Build.0 = Release|Any CPU
{E263A9ED-D5DB-4495-A0C7-6268ED92EB92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E263A9ED-D5DB-4495-A0C7-6268ED92EB92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E263A9ED-D5DB-4495-A0C7-6268ED92EB92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E263A9ED-D5DB-4495-A0C7-6268ED92EB92}.Release|Any CPU.Build.0 = Release|Any CPU
{E74FF671-6E5E-430C-9211-ED910634DDBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E74FF671-6E5E-430C-9211-ED910634DDBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E74FF671-6E5E-430C-9211-ED910634DDBE}.Debug|Any CPU.Build.0 = Debug|Any CPU {E74FF671-6E5E-430C-9211-ED910634DDBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E74FF671-6E5E-430C-9211-ED910634DDBE}.Release|Any CPU.ActiveCfg = Release|Any CPU {E74FF671-6E5E-430C-9211-ED910634DDBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -418,6 +408,10 @@ Global
{8968EDAF-9F5C-4786-AF2A-D3928B70C3EC}.Debug|Any CPU.Build.0 = Debug|Any CPU {8968EDAF-9F5C-4786-AF2A-D3928B70C3EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8968EDAF-9F5C-4786-AF2A-D3928B70C3EC}.Release|Any CPU.ActiveCfg = Release|Any CPU {8968EDAF-9F5C-4786-AF2A-D3928B70C3EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8968EDAF-9F5C-4786-AF2A-D3928B70C3EC}.Release|Any CPU.Build.0 = Release|Any CPU {8968EDAF-9F5C-4786-AF2A-D3928B70C3EC}.Release|Any CPU.Build.0 = Release|Any CPU
{CF30221B-CA7A-42CD-B91A-B7224AB2F38B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF30221B-CA7A-42CD-B91A-B7224AB2F38B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF30221B-CA7A-42CD-B91A-B7224AB2F38B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF30221B-CA7A-42CD-B91A-B7224AB2F38B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -485,8 +479,6 @@ Global
{BA2F4EC9-BC2C-482A-9123-BDACB8B15295} = {B86C21A4-73B7-471E-B73A-B4B905EC9435} {BA2F4EC9-BC2C-482A-9123-BDACB8B15295} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
{7FDFB22F-1BFF-4E05-9427-78B7A8461D50} = {02EA4E78-5891-43BC-944F-3E52FEE032E4} {7FDFB22F-1BFF-4E05-9427-78B7A8461D50} = {02EA4E78-5891-43BC-944F-3E52FEE032E4}
{C72E0407-06FE-4CAA-86E5-30FF216A7B82} = {7FDFB22F-1BFF-4E05-9427-78B7A8461D50} {C72E0407-06FE-4CAA-86E5-30FF216A7B82} = {7FDFB22F-1BFF-4E05-9427-78B7A8461D50}
{A5DC8C25-6504-4C35-A657-7A1BF051570F} = {7FDFB22F-1BFF-4E05-9427-78B7A8461D50}
{E263A9ED-D5DB-4495-A0C7-6268ED92EB92} = {7FDFB22F-1BFF-4E05-9427-78B7A8461D50}
{E74FF671-6E5E-430C-9211-ED910634DDBE} = {7FDFB22F-1BFF-4E05-9427-78B7A8461D50} {E74FF671-6E5E-430C-9211-ED910634DDBE} = {7FDFB22F-1BFF-4E05-9427-78B7A8461D50}
{879791A3-BD69-42E4-A3BC-9878EFAADDD1} = {7FDFB22F-1BFF-4E05-9427-78B7A8461D50} {879791A3-BD69-42E4-A3BC-9878EFAADDD1} = {7FDFB22F-1BFF-4E05-9427-78B7A8461D50}
{C8891F1A-E6E5-448A-B527-EBFA44D20808} = {02EA4E78-5891-43BC-944F-3E52FEE032E4} {C8891F1A-E6E5-448A-B527-EBFA44D20808} = {02EA4E78-5891-43BC-944F-3E52FEE032E4}
@ -498,6 +490,7 @@ Global
{9403FC1F-9677-489F-A03A-0B456153EE86} = {B86C21A4-73B7-471E-B73A-B4B905EC9435} {9403FC1F-9677-489F-A03A-0B456153EE86} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
{26E87199-F0AD-4B30-B0E4-080B12E6F8FC} = {B86C21A4-73B7-471E-B73A-B4B905EC9435} {26E87199-F0AD-4B30-B0E4-080B12E6F8FC} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
{8968EDAF-9F5C-4786-AF2A-D3928B70C3EC} = {B86C21A4-73B7-471E-B73A-B4B905EC9435} {8968EDAF-9F5C-4786-AF2A-D3928B70C3EC} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
{CF30221B-CA7A-42CD-B91A-B7224AB2F38B} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {06C707C6-02C0-411A-AD3B-2D0E13787CB8} SolutionGuid = {06C707C6-02C0-411A-AD3B-2D0E13787CB8}

1
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN.Abp.Dapr.Actors.csproj

@ -13,5 +13,6 @@
<PackageReference Include="Volo.Abp.ExceptionHandling" Version="4.3.0" /> <PackageReference Include="Volo.Abp.ExceptionHandling" Version="4.3.0" />
<PackageReference Include="Volo.Abp.MultiTenancy" Version="4.3.0" /> <PackageReference Include="Volo.Abp.MultiTenancy" Version="4.3.0" />
<PackageReference Include="Volo.Abp.Validation" Version="4.3.0" /> <PackageReference Include="Volo.Abp.Validation" Version="4.3.0" />
<PackageReference Include="Volo.Abp.Http.Client" Version="4.3.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

12
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/AbpDaprActorOptions.cs

@ -1,12 +0,0 @@
namespace LINGYUN.Abp.Dapr.Actors
{
public class AbpDaprActorOptions
{
public DaprActorConfigurationDictionary RemoteActors { get; set; }
public AbpDaprActorOptions()
{
RemoteActors = new DaprActorConfigurationDictionary();
}
}
}

24
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/AbpDaprActorsModule.cs

@ -1,24 +1,28 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration;
using Volo.Abp.Castle; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.ExceptionHandling; using Volo.Abp.Http.Client;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Validation;
namespace LINGYUN.Abp.Dapr.Actors namespace LINGYUN.Abp.Dapr.Actors
{ {
[DependsOn( [DependsOn(
typeof(AbpCastleCoreModule), typeof(AbpHttpClientModule)
typeof(AbpMultiTenancyModule),
typeof(AbpValidationModule),
typeof(AbpExceptionHandlingModule)
)] )]
public class AbpDaprActorsModule : AbpModule public class AbpDaprActorsModule : AbpModule
{ {
/// <summary>
/// 与AbpHttpClient集成,创建一个命名HttpClient
/// </summary>
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<AbpDaprActorOptions>(configuration); Configure<AbpDaprRemoteServiceOptions>(options =>
{
configuration.Bind(options);
});
context.Services.AddHttpClient(DaprHttpClient);
} }
} }
} }

14
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/AbpDaprRemoteServiceOptions.cs

@ -0,0 +1,14 @@
using Volo.Abp.Http.Client;
namespace LINGYUN.Abp.Dapr.Actors
{
public class AbpDaprRemoteServiceOptions
{
public RemoteServiceConfigurationDictionary RemoteServices { get; set; }
public AbpDaprRemoteServiceOptions()
{
RemoteServices = new RemoteServiceConfigurationDictionary();
}
}
}

21
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/Authentication/DaprActorProxyAuthenticateContext.cs

@ -1,21 +0,0 @@
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;
}
}
}

9
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/Authentication/IDaprActorProxyAuthenticator.cs

@ -1,9 +0,0 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.Dapr.Actors.Authentication
{
public interface IDaprActorProxyAuthenticator
{
Task AuthenticateAsync(DaprActorProxyAuthenticateContext context);
}
}

14
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/Authentication/NullDaprActorProxyAuthenticator.cs

@ -1,14 +0,0 @@
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;
}
}
}

37
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/DaprActorConfiguration.cs

@ -1,37 +0,0 @@
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;
}
}
}

23
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/DaprActorConfigurationDictionary.cs

@ -1,23 +0,0 @@
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.");
}
}
}

24
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/DynamicProxying/DaprHttpClientHandler.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -7,10 +8,10 @@ namespace LINGYUN.Abp.Dapr.Actors.DynamicProxying
{ {
public class DaprHttpClientHandler : HttpClientHandler public class DaprHttpClientHandler : HttpClientHandler
{ {
private Action<HttpRequestMessage> _preConfigureInvoke; private Func<HttpRequestMessage, Task> _preConfigureInvoke;
protected Action<HttpRequestMessage> PreConfigureInvoke => _preConfigureInvoke; protected Func<HttpRequestMessage, Task> PreConfigureInvoke => _preConfigureInvoke;
public virtual void PreConfigure(Action<HttpRequestMessage> config) public virtual void PreConfigure(Func<HttpRequestMessage, Task> config)
{ {
if (_preConfigureInvoke == null) if (_preConfigureInvoke == null)
{ {
@ -27,12 +28,27 @@ namespace LINGYUN.Abp.Dapr.Actors.DynamicProxying
PreConfigure(request => PreConfigure(request =>
{ {
request.Headers.Add(key, value); request.Headers.Add(key, value);
return Task.CompletedTask;
});
}
public void AcceptLanguage(string value)
{
PreConfigure(request =>
{
request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(value));
return Task.CompletedTask;
}); });
} }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{ {
PreConfigureInvoke?.Invoke(request); if (PreConfigureInvoke != null)
{
await PreConfigureInvoke(request);
}
return await base.SendAsync(request, cancellationToken); return await base.SendAsync(request, cancellationToken);
} }

63
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/LINGYUN/Abp/Dapr/Actors/DynamicProxying/DynamicDaprActorProxyInterceptor.cs

@ -1,6 +1,5 @@
using Dapr.Actors; using Dapr.Actors;
using Dapr.Actors.Client; using Dapr.Actors.Client;
using LINGYUN.Abp.Dapr.Actors.Authentication;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -8,13 +7,14 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy; using Volo.Abp.DynamicProxy;
using Volo.Abp.Http; using Volo.Abp.Http;
using Volo.Abp.Http.Client.Authentication;
using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
@ -24,22 +24,24 @@ namespace LINGYUN.Abp.Dapr.Actors.DynamicProxying
where TService: IActor where TService: IActor
{ {
protected ICurrentTenant CurrentTenant { get; } protected ICurrentTenant CurrentTenant { get; }
protected AbpDaprActorOptions DaprActorOptions { get; } protected AbpDaprRemoteServiceOptions DaprServiceOptions { get; }
protected AbpDaprActorProxyOptions DaprActorProxyOptions { get; } protected AbpDaprActorProxyOptions DaprActorProxyOptions { get; }
protected IDaprActorProxyAuthenticator ActoryProxyAuthenticator { get; } protected IDynamicProxyHttpClientFactory HttpClientFactory { get; }
protected IRemoteServiceHttpClientAuthenticator ClientAuthenticator { get; }
public ILogger<DynamicDaprActorProxyInterceptor<TService>> Logger { get; set; } public ILogger<DynamicDaprActorProxyInterceptor<TService>> Logger { get; set; }
public DynamicDaprActorProxyInterceptor( public DynamicDaprActorProxyInterceptor(
IOptions<AbpDaprActorProxyOptions> daprActorProxyOptions, IOptions<AbpDaprActorProxyOptions> daprActorProxyOptions,
IOptionsSnapshot<AbpDaprActorOptions> daprActorOptions, IOptionsSnapshot<AbpDaprRemoteServiceOptions> daprActorOptions,
IDaprActorProxyAuthenticator actorProxyAuthenticator, IDynamicProxyHttpClientFactory httpClientFactory,
IRemoteServiceHttpClientAuthenticator clientAuthenticator,
ICurrentTenant currentTenant) ICurrentTenant currentTenant)
{ {
CurrentTenant = currentTenant; CurrentTenant = currentTenant;
ActoryProxyAuthenticator = actorProxyAuthenticator; HttpClientFactory = httpClientFactory;
ClientAuthenticator = clientAuthenticator;
DaprActorProxyOptions = daprActorProxyOptions.Value; DaprActorProxyOptions = daprActorProxyOptions.Value;
DaprActorOptions = daprActorOptions.Value; DaprServiceOptions = daprActorOptions.Value;
Logger = NullLogger<DynamicDaprActorProxyInterceptor<TService>>.Instance; Logger = NullLogger<DynamicDaprActorProxyInterceptor<TService>>.Instance;
} }
@ -66,7 +68,13 @@ namespace LINGYUN.Abp.Dapr.Actors.DynamicProxying
{ {
// 获取Actor配置 // 获取Actor配置
var actorProxyConfig = DaprActorProxyOptions.ActorProxies.GetOrDefault(typeof(TService)) ?? throw new AbpException($"Could not get DynamicDaprActorProxyConfig for {typeof(TService).FullName}."); 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 remoteServiceConfig = DaprServiceOptions.RemoteServices.GetConfigurationOrDefault(actorProxyConfig.RemoteServiceName);
// Actors的定义太多, 可以考虑使用默认的 BaseUrl 作为远程地址
if (remoteServiceConfig.BaseUrl.IsNullOrWhiteSpace())
{
throw new AbpException($"Could not get BaseUrl for {actorProxyConfig.RemoteServiceName} Or Default.");
}
var actorProxyOptions = new ActorProxyOptions var actorProxyOptions = new ActorProxyOptions
{ {
@ -78,34 +86,47 @@ namespace LINGYUN.Abp.Dapr.Actors.DynamicProxying
// TODO: Actor一次只能处理一个请求,使用状态管理来传递状态的可行性? // TODO: Actor一次只能处理一个请求,使用状态管理来传递状态的可行性?
var httpClientHandler = new DaprHttpClientHandler(); var httpClientHandler = new DaprHttpClientHandler();
// 身份认证处理
await ActoryProxyAuthenticator.AuthenticateAsync(
new DaprActorProxyAuthenticateContext(
httpClientHandler, remoteServiceConfig, actorProxyConfig.RemoteServiceName));
AddHeaders(httpClientHandler); AddHeaders(httpClientHandler);
httpClientHandler.PreConfigure(async (requestMessage) =>
{
// 占位
var httpClient = HttpClientFactory.Create(AbpDaprActorsModule.DaprHttpClient);
await ClientAuthenticator.Authenticate(
new RemoteServiceHttpClientAuthenticateContext(
httpClient,
requestMessage,
remoteServiceConfig,
actorProxyConfig.RemoteServiceName));
// 标头
if (requestMessage.Headers.Authorization == null &&
httpClient.DefaultRequestHeaders.Authorization != null)
{
requestMessage.Headers.Authorization = httpClient.DefaultRequestHeaders.Authorization;
}
});
// 代理工厂 // 代理工厂
var proxyFactory = new ActorProxyFactory(actorProxyOptions, (HttpMessageHandler)httpClientHandler); var proxyFactory = new ActorProxyFactory(actorProxyOptions, (HttpMessageHandler)httpClientHandler);
await MakeRequestAsync(invocation, proxyFactory, remoteServiceConfig); await MakeRequestAsync(invocation, proxyFactory);
} }
private async Task MakeRequestAsync( private async Task MakeRequestAsync(
IAbpMethodInvocation invocation, IAbpMethodInvocation invocation,
ActorProxyFactory proxyFactory, ActorProxyFactory proxyFactory
DaprActorConfiguration configuration
) )
{ {
var actorId = new ActorId(configuration.ActorId);
var invokeType = typeof(TService); var invokeType = typeof(TService);
// 约定的 RemoteServiceAttribute 为Actor名称 // 约定的 RemoteServiceAttribute 为Actor名称
var remoteServiceAttr = invokeType.GetTypeInfo().GetCustomAttribute<RemoteServiceAttribute>(); var remoteServiceAttr = invokeType.GetTypeInfo().GetCustomAttribute<RemoteServiceAttribute>();
var actorType = remoteServiceAttr != null var actorType = remoteServiceAttr != null
? remoteServiceAttr.Name ? remoteServiceAttr.Name
: invokeType.Name; : invokeType.Name;
var actorId = new ActorId(invokeType.FullName);
try try
{ {
@ -155,7 +176,7 @@ namespace LINGYUN.Abp.Dapr.Actors.DynamicProxying
var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name; var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name;
if (!currentCulture.IsNullOrEmpty()) if (!currentCulture.IsNullOrEmpty())
{ {
handler.PreConfigure(request => request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(currentCulture))); handler.AcceptLanguage(currentCulture);
} }
} }
} }

7
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicDaprActorProxyExtensions.cs

@ -8,6 +8,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Castle.DynamicProxy; using Volo.Abp.Castle.DynamicProxy;
using Volo.Abp.Http.Client;
using Volo.Abp.Validation; using Volo.Abp.Validation;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
@ -19,7 +20,7 @@ namespace Microsoft.Extensions.DependencyInjection
public static IServiceCollection AddDaprActorProxies( public static IServiceCollection AddDaprActorProxies(
[NotNull] this IServiceCollection services, [NotNull] this IServiceCollection services,
[NotNull] Assembly assembly, [NotNull] Assembly assembly,
[NotNull] string remoteServiceConfigurationName = DaprActorConfigurationDictionary.DefaultName, [NotNull] string remoteServiceConfigurationName = RemoteServiceConfigurationDictionary.DefaultName,
bool asDefaultServices = true) bool asDefaultServices = true)
{ {
Check.NotNull(services, nameof(assembly)); Check.NotNull(services, nameof(assembly));
@ -40,7 +41,7 @@ namespace Microsoft.Extensions.DependencyInjection
public static IServiceCollection AddDaprActorProxy<T>( public static IServiceCollection AddDaprActorProxy<T>(
[NotNull] this IServiceCollection services, [NotNull] this IServiceCollection services,
[NotNull] string remoteServiceConfigurationName = DaprActorConfigurationDictionary.DefaultName, [NotNull] string remoteServiceConfigurationName = RemoteServiceConfigurationDictionary.DefaultName,
bool asDefaultService = true) bool asDefaultService = true)
{ {
return services.AddDaprActorProxy( return services.AddDaprActorProxy(
@ -53,7 +54,7 @@ namespace Microsoft.Extensions.DependencyInjection
public static IServiceCollection AddDaprActorProxy( public static IServiceCollection AddDaprActorProxy(
[NotNull] this IServiceCollection services, [NotNull] this IServiceCollection services,
[NotNull] Type type, [NotNull] Type type,
[NotNull] string remoteServiceConfigurationName = DaprActorConfigurationDictionary.DefaultName, [NotNull] string remoteServiceConfigurationName = RemoteServiceConfigurationDictionary.DefaultName,
bool asDefaultService = true) bool asDefaultService = true)
{ {
Check.NotNull(services, nameof(services)); Check.NotNull(services, nameof(services));

6
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/AbpDaprClientModule.cs

@ -1,18 +1,18 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Http.Client; using Volo.Abp.Http.Client;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Dapr.Client namespace LINGYUN.Abp.Dapr.Client
{ {
[DependsOn( [DependsOn(
typeof(AbpHttpClientModule))] typeof(AbpHttpClientModule)
)]
public class AbpDaprClientModule : AbpModule public class AbpDaprClientModule : AbpModule
{ {
/// <summary> /// <summary>
/// 与AbpHttpClient集成,创建一个命名HttpClient /// 与AbpHttpClient集成,创建一个命名HttpClient
/// </summary> /// </summary>
internal const string DaprHttpClient = "_AbpDaprClient"; internal const string DaprHttpClient = "_AbpDaprProxyClient";
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {

4
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Client/LINGYUN/Abp/Dapr/Client/DynamicProxying/DynamicDaprClientProxyInterceptor.cs

@ -172,9 +172,7 @@ namespace LINGYUN.Abp.Dapr.Client.DynamicProxying
new RemoteServiceHttpClientAuthenticateContext( new RemoteServiceHttpClientAuthenticateContext(
httpClient, httpClient,
requestMessage, requestMessage,
new RemoteServiceConfiguration( remoteServiceConfig,
remoteServiceConfig.BaseUrl,
remoteServiceConfig.Version),
clientConfig.RemoteServiceName clientConfig.RemoteServiceName
) )
); );

7
aspnet-core/modules/dapr/README.md

@ -75,9 +75,8 @@ dapr run --app-id myapp --app-port 5000 -H 50000 -G 40001 -- dotnet run
```json ```json
{ {
"RemoteActors": { "RemoteServices": {
"System": { "Shop": {
"ActorId": "1",
"BaseUrl": "http://127.0.0.1:50000" "BaseUrl": "http://127.0.0.1:50000"
} }
} }
@ -99,7 +98,7 @@ public class SystemActorClientModule : AbpModule
// 注册代理类似于 Volo.Abp.Http.Client 模块 // 注册代理类似于 Volo.Abp.Http.Client 模块
context.Services.AddDaprActorProxies( context.Services.AddDaprActorProxies(
typeof(SystemActorInterfaceModule).Assembly, // 搜索 SystemActorInterfaceModule 模块下的IActor定义 typeof(SystemActorInterfaceModule).Assembly, // 搜索 SystemActorInterfaceModule 模块下的IActor定义
RemoteServiceName "Shop"
); );
} }
} }

34
aspnet-core/tests/LINGYUN.Abp.Dapr.Actors.Tests/LINGYUN.Abp.Dapr.Actors.Tests.csproj

@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace />
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\modules\dapr\LINGYUN.Abp.Dapr.Actors\LINGYUN.Abp.Dapr.Actors.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.Dapr.Tests\LINGYUN.Abp.Dapr.Tests.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.Development.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

34
aspnet-core/tests/LINGYUN.Abp.Dapr.Actors.Tests/LINGYUN/Abp/Dapr/Actors/Tests/AbpDaprActorsTestBase.cs

@ -0,0 +1,34 @@
using LINGYUN.Abp.Tests;
using Microsoft.Extensions.DependencyInjection;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace LINGYUN.Abp.Dapr.Actors.Tests
{
public class AbpDaprActorsTestBase : AbpTestsBase<AbpDaprActorsTestModule>
{
// private Process _hostProcess;
//protected override void BeforeAddApplication(IServiceCollection services)
//{
// // TODO: 运行测试前先启动宿主进程 dapr run --app-id testdapr --app-port 5000 -H 10000 -- dotnet run --no-build
// var workingDirectory = Path.Combine(Directory.GetCurrentDirectory(), "../../../../LINGYUN.Abp.Dapr.AspNetCore.TestHost");
// _hostProcess = Process.Start(new ProcessStartInfo
// {
// WorkingDirectory = workingDirectory,
// FileName = "powershell",
// Arguments = "dapr run --app-id testdapr --app-port 5000 -H 10000 -- dotnet run --no-build",
// UseShellExecute = true
// });
// // 等待.NET进程启动完毕
// Thread.Sleep(15000);
//}
//public override void Dispose()
//{
// _hostProcess?.CloseMainWindow();
//}
}
}

33
aspnet-core/tests/LINGYUN.Abp.Dapr.Actors.Tests/LINGYUN/Abp/Dapr/Actors/Tests/AbpDaprActorsTestModule.cs

@ -0,0 +1,33 @@
using LINGYUN.Abp.Tests;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.IO;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Dapr.Actors.Tests
{
[DependsOn(
typeof(AbpDaprTestModule),
typeof(AbpTestsBaseModule),
typeof(AbpDaprActorsModule))]
public class AbpDaprActorsTestModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.ReplaceConfiguration(
ConfigurationHelper.BuildConfiguration(
new AbpConfigurationBuilderOptions
{
EnvironmentName = "Development",
BasePath = Directory.GetCurrentDirectory()
}));
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddDaprActorProxies(
typeof(AbpDaprTestModule).Assembly,
"TestDapr");
}
}
}

39
aspnet-core/tests/LINGYUN.Abp.Dapr.Actors.Tests/LINGYUN/Abp/Dapr/Actors/Tests/TestActorsTests.cs

@ -0,0 +1,39 @@
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using System.Threading.Tasks;
using Xunit;
namespace LINGYUN.Abp.Dapr.Actors.Tests
{
public class TestAppServiceTests : AbpDaprActorsTestBase
{
private readonly ITestActor _actor;
public TestAppServiceTests()
{
_actor = GetRequiredService<ITestActor>();
}
[Fact]
public async Task Get_Result_Items_Count_Should_5()
{
var result = await _actor.GetAsync();
result.Count.ShouldBe(5);
}
[Fact]
public async Task Update_Result_Value_Should_Value_Updated_1()
{
var result = await _actor.UpdateAsync();
result.Value.ShouldBe("value:updated:1");
}
public override void Dispose()
{
_ = _actor.ClearAsync();
base.Dispose();
}
}
}

4
aspnet-core/tests/LINGYUN.Abp.Dapr.AspNetCore.TestHost/LINGYUN/Abp/Dapr/Actors/TestActor.cs

@ -13,11 +13,11 @@ namespace LINGYUN.Abp.Dapr.Actors
{ {
} }
public async Task<ListResultDto<NameValue>> GetAsync() public async Task<List<NameValue>> GetAsync()
{ {
var values = await GetValuesByStateAsync(); var values = await GetValuesByStateAsync();
return new ListResultDto<NameValue>(values); return values;
} }
public async Task<NameValue> UpdateAsync() public async Task<NameValue> UpdateAsync()

4
aspnet-core/tests/LINGYUN.Abp.Dapr.Tests/LINGYUN/Abp/Dapr/Actors/ITestActor.cs

@ -1,14 +1,14 @@
using Dapr.Actors; using Dapr.Actors;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Application.Dtos;
namespace LINGYUN.Abp.Dapr.Actors namespace LINGYUN.Abp.Dapr.Actors
{ {
[RemoteService(Name = "Test")] [RemoteService(Name = "Test")]
public interface ITestActor : IActor public interface ITestActor : IActor
{ {
Task<ListResultDto<NameValue>> GetAsync(); Task<List<NameValue>> GetAsync();
Task<NameValue> UpdateAsync(); Task<NameValue> UpdateAsync();

17
aspnet-core/tests/LINGYUN.Abp.Dapr.Tests/LINGYUN/Abp/Dapr/NameValue.cs

@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace LINGYUN.Abp.Dapr
{
[System.Serializable]
public class NameValue
{
public string Key { get; set; }
public string Value { get; set; }
public NameValue() { }
public NameValue(string key, string value)
{
Key = key;
Value = value;
}
}
}
Loading…
Cancel
Save