iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > ASP.NET >.NET6开发TodoList应用之实现接口请求验证
  • 725
分享到

.NET6开发TodoList应用之实现接口请求验证

2024-04-02 19:04:59 725人浏览 薄情痞子
摘要

目录需求目标原理与思路实现验证一点扩展总结参考资料需求 在响应请求处理的过程中,我们经常需要对请求参数的合法性进行校验,如果参数不合法,将不继续进行业务逻辑的处理。我们当然可以将每个

需求

在响应请求处理的过程中,我们经常需要对请求参数的合法性进行校验,如果参数不合法,将不继续进行业务逻辑的处理。我们当然可以将每个接口的参数校验逻辑写到对应的Handle方法中,但是更好的做法是借助MediatR提供的特性,将这部分与实际业务逻辑无关的代码整理到单独的地方进行管理。

为了实现这个需求,我们需要结合FluentValidation和MediatR提供的特性。

目标

将请求的参数校验逻辑从CQRS的Handler中分离到MediatR的Pipeline框架中处理。

原理与思路

MediatR不仅提供了用于实现CQRS的框架,还提供了IPipelineBehavior<TRequest, TResult>接口用于实现CQRS响应之前进行一系列的与实际业务逻辑不紧密相关的特性,诸如请求日志、参数校验、异常处理、授权、性能监控等等功能。

在本文中我们将结合FluentValidation和IPipelineBehavior<TRequest, TResult>实现对请求参数的校验功能。

实现

添加MediatR参数校验Pipeline Behavior框架支持#

首先向Application项目中引入FluentValidation.DependencyInjectionExtensionsNuget包。为了抽象所有的校验异常,先创建ValidationException类:

ValidationException.cs


namespace TodoList.Application.Common.Exceptions;

public class ValidationException : Exception
{
    public ValidationException() : base("One or more validation failures have occurred.")
    {
    }

    public ValidationException(string failures)
        : base(failures)
    {
    }
}

参数校验的基础框架我们创建到Application/Common/Behaviors/中:

ValidationBehaviour.cs


using FluentValidation;
using FluentValidation.Results;
using MediatR;
using ValidationException = TodoList.Application.Common.Exceptions.ValidationException;

namespace TodoList.Application.Common.Behaviors;

public class ValidationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : notnull
{
    private readonly IEnumerable<IValidator<TRequest>> _validators;

    // 注入所有自定义的Validators
    public ValidationBehaviour(IEnumerable<IValidator<TRequest>> validators) 
        => _validators = validators;

    public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
    {
        if (_validators.Any())
        {
            var context = new ValidationContext<TRequest>(request);

            var validationResults = await Task.WhenAll(_validators.Select(v => v.ValidateAsync(context, cancellationToken)));

            var failures = validationResults
                .Where(r => r.Errors.Any())
                .SelectMany(r => r.Errors)
                .ToList();

            // 如果有validator校验失败,抛出异常,这里的异常是我们自定义的包装类型
            if (failures.Any())
                throw new ValidationException(GetValidationErrORMessage(failures));
        }
        return await next();
    }

    // 格式化校验失败消息
    private string GetValidationErrorMessage(IEnumerable<ValidationFailure> failures)
    {
        var failureDict = failures
            .GroupBy(e => e.PropertyName, e => e.ErrorMessage)
            .ToDictionary(failureGroup => failureGroup.Key, failureGroup => failureGroup.ToArray());

        return string.Join(";", failureDict.Select(kv => kv.Key + ": " + string.Join(' ', kv.Value.ToArray())));
    }
}

在DependencyInjection中进行依赖注入:

DependencyInjection.cs


// 省略其他...
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>) 

添加Validation Pipeline Behavior

接下来我们以添加TodoItem接口为例,在Application/TodoItems/CreateTodoItem/中创建CreateTodoItemCommandValidator:

CreateTodoItemCommandValidator.cs


using FluentValidation;
using Microsoft.EntityFrameworkCore;
using TodoList.Application.Common.Interfaces;
using TodoList.Domain.Entities;

namespace TodoList.Application.TodoItems.Commands.CreateTodoItem;

public class CreateTodoItemCommandValidator : AbstractValidator<CreateTodoItemCommand>
{
    private readonly IRepository<TodoItem> _repository;

    public CreateTodoItemCommandValidator(IRepository<TodoItem> repository)
    {
        _repository = repository;

        // 我们把最大长度限制到10,以便更好地验证这个校验
        // 更多的用法请参考FluentValidation官方文档
        RuleFor(v => v.Title)
            .MaximumLength(10).WithMessage("TodoItem title must not exceed 10 characters.").WithSeverity(Severity.Warning)
            .NotEmpty().WithMessage("Title is required.").WithSeverity(Severity.Error)
            .MustAsync(BeUniqueTitle).WithMessage("The specified title already exists.").WithSeverity(Severity.Warning);
    }

