refactor(gateway): 使用值对象替代字符串类型属性
- GwRouteMatch: 路由匹配配置值对象(Path, Methods, Hosts, Headers, QueryParameters) - GwRouteHeader: Header 匹配规则值对象 - GwRouteQueryParameter: 查询参数匹配规则值对象 - GwLoadBalancingPolicy: 负载均衡策略枚举 - GwTransform: 请求/响应转换规则值对象 - EF Core 使用 ToJson() 将值对象映射为 JSON 列
This commit is contained in:
parent
0841d81318
commit
033fcc9e9b
@ -25,20 +25,20 @@ public class GwCluster
|
||||
/// <summary>
|
||||
/// 目标端点列表(内嵌)
|
||||
/// </summary>
|
||||
public List<GwDestination> Destinations { get; set; } = new();
|
||||
public List<GwDestination> Destinations { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 负载均衡策略
|
||||
/// </summary>
|
||||
public string LoadBalancingPolicy { get; set; } = "RoundRobin";
|
||||
public GwLoadBalancingPolicy LoadBalancingPolicy { get; set; } = GwLoadBalancingPolicy.RoundRobin;
|
||||
|
||||
/// <summary>
|
||||
/// 健康检查配置
|
||||
/// 健康检查配置(JSON 列存储)
|
||||
/// </summary>
|
||||
public GwHealthCheckConfig? HealthCheck { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 会话亲和配置
|
||||
/// 会话亲和配置(JSON 列存储)
|
||||
/// </summary>
|
||||
public GwSessionAffinityConfig? SessionAffinity { get; set; }
|
||||
|
||||
@ -76,4 +76,4 @@ public class GwCluster
|
||||
/// 版本号,用于乐观并发
|
||||
/// </summary>
|
||||
public int Version { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
namespace Fengling.Platform.Domain.AggregatesModel.GatewayAggregate;
|
||||
|
||||
/// <summary>
|
||||
/// 负载均衡策略
|
||||
/// </summary>
|
||||
public enum GwLoadBalancingPolicy
|
||||
{
|
||||
RoundRobin = 0,
|
||||
Random = 1,
|
||||
PowerOfTwoChoices = 2,
|
||||
LeastRequests = 3,
|
||||
First = 4,
|
||||
WeightedRoundRobin = 5
|
||||
}
|
||||
@ -0,0 +1,108 @@
|
||||
namespace Fengling.Platform.Domain.AggregatesModel.GatewayAggregate;
|
||||
|
||||
/// <summary>
|
||||
/// 路由匹配配置(值对象)
|
||||
/// 对应 YARP 的 RouteMatch,以 JSON 存储在数据库中
|
||||
/// </summary>
|
||||
public class GwRouteMatch
|
||||
{
|
||||
/// <summary>
|
||||
/// 路径匹配模式
|
||||
/// </summary>
|
||||
public string Path { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// HTTP 方法列表(如 ["GET", "POST"])
|
||||
/// </summary>
|
||||
public List<string>? Methods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Host 匹配列表(如 ["api.example.com", "*.example.com"])
|
||||
/// </summary>
|
||||
public List<string>? Hosts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header 匹配规则
|
||||
/// </summary>
|
||||
public List<GwRouteHeader>? Headers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 查询参数匹配规则
|
||||
/// </summary>
|
||||
public List<GwRouteQueryParameter>? QueryParameters { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Header 匹配规则(值对象)
|
||||
/// </summary>
|
||||
public class GwRouteHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Header 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 匹配值列表
|
||||
/// </summary>
|
||||
public List<string> Values { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 匹配模式
|
||||
/// </summary>
|
||||
public GwHeaderMatchMode Mode { get; set; } = GwHeaderMatchMode.ExactHeader;
|
||||
|
||||
/// <summary>
|
||||
/// 是否区分大小写
|
||||
/// </summary>
|
||||
public bool IsCaseSensitive { get; set; } = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询参数匹配规则(值对象)
|
||||
/// </summary>
|
||||
public class GwRouteQueryParameter
|
||||
{
|
||||
/// <summary>
|
||||
/// 参数名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 匹配值列表
|
||||
/// </summary>
|
||||
public List<string> Values { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 匹配模式
|
||||
/// </summary>
|
||||
public GwQueryParameterMatchMode Mode { get; set; } = GwQueryParameterMatchMode.Exact;
|
||||
|
||||
/// <summary>
|
||||
/// 是否区分大小写
|
||||
/// </summary>
|
||||
public bool IsCaseSensitive { get; set; } = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Header 匹配模式
|
||||
/// </summary>
|
||||
public enum GwHeaderMatchMode
|
||||
{
|
||||
ExactHeader = 0,
|
||||
Prefix = 1,
|
||||
Contains = 2,
|
||||
NotContains = 3,
|
||||
Exists = 4
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询参数匹配模式
|
||||
/// </summary>
|
||||
public enum GwQueryParameterMatchMode
|
||||
{
|
||||
Exact = 0,
|
||||
Contains = 1,
|
||||
Prefix = 2,
|
||||
Exists = 3
|
||||
}
|
||||
@ -23,15 +23,45 @@ public class GwTenantRoute
|
||||
public string ClusterId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 路径匹配模式
|
||||
/// 路由匹配配置(JSON 列存储)
|
||||
/// </summary>
|
||||
public string PathPattern { get; set; } = string.Empty;
|
||||
public GwRouteMatch Match { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 优先级
|
||||
/// 优先级(对应 YARP Order,数值越小优先级越高)
|
||||
/// </summary>
|
||||
public int Priority { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 路由级别负载均衡策略覆盖(可选,默认使用集群策略)
|
||||
/// </summary>
|
||||
public GwLoadBalancingPolicy? LoadBalancingPolicy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 授权策略名称
|
||||
/// </summary>
|
||||
public string? AuthorizationPolicy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// CORS 策略名称
|
||||
/// </summary>
|
||||
public string? CorsPolicy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 限流策略名称
|
||||
/// </summary>
|
||||
public string? RateLimiterPolicy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求/响应转换规则(JSON 列存储)
|
||||
/// </summary>
|
||||
public List<GwTransform>? Transforms { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求超时时间(秒)
|
||||
/// </summary>
|
||||
public int? TimeoutSeconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
@ -71,45 +101,4 @@ public class GwTenantRoute
|
||||
/// 版本号,用于乐观并发
|
||||
/// </summary>
|
||||
public int Version { get; set; } = 0;
|
||||
|
||||
// ===== 路由匹配能力 =====
|
||||
|
||||
/// <summary>
|
||||
/// HTTP 方法匹配(如 "GET,POST")
|
||||
/// </summary>
|
||||
public string? Methods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Host 头匹配(如 "api.example.com")
|
||||
/// </summary>
|
||||
public string? Hosts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Header 匹配规则(JSON 格式)
|
||||
/// </summary>
|
||||
public string? Headers { get; set; }
|
||||
|
||||
// ===== 策略配置 =====
|
||||
|
||||
/// <summary>
|
||||
/// 路由级别负载均衡策略覆盖
|
||||
/// </summary>
|
||||
public string? LoadBalancingPolicy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 授权策略
|
||||
/// </summary>
|
||||
public string? AuthorizationPolicy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// CORS 策略
|
||||
/// </summary>
|
||||
public string? CorsPolicy { get; set; }
|
||||
|
||||
// ===== 请求转换 =====
|
||||
|
||||
/// <summary>
|
||||
/// 请求/响应转换规则(JSON 格式)
|
||||
/// </summary>
|
||||
public string? Transforms { get; set; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
namespace Fengling.Platform.Domain.AggregatesModel.GatewayAggregate;
|
||||
|
||||
/// <summary>
|
||||
/// 请求/响应转换规则(值对象)
|
||||
/// 以 JSON 列存储在数据库中
|
||||
/// </summary>
|
||||
public class GwTransform
|
||||
{
|
||||
/// <summary>
|
||||
/// 转换规则键值对
|
||||
/// 例如: {"RequestHeader": "X-Custom-Header", "Set": "value"}
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Rules { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 常用转换规则工厂
|
||||
/// </summary>
|
||||
public static class GwTransforms
|
||||
{
|
||||
/// <summary>
|
||||
/// 设置请求头
|
||||
/// </summary>
|
||||
public static GwTransform SetRequestHeader(string headerName, string value)
|
||||
=> new() { Rules = new Dictionary<string, string>
|
||||
{
|
||||
{ "RequestHeader", headerName },
|
||||
{ "Set", value }
|
||||
}};
|
||||
|
||||
/// <summary>
|
||||
/// 添加请求头
|
||||
/// </summary>
|
||||
public static GwTransform AppendRequestHeader(string headerName, string value)
|
||||
=> new() { Rules = new Dictionary<string, string>
|
||||
{
|
||||
{ "RequestHeader", headerName },
|
||||
{ "Append", value }
|
||||
}};
|
||||
|
||||
/// <summary>
|
||||
/// 设置响应头
|
||||
/// </summary>
|
||||
public static GwTransform SetResponseHeader(string headerName, string value)
|
||||
=> new() { Rules = new Dictionary<string, string>
|
||||
{
|
||||
{ "ResponseHeader", headerName },
|
||||
{ "Set", value }
|
||||
}};
|
||||
|
||||
/// <summary>
|
||||
/// 移除路径前缀
|
||||
/// </summary>
|
||||
public static GwTransform PathRemovePrefix(string prefix)
|
||||
=> new() { Rules = new Dictionary<string, string>
|
||||
{
|
||||
{ "PathRemovePrefix", prefix }
|
||||
}};
|
||||
|
||||
/// <summary>
|
||||
/// 设置路径前缀
|
||||
/// </summary>
|
||||
public static GwTransform PathSetPrefix(string prefix)
|
||||
=> new() { Rules = new Dictionary<string, string>
|
||||
{
|
||||
{ "PathPrefix", prefix }
|
||||
}};
|
||||
|
||||
/// <summary>
|
||||
/// 使用原始 Host 头
|
||||
/// </summary>
|
||||
public static GwTransform RequestHeaderOriginalHost()
|
||||
=> new() { Rules = new Dictionary<string, string>
|
||||
{
|
||||
{ "RequestHeaderOriginalHost", "true" }
|
||||
}};
|
||||
}
|
||||
@ -1,15 +1,12 @@
|
||||
using Fengling.Platform.Domain.AggregatesModel.GatewayAggregate;
|
||||
|
||||
using Fengling.Platform.Domain.AggregatesModel.RoleAggregate;
|
||||
using Fengling.Platform.Domain.AggregatesModel.TenantAggregate;
|
||||
using Fengling.Platform.Domain.AggregatesModel.UserAggregate;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
|
||||
namespace Fengling.Platform.Infrastructure;
|
||||
|
||||
|
||||
public class PlatformDbContext(DbContextOptions options)
|
||||
: IdentityDbContext<ApplicationUser, ApplicationRole, long>(options)
|
||||
{
|
||||
@ -91,26 +88,57 @@ public class PlatformDbContext(DbContextOptions options)
|
||||
entity.Property(e => e.TenantCode).HasMaxLength(50);
|
||||
entity.Property(e => e.ServiceName).HasMaxLength(100).IsRequired();
|
||||
entity.Property(e => e.ClusterId).HasMaxLength(100).IsRequired();
|
||||
entity.Property(e => e.PathPattern).HasMaxLength(200).IsRequired();
|
||||
entity.Property(e => e.AuthorizationPolicy).HasMaxLength(100);
|
||||
entity.Property(e => e.CorsPolicy).HasMaxLength(100);
|
||||
entity.Property(e => e.RateLimiterPolicy).HasMaxLength(100);
|
||||
|
||||
// 枚举转换为字符串
|
||||
entity.Property(e => e.LoadBalancingPolicy)
|
||||
.HasConversion(
|
||||
v => v.HasValue ? v.Value.ToString() : null,
|
||||
v => v != null ? Enum.Parse<GwLoadBalancingPolicy>(v) : null
|
||||
)
|
||||
.HasMaxLength(50);
|
||||
|
||||
// 值对象映射为 JSON 列
|
||||
entity.OwnsOne(e => e.Match, navigationBuilder =>
|
||||
{
|
||||
navigationBuilder.ToJson();
|
||||
});
|
||||
|
||||
// 转换规则映射为 JSON 列
|
||||
entity.OwnsMany(e => e.Transforms, navigationBuilder =>
|
||||
{
|
||||
navigationBuilder.ToJson();
|
||||
});
|
||||
|
||||
entity.HasIndex(e => e.TenantCode);
|
||||
entity.HasIndex(e => e.ServiceName);
|
||||
entity.HasIndex(e => e.ClusterId);
|
||||
entity.HasIndex(e => new { e.ServiceName, e.IsGlobal, e.Status });
|
||||
});
|
||||
|
||||
// GwCluster 聚合根配置 - 使用 Owned 类型
|
||||
// GwCluster 聚合根配置
|
||||
modelBuilder.Entity<GwCluster>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id);
|
||||
entity.Property(e => e.ClusterId).HasMaxLength(100).IsRequired();
|
||||
entity.Property(e => e.Name).HasMaxLength(100).IsRequired();
|
||||
entity.Property(e => e.Description).HasMaxLength(500);
|
||||
entity.Property(e => e.LoadBalancingPolicy).HasMaxLength(50);
|
||||
|
||||
// 枚举转换为字符串
|
||||
entity.Property(e => e.LoadBalancingPolicy)
|
||||
.HasConversion(
|
||||
v => v.ToString(),
|
||||
v => Enum.Parse<GwLoadBalancingPolicy>(v)
|
||||
)
|
||||
.HasMaxLength(50);
|
||||
|
||||
entity.HasIndex(e => e.ClusterId).IsUnique();
|
||||
entity.HasIndex(e => e.Name);
|
||||
entity.HasIndex(e => e.Status);
|
||||
|
||||
// 配置内嵌的目标端点列表 - 使用 OwnedMany
|
||||
// 配置内嵌的目标端点列表
|
||||
entity.OwnsMany(e => e.Destinations, owned =>
|
||||
{
|
||||
owned.WithOwner().HasForeignKey("ClusterId");
|
||||
@ -121,21 +149,20 @@ public class PlatformDbContext(DbContextOptions options)
|
||||
owned.HasIndex("ClusterId", "DestinationId");
|
||||
});
|
||||
|
||||
// 配置内嵌健康检查配置
|
||||
// 配置内嵌健康检查配置(JSON 列)
|
||||
entity.OwnsOne(e => e.HealthCheck, owned =>
|
||||
{
|
||||
owned.Property(h => h.Path).HasMaxLength(200);
|
||||
owned.ToJson();
|
||||
});
|
||||
|
||||
// 配置内嵌会话亲和配置
|
||||
// 配置内嵌会话亲和配置(JSON 列)
|
||||
entity.OwnsOne(e => e.SessionAffinity, owned =>
|
||||
{
|
||||
owned.Property(s => s.Policy).HasMaxLength(50);
|
||||
owned.Property(s => s.AffinityKeyName).HasMaxLength(50);
|
||||
owned.ToJson();
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.ApplyConfigurationsFromAssembly(typeof(PlatformDbContext).Assembly);
|
||||
base.OnModelCreating(modelBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user