Browse Source

feat(docs): 添加Dapr模块文档

pull/1049/head
feijie 1 year ago
parent
commit
984310f316
  1. 181
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors.AspNetCore.Wrapper/README.EN.md
  2. 181
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors.AspNetCore.Wrapper/README.md
  3. 123
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors.AspNetCore/README.EN.md
  4. 110
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors.AspNetCore/README.md
  5. 129
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors/README.EN.md
  6. 111
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors/README.md
  7. 189
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Client.Wrapper/README.EN.md
  8. 175
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Client.Wrapper/README.md
  9. 277
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Client/README.EN.md
  10. 264
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Client/README.md
  11. 204
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr/README.EN.md
  12. 184
      aspnet-core/framework/dapr/LINGYUN.Abp.Dapr/README.md
  13. 256
      aspnet-core/framework/dapr/LINGYUN.Abp.DistributedLocking.Dapr/README.EN.md
  14. 250
      aspnet-core/framework/dapr/LINGYUN.Abp.DistributedLocking.Dapr/README.md

181
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors.AspNetCore.Wrapper/README.EN.md

@ -0,0 +1,181 @@
# LINGYUN.Abp.Dapr.Actors.AspNetCore.Wrapper
Dapr Actors ASP.NET Core wrapper module for handling Actor method call response wrapping and unwrapping.
## Features
* Automatic Actor response result wrapping/unwrapping
* Integration with ABP's wrapper system
* Error handling for Actor method calls
* Support for success/error code configuration
* Integration with Dapr.Actors.AspNetCore
* Support for custom response wrapper format
* Flexible wrapping control options
## Basic Usage
Module reference as needed:
```csharp
[DependsOn(
typeof(AbpDaprActorsAspNetCoreModule),
typeof(AbpWrapperModule)
)]
public class YouProjectModule : AbpModule
{
}
```
## Configuration Options
The module uses `AbpWrapperOptions` from the `LINGYUN.Abp.Wrapper` package for configuration:
```json
{
"Wrapper": {
"IsEnabled": true, // Enable/disable response wrapping
"CodeWithSuccess": "0", // Success code in wrapped response
"HttpStatusCode": 200, // Default HTTP status code for wrapped responses
"WrapOnError": true, // Whether to wrap error responses
"WrapOnSuccess": true // Whether to wrap success responses
}
}
```
## Implementation Example
1. Actor Interface Definition
```csharp
public interface ICounterActor : IActor
{
Task<int> GetCountAsync();
Task IncrementCountAsync();
}
```
2. Actor Implementation
```csharp
public class CounterActor : Actor, ICounterActor
{
private const string CountStateName = "count";
public CounterActor(ActorHost host) : base(host)
{
}
public async Task<int> GetCountAsync()
{
var count = await StateManager.TryGetStateAsync<int>(CountStateName);
return count.HasValue ? count.Value : 0;
}
public async Task IncrementCountAsync()
{
var currentCount = await GetCountAsync();
await StateManager.SetStateAsync(CountStateName, currentCount + 1);
}
}
```
## Response Format
When wrapping is enabled, Actor method responses will be in the following format:
```json
{
"code": "0", // Response code, "0" indicates success by default
"message": "Success", // Response message
"details": null, // Additional details (optional)
"result": { // Actual response data
// ... Actor method return value
}
}
```
## Error Handling
The module automatically handles Actor method call errors:
* For wrapped responses:
* Unwraps the response and checks the code
* If code doesn't match `CodeWithSuccess`, throws `AbpRemoteCallException`
* Includes error message, details, and code in the exception
* Supports custom error code mapping
* For Actor runtime errors:
* Automatically wraps as standard error response
* Preserves original exception information
* Includes Actor-related context information
### Error Response Example
```json
{
"code": "ERROR_001",
"message": "Actor method call failed",
"details": "Failed to access state for actor 'counter'",
"result": null
}
```
## Advanced Usage
### 1. Controlling Response Wrapping
Response wrapping can be controlled per Actor call using HTTP headers:
```csharp
// Add to request headers
var headers = new Dictionary<string, string>
{
{ "X-Abp-Wrap-Result", "true" }, // Force enable wrapping
// or
{ "X-Abp-Dont-Wrap-Result", "true" } // Force disable wrapping
};
// Use in Actor method
public async Task<int> GetCountAsync()
{
var context = ActorContext.GetContext();
context.Headers.Add("X-Abp-Wrap-Result", "true");
var count = await StateManager.TryGetStateAsync<int>(CountStateName);
return count.HasValue ? count.Value : 0;
}
```
### 2. Custom Error Handling
```csharp
public class CustomActorErrorHandler : IAbpWrapperErrorHandler
{
public Task HandleAsync(AbpWrapperErrorContext context)
{
if (context.Exception is ActorMethodInvocationException actorException)
{
// Custom Actor error handling logic
context.Response = new WrapperResponse
{
Code = "ACTOR_ERROR",
Message = actorException.Message,
Details = actorException.ActorId
};
}
return Task.CompletedTask;
}
}
```
## Important Notes
* Response wrapping can be controlled through:
* Global settings in configuration
* HTTP headers for individual requests
* Dynamic control in Actor methods
* Error responses maintain original error structure for Actor methods
* The module integrates with ABP's remote service error handling system
* Recommended to use response wrapping consistently in microservices architecture
* Wrapper format can be customized by implementing `IAbpWrapperResponseBuilder`
* Actor state operation errors are properly wrapped and handled
[查看中文](README.md)

181
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors.AspNetCore.Wrapper/README.md

@ -0,0 +1,181 @@
# LINGYUN.Abp.Dapr.Actors.AspNetCore.Wrapper
Dapr Actors ASP.NET Core响应包装模块,用于处理Actor方法调用的响应包装和解包。
## 功能特性
* Actor响应结果自动包装/解包
* 与ABP包装系统集成
* 支持Actor方法调用的错误处理
* 支持成功/错误代码配置
* 与Dapr.Actors.AspNetCore集成
* 支持自定义响应包装格式
* 灵活的包装控制选项
## 配置使用
模块按需引用:
```csharp
[DependsOn(
typeof(AbpDaprActorsAspNetCoreModule),
typeof(AbpWrapperModule)
)]
public class YouProjectModule : AbpModule
{
}
```
## 配置选项
模块使用来自`LINGYUN.Abp.Wrapper`包的`AbpWrapperOptions`进行配置:
```json
{
"Wrapper": {
"IsEnabled": true, // 启用/禁用响应包装
"CodeWithSuccess": "0", // 包装响应中的成功代码
"HttpStatusCode": 200, // 包装响应的默认HTTP状态码
"WrapOnError": true, // 是否包装错误响应
"WrapOnSuccess": true // 是否包装成功响应
}
}
```
## 实现示例
1. Actor接口定义
```csharp
public interface ICounterActor : IActor
{
Task<int> GetCountAsync();
Task IncrementCountAsync();
}
```
2. Actor实现
```csharp
public class CounterActor : Actor, ICounterActor
{
private const string CountStateName = "count";
public CounterActor(ActorHost host) : base(host)
{
}
public async Task<int> GetCountAsync()
{
var count = await StateManager.TryGetStateAsync<int>(CountStateName);
return count.HasValue ? count.Value : 0;
}
public async Task IncrementCountAsync()
{
var currentCount = await GetCountAsync();
await StateManager.SetStateAsync(CountStateName, currentCount + 1);
}
}
```
## 响应格式
当启用包装时,Actor方法的响应将采用以下格式:
```json
{
"code": "0", // 响应代码,默认"0"表示成功
"message": "Success", // 响应消息
"details": null, // 附加详情(可选)
"result": { // 实际响应数据
// ... Actor方法的返回值
}
}
```
## 错误处理
模块自动处理Actor方法调用的错误:
* 对于包装的响应:
* 解包响应并检查代码
* 如果代码与`CodeWithSuccess`不匹配,抛出`AbpRemoteCallException`
* 在异常中包含错误消息、详情和代码
* 支持自定义错误代码映射
* 对于Actor运行时错误:
* 自动包装为标准错误响应
* 保留原始异常信息
* 包含Actor相关的上下文信息
### 错误响应示例
```json
{
"code": "ERROR_001",
"message": "Actor方法调用失败",
"details": "Actor 'counter' 的状态访问失败",
"result": null
}
```
## 高级用法
### 1. 控制响应包装
可以通过HTTP头控制单个Actor调用的响应包装:
```csharp
// 在请求头中添加
var headers = new Dictionary<string, string>
{
{ "X-Abp-Wrap-Result", "true" }, // 强制启用包装
// 或
{ "X-Abp-Dont-Wrap-Result", "true" } // 强制禁用包装
};
// 在Actor方法中使用
public async Task<int> GetCountAsync()
{
var context = ActorContext.GetContext();
context.Headers.Add("X-Abp-Wrap-Result", "true");
var count = await StateManager.TryGetStateAsync<int>(CountStateName);
return count.HasValue ? count.Value : 0;
}
```
### 2. 自定义错误处理
```csharp
public class CustomActorErrorHandler : IAbpWrapperErrorHandler
{
public Task HandleAsync(AbpWrapperErrorContext context)
{
if (context.Exception is ActorMethodInvocationException actorException)
{
// 自定义Actor错误处理逻辑
context.Response = new WrapperResponse
{
Code = "ACTOR_ERROR",
Message = actorException.Message,
Details = actorException.ActorId
};
}
return Task.CompletedTask;
}
}
```
## 注意事项
* 响应包装可以通过以下方式控制:
* 配置文件中的全局设置
* HTTP头控制单个请求
* Actor方法中的动态控制
* Actor方法的错误响应会保持原始错误结构
* 模块与ABP的远程服务错误处理系统集成
* 建议在微服务架构中统一使用响应包装
* 包装格式可以通过继承`IAbpWrapperResponseBuilder`自定义
* Actor状态操作的错误会被正确包装和处理
[查看英文](README.EN.md)