    public async Task<bool> BeUniqueTitle(string title, CancellationToken cancellationToken)
    {
        return await _repository.GetAsQueryable().AllAsync(l => l.Title != title, cancellationToken);
    }
}

其他接口的参数校验添加方法与此类似,不再继续演示。

验证

启动api项目,我们用一个校验会失败的请求去创建TodoItem:

请求

响应

因为之前测试的时候已经在没有加校验的时候用同样的请求生成了一个TodoItem,所以校验失败的消息里有两项校验都没有满足。

一点扩展

我们在前文中说了使用MediatR的PipelineBehavior可以实现在CQRS请求前执行一些逻辑,其中就包含了日志记录,这里就把实现方式也放在下面,在这里我们使用的是Pipeline里的IRequestPreProcessor<TRequest>接口实现,因为只关心请求处理前的信息,如果关心请求处理返回后的信息,那么和前文一样,需要实现IPipelineBehavior<TRequest, TResponse>接口并在Handle中返回response对象:


// 省略其他...
var response = await next();
//Response
_logger.LogInformation($"Handled {typeof(TResponse).Name}");

return response;

创建一个LoggingBehavior:


using System.Reflection;
using MediatR.Pipeline;
using Microsoft.Extensions.Logging;

public class LoggingBehaviour<TRequest> : IRequestPreProcessor<TRequest> where TRequest : notnull
{
    private readonly ILogger<LoggingBehaviour<TRequest>> _logger;

    // 在构造函数中后面我们还可以注入类似ICurrentUser和IIdentity相关的对象进行日志输出
    public LoggingBehaviour(ILogger<LoggingBehaviour<TRequest>> logger)
    {
        _logger = logger;
    }

    public async Task Process(TRequest request, CancellationToken cancellationToken)
    {
        // 你可以在这里log关于请求的任何信息
        _logger.LogInformation($"Handling {typeof(TRequest).Name}");

        IList<PropertyInfo> props = new List<PropertyInfo>(request.GetType().GetProperties());
        foreach (var prop in props)
        {
            var propValue = prop.GetValue(request, null);
            _logger.LogInformation("{Property} : {@Value}", prop.Name, propValue);
        }
    }
}

如果是实现IPipelineBehavior<TRequest, TResponse>接口,最后注入即可。


// 省略其他...
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehaviour<,>));

如果实现IRequestPreProcessor<TRequest>接口,则不需要再进行注入。

效果如下图所示:

可以看到日志中已经输出了Command名称和请求参数字段值。

总结

在本文中我们通过FluentValidation和MediatR实现了不侵入业务代码的请求参数校验逻辑,在下一篇文章中我们将介绍.net开发中会经常用到的ActionFilters。

参考资料

FluentValidation

How to use MediatR Pipeline Behaviours 

到此这篇关于.NET 6开发TodoList应用之实现接口请求验证的文章就介绍到这了,更多相关.NET 6接口请求验证内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: .NET6开发TodoList应用之实现接口请求验证

