|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- # 引出`Result`模式
-
-
-
- 通常的方式
-
- ```
- public Customer GetCustomer(int customerId)
- {
- // more logic
- return customer;
- }
-
- public Customer CreateCustomer(string firstName, string lastName)
- {
- // more logic
- return customer;
- }
- ```
-
- 在逻辑中,我们可能会判断`customerId`不存在,判断`lastName`没有提供,甚至当前用户是否有权限创建用户。
-
- 我们在处理正常和异常这两种情况。
-
- `Result`模式用来对这两种情况进行封装,并且统一了返回结果的格式。
-
- ```
- public async Task<Result<BlogCategory>> UpdateAsync(BlogCategory blogCategory)
- {
- if (Guid.Empty == blogCategory.BlogCategoryId) return Result<BlogCategory>.NotFound();//没有找到
-
- var validator = new BlogCategoryValidator();
- var validation = await validator.ValidateAsync(blogCategory);
- if (!validation.IsValid)
- {
- return Result<BlogCategory>.Invalid(validation.AsErrors());//验证异常
- }
-
- var itemToUpdate = (await GetByIdAsync(blogCategory.BlogCategoryId)).Value;
- if (itemToUpdate == null)
- {
- return Result<BlogCategory>.NotFound();
- }
-
- itemToUpdate.Update(blogCategory.Name, blogCategory.ParentId);
-
- return Result<BlogCategory>.Success(await _blogCategoryRepository.UpdateAsync(itemToUpdate));
- }
- ```
-
- 结果
-
- ![ddd12](F:\SourceCodes\DDWiki\专题\后端\DDD\ddd12.png)
-
- # 接口
-
- ```
- [ApiController]
- [Route("mediatr/[controller]")]
- public class WeatherForecastController : ControllerBase
- {
- private readonly IMediator _mediator;
- private readonly ILogger<WeatherForecastController> _logger;
-
- public WeatherForecastController(
- IMediator mediator,
- ILogger<WeatherForecastController> logger)
- {
- _mediator = mediator;
- _logger = logger;
- }
-
- /// <summary>
- /// This uses a filter to convert an Ardalis.Result return type to an ActionResult.
- /// This filter could be used per controller or globally!
- /// </summary>
- /// <param name="model"></param>
- /// <returns></returns>
- [TranslateResultToActionResult]//把Result的结果转换成ActionResult的结果,可以定义我们自己的特性,这点特别重要
- [HttpPost("Create")]
- public Task<Result<IEnumerable<WeatherForecast>>> CreateForecast([FromBody] NewForecastCommand model)
- {
- // One might try to perform translation from Result<T> to an appropriate IActionResult from within a MediatR pipeline
- // Unfortunately without having Result<T> depend on IActionResult there doesn't appear to be a way to do this, so this
- // example is still using the TranslateResultToActionResult filter.
- return _mediator.Send(model);
- }
-
- public class NewForecastCommand : IRequest<Result<IEnumerable<WeatherForecast>>>
- {
- [Required]
- public string PostalCode { get; set; }
- }
-
- public class NewForecastHandler : IRequestHandler<NewForecastCommand, Result<IEnumerable<WeatherForecast>>>
- {
- private readonly WeatherService _weatherService;
-
- public NewForecastHandler(WeatherService weatherService)
- {
- _weatherService = weatherService;
- }
- public Task<Result<IEnumerable<WeatherForecast>>> Handle(NewForecastCommand request, CancellationToken cancellationToken)
- {
- var result = _weatherService.GetForecastAsync(new ForecastRequestDto { PostalCode = request.PostalCode });
- return result;
- }
- }
- }
- ```
-
- 在`WeatherService`中
-
- ```
- public class WeatherService
- {
- public WeatherService(IStringLocalizer<WeatherService> stringLocalizer)
- {
- _stringLocalizer = stringLocalizer;
- }
- private static readonly string[] Summaries = new[]
- {
- "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
- };
-
- private IStringLocalizer<WeatherService> _stringLocalizer;
-
- public Task<Result<IEnumerable<WeatherForecast>>> GetForecastAsync(ForecastRequestDto model)
- {
- return Task.FromResult(GetForecast(model));
- }
-
- public Result<IEnumerable<WeatherForecast>> GetForecast(ForecastRequestDto model)
- {
- if (model.PostalCode == "NotFound") return Result<IEnumerable<WeatherForecast>>.NotFound();//没有找到
-
- // validate model
- if (model.PostalCode.Length > 10)
- {
- return Result<IEnumerable<WeatherForecast>>.Invalid(new List<ValidationError> {
- new ValidationError
- {
- Identifier = nameof(model.PostalCode),
- ErrorMessage = _stringLocalizer["PostalCode cannot exceed 10 characters."].Value }
- });//模型验证失败
- }
-
- // test value
- if (model.PostalCode == "55555")
- {
- return new Result<IEnumerable<WeatherForecast>>(Enumerable.Range(1, 1)//返回成功的结果
- .Select(index =>
- new WeatherForecast
- {
- Date = DateTime.Now,
- TemperatureC = 0,
- Summary = Summaries[0]
- }));
- }
-
- var rng = new Random();
- return new Result<IEnumerable<WeatherForecast>>(Enumerable.Range(1, 5)//返回成功的结果
- .Select(index => new WeatherForecast
- {
- Date = DateTime.Now.AddDays(index),
- TemperatureC = rng.Next(-20, 55),
- Summary = Summaries[rng.Next(Summaries.Length)]
- })
- .ToArray());
- }
- }
- ```
-
- 如何影射`Result`结果呢?
-
- ```
- public class TranslateResultToActionResultAttribute : ActionFilterAttribute
- {
- public override void OnActionExecuted(ActionExecutedContext context)
- {
- if (!((context.Result as ObjectResult)?.Value is IResult result)) return;
-
- if (!(context.Controller is ControllerBase controller)) return;
-
- //判断IResult的ResultStatus
- if (result.Status == ResultStatus.NotFound)
- context.Result = controller.NotFound();
-
- if (result.Status == ResultStatus.Invalid)
- {
- foreach (var error in result.ValidationErrors)
- {
- // TODO: Fix after updating to 3.0.0
- (context.Controller as ControllerBase)?.ModelState.AddModelError(error.Identifier, error.ErrorMessage);
- }
-
- context.Result = controller.BadRequest(controller.ModelState);
- }
-
- if (result.Status == ResultStatus.Ok)
- {
- context.Result = new OkObjectResult(result.GetValue());
- }
- }
- }
- ```
-
- `IResult`
-
- ```
- public interface IResult
- {
- ResultStatus Status { get; }
- IEnumerable<string> Errors { get; }
- List<ValidationError> ValidationErrors { get; }
- Type ValueType { get; }
- Object GetValue();
- }
- ```
-
- `ResultStatus`
-
- ```
- public enum ResultStatus
- {
- Ok,
- Error,
- Forbidden,
- Invalid,
- NotFound
- }
- ```
-
|