123
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors.AspNetCore/README.EN.md

@ -0,0 +1,123 @@
# LINGYUN.Abp.Dapr.Actors.AspNetCore
Integration of Dapr.Actors with ASP.NET Core in the ABP framework. This module automatically scans and registers Actor services defined within assemblies as Dapr.Actors.
## Features
* Automatic Actor service registration
* Integration with ABP's dependency injection system
* Support for custom Actor type names through `RemoteServiceAttribute`
* Actor runtime configuration through `ActorRuntimeOptions`
* Automatic Actor endpoint mapping
* Actor interface validation
## Basic Usage
Module reference as needed:
```csharp
[DependsOn(typeof(AbpDaprActorsAspNetCoreModule))]
public class YourProjectModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
// Configure Actor runtime options
PreConfigure<ActorRuntimeOptions>(options =>
{
options.ActorIdleTimeout = TimeSpan.FromMinutes(60);
options.ActorScanInterval = TimeSpan.FromSeconds(30);
options.DrainOngoingCallTimeout = TimeSpan.FromSeconds(30);
options.DrainRebalancedActors = true;
options.RemindersStoragePartitions = 7;
});
}
}
```
## Implementation Example
1. Define Actor Interface
```csharp
[RemoteService("counter")] // Optional: customize Actor type name
public interface ICounterActor : IActor
{
Task<int> GetCountAsync();
Task IncrementCountAsync();
}
```
2. Implement Actor
```csharp
public class CounterActor : Actor, ICounterActor
{
private const string CountStateName = "count";
public CounterActor(ActorHost host) : base(host)
{
}
public async Task<int> GetCountAsync()
{
var count = await StateManager.TryGetStateAsync<int>(CountStateName);
return count.HasValue ? count.Value : 0;
}
public async Task IncrementCountAsync()
{
var currentCount = await GetCountAsync();
await StateManager.SetStateAsync(CountStateName, currentCount + 1);
}
}
```
The module will automatically:
1. Detect the `CounterActor` implementation
2. Register it with Dapr.Actors
3. Configure the Actor runtime
4. Map the Actor endpoints
## Actor Runtime Configuration
The module supports all standard Dapr Actor runtime configurations through `ActorRuntimeOptions`:
```csharp
PreConfigure<ActorRuntimeOptions>(options =>
{
// Actor timeout settings
options.ActorIdleTimeout = TimeSpan.FromMinutes(60);
options.ActorScanInterval = TimeSpan.FromSeconds(30);
// Draining settings
options.DrainOngoingCallTimeout = TimeSpan.FromSeconds(30);
options.DrainRebalancedActors = true;
// Reminders settings
options.RemindersStoragePartitions = 7;
// Custom serialization settings
options.JsonSerializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
});
```
## Important Notes
* Actor implementations must be registered in the dependency injection container
* Actor interfaces must inherit from `IActor`
* Actor type names can be customized using the `RemoteServiceAttribute`
* The module automatically maps Actor endpoints using ABP's endpoint routing system
* Actor runtime options should be configured in the `PreConfigureServices` phase
## Endpoint Mapping
The module automatically maps the following Actor endpoints:
* `/dapr/actors/{actorType}/{actorId}/method/{methodName}`
* `/dapr/actors/{actorType}/{actorId}/state`
* `/dapr/actors/{actorType}/{actorId}/reminders/{reminderName}`
* `/dapr/actors/{actorType}/{actorId}/timers/{timerName}`
[查看中文](README.md)

110
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors.AspNetCore/README.md

@ -2,6 +2,15 @@
Dapr.Asp.NetCore的Abp框架集成,扫描程序集内部实现的Actor服务列表,批量注册为Dapr.Actors
## 功能特性
* 自动Actor服务注册
* 与ABP依赖注入系统集成
* 通过`RemoteServiceAttribute`支持自定义Actor类型名称
* 通过`ActorRuntimeOptions`配置Actor运行时
* 自动Actor端点映射
* Actor接口验证
## 配置使用
模块按需引用
@ -10,10 +19,105 @@ Dapr.Asp.NetCore的Abp框架集成,扫描程序集内部实现的Actor服务列
[DependsOn(typeof(AbpDaprActorsAspNetCoreModule))]
public class YouProjectModule : AbpModule
{
// other
public override void PreConfigureServices(ServiceConfigurationContext context)
{
// 配置Actor运行时选项
PreConfigure<ActorRuntimeOptions>(options =>
{
options.ActorIdleTimeout = TimeSpan.FromMinutes(60);
options.ActorScanInterval = TimeSpan.FromSeconds(30);
options.DrainOngoingCallTimeout = TimeSpan.FromSeconds(30);
options.DrainRebalancedActors = true;
options.RemindersStoragePartitions = 7;
});
}
}
```
## 实现示例
1. 定义Actor接口
```csharp
[RemoteService("counter")] // 可选:自定义Actor类型名称
public interface ICounterActor : IActor
{
Task<int> GetCountAsync();
Task IncrementCountAsync();
}
```
## 配置项说明
2. 实现Actor
```csharp
public class CounterActor : Actor, ICounterActor
{
private const string CountStateName = "count";
public CounterActor(ActorHost host) : base(host)
{
}
public async Task<int> GetCountAsync()
{
var count = await StateManager.TryGetStateAsync<int>(CountStateName);
return count.HasValue ? count.Value : 0;
}
public async Task IncrementCountAsync()
{
var currentCount = await GetCountAsync();
await StateManager.SetStateAsync(CountStateName, currentCount + 1);
}
}
```
模块将自动:
1. 检测`CounterActor`实现
2. 将其注册到Dapr.Actors
3. 配置Actor运行时
4. 映射Actor端点
## Actor运行时配置
模块通过`ActorRuntimeOptions`支持所有标准的Dapr Actor运行时配置:
```csharp
PreConfigure<ActorRuntimeOptions>(options =>
{
// Actor超时设置
options.ActorIdleTimeout = TimeSpan.FromMinutes(60);
options.ActorScanInterval = TimeSpan.FromSeconds(30);
// 清理设置
options.DrainOngoingCallTimeout = TimeSpan.FromSeconds(30);
options.DrainRebalancedActors = true;
// 提醒器设置
options.RemindersStoragePartitions = 7;
// 自定义序列化设置
options.JsonSerializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
});
```
## 重要说明
* Actor实现必须在依赖注入容器中注册
* Actor接口必须继承自`IActor`
* Actor类型名称可以使用`RemoteServiceAttribute`自定义
* 模块使用ABP的端点路由系统自动映射Actor端点
* Actor运行时选项应在`PreConfigureServices`阶段配置
## 端点映射
模块自动映射以下Actor端点:
* `/dapr/actors/{actorType}/{actorId}/method/{methodName}`
* `/dapr/actors/{actorType}/{actorId}/state`
* `/dapr/actors/{actorType}/{actorId}/reminders/{reminderName}`
* `/dapr/actors/{actorType}/{actorId}/timers/{timerName}`
## 其他
[View English](README.EN.md)

129
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors/README.EN.md

@ -0,0 +1,129 @@
# LINGYUN.Abp.Dapr.Actors
Dapr.IActor client proxy module
## Features
* Dynamic proxy generation for Dapr Actors
* Integration with ABP's remote service system
* Support for Actor authentication and authorization
* Multi-tenant support
* Automatic request/response handling
* Custom error handling
* Culture and language header support
## Basic Usage
Module reference as needed:
```csharp
[DependsOn(typeof(AbpDaprActorsModule))]
public class YouProjectModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Register proxies similar to Volo.Abp.Http.Client module
context.Services.AddDaprActorProxies(
typeof(YouProjectActorInterfaceModule).Assembly, // Search for IActor definitions in YouProjectActorInterfaceModule
RemoteServiceName
);
}
}
```
## Configuration Options
```json
{
"RemoteServices": {
"Default": {
"BaseUrl": "http://localhost:3500", // Required, Dapr HTTP endpoint
"DaprApiToken": "your-api-token", // Optional, Dapr API Token
"RequestTimeout": "30000" // Optional, request timeout in milliseconds (default: 30000)
}
}
}
```
## Implementation Example
1. Actor Interface Definition
```csharp
public interface ICounterActor : IActor
{
Task<int> GetCountAsync();
Task IncrementCountAsync();
}
```
2. Actor Implementation
```csharp
public class CounterActor : Actor, ICounterActor
{
private const string CountStateName = "count";
public CounterActor(ActorHost host) : base(host)
{
}
public async Task<int> GetCountAsync()
{
var count = await StateManager.TryGetStateAsync<int>(CountStateName);
return count.HasValue ? count.Value : 0;
}
public async Task IncrementCountAsync()
{
var currentCount = await GetCountAsync();
await StateManager.SetStateAsync(CountStateName, currentCount + 1);
}
}
```
3. Client Usage
```csharp
public class CounterService
{
private readonly ICounterActor _counterActor;
public CounterService(ICounterActor counterActor)
{
_counterActor = counterActor;
}
public async Task<int> GetAndIncrementCountAsync()
{
var count = await _counterActor.GetCountAsync();
await _counterActor.IncrementCountAsync();
return count;
}
}
```
## Important Notes
* Actor methods must return `Task` or `Task<T>`
* Actor methods can have at most one parameter
* Actor instances are single-threaded, processing one request at a time
* Actor state is managed by the Dapr runtime
* The module automatically handles:
* Authentication headers
* Tenant context
* Culture information
* Request timeouts
* Error handling
## Error Handling
The module provides custom error handling for Actor calls:
* `AbpDaprActorCallException`: Thrown when an Actor method call fails
* `ActorMethodInvocationException`: Contains detailed information about the failure
* Error responses include:
* Error message
* Error code
* Original exception type
[查看中文](README.md)

111
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Actors/README.md

@ -1,6 +1,16 @@
# LINGYUN.Abp.Dapr.Actors
Dapr.IActor客户端代理
Dapr.IActor客户端代理模块
## 功能特性
* Dapr Actors的动态代理生成
* 与ABP远程服务系统集成
* 支持Actor认证和授权
* 多租户支持
* 自动请求/响应处理
* 自定义错误处理
* 文化和语言标头支持
## 配置使用
@ -10,7 +20,7 @@ Dapr.IActor客户端代理
[DependsOn(typeof(AbpDaprActorsModule))]
public class YouProjectModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
public override void ConfigureServices(ServiceConfigurationContext context)
{
// 注册代理类似于 Volo.Abp.Http.Client 模块
context.Services.AddDaprActorProxies(
@ -20,7 +30,100 @@ public class YouProjectModule : AbpModule
}
}
```
## 配置项说明
## 配置选项
```json
{
"RemoteServices": {
"Default": {
"BaseUrl": "http://localhost:3500", // 必需,Dapr HTTP端点
"DaprApiToken": "your-api-token", // 可选,Dapr API Token
"RequestTimeout": "30000" // 可选,请求超时时间(毫秒,默认:30000)
}
}
}
```
## 实现示例
1. Actor接口定义
```csharp
public interface ICounterActor : IActor
{
Task<int> GetCountAsync();
Task IncrementCountAsync();
}
```
2. Actor实现
```csharp
public class CounterActor : Actor, ICounterActor
{
private const string CountStateName = "count";
public CounterActor(ActorHost host) : base(host)
{
}
public async Task<int> GetCountAsync()
{
var count = await StateManager.TryGetStateAsync<int>(CountStateName);
return count.HasValue ? count.Value : 0;
}
public async Task IncrementCountAsync()
{
var currentCount = await GetCountAsync();
await StateManager.SetStateAsync(CountStateName, currentCount + 1);
}
}
```
3. 客户端使用
```csharp
public class CounterService
{
private readonly ICounterActor _counterActor;
public CounterService(ICounterActor counterActor)
{
_counterActor = counterActor;
}
public async Task<int> GetAndIncrementCountAsync()
{
var count = await _counterActor.GetCountAsync();
await _counterActor.IncrementCountAsync();
return count;
}
}
```
## 注意事项
* Actor方法必须返回`Task`或`Task<T>`
* Actor方法最多只能有一个参数
* Actor实例是单线程的,一次只能处理一个请求
* Actor状态由Dapr运行时管理
* 模块自动处理:
* 认证标头
* 租户上下文
* 文化信息
* 请求超时
* 错误处理
## 错误处理
模块为Actor调用提供自定义错误处理:
* `AbpDaprActorCallException`:当Actor方法调用失败时抛出
* `ActorMethodInvocationException`:包含有关失败的详细信息
* 错误响应包括:
* 错误消息
* 错误代码
* 原始异常类型
## 其他
[查看更多](README.EN.md)

189
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Client.Wrapper/README.EN.md

@ -0,0 +1,189 @@
# LINGYUN.Abp.Dapr.Client.Wrapper
Dapr service-to-service invocation module that handles wrapped response result unpacking.
## Features
* Automatic response result wrapping/unwrapping
* Integration with ABP's wrapper system
* Custom error handling for wrapped responses
* Support for success/error code configuration
* HTTP status code mapping
* Support for custom response wrapper format
* Flexible wrapping control options
## Basic Usage
Module reference as needed:
```csharp
[DependsOn(typeof(AbpDaprClientModule))]
public class AbpDaprClientWrapperModule : AbpModule
{
}
```
## Configuration Options
The module uses `AbpWrapperOptions` from the `LINGYUN.Abp.Wrapper` package for configuration:
```json
{
"Wrapper": {
"IsEnabled": true, // Enable/disable response wrapping
"CodeWithSuccess": "0", // Success code in wrapped response
"HttpStatusCode": 200, // Default HTTP status code for wrapped responses
"WrapOnError": true, // Whether to wrap error responses
"WrapOnSuccess": true // Whether to wrap success responses
}
}
```
## Implementation Example
1. Service Definition
```csharp
public interface IProductService
{
Task<ProductDto> GetAsync(string id);
Task<List<ProductDto>> GetListAsync();
Task<ProductDto> CreateAsync(CreateProductDto input);
}
```
2. Service Implementation
```csharp
public class ProductService : IProductService
{
private readonly DaprClient _daprClient;
public ProductService(DaprClient daprClient)
{
_daprClient = daprClient;
}
public async Task<ProductDto> GetAsync(string id)
{
// Response wrapping is handled automatically
return await _daprClient.InvokeMethodAsync<ProductDto>(
"product-service", // Target service ID
$"api/products/{id}", // Method path
HttpMethod.Get
);
}
public async Task<List<ProductDto>> GetListAsync()
{
return await _daprClient.InvokeMethodAsync<List<ProductDto>>(
"product-service",
"api/products",
HttpMethod.Get
);
}
public async Task<ProductDto> CreateAsync(CreateProductDto input)
{
return await _daprClient.InvokeMethodAsync<ProductDto>(
"product-service",
"api/products",
HttpMethod.Post,
input
);
}
}
```
## Response Format
When wrapping is enabled, the response will be in the following format:
```json
{
"code": "0", // Response code, "0" indicates success by default
"message": "Success", // Response message
"details": null, // Additional details (optional)
"result": { // Actual response data
// ... response content
}
}
```
## Error Handling
The module automatically handles error responses:
* For wrapped responses (with `AbpWrapResult` header):
* Unwraps the response and checks the code
* If code doesn't match `CodeWithSuccess`, throws `AbpRemoteCallException`
* Includes error message, details, and code in the exception
* Supports custom error code mapping
* For unwrapped responses:
* Passes through the original response
* Uses standard HTTP error handling
* Maintains original error information
### Error Response Example
```json
{
"code": "ERROR_001",
"message": "Product not found",
"details": "Product with ID '123' does not exist",
"result": null
}
```
## Advanced Usage
### 1. Controlling Response Wrapping
Response wrapping can be controlled per request using HTTP headers:
```csharp
// Add to request headers
var headers = new Dictionary<string, string>
{
{ "X-Abp-Wrap-Result", "true" }, // Force enable wrapping
// or
{ "X-Abp-Dont-Wrap-Result", "true" } // Force disable wrapping
};
await _daprClient.InvokeMethodAsync<ProductDto>(
"product-service",
"api/products",
HttpMethod.Get,
null,
headers
);
```
### 2. Custom Error Handling
```csharp
public class CustomErrorHandler : IAbpWrapperErrorHandler
{
public Task HandleAsync(AbpWrapperErrorContext context)
{
// Custom error handling logic
if (context.Response.Code == "CUSTOM_ERROR")
{
// Special handling
}
return Task.CompletedTask;
}
}
```
## Important Notes
* Response wrapping can be controlled through:
* Global settings in configuration
* HTTP headers for individual requests
* Dynamic control in code
* Error responses maintain original error structure when possible
* The module integrates with ABP's remote service error handling system
* Recommended to use response wrapping consistently in microservices architecture
* Wrapper format can be customized by implementing `IAbpWrapperResponseBuilder`
[查看中文](README.md)