本文链接: https://www.lsjlt.com/news/161199.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • .NET6开发TodoList应用之实现接口请求验证
    目录需求目标原理与思路实现验证一点扩展总结参考资料需求 在响应请求处理的过程中,我们经常需要对请求参数的合法性进行校验,如果参数不合法,将不继续进行业务逻辑的处理。我们当然可以将每个...
    99+
    2024-04-02
  • .NET6开发TodoList应用之实现PUT请求
    目录需求目标原理与思路实现PUT请求领域事件的发布和响应验证总结需求 PUT请求本身其实可说的并不多,过程也和创建基本类似。在这篇文章中,重点是填上之前文章里留的一个坑,我们曾经给T...
    99+
    2024-04-02
  • .NET6开发TodoList应用之使用AutoMapper实现GET请求
    目录需求目标原理与思路实现引入AutoMapper实现GET请求验证获取所有TodoList列表获取单个TodoList详情填一个POST文章里的坑总结需求 需求很简单:实现GET请...
    99+
    2024-04-02
  • .NET6开发TodoList应用之实现ActionFilter
    目录需求目标原理与思路实现验证总结需求 Filter在.NET Web API项目开发中也是很重要的一个概念,它运行在执行MVC响应的Pipeline中执行,允许我们将一些可以在多个...
    99+
    2024-04-02
  • .NET6开发TodoList应用之实现查询排序
    目录需求目标原理与思路实现验证总结需求 关于查询的另一个需求是要根据前端请求的排序字段进行对结果相应的排序。 目标 实现根据排序要求返回排序后的结果 原理与思路 要实现根据前端请求的...
    99+
    2024-04-02
  • .NET6开发TodoList应用之实现查询分页
    目录需求目标原理与思路实现定义分页结果数据结构添加对于分页结果的Mapping Profile创建分页查询请求创建查询Controller验证总结需求 查询中有个非常常见的需求就是后...
    99+
    2024-04-02
  • .NET6开发TodoList应用之实现数据塑形
    目录需求目标原理与思路实现定义通用接口和泛型类实现定义扩展方法添加依赖注入修改查询请求和Controller接口验证总结需求 在查询的场景中,还有一类需求不是很常见,就是在前端请求中...
    99+
    2024-04-02
  • .NET 6开发TodoList应用之如何实现PUT请求
    这篇文章将为大家详细讲解有关.NET 6开发TodoList应用之如何实现PUT请求,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。需求PUT请求本身其实可说的并不多,过程也和创建基本类似。在这篇...
    99+
    2023-06-22
  • .NET6开发TodoList应用之实现API版本控制
    目录需求目标原理与思路实现添加Nuget Package并配置服务实现API版本控制一点扩展总结需求 API接口版本管理,对于一些规模稍大的企业应用来说,是经常需要关注的一大需求。尽...
    99+
    2024-04-02
  • .NET 6开发TodoList应用之使用MediatR实现POST请求
    目录需求目标原理与思路CQRS模式中介者Mediator模式MediatR实现引入MediatR实现Post请求验证创建TodoList验证创建TodoItem验证总结参考资料需求 ...
    99+
    2024-04-02
  • .NET 6开发TodoList应用之实现DELETE请求与HTTP请求幂等性
    目录需求目标原理与思路实现验证总结需求 先说明一下关于原本想要去更新的PATCH请求的文章,从目前试验的情况来看,如果是按照.NET 6的项目结构(即只使用一个Program.cs完...
    99+
    2024-04-02
  • .NET6开发TodoList应用之实现全局异常处理
    目录需求目标原理和思路实现验证总结参考资料需求 因为在项目中,会有各种各样的领域异常或系统异常被抛出来,那么在Controller里就需要进行完整的try-catch捕获,并根据是否...
    99+
    2024-04-02
  • .NET6开发TodoList应用实现结构搭建
    目录1.TodoList需求简介2.开发工具2.1.NET 62.2Visual Studio Code2.3Hoppscotch3.Clean Architecture简介4.搭建...
    99+
    2024-04-02
  • .NET 6开发TodoList应用中如何实现DELETE请求与HTTP请求幂等性
    本篇文章为大家展示了.NET 6开发TodoList应用中如何实现DELETE请求与HTTP请求幂等性,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。需求先说明一下关于原本想要去更新的PAT...
    99+
    2023-06-22
  • .NET 6开发TodoList应用之请求日志组件HttpLogging介绍
    背景 因为在上篇演示Action Filter的时候可能是因为举的例子不够好,有小伙伴在评论区指出.NET 6新增加的特性可以实现在视图模型绑定之前允许记录Http请求日志的组件:H...
    99+
    2024-04-02
  • .NET 6开发TodoList应用之实现Repository模式
    目录需求目标原理和思路实现通用Repository实现引入使用验证总结参考资料需求 经常写CRUD程序的小伙伴们可能都经历过定义很多Repository接口,分别做对应的实现,依赖注...
    99+
    2024-04-02
  • .NET 6开发TodoList应用怎么实现
    这篇文章主要介绍“.NET 6开发TodoList应用怎么实现”,在日常操作中,相信很多人在.NET 6开发TodoList应用怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”.NE...
    99+
    2023-06-22
  • Python自动化实战之接口请求的实现
    目录使用 Python 发送 请求Python 发送请求的方式requests 库的配置天行数据 - 空气质量接口利用 requests 发送查询 空气质量接口 请求在前文说过,如果...
    99+
    2024-04-02
  • .NET 6开发TodoList应用实现系列背景
    目录1.列说明2.系列导航2.1 使用.NET 6开发TodoList应用文章索引2.1.1创建项目2.1.2.NET 6 WebAPI Program.cs的变更2.1.3Chan...
    99+
    2024-04-02
  • Python应用开发之实现串口通信
    目录前言1.环境搭建2.硬件准备3.代码编写与测试3.1 简单测一下串口收发3.2 补充细节3.3 完善整个收发流程前言 在嵌入式开发中我们经常会用到串口,串口通信简单,使用起来方便...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作