文章目录
项目地址
- 教程作者:
- 教程地址:
- 代码仓库地址:
- 所用到的框架和插件:
dbt
airflow
一、异常处理
1.1 自定异常
- BadRequestException
- InternalServerException
- NotFoundException
1.2 自定义异常处理中间件
- 异常处理中间件
public class CustomExceptionHandler
(ILogger<CustomExceptionHandler> logger)
: IExceptionHandler
{
public async ValueTask<bool> TryHandleAsync(HttpContext context, Exception exception, CancellationToken cancellationToken)
{
logger.LogError(
"Error Message: {exceptionMessage}, Time of occurrence {time}",
exception.Message, DateTime.UtcNow);
(string Detail, string Title, int StatusCode) details = exception switch
{
InternalServerException =>
(
exception.Message,
exception.GetType().Name,
context.Response.StatusCode = StatusCodes.Status500InternalServerError
),
ValidationException =>
(
exception.Message,
exception.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
BadRequestException =>
(
exception.Message,
exception.GetType().Name,
context.Response.StatusCode = StatusCodes.Status400BadRequest
),
NotFoundException =>
(
exception.Message,
exception.GetType().Name,
context.Response.StatusCode = StatusCodes.Status404NotFound
),
_ =>
(
exception.Message,
exception.GetType().Name,
context.Response.StatusCode = StatusCodes.Status500InternalServerError
)
};
var problemDetails = new ProblemDetails
{
Title = details.Title,
Detail = details.Detail,
Status = details.StatusCode,
Instance = context.Request.Path
};
problemDetails.Extensions.Add("traceId", context.TraceIdentifier);
if (exception is ValidationException validationException)
{
problemDetails.Extensions.Add("ValidationErrors", validationException.Errors);
}
await context.Response.WriteAsJsonAsync(problemDetails, cancellationToken: cancellationToken);
return true;
}
}
- 返回例
{
"title": "ValidationException",
"detail": "参数验证失败",
"status": 400,
"instance": "/api/products",
"traceId": "00-9d4a78437e-abc123def456-01",
"ValidationErrors": [
{
"PropertyName": "Name",
"ErrorMessage": "Name 不能为空"
},
{
"PropertyName": "Age",
"ErrorMessage": "Age 必须大于 0"
}
]
}
1.3 注册中间件
- 给所有微服务注册
二、grpc服务
土耳其146
- 这里主要实现了discount模块的grpc,我们可以通过api进行增删改查
2.1 创建protos
1. 打折的protos
- 定义请求和返回值
syntax = "proto3";
option csharp_namespace = "Discount.Grpc";
package discount;
// The discount service definition.
service DiscountProtoService {
// Discount CRUD Operations
rpc GetDiscount (GetDiscountRequest) returns (CouponModel);
rpc CreateDiscount (CreateDiscountRequest) returns (CouponModel);
rpc UpdateDiscount (UpdateDiscountRequest) returns (CouponModel);
rpc DeleteDiscount (DeleteDiscountRequest) returns (DeleteDiscountResponse);
}
message GetDiscountRequest {
string productName = 1;
}
message CouponModel {
int32 id = 1;
string productName = 2;
string description = 3;
int32 amount = 4;
}
message CreateDiscountRequest {
CouponModel coupon = 1;
}
message UpdateDiscountRequest {
CouponModel coupon = 1;
}
message DeleteDiscountRequest {
string productName = 1;
}
message DeleteDiscountResponse {
bool success = 1;
}
2. 设置grpc server
- 设置grpc服务
- 设置成功后,可以在模块的包管理器看到
3. program配置服务
4. docker-compose
2.2 CRUD
1. 查询
2.3 测试
1. 发起查询请求
三、grpc服务消费
土167
- Basket.Api 服务调用Discount.Grpc服务
3.1 创建client
- Basket服务要去调用Discount服务,所以Basket是 Client, Discount是 service
1. 添加服务
2. 选择需要添加的服务类型
3. 选择服务路径
4. 添加成功后
- 添加成功后,basket模块会有Protos文件夹
5. Program里添加Client服务
- 在Basket模块的Program里添加
6. appSettings里添加grpc服务地址
- 添加Grpc的服务地址
3.2 grpc通讯
1. 在StoreBasketCommandHandler使用
- 在StoreBasketCommandHandler里进行折扣服务的扣减