175
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Client.Wrapper/README.md

@ -2,6 +2,16 @@
Dapr服务间调用,对包装后的响应结果解包
## 功能特性
* 自动响应结果包装/解包
* 与ABP包装系统集成
* 自定义包装响应的错误处理
* 支持成功/错误代码配置
* HTTP状态码映射
* 支持自定义响应包装格式
* 灵活的包装控制选项
## 配置使用
模块按需引用
@ -13,4 +23,167 @@ public class AbpDaprClientWrapperModule : AbpModule
}
```
## 其他
## 配置选项
模块使用来自`LINGYUN.Abp.Wrapper`包的`AbpWrapperOptions`进行配置:
```json
{
"Wrapper": {
"IsEnabled": true, // 启用/禁用响应包装
"CodeWithSuccess": "0", // 包装响应中的成功代码
"HttpStatusCode": 200, // 包装响应的默认HTTP状态码
"WrapOnError": true, // 是否包装错误响应
"WrapOnSuccess": true // 是否包装成功响应
}
}
```
## 实现示例
1. 服务定义
```csharp
public interface IProductService
{
Task<ProductDto> GetAsync(string id);
Task<List<ProductDto>> GetListAsync();
Task<ProductDto> CreateAsync(CreateProductDto input);
}
```
2. 服务实现
```csharp
public class ProductService : IProductService
{
private readonly DaprClient _daprClient;
public ProductService(DaprClient daprClient)
{
_daprClient = daprClient;
}
public async Task<ProductDto> GetAsync(string id)
{
// 调用会自动处理响应包装
return await _daprClient.InvokeMethodAsync<ProductDto>(
"product-service", // 目标服务ID
$"api/products/{id}", // 方法路径
HttpMethod.Get
);
}
public async Task<List<ProductDto>> GetListAsync()
{
return await _daprClient.InvokeMethodAsync<List<ProductDto>>(
"product-service",
"api/products",
HttpMethod.Get
);
}
public async Task<ProductDto> CreateAsync(CreateProductDto input)
{
return await _daprClient.InvokeMethodAsync<ProductDto>(
"product-service",
"api/products",
HttpMethod.Post,
input
);
}
}
```
## 响应格式
当启用包装时,响应将采用以下格式:
```json
{
"code": "0", // 响应代码,默认"0"表示成功
"message": "Success", // 响应消息
"details": null, // 附加详情(可选)
"result": { // 实际响应数据
// ... 响应内容
}
}
```
## 错误处理
模块自动处理错误响应:
* 对于包装的响应(带有`AbpWrapResult`头):
* 解包响应并检查代码
* 如果代码与`CodeWithSuccess`不匹配,抛出`AbpRemoteCallException`
* 在异常中包含错误消息、详情和代码
* 支持自定义错误代码映射
* 对于未包装的响应:
* 传递原始响应
* 使用标准HTTP错误处理
* 保持原始错误信息
### 错误响应示例
```json
{
"code": "ERROR_001",
"message": "产品未找到",
"details": "ID为'123'的产品不存在",
"result": null
}
```
## 高级用法
### 1. 控制响应包装
可以通过HTTP头控制单个请求的响应包装:
```csharp
// 在请求头中添加
var headers = new Dictionary<string, string>
{
{ "X-Abp-Wrap-Result", "true" }, // 强制启用包装
// 或
{ "X-Abp-Dont-Wrap-Result", "true" } // 强制禁用包装
};
await _daprClient.InvokeMethodAsync<ProductDto>(
"product-service",
"api/products",
HttpMethod.Get,
null,
headers
);
```
### 2. 自定义错误处理
```csharp
public class CustomErrorHandler : IAbpWrapperErrorHandler
{
public Task HandleAsync(AbpWrapperErrorContext context)
{
// 自定义错误处理逻辑
if (context.Response.Code == "CUSTOM_ERROR")
{
// 特殊处理
}
return Task.CompletedTask;
}
}
```
## 注意事项
* 响应包装可以通过以下方式控制:
* 配置文件中的全局设置
* HTTP头控制单个请求
* 代码中的动态控制
* 错误响应尽可能保持原始错误结构
* 模块与ABP的远程服务错误处理系统集成
* 建议在微服务架构中统一使用响应包装
* 包装格式可以通过继承`IAbpWrapperResponseBuilder`自定义
[查看英文](README.EN.md)

277
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Client/README.EN.md

@ -0,0 +1,277 @@
[Actors](../README.md) | Dapr.Client Documentation
# LINGYUN.Abp.Dapr.Client
Implements service-to-service invocation as described in the Dapr documentation. The project design is consistent with Volo.Abp.Http.Client and can seamlessly replace Volo.Abp.Http.Client through configuration.
For configuration reference, see [AbpRemoteServiceOptions](https://docs.abp.io/en/abp/latest/API/Dynamic-CSharp-API-Clients#abpremoteserviceoptions)
## Features
* Integration with ABP remote service system
* Dynamic proxy generation
* Service discovery and load balancing
* Custom request and response handling
* Error handling and formatting
* Multiple service endpoint configuration
* Request/response interceptors
* Custom DaprClient behavior support
## Configuration Options
```json
{
"RemoteServices": {
"Default": {
"AppId": "default-app", // Dapr application ID
"BaseUrl": "http://localhost:3500", // Dapr HTTP endpoint
"HealthCheckUrl": "/health", // Health check endpoint
"RequestTimeout": 30000, // Request timeout in milliseconds
"RetryCount": 3, // Number of retry attempts
"RetryWaitTime": 1000 // Retry wait time in milliseconds
},
"System": {
"AppId": "system-app",
"BaseUrl": "http://localhost:50000",
"Headers": { // Custom request headers
"Tenant": "Default",
"Culture": "en-US"
}
}
}
}
```
## Basic Usage
Module reference as needed:
```csharp
[DependsOn(typeof(AbpDaprClientModule))]
public class YourProjectModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Register proxies similar to Volo.Abp.Http.Client module
context.Services.AddDaprClientProxies(
typeof(YourProjectInterfaceModule).Assembly, // Search for remote service definitions
RemoteServiceName
);
// Configure proxy options
Configure<AbpDaprClientProxyOptions>(options =>
{
// Configure request interceptor
options.ProxyRequestActions.Add((appId, request) =>
{
request.Headers.Add("Custom-Header", "Value");
});
// Configure response handling
options.OnResponse(async (response, serviceProvider) =>
{
return await response.Content.ReadAsStringAsync();
});
// Configure error handling
options.OnError(async (response, serviceProvider) =>
{
var error = await response.Content.ReadAsStringAsync();
return new RemoteServiceErrorInfo
{
Code = response.StatusCode.ToString(),
Message = error
};
});
});
}
}
```
## Implementation Example
### 1. Interface Definition
```csharp
// IApplicationService implements IRemoteService
public interface ISystemAppService : IApplicationService
{
Task<string> GetAsync();
Task<SystemDto> CreateAsync(CreateSystemDto input);
Task<List<SystemDto>> GetListAsync();
Task DeleteAsync(string id);
}
public class SystemInterfaceModule : AbpModule
{
}
```
### 2. Server Implementation
```csharp
[DependsOn(
typeof(SystemInterfaceModule),
typeof(AbpAspNetCoreMvcModule)
)]
public class SystemServerModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(SystemServerModule).Assembly);
});
}
}
public class SystemAppService : ApplicationService, ISystemAppService
{
private readonly ISystemRepository _systemRepository;
public SystemAppService(ISystemRepository systemRepository)
{
_systemRepository = systemRepository;
}
public async Task<string> GetAsync()
{
return "System";
}
public async Task<SystemDto> CreateAsync(CreateSystemDto input)
{
var system = await _systemRepository.CreateAsync(
new System
{
Name = input.Name,
Description = input.Description
}
);
return ObjectMapper.Map<System, SystemDto>(system);
}
public async Task<List<SystemDto>> GetListAsync()
{
var systems = await _systemRepository.GetListAsync();
return ObjectMapper.Map<List<System>, List<SystemDto>>(systems);
}
public async Task DeleteAsync(string id)
{
await _systemRepository.DeleteAsync(id);
}
}
```
### 3. Client Usage
```csharp
[DependsOn(typeof(AbpDaprClientModule))]
public class SystemClientModule : AbpModule
{
private const string RemoteServiceName = "System";
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Register proxies
context.Services.AddDaprClientProxies(
typeof(SystemInterfaceModule).Assembly,
RemoteServiceName
);
// Configure retry policy
context.Services.AddDaprClientBuilder(builder =>
{
builder.ConfigureHttpClient((sp, client) =>
{
client.Timeout = TimeSpan.FromSeconds(30);
});
});
}
}
public class SystemService
{
private readonly ISystemAppService _systemAppService;
public SystemService(ISystemAppService systemAppService)
{
_systemAppService = systemAppService;
}
public async Task<List<SystemDto>> GetSystemsAsync()
{
try
{
return await _systemAppService.GetListAsync();
}
catch (AbpRemoteCallException ex)
{
// Handle remote call exception
_logger.LogError(ex, "Failed to get systems");
throw;
}
}
}
```
## Advanced Usage
### 1. Custom Request Handling
```csharp
public class CustomRequestHandler
{
public void Configure(HttpRequestMessage request)
{
request.Headers.Add("Correlation-Id", Guid.NewGuid().ToString());
request.Headers.Add("Client-Version", "1.0.0");
}
}
// Register in module
Configure<AbpDaprClientProxyOptions>(options =>
{
options.ProxyRequestActions.Add((appId, request) =>
{
new CustomRequestHandler().Configure(request);
});
});
```
### 2. Custom Response Handling
```csharp
public class CustomResponseHandler
{
public async Task<string> HandleAsync(HttpResponseMessage response)
{
var content = await response.Content.ReadAsStringAsync();
// Custom response handling logic
return content;
}
}
// Register in module
Configure<AbpDaprClientProxyOptions>(options =>
{
options.OnResponse(async (response, sp) =>
{
return await new CustomResponseHandler().HandleAsync(response);
});
});
```
## Important Notes
* Remote service interfaces must inherit `IRemoteService`
* Configuration changes require recreating proxy instances
* Configure appropriate timeout and retry policies
* Error handling should consider network exceptions and service unavailability
* Enable service discovery in production environments
* Use health checks to ensure service availability
* Request header configuration should consider security and authentication requirements
* Logging is important for problem diagnosis
[查看中文](README.md)

264
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr.Client/README.md

@ -2,72 +2,118 @@
# LINGYUN.Abp.Dapr.Client
实现了Dapr文档中的服务间调用,项目设计与Volo.Abp.Http.Client一致,通过配置文件即可无缝替代Volo.Abp.Http.Client
实现了Dapr文档中的服务间调用,项目设计与Volo.Abp.Http.Client一致,通过配置文件即可无缝替代Volo.Abp.Http.Client。
配置参考 [AbpRemoteServiceOptions](https://docs.abp.io/zh-Hans/abp/latest/API/Dynamic-CSharp-API-Clients#abpremoteserviceoptions)
## 功能特性
* 与ABP远程服务系统集成
* 支持动态代理生成
* 支持服务发现和负载均衡
* 支持自定义请求和响应处理
* 支持错误处理和格式化
* 支持多服务端点配置
* 支持请求/响应拦截器
* 支持自定义DaprClient行为
## 配置选项
```json
{
"RemoteServices": {
"Default": {
"AppId": "default-app", // Dapr应用ID
"BaseUrl": "http://localhost:3500", // Dapr HTTP端点
"HealthCheckUrl": "/health", // 健康检查端点
"RequestTimeout": 30000, // 请求超时时间(毫秒)
"RetryCount": 3, // 重试次数
"RetryWaitTime": 1000 // 重试等待时间(毫秒)
},
"System": {
"AppId": "system-app",
"BaseUrl": "http://localhost:50000",
"Headers": { // 自定义请求头
"Tenant": "Default",
"Culture": "zh-Hans"
}
}
}
}
```
## 配置使用
模块按需引用
模块按需引用
```csharp
[DependsOn(typeof(AbpDaprClientModule))]
public class YouProjectModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
public override void ConfigureServices(ServiceConfigurationContext context)
{
// 注册代理类似于 Volo.Abp.Http.Client 模块
// 注册代理类似于 Volo.Abp.Http.Client 模块
context.Services.AddDaprClientProxies(
typeof(YouProjectInterfaceModule).Assembly, // 搜索 YouProjectInterfaceModule 模块下的远程服务定义
typeof(YouProjectInterfaceModule).Assembly, // 搜索模块下的远程服务定义
RemoteServiceName
);
// 配置代理选项
Configure<AbpDaprClientProxyOptions>(options =>
{
// 配置请求拦截器
options.ProxyRequestActions.Add((appId, request) =>
{
request.Headers.Add("Custom-Header", "Value");
});
// 配置响应处理
options.OnResponse(async (response, serviceProvider) =>
{
return await response.Content.ReadAsStringAsync();
});
// 配置错误处理
options.OnError(async (response, serviceProvider) =>
{
var error = await response.Content.ReadAsStringAsync();
return new RemoteServiceErrorInfo
{
Code = response.StatusCode.ToString(),
Message = error
};
});
});
}
}
```
## 实现示例
### 1、接口定义
```c#
### 1. 接口定义
```csharp
// IApplicationService 实现了 IRemoteService
public interface ISystemAppService : IApplicationService
{
Task<string> GetAsync();
Task<SystemDto> CreateAsync(CreateSystemDto input);
Task<List<SystemDto>> GetListAsync();
Task DeleteAsync(string id);
}
public class SystemInterfaceModule : AbpModule
{
}
```
### 2、服务端
引用 Volo.Abp.AspNetCore.Mvc
* 实现接口
```c#
public class SystemAppService : ApplicationService, ISystemAppService
{
public Task<string> GetAsync()
{
retuen Task.FromResult("System");
}
}
```
* 创建模块
```c#
### 2. 服务端实现
```csharp
[DependsOn(
typeof(SystemInterfaceModule),
typeof(AbpAspNetCoreMvcModule))]
typeof(SystemInterfaceModule),
typeof(AbpAspNetCoreMvcModule)
)]
public class SystemServerModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
@ -79,93 +125,153 @@ public class SystemServerModule : AbpModule
}
}
```
* 发布到Dapr
```shell
# --app-port .net程序映射端口
# -H 对外暴露 http 监听端口
# -G 对外暴露 grpc 监听端口
dapr run --app-id myapp --app-port 5000 -H 50000 -G 40001 -- dotnet run
```
public class SystemAppService : ApplicationService, ISystemAppService
{
private readonly ISystemRepository _systemRepository;
### 3、客户端
public SystemAppService(ISystemRepository systemRepository)
{
_systemRepository = systemRepository;
}
引用 LINGYUN.Abp.Dapr.Client
public async Task<string> GetAsync()
{
return "System";
}
* 配置文件 **appsettings.json**
public async Task<SystemDto> CreateAsync(CreateSystemDto input)
{
var system = await _systemRepository.CreateAsync(
new System
{
Name = input.Name,
Description = input.Description
}
);
return ObjectMapper.Map<System, SystemDto>(system);
}
```json
public async Task<List<SystemDto>> GetListAsync()
{
var systems = await _systemRepository.GetListAsync();
return ObjectMapper.Map<List<System>, List<SystemDto>>(systems);
}
{
"RemoteServices": {
"System": {
"AppId": "myapp",
"BaseUrl": "http://127.0.0.1:50000"
}
public async Task DeleteAsync(string id)
{
await _systemRepository.DeleteAsync(id);
}
}
```
* 客户端代码
```c#
### 3. 客户端使用
// 模块依赖
[DependsOn(
typeof(AbpDaprClientModule))]
public class SystemActorClientModule : AbpModule
```csharp
[DependsOn(typeof(AbpDaprClientModule))]
public class SystemClientModule : AbpModule
{
private const string RemoteServiceName = "System";
public override void ConfigureServices(ServiceConfigurationContext context)
{
// 注册代理类似于 Volo.Abp.Http.Client 模块
// 注册代理
context.Services.AddDaprClientProxies(
typeof(SystemInterfaceModule).Assembly, // 搜索 SystemInterfaceModule 模块下的IRemoteService定义创建代理
typeof(SystemInterfaceModule).Assembly,
RemoteServiceName
);
// 配置重试策略
context.Services.AddDaprClientBuilder(builder =>
{
builder.ConfigureHttpClient((sp, client) =>
{
client.Timeout = TimeSpan.FromSeconds(30);
});
});
}
}
// 调用方法,直接依赖注入即可
public class InvokeClass
public class SystemService
{
private readonly ISystemAppService _systemAppService;
public InvokeClass(ISystemAppService systemAppService)
public SystemService(ISystemAppService systemAppService)
{
_systemAppService = systemAppService;
}
public async Task InvokeAsync()
public async Task<List<SystemDto>> GetSystemsAsync()
{
await _systemAppService.GetAsync();
try
{
return await _systemAppService.GetListAsync();
}
catch (AbpRemoteCallException ex)
{
// 处理远程调用异常
_logger.LogError(ex, "Failed to get systems");
throw;
}
}
}
```
## 高级用法
## 配置项说明
### 1. 自定义请求处理
* AbpRemoteServiceOptions.RemoteServices 配置Dapr.AppId
```csharp
public class CustomRequestHandler
{
public void Configure(HttpRequestMessage request)
{
request.Headers.Add("Correlation-Id", Guid.NewGuid().ToString());
request.Headers.Add("Client-Version", "1.0.0");
}
}
```json
// 在模块中注册
Configure<AbpDaprClientProxyOptions>(options =>
{
options.ProxyRequestActions.Add((appId, request) =>
{
new CustomRequestHandler().Configure(request);
});
});
```
### 2. 自定义响应处理
```csharp
public class CustomResponseHandler
{
"RemoteServices": {
"System": {
"AppId": "myapp",
"BaserUrl": "http://127.0.0.1:50000"
}
public async Task<string> HandleAsync(HttpResponseMessage response)
{
var content = await response.Content.ReadAsStringAsync();
// 自定义响应处理逻辑
return content;
}
}
// 在模块中注册
Configure<AbpDaprClientProxyOptions>(options =>
{
options.OnResponse(async (response, sp) =>
{
return await new CustomResponseHandler().HandleAsync(response);
});
});
```
## 注意事项
* 远程服务接口必须继承`IRemoteService`
* 配置更改需要重新创建代理实例才能生效
* 建议配置适当的超时和重试策略
* 错误处理应该考虑网络异常和服务不可用的情况
* 在生产环境中应该启用服务发现
* 建议使用健康检查确保服务可用性
* 请求头配置应考虑安全性和身份验证需求
* 日志记录对于问题诊断很重要
## 其他
[查看英文](README.EN.md)

204
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr/README.EN.md

@ -0,0 +1,204 @@
# LINGYUN.Abp.Dapr
Dapr integration base module, implementing the named singleton DaprClient as described in the Dapr documentation.
See: https://docs.dapr.io/developing-applications/sdks/dotnet/dotnet-client/dotnet-daprclient-usage
## Features
* Support for creating default and named DaprClient instances
* Support for configuring HTTP and gRPC endpoints
* Support for custom JSON serialization options
* Support for Dapr API Token authentication
* Support for gRPC channel configuration
* Support for DaprClient instance configuration and builder configuration extensions
* Support for multiple Dapr Sidecar connections
* Support for custom DaprClient behaviors
## Configuration Options
```json
{
"Dapr": {
"Client": {
"DaprApiToken": "your-api-token", // Optional, Dapr API Token
"HttpEndpoint": "http://localhost:3500", // Optional, HTTP endpoint
"GrpcEndpoint": "http://localhost:50001", // Optional, gRPC endpoint
"JsonSerializerOptions": { // Optional, JSON serialization options
"PropertyNamingPolicy": "CamelCase",
"PropertyNameCaseInsensitive": true,
"WriteIndented": true,
"DefaultIgnoreCondition": "WhenWritingNull"
},
"GrpcChannelOptions": { // Optional, gRPC channel options
"Credentials": "Insecure",
"MaxReceiveMessageSize": 1048576,
"MaxSendMessageSize": 1048576
}
}
}
}
```
## Basic Usage
Module reference as needed:
```csharp
[DependsOn(typeof(AbpDaprModule))]
public class YouProjectModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Create a DaprClient
context.Services.AddDaprClient();
// Create a named DaprClient
context.Services.AddDaprClient("__DaprClient");
// Configure DaprClient options
Configure<DaprClientFactoryOptions>(options =>
{
options.HttpEndpoint = "http://localhost:3500";
options.GrpcEndpoint = "http://localhost:50001";
options.DaprApiToken = "your-api-token";
// Add DaprClient configuration actions
options.DaprClientActions.Add(client =>
{
// Configure DaprClient instance
});
// Add DaprClientBuilder configuration actions
options.DaprClientBuilderActions.Add(builder =>
{
// Configure DaprClientBuilder
});
});
}
}
```
## Advanced Usage
### 1. Configure DaprClient
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Configure named DaprClient
context.Services.AddDaprClient("CustomClient", builder =>
{
// Configure HTTP endpoint
builder.UseHttpEndpoint("http://localhost:3500");
// Configure gRPC endpoint
builder.UseGrpcEndpoint("http://localhost:50001");
// Configure API Token
builder.UseDaprApiToken("your-api-token");
// Configure JSON serialization options
builder.UseJsonSerializerOptions(new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true
});
// Configure gRPC channel options
builder.UseGrpcChannelOptions(new GrpcChannelOptions
{
MaxReceiveMessageSize = 1024 * 1024,
MaxSendMessageSize = 1024 * 1024
});
});
}
```
### 2. Using DaprClient
```csharp
public class YourService
{
private readonly IDaprClientFactory _daprClientFactory;
public YourService(IDaprClientFactory daprClientFactory)
{
_daprClientFactory = daprClientFactory;
}
public async Task InvokeMethodAsync()
{
// Use default client
var defaultClient = _daprClientFactory.CreateClient();
// Use named client
var namedClient = _daprClientFactory.CreateClient("CustomClient");
// Invoke service method
var response = await defaultClient.InvokeMethodAsync<OrderDto>(
HttpMethod.Get,
"order-service", // Target service ID
"api/orders/1", // Method path
new { id = 1 } // Request parameters
);
// Publish event
await defaultClient.PublishEventAsync(
"pubsub", // Pub/sub component name
"order-created", // Topic name
response // Event data
);
// Save state
await defaultClient.SaveStateAsync(
"statestore", // State store component name
"order-1", // Key
response // Value
);
// Get state
var state = await defaultClient.GetStateAsync<OrderDto>(
"statestore", // State store component name
"order-1" // Key
);
}
}
```
### 3. Custom DaprClient Behavior
```csharp
public class CustomDaprClientBehavior
{
public void Configure(DaprClient client)
{
// Configure custom behavior
}
}
// Register in module
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<DaprClientFactoryOptions>(options =>
{
options.DaprClientActions.Add(client =>
{
new CustomDaprClientBehavior().Configure(client);
});
});
}
```
## Important Notes
* DaprClient instances are thread-safe, singleton pattern is recommended
* Named DaprClients can have different configurations, suitable for scenarios requiring connections to different Dapr Sidecars
* Configuration changes require recreating the DaprClient instance to take effect
* Pay attention to performance and resource consumption when configuring gRPC channels
* JSON serialization options affect all requests using that DaprClient
* API Tokens should be managed through secure configuration management systems
* Recommended to use different named DaprClients for different microservices
* Configure appropriate timeout and retry policies in production environments
[查看中文](README.md)

184
aspnet-core/framework/dapr/LINGYUN.Abp.Dapr/README.md

@ -4,23 +4,201 @@ Dapr 集成基础模块, 实现dapr文档中的命名单例DaprClient
See: https://docs.dapr.io/developing-applications/sdks/dotnet/dotnet-client/dotnet-daprclient-usage
## 功能特性
* 支持创建默认和具名DaprClient实例
* 支持配置HTTP和gRPC端点
* 支持自定义JSON序列化选项
* 支持Dapr API Token认证
* 支持gRPC通道配置
* 支持DaprClient实例配置和构建配置的扩展
* 支持多个Dapr Sidecar连接
* 支持自定义DaprClient行为
## 配置选项
```json
{
"Dapr": {
"Client": {
"DaprApiToken": "your-api-token", // 可选,Dapr API Token
"HttpEndpoint": "http://localhost:3500", // 可选,HTTP端点
"GrpcEndpoint": "http://localhost:50001", // 可选,gRPC端点
"JsonSerializerOptions": { // 可选,JSON序列化选项
"PropertyNamingPolicy": "CamelCase",
"PropertyNameCaseInsensitive": true,
"WriteIndented": true,
"DefaultIgnoreCondition": "WhenWritingNull"
},
"GrpcChannelOptions": { // 可选,gRPC通道选项
"Credentials": "Insecure",
"MaxReceiveMessageSize": 1048576,
"MaxSendMessageSize": 1048576
}
}
}
}
```
## 配置使用
模块按需引用
模块按需引用
```csharp
[DependsOn(typeof(AbpDaprModule))]
public class YouProjectModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
public override void ConfigureServices(ServiceConfigurationContext context)
{
// 创建一个DaprClient
context.Services.AddDaprClient();
// 创建一个具名DaprClient
context.Services.AddDaprClient("__DaprClient");
// 配置DaprClient选项
Configure<DaprClientFactoryOptions>(options =>
{
options.HttpEndpoint = "http://localhost:3500";
options.GrpcEndpoint = "http://localhost:50001";
options.DaprApiToken = "your-api-token";
// 添加DaprClient配置动作
options.DaprClientActions.Add(client =>
{
// 配置DaprClient实例
});
// 添加DaprClientBuilder配置动作
options.DaprClientBuilderActions.Add(builder =>
{
// 配置DaprClientBuilder
});
});
}
}
```
## 高级用法
### 1. 配置DaprClient
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
// 配置具名DaprClient
context.Services.AddDaprClient("CustomClient", builder =>
{
// 配置HTTP端点
builder.UseHttpEndpoint("http://localhost:3500");
// 配置gRPC端点
builder.UseGrpcEndpoint("http://localhost:50001");
// 配置API Token
builder.UseDaprApiToken("your-api-token");
// 配置JSON序列化选项
builder.UseJsonSerializerOptions(new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true
});
// 配置gRPC通道选项
builder.UseGrpcChannelOptions(new GrpcChannelOptions
{
MaxReceiveMessageSize = 1024 * 1024,
MaxSendMessageSize = 1024 * 1024
});
});
}
```
### 2. 使用DaprClient
```csharp
public class YourService
{
private readonly IDaprClientFactory _daprClientFactory;
public YourService(IDaprClientFactory daprClientFactory)
{
_daprClientFactory = daprClientFactory;
}
public async Task InvokeMethodAsync()
{
// 使用默认客户端
var defaultClient = _daprClientFactory.CreateClient();
// 使用具名客户端
var namedClient = _daprClientFactory.CreateClient("CustomClient");
// 调用服务方法
var response = await defaultClient.InvokeMethodAsync<OrderDto>(
HttpMethod.Get,
"order-service", // 目标服务ID
"api/orders/1", // 方法路径
new { id = 1 } // 请求参数
);
// 发布事件
await defaultClient.PublishEventAsync(
"pubsub", // Pub/sub组件名称
"order-created", // 主题名称
response // 事件数据
);
// 保存状态
await defaultClient.SaveStateAsync(
"statestore", // 状态存储组件名称
"order-1", // 键
response // 值
);
// 获取状态
var state = await defaultClient.GetStateAsync<OrderDto>(
"statestore", // 状态存储组件名称
"order-1" // 键
);
}
}
```
## 其他
### 3. 自定义DaprClient行为
```csharp
public class CustomDaprClientBehavior
{
public void Configure(DaprClient client)
{
// 配置自定义行为
}
}
// 在模块中注册
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<DaprClientFactoryOptions>(options =>
{
options.DaprClientActions.Add(client =>
{
new CustomDaprClientBehavior().Configure(client);
});
});
}
```
## 注意事项
* DaprClient实例是线程安全的,建议使用单例模式
* 具名DaprClient可以有不同的配置,适用于需要连接不同Dapr Sidecar的场景
* 配置更改后需要重新创建DaprClient实例才能生效
* gRPC通道配置需要注意性能和资源消耗
* JSON序列化选项会影响所有使用该DaprClient的请求
* API Token应该通过安全的配置管理系统管理
* 建议为不同的微服务使用不同的具名DaprClient
* 在生产环境中应该适当配置超时和重试策略
[查看英文](README.EN.md)

256
aspnet-core/framework/dapr/LINGYUN.Abp.DistributedLocking.Dapr/README.EN.md

@ -0,0 +1,256 @@
# LINGYUN.Abp.DistributedLocking.Dapr
An ABP distributed locking implementation based on the Dapr distributed lock API. This module provides seamless integration with Dapr's distributed locking service, supporting cross-service and cross-instance locking capabilities.
Reference: [Dapr Distributed Lock API](https://docs.dapr.io/developing-applications/building-blocks/distributed-lock/distributed-lock-api-overview/)
## Features
* Integration with ABP distributed locking system
* Support for custom lock resource owner identification
* Configurable lock timeout duration
* Automatic lock release support
* Multiple lock storage component support
* Lock acquisition and release event notifications
* Distributed lock health check support
## Configuration Options
```json
{
"DistributedLocking": {
"Dapr": {
"StoreName": "lockstore", // Storage name defined in Dapr component
"DefaultIdentifier": "dapr-lock-owner", // Default lock resource owner identifier
"DefaultTimeout": "00:00:30" // Default lock timeout (30 seconds)
}
}
}
```
## Basic Usage
### 1. Module Configuration
```csharp
[DependsOn(typeof(AbpDistributedLockingDaprModule))]
public class YourProjectModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Basic configuration
Configure<AbpDistributedLockingDaprOptions>(options =>
{
options.StoreName = "redis-lock"; // Use Redis as lock storage
options.DefaultIdentifier = "my-service"; // Custom lock owner identifier
options.DefaultTimeout = TimeSpan.FromMinutes(1); // Set default timeout to 1 minute
});
}
}
```
### 2. Basic Usage
```csharp
public class OrderService
{
private readonly IDistributedLockProvider _lockProvider;
public OrderService(IDistributedLockProvider lockProvider)
{
_lockProvider = lockProvider;
}
public async Task ProcessOrderAsync(string orderId)
{
// Try to acquire lock
using (var handle = await _lockProvider.TryAcquireAsync($"order:{orderId}"))
{
if (handle != null)
{
try
{
// Execute business logic that requires locking
await ProcessOrderInternalAsync(orderId);
}
catch (Exception ex)
{
// Handle exception
_logger.LogError(ex, "Error occurred while processing order");
throw;
}
}
else
{
throw new ConcurrencyException("Order is being processed by another process");
}
}
}
}
```
### 3. Advanced Usage
```csharp
public class InventoryService
{
private readonly IDistributedLockProvider _lockProvider;
private readonly ILogger<InventoryService> _logger;
public InventoryService(
IDistributedLockProvider lockProvider,
ILogger<InventoryService> logger)
{
_lockProvider = lockProvider;
_logger = logger;
}
public async Task UpdateInventoryAsync(string productId, int quantity)
{
// Custom lock configuration
var lockOptions = new DistributedLockOptions
{
Timeout = TimeSpan.FromSeconds(10), // Custom timeout
RetryDelay = TimeSpan.FromMilliseconds(100) // Retry delay
};
try
{
using (var handle = await _lockProvider.TryAcquireAsync(
$"inventory:{productId}",
lockOptions))
{
if (handle == null)
{
_logger.LogWarning("Unable to acquire inventory lock for product ID: {ProductId}", productId);
throw new ConcurrencyException("Unable to acquire inventory lock");
}
// Execute inventory update operation
await UpdateInventoryInternalAsync(productId, quantity);
}
}
catch (Exception ex) when (ex is not ConcurrencyException)
{
_logger.LogError(ex, "Error occurred while updating inventory");
throw;
}
}
}
```
## Component Configuration
### Redis Lock Store Configuration Example
```yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: redis-lock # Corresponds to StoreName configuration
spec:
type: lock.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
- name: enableTLS
value: false
- name: maxRetries
value: 5
- name: maxRetryBackoff
value: 5s
```
### Consul Lock Store Configuration Example
```yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: consul-lock
spec:
type: lock.consul
version: v1
metadata:
- name: host
value: localhost:8500
- name: sessionTTL
value: 10
- name: scheme
value: http
```
## Core Interfaces
### ILockOwnerFinder
Interface for providing lock resource owner identification.
```csharp
public interface ILockOwnerFinder
{
string GetOwner();
}
```
The default implementation `LockOwnerFinder`:
1. Primarily uses the current user ID as the lock owner identifier
2. Falls back to the configured `DefaultIdentifier` if no user is logged in
### Custom Lock Owner Identifier Implementation
```csharp
public class CustomLockOwnerFinder : ILockOwnerFinder
{
private readonly ICurrentTenant _currentTenant;
public CustomLockOwnerFinder(ICurrentTenant currentTenant)
{
_currentTenant = currentTenant;
}
public string GetOwner()
{
// Use combination of tenant ID and machine name as lock owner identifier
return $"{_currentTenant.Id ?? "host"}-{Environment.MachineName}";
}
}
// Register custom implementation
context.Services.AddTransient<ILockOwnerFinder, CustomLockOwnerFinder>();
```
## Best Practices
1. **Set Appropriate Timeout Duration**
- Set timeout based on expected execution time of business operations
- Avoid setting excessively long timeouts to prevent deadlocks
2. **Proper Lock Granularity**
- Keep lock scope as small as possible, only lock necessary resources
- Avoid holding locks for extended periods, release promptly
3. **Exception Handling**
- Always use locks within using blocks
- Handle lock acquisition failures appropriately
- Log critical lock operations
4. **Performance Optimization**
- Use appropriate storage components
- Configure suitable retry policies
- Monitor lock usage
## Important Notes
* Ensure Dapr Sidecar is properly configured and running
* Distributed lock component must be correctly defined in Dapr configuration
* Set appropriate lock timeouts to avoid deadlocks
* Handle lock acquisition failures properly
* Consider performance impact in high-concurrency scenarios
* Configure health checks for lock components
* Add logging for important operations
[查看中文](README.md)

250
aspnet-core/framework/dapr/LINGYUN.Abp.DistributedLocking.Dapr/README.md

@ -1,38 +1,256 @@
# LINGYUN.Abp.DistributedLocking.Dapr
Abp分布式锁的Dapr实现
基于Dapr分布式锁API的ABP分布式锁实现。该模块提供了与Dapr分布式锁服务的无缝集成,支持跨服务、跨实例的分布式锁定功能。
See: https://docs.dapr.io/developing-applications/building-blocks/distributed-lock/distributed-lock-api-overview/
参考文档: [Dapr Distributed Lock API](https://docs.dapr.io/developing-applications/building-blocks/distributed-lock/distributed-lock-api-overview/)
## 配置使用
## 功能特性
模块按需引用
* 与ABP分布式锁系统集成
* 支持自定义锁资源拥有者标识
* 支持可配置的锁定超时时间
* 支持锁资源自动释放
* 支持多种锁存储组件
* 支持锁获取和释放的事件通知
* 支持分布式锁的健康检查
## 配置选项
```json
{
"DistributedLocking": {
"Dapr": {
"StoreName": "lockstore", // Dapr组件中定义的存储名称
"DefaultIdentifier": "dapr-lock-owner", // 默认锁资源拥有者标识
"DefaultTimeout": "00:00:30" // 默认锁定超时时间(30秒)
}
}
}
```
## 基础使用
### 1. 模块配置
```csharp
[DependsOn(typeof(AbpDistributedLockingDaprModule))]
public class YouProjectModule : AbpModule
public class YourProjectModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// 基础配置
Configure<AbpDistributedLockingDaprOptions>(options =>
{
options.StoreName = "store-name";
options.DefaultIdentifier = "default-owner-id";
options.DefaultTimeout = TimeSpan.FromSeconds(30);
options.StoreName = "redis-lock"; // 使用Redis作为锁存储
options.DefaultIdentifier = "my-service"; // 自定义锁拥有者标识
options.DefaultTimeout = TimeSpan.FromMinutes(1); // 设置默认超时时间为1分钟
});
}
}
```
## 配置说明
### 2. 基本用法
```csharp
public class OrderService
{
private readonly IDistributedLockProvider _lockProvider;
public OrderService(IDistributedLockProvider lockProvider)
{
_lockProvider = lockProvider;
}
public async Task ProcessOrderAsync(string orderId)
{
// 尝试获取锁
using (var handle = await _lockProvider.TryAcquireAsync($"order:{orderId}"))
{
if (handle != null)
{
try
{
// 执行需要加锁的业务逻辑
await ProcessOrderInternalAsync(orderId);
}
catch (Exception ex)
{
// 处理异常
_logger.LogError(ex, "处理订单时发生错误");
throw;
}
}
else
{
throw new ConcurrencyException("订单正在被其他进程处理");
}
}
}
}
```
### 3. 高级用法
```csharp
public class InventoryService
{
private readonly IDistributedLockProvider _lockProvider;
private readonly ILogger<InventoryService> _logger;
public InventoryService(
IDistributedLockProvider lockProvider,
ILogger<InventoryService> logger)
{
_lockProvider = lockProvider;
_logger = logger;
}
public async Task UpdateInventoryAsync(string productId, int quantity)
{
// 自定义锁配置
var lockOptions = new DistributedLockOptions
{
Timeout = TimeSpan.FromSeconds(10), // 自定义超时时间
RetryDelay = TimeSpan.FromMilliseconds(100) // 重试延迟
};
try
{
using (var handle = await _lockProvider.TryAcquireAsync(
$"inventory:{productId}",
lockOptions))
{
if (handle == null)
{
_logger.LogWarning("无法获取库存锁,产品ID: {ProductId}", productId);
throw new ConcurrencyException("无法获取库存锁");
}
// 执行库存更新操作
await UpdateInventoryInternalAsync(productId, quantity);
}
}
catch (Exception ex) when (ex is not ConcurrencyException)
{
_logger.LogError(ex, "更新库存时发生错误");
throw;
}
}
}
```
## 组件配置
### Redis锁存储配置示例
```yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: redis-lock # 对应StoreName配置
spec:
type: lock.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
- name: enableTLS
value: false
- name: maxRetries
value: 5
- name: maxRetryBackoff
value: 5s
```
### Consul锁存储配置示例
```yaml
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: consul-lock
spec:
type: lock.consul
version: v1
metadata:
- name: host
value: localhost:8500
- name: sessionTTL
value: 10
- name: scheme
value: http
```
## 核心接口
### ILockOwnerFinder
提供锁资源持有者标识的接口。
```csharp
public interface ILockOwnerFinder
{
string GetOwner();
}
```
默认实现 `LockOwnerFinder` 会:
1. 优先使用当前用户ID作为锁拥有者标识
2. 如果用户未登录,则使用配置的 `DefaultIdentifier`
### 自定义锁拥有者标识实现
```csharp
public class CustomLockOwnerFinder : ILockOwnerFinder
{
private readonly ICurrentTenant _currentTenant;
public CustomLockOwnerFinder(ICurrentTenant currentTenant)
{
_currentTenant = currentTenant;
}
public string GetOwner()
{
// 使用租户ID和机器名称组合作为锁拥有者标识
return $"{_currentTenant.Id ?? "host"}-{Environment.MachineName}";
}
}
// 注册自定义实现
context.Services.AddTransient<ILockOwnerFinder, CustomLockOwnerFinder>();
```
## 最佳实践
1. **合理设置超时时间**
- 根据业务操作的预期执行时间设置合适的超时时间
- 避免设置过长的超时时间,以防止死锁
2. **正确的锁粒度**
- 锁的范围应该尽可能小,只锁定必要的资源
- 避免长时间持有锁,及时释放
3. **异常处理**
- 始终在 using 块中使用锁
- 妥善处理锁获取失败的情况
- 记录关键的锁操作日志
* AbpDistributedLockingDaprOptions.StoreName 在dapr component文件中定义的metadata name,默认: lockstore;
* AbpDistributedLockingDaprOptions.DefaultIdentifier 默认锁资源拥有者标识,默认: dapr-lock-owner;
* AbpDistributedLockingDaprOptions.DefaultTimeout 默认锁定超时时间,默认: 30s.
4. **性能优化**
- 使用合适的存储组件
- 配置适当的重试策略
- 监控锁的使用情况
## 接口说明
## 注意事项
[ILockOwnerFinder](./LINGYUN/Abp/DistributedLocking/Dapr/ILockOwnerFinder), 提供锁资源持有者标识
默认实现 [LockOwnerFinder](./LINGYUN/Abp/DistributedLocking/Dapr/LockOwnerFinder), 获取用户标识,如果不存在,返回DefaultIdentifier
* 确保Dapr Sidecar已正确配置并运行
* 分布式锁组件需要在Dapr配置中正确定义
* 合理设置锁的超时时间,避免死锁
* 正确处理锁获取失败的情况
* 在高并发场景下注意性能影响
* 建议配置锁组件的健康检查
* 重要操作建议添加日志记录
## 其他
[查看英文](README.EN.md)

Loading…
Cancel
Save