我有在业务服务中使用的错误类。OneOf<>
使用可区分联合允许服务方法从多个可能结果中返回一个结果。
// Errors
public record Error(string Code, string Description);
public sealed record NotDeleted(int Id, string EntityName) : Error("NotDeleted",
$"{EntityName} with Id = {Id} cannot be deleted.");
public sealed record NotFound(int Id, string EntityName) : Error("NotFound",
$"{EntityName} with Id = {Id} cannot be found.");
// Business Services
public sealed class MovieService(AppDbContext db)
{
private readonly AppDbContext _db = db;
public async Task<OneOf<NotFound, NotDeleted, Movie>> DeleteMovieAsync(int id, CancellationToken ct)
{
var movie = await _db.Movies
.Include(m => m.Genres)
.FirstOrDefaultAsync(m => m.Id == id, ct);
if (movie is null)
return new NotFound(id, nameof(Movie));
_db.Movies.Remove(movie);
return await _db.SaveChangesAsync(ct) > 0
? movie
: new NotDeleted(id, nameof(Movie));
}
}
业务服务被注入到端点。
// Endpoints
public static class MovieEndpoints
{
public static void MapMovieEndpoints(this IEndpointRouteBuilder app)
{
var group = app.MapGroup("api/movies");
group.MapDelete("{id}", DeleteMovieAsync);
}
private static async Task<Results<ProblemHttpResult, Ok<MovieResponse>>>
DeleteMovieAsync(int id, MovieService ms, CancellationToken ct)
{
var result = await ms.DeleteMovieAsync(id, ct);
return result.Match<Results<ProblemHttpResult, Ok<MovieResponse>>>(
notFoundError => notFoundError.ToProblemDetails(),
notDeletedError => notDeletedError.ToProblemDetails(),
movie => TypedResults.Ok(movie.MapToMovieResponse()));
}
}
我扩展Error
类以生成ProblemDetails
如下内容。我如何登录内部ToProblemDetails()
(以 表示// Logging goes here!
)?
// Mappers
public static class ErrorMapper
{
private static ProblemHttpResult ToProblemDetails(Error error, int statusCode)
{
// Logging goes here!
return TypedResults.Problem(new ProblemDetails
{
Title = error.Code,
Detail = error.Description,
Status = statusCode
});
}
public static ProblemHttpResult ToProblemDetails(this NotFound error)
=> ToProblemDetails(error, StatusCodes.Status404NotFound);
public static ProblemHttpResult ToProblemDetails(NotDeleted error)
=> ToProblemDetails(error, StatusCodes.Status500InternalServerError);
}
您需要 a) 将记录器实例作为参数传递,或者 b) 向类添加静态记录器
ErrorMapper
。但实际上,这不是记录错误的好地方。静态方法无法被模拟,记录并不是该函数的真正目的。
您应该登录控制器。类似这样的内容: