DDD 需要引用的程序集
例如 订单服务 涉及到并发 业务复杂 所以使用领域驱动涉及到
集成事件总线 基于 rabbitmq 异步发布用于与其他服务通信 (订阅发布模式)
领域事件 基于 MediatR 涉及到 一对一 (IRequest<bool>,IRequestHandler<AddUserCommand, bool>) ,一对多(INotification,INotificationHandler<RegistorSendMailEvent>)
Dapper 用于查询
Grpc 用于服务与服务之间的通信
健康检查
身份验证 jwt 或者 identityserver4
身份授权
先来Program 配置
对前台 返回实体 帕斯卡命名
引用 NewtonsoftJson 实现
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.4" />
builder.Services.AddControllers(options =>
{
//全局异常过滤器
options.Filters.Add<GolbalExceptionFilter>();
}).AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
健康检查
可以检查 mysql 健康状态 可以使用UI查看健康检查
引用 AspNetCore.HealthChecks.UI
<PackageReference Include="AspNetCore.HealthChecks.UI" Version="8.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="8.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="8.0.1" />
builder.Services.AddHealthChecks().AddCheck("self", check => HealthCheckResult.Healthy(), tags: new string[] { "self" });
app.UseHealthChecks("/healthz", new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.UseHealthChecks("/health_self", new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions
{
Predicate = result => result.Name.Contains("self")
});
//增加 HealthChecksUI 中间件
app.UseHealthChecksUI(setup: options =>
{
//UI 访问路径
options.UIPath = "/health-ui";
});
HealthChecksUI appsettings.json 配置
"HealthChecksUI": {
"HealthChecks": [
{
"Name": "Test Health",
"Uri": "/healthz"
}
],
"EvaluationTimeinSeconds": 10,
"MinimumSecondsBetweenFailureNotifications": 30
}
mysql 开启失败重试
//添加事件总线日志数据库配置
builder.Services.AddDbContext<IntegrationEventLogContext>(options =>
{
// 内存数据库
// options.UseInMemoryDatabase("test");
//mysql 数据库
string mysqlStr = builder.Configuration.GetConnectionString("mysql") ?? throw new UserDomainException("mysql连接字符串为null");
options.UseMySql(mysqlStr, new MySqlServerVersion(new Version(8, 0, 27)), dbOptions =>
{
//数据迁移
dbOptions.MigrationsAssembly(Assembly.GetExecutingAssembly().GetName().Name);
//开启失败重试
dbOptions.EnableRetryOnFailure(maxRetryCount: 15, TimeSpan.FromSeconds(15), null);
});
});
"ConnectionStrings": {
"redis": "192.168.0.168:6379",
"mysql": "server=192.168.0.168;port=3306;database=UserDDD;pwd=123456;uid=root;"
},
一定要注意事务 需要用到事务的时候 需要编写执行策略否测失败重试会报错
public async Task ExecuteAsync(Func<Task> action)
{
var strategy = _context.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
await using var transaction = await _context.Database.BeginTransactionAsync();
await action();
await transaction.CommitAsync();
});
}
MediatR
<PackageReference Include="MediatR" Version="12.2.0" />
builder.Services.AddMediatR(config =>
{
config.RegisterServicesFromAssemblies(typeof(Program).Assembly);
});
AutoMapper
<PackageReference Include="AutoMapper" Version="13.0.1" />
builder.Services.AddAutoMapper(options =>
{
//程序集注册
options.AddMaps(Assembly.GetExecutingAssembly());
});
使用 AutoMapper 时
- 会扫描程序集的Profiles 名称的文件夹
- 对象有子对象时 应先映射子对象
- 映射类需要继承 Profile
public class AccountProfile : Profile { public AccountProfile() { //子对象先映射 CreateMap<BillInputCreate, Bill>().ReverseMap(); //子对象先映射 CreateMap<BillViewModel, Bill>().ReverseMap(); CreateMap<AccountViewModel, Account>() .ForMember(x => x.Bills, p => p.MapFrom(y => y.Bills)).ReverseMap(); CreateMap<AccountInputCreate, Account>().ForMember(x => x.Bills, p => p.MapFrom(y => y.billInputCreates)).ReverseMap(); } }
浙公网安备 33010602011771号