public async Task ExecuteAsync(QueryContext context) { if (context.IsArrayModel()) { var models = context.ToModels <T>() ?? throw new QueryException("models is required", QueryErrorCode.BadRequest); var errors = new List <RecordError>(models.Length); if (context.Descriptor.Validate) { var validationContext = new ValidationContext <T>(context); for (var index = 0; index < models.Length; ++index) { var model = models[index]; var validationResult = await validationContext.ValidateAsync(model, context.CancellationToken); if (validationResult.IsValid) { continue; } errors.Add(new RecordError { ErrorCode = QueryErrorCode.ValidationError, ErrorDescription = QueryErrorCode.ValidationError.ToString(), At = index, Details = validationResult.Errors }); } if (errors.Count > 0) { context.Fail(errors, QueryErrorCode.ValidationError, QueryErrorCode.ValidationError.ToString()); return; } } if (context.Descriptor.OnlyOwnerCanUpdate) { var authContext = new AuthorizationContext <T>(context); await _repo.UpdateRangeAsync(models, async (newDto, oldDto, index, continuation, cancellationToken) => { var authorized = await authContext.AuthorizeAsync(oldDto, context.Descriptor.UpdatePolicy); if (authorized) { return(true); } errors.Add(new RecordError { ErrorCode = QueryErrorCode.Unauthorized, ErrorDescription = QueryErrorCode.Unauthorized.ToString(), At = index }); continuation.Yes = true; return(false); }, (dto, index, continuation) => { errors.Add(new RecordError { ErrorCode = QueryErrorCode.NotFound, ErrorDescription = QueryErrorCode.NotFound.ToString(), At = index }); continuation.Yes = true; }, context.CancellationToken); } else { await _repo.UpdateRangeAsync(models, (dto, index, continuation) => { errors.Add(new RecordError { ErrorCode = QueryErrorCode.NotFound, ErrorDescription = QueryErrorCode.NotFound.ToString(), At = index }); continuation.Yes = true; }, context.CancellationToken); } if (errors.Count > 0) { context.Fail(errors, QueryErrorCode.UnauthorizedOrNotFound, "unauthorized or not found to update"); } else { context.Succeed(models); } } else { var model = context.ToModel <T>() ?? throw new QueryException("model is required", QueryErrorCode.BadRequest); if (context.Descriptor.Validate) { var validationContext = new ValidationContext <T>(context); var validationResult = await validationContext.ValidateAsync(model, context.CancellationToken); if (!validationResult.IsValid) { context.Fail(validationResult.Errors, QueryErrorCode.ValidationError, QueryErrorCode.ValidationError.ToString()); return; } } if (context.Descriptor.OnlyOwnerCanUpdate) { var authContext = new AuthorizationContext <T>(context); await _repo.UpdateAsync(model, async (newDto, oldDto, cancellationToken) => { var authorized = await authContext.AuthorizeAsync(oldDto, context.Descriptor.UpdatePolicy); if (authorized) { return(true); } context.Fail(newDto, QueryErrorCode.Unauthorized, "unauthorized"); return(false); }, (dto) => context.Fail(dto, QueryErrorCode.NotFound, "not found"), context.CancellationToken); } else { await _repo.UpdateAsync(model, (dto) => context.Fail(dto, QueryErrorCode.NotFound, "not found"), context.CancellationToken); } if (!context.HasError) { context.Succeed(model); } } }