chore: add documentation comments and stylecop rules
This commit is contained in:
@@ -22,17 +22,21 @@ public sealed class RabbitMqMessagePublisher(RabbitMqConnectionFactory connectio
|
||||
/// <inheritdoc />
|
||||
public Task PublishAsync<T>(string routingKey, T message, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 1. 确保通道可用
|
||||
EnsureChannel();
|
||||
var options = optionsMonitor.CurrentValue;
|
||||
|
||||
var channel = _channel ?? throw new InvalidOperationException("RabbitMQ channel is not available.");
|
||||
// 2. 声明交换机
|
||||
channel.ExchangeDeclare(options.Exchange, options.ExchangeType, durable: true, autoDelete: false);
|
||||
// 3. 序列化消息并设置属性
|
||||
var body = serializer.Serialize(message);
|
||||
var props = channel.CreateBasicProperties();
|
||||
props.ContentType = "application/json";
|
||||
props.DeliveryMode = 2;
|
||||
props.MessageId = Guid.NewGuid().ToString("N");
|
||||
|
||||
// 4. 发布消息
|
||||
channel.BasicPublish(options.Exchange, routingKey, props, body);
|
||||
logger.LogDebug("发布消息到交换机 {Exchange} RoutingKey {RoutingKey}", options.Exchange, routingKey);
|
||||
return Task.CompletedTask;
|
||||
|
||||
@@ -21,16 +21,19 @@ public sealed class RabbitMqMessageSubscriber(RabbitMqConnectionFactory connecti
|
||||
/// <inheritdoc />
|
||||
public async Task SubscribeAsync<T>(string queue, string routingKey, Func<T, CancellationToken, Task<bool>> handler, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 1. 确保通道可用
|
||||
EnsureChannel();
|
||||
var options = optionsMonitor.CurrentValue;
|
||||
|
||||
var channel = _channel ?? throw new InvalidOperationException("RabbitMQ channel is not available.");
|
||||
|
||||
// 2. 声明交换机、队列及绑定
|
||||
channel.ExchangeDeclare(options.Exchange, options.ExchangeType, durable: true, autoDelete: false);
|
||||
channel.QueueDeclare(queue, durable: true, exclusive: false, autoDelete: false);
|
||||
channel.QueueBind(queue, options.Exchange, routingKey);
|
||||
channel.BasicQos(0, options.PrefetchCount, global: false);
|
||||
|
||||
// 3. 设置消费者回调
|
||||
var consumer = new AsyncEventingBasicConsumer(channel);
|
||||
consumer.Received += async (_, ea) =>
|
||||
{
|
||||
@@ -61,6 +64,7 @@ public sealed class RabbitMqMessageSubscriber(RabbitMqConnectionFactory connecti
|
||||
}
|
||||
};
|
||||
|
||||
// 4. 开始消费
|
||||
channel.BasicConsume(queue, autoAck: false, consumer);
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace TakeoutSaaS.Module.Sms.Services;
|
||||
public sealed class AliyunSmsSender(IHttpClientFactory httpClientFactory, IOptionsMonitor<SmsOptions> optionsMonitor, ILogger<AliyunSmsSender> logger)
|
||||
: ISmsSender
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
|
||||
|
||||
/// <inheritdoc />
|
||||
public SmsProviderKind Provider => SmsProviderKind.Aliyun;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ public sealed class TencentSmsSender(IHttpClientFactory httpClientFactory, IOpti
|
||||
/// <inheritdoc />
|
||||
public async Task<SmsSendResult> SendAsync(SmsSendRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 1. 读取配置并处理 Mock
|
||||
var options = optionsMonitor.CurrentValue;
|
||||
if (options.UseMock)
|
||||
{
|
||||
@@ -34,6 +35,7 @@ public sealed class TencentSmsSender(IHttpClientFactory httpClientFactory, IOpti
|
||||
return new SmsSendResult { Success = true, Message = "Mocked" };
|
||||
}
|
||||
|
||||
// 2. 构建请求负载与签名所需字段
|
||||
var tencent = options.Tencent;
|
||||
var payload = BuildPayload(request, tencent);
|
||||
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
@@ -44,6 +46,7 @@ public sealed class TencentSmsSender(IHttpClientFactory httpClientFactory, IOpti
|
||||
var stringToSign = BuildStringToSign(canonicalRequest, timestamp, date);
|
||||
var signature = Sign(stringToSign, tencent.SecretKey, date);
|
||||
|
||||
// 3. 构建 HTTP 请求
|
||||
using var httpClient = httpClientFactory.CreateClient(nameof(TencentSmsSender));
|
||||
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, tencent.Endpoint)
|
||||
{
|
||||
@@ -58,6 +61,7 @@ public sealed class TencentSmsSender(IHttpClientFactory httpClientFactory, IOpti
|
||||
httpRequest.Headers.Add("Authorization",
|
||||
$"TC3-HMAC-SHA256 Credential={tencent.SecretId}/{date}/{Service}/tc3_request, SignedHeaders=content-type;host, Signature={signature}");
|
||||
|
||||
// 4. 发送请求并读取响应
|
||||
var response = await httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);
|
||||
var content = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -67,6 +71,7 @@ public sealed class TencentSmsSender(IHttpClientFactory httpClientFactory, IOpti
|
||||
return new SmsSendResult { Success = false, Message = content };
|
||||
}
|
||||
|
||||
// 5. 解析响应
|
||||
using var doc = JsonDocument.Parse(content);
|
||||
var root = doc.RootElement.GetProperty("Response");
|
||||
var status = root.GetProperty("SendStatusSet")[0];
|
||||
|
||||
@@ -12,8 +12,6 @@ namespace TakeoutSaaS.Module.Storage.Models;
|
||||
/// <param name="expires">签名有效期。</param>
|
||||
public sealed class StorageDirectUploadRequest(string objectKey, string contentType, long contentLength, TimeSpan expires)
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 目标对象键。
|
||||
/// </summary>
|
||||
|
||||
@@ -25,7 +25,6 @@ public sealed class StorageUploadRequest(
|
||||
TimeSpan signedUrlExpires,
|
||||
IDictionary<string, string>? metadata = null)
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 对象键。
|
||||
/// </summary>
|
||||
|
||||
@@ -28,6 +28,7 @@ public sealed class AliyunOssStorageProvider(IOptionsMonitor<StorageOptions> opt
|
||||
/// <inheritdoc />
|
||||
public async Task<StorageUploadResult> UploadAsync(StorageUploadRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 1. 准备元数据
|
||||
var options = CurrentOptions;
|
||||
var metadata = new ObjectMetadata
|
||||
{
|
||||
@@ -41,13 +42,16 @@ public sealed class AliyunOssStorageProvider(IOptionsMonitor<StorageOptions> opt
|
||||
}
|
||||
|
||||
// Aliyun OSS SDK 支持异步方法,如未支持将同步封装为任务。
|
||||
// 2. 上传对象
|
||||
await PutObjectAsync(options.AliyunOss.Bucket, request.ObjectKey, request.Content, metadata, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// 3. 生成签名或公有 URL
|
||||
var signedUrl = request.GenerateSignedUrl
|
||||
? await GenerateDownloadUrlAsync(request.ObjectKey, request.SignedUrlExpires, cancellationToken).ConfigureAwait(false)
|
||||
: null;
|
||||
|
||||
// 4. 返回上传结果
|
||||
return new StorageUploadResult
|
||||
{
|
||||
ObjectKey = request.ObjectKey,
|
||||
@@ -61,10 +65,12 @@ public sealed class AliyunOssStorageProvider(IOptionsMonitor<StorageOptions> opt
|
||||
/// <inheritdoc />
|
||||
public Task<StorageDirectUploadResult> CreateDirectUploadAsync(StorageDirectUploadRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 1. 计算过期时间并生成直传/下载链接
|
||||
var expiresAt = DateTimeOffset.UtcNow.Add(request.Expires);
|
||||
var uploadUrl = GeneratePresignedUrl(request.ObjectKey, request.Expires, SignHttpMethod.Put, request.ContentType);
|
||||
var downloadUrl = GeneratePresignedUrl(request.ObjectKey, request.Expires, SignHttpMethod.Get, null);
|
||||
|
||||
// 2. 返回直传参数
|
||||
var result = new StorageDirectUploadResult
|
||||
{
|
||||
UploadUrl = uploadUrl,
|
||||
@@ -80,6 +86,7 @@ public sealed class AliyunOssStorageProvider(IOptionsMonitor<StorageOptions> opt
|
||||
/// <inheritdoc />
|
||||
public Task<string> GenerateDownloadUrlAsync(string objectKey, TimeSpan expires, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 1. 生成预签名下载 URL
|
||||
var url = GeneratePresignedUrl(objectKey, expires, SignHttpMethod.Get, null);
|
||||
return Task.FromResult(url);
|
||||
}
|
||||
@@ -110,6 +117,7 @@ public sealed class AliyunOssStorageProvider(IOptionsMonitor<StorageOptions> opt
|
||||
private async Task PutObjectAsync(string bucket, string key, Stream content, ObjectMetadata metadata, CancellationToken cancellationToken)
|
||||
{
|
||||
var client = EnsureClient();
|
||||
// SDK 无异步则封装为 Task
|
||||
await Task.Run(() => client.PutObject(bucket, key, content, metadata), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ public abstract class S3StorageProviderBase : IObjectStorageProvider, IDisposabl
|
||||
/// <inheritdoc />
|
||||
public virtual async Task<StorageUploadResult> UploadAsync(StorageUploadRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 1. 构建上传请求
|
||||
var putRequest = new PutObjectRequest
|
||||
{
|
||||
BucketName = Bucket,
|
||||
@@ -79,12 +80,15 @@ public abstract class S3StorageProviderBase : IObjectStorageProvider, IDisposabl
|
||||
putRequest.Metadata[kv.Key] = kv.Value;
|
||||
}
|
||||
|
||||
// 2. 执行上传
|
||||
await Client.PutObjectAsync(putRequest, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// 3. 根据需要生成签名 URL
|
||||
var signedUrl = request.GenerateSignedUrl
|
||||
? GenerateSignedUrl(request.ObjectKey, request.SignedUrlExpires)
|
||||
: null;
|
||||
|
||||
// 4. 返回上传结果
|
||||
return new StorageUploadResult
|
||||
{
|
||||
ObjectKey = request.ObjectKey,
|
||||
@@ -98,10 +102,12 @@ public abstract class S3StorageProviderBase : IObjectStorageProvider, IDisposabl
|
||||
/// <inheritdoc />
|
||||
public virtual Task<StorageDirectUploadResult> CreateDirectUploadAsync(StorageDirectUploadRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 1. 计算过期时间并生成直传 URL
|
||||
var expiresAt = DateTimeOffset.UtcNow.Add(request.Expires);
|
||||
var uploadUrl = GenerateSignedUrl(request.ObjectKey, request.Expires, HttpVerb.PUT, request.ContentType);
|
||||
var signedDownload = GenerateSignedUrl(request.ObjectKey, request.Expires);
|
||||
|
||||
// 2. 返回直传参数
|
||||
var result = new StorageDirectUploadResult
|
||||
{
|
||||
UploadUrl = uploadUrl,
|
||||
@@ -117,6 +123,7 @@ public abstract class S3StorageProviderBase : IObjectStorageProvider, IDisposabl
|
||||
/// <inheritdoc />
|
||||
public virtual Task<string> GenerateDownloadUrlAsync(string objectKey, TimeSpan expires, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 1. 生成下载签名 URL
|
||||
var url = GenerateSignedUrl(objectKey, expires);
|
||||
return Task.FromResult(url);
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@ namespace TakeoutSaaS.Module.Tenancy;
|
||||
/// <param name="tenantContextAccessor">租户上下文访问器</param>
|
||||
public sealed class TenantProvider(ITenantContextAccessor tenantContextAccessor) : ITenantProvider
|
||||
{
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public long GetCurrentTenantId()
|
||||
=> tenantContextAccessor.Current?.TenantId ?? 0;
|
||||
|
||||
@@ -20,8 +20,6 @@ public sealed class TenantResolutionMiddleware(
|
||||
ITenantContextAccessor tenantContextAccessor,
|
||||
IOptionsMonitor<TenantResolutionOptions> optionsMonitor)
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 解析租户并将上下文注入请求。
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user