欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

.NET 6開發(fā)TodoList應(yīng)用之實(shí)現(xiàn)接口請(qǐng)求驗(yàn)證

 更新時(shí)間:2021年12月30日 08:35:35   作者:CODE4NOTHING  
在響應(yīng)請(qǐng)求處理的過(guò)程中,我們經(jīng)常需要對(duì)請(qǐng)求參數(shù)的合法性進(jìn)行校驗(yàn),如果參數(shù)不合法,將不繼續(xù)進(jìn)行業(yè)務(wù)邏輯的處理。本文將介紹如何使用FluentValidation和MediatR實(shí)現(xiàn)接口請(qǐng)求驗(yàn)證,需要的可以參考一下

需求

在響應(yīng)請(qǐng)求處理的過(guò)程中,我們經(jīng)常需要對(duì)請(qǐng)求參數(shù)的合法性進(jìn)行校驗(yàn),如果參數(shù)不合法,將不繼續(xù)進(jìn)行業(yè)務(wù)邏輯的處理。我們當(dāng)然可以將每個(gè)接口的參數(shù)校驗(yàn)邏輯寫到對(duì)應(yīng)的Handle方法中,但是更好的做法是借助MediatR提供的特性,將這部分與實(shí)際業(yè)務(wù)邏輯無(wú)關(guān)的代碼整理到單獨(dú)的地方進(jìn)行管理。

為了實(shí)現(xiàn)這個(gè)需求,我們需要結(jié)合FluentValidation和MediatR提供的特性。

目標(biāo)

將請(qǐng)求的參數(shù)校驗(yàn)邏輯從CQRS的Handler中分離到MediatR的Pipeline框架中處理。

原理與思路

MediatR不僅提供了用于實(shí)現(xiàn)CQRS的框架,還提供了IPipelineBehavior<TRequest, TResult>接口用于實(shí)現(xiàn)CQRS響應(yīng)之前進(jìn)行一系列的與實(shí)際業(yè)務(wù)邏輯不緊密相關(guān)的特性,諸如請(qǐng)求日志、參數(shù)校驗(yàn)、異常處理、授權(quán)、性能監(jiān)控等等功能。

在本文中我們將結(jié)合FluentValidation和IPipelineBehavior<TRequest, TResult>實(shí)現(xiàn)對(duì)請(qǐng)求參數(shù)的校驗(yàn)功能。

實(shí)現(xiàn)

添加MediatR參數(shù)校驗(yàn)Pipeline Behavior框架支持#

首先向Application項(xiàng)目中引入FluentValidation.DependencyInjectionExtensionsNuget包。為了抽象所有的校驗(yàn)異常,先創(chuàng)建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)
    {
    }
}

參數(shù)校驗(yàn)的基礎(chǔ)框架我們創(chuàng)建到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校驗(yàn)失敗,拋出異常,這里的異常是我們自定義的包裝類型
            if (failures.Any())
                throw new ValidationException(GetValidationErrorMessage(failures));
        }
        return await next();
    }

    // 格式化校驗(yàn)失敗消息
    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中進(jìn)行依賴注入:

DependencyInjection.cs

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

添加Validation Pipeline Behavior

接下來(lái)我們以添加TodoItem接口為例,在Application/TodoItems/CreateTodoItem/中創(chuàng)建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;

        // 我們把最大長(zhǎng)度限制到10,以便更好地驗(yàn)證這個(gè)校驗(yàn)
        // 更多的用法請(qǐng)參考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);
    }
}

其他接口的參數(shù)校驗(yàn)添加方法與此類似,不再繼續(xù)演示。

驗(yàn)證

啟動(dòng)Api項(xiàng)目,我們用一個(gè)校驗(yàn)會(huì)失敗的請(qǐng)求去創(chuàng)建TodoItem:

請(qǐng)求

響應(yīng)

因?yàn)橹皽y(cè)試的時(shí)候已經(jīng)在沒有加校驗(yàn)的時(shí)候用同樣的請(qǐng)求生成了一個(gè)TodoItem,所以校驗(yàn)失敗的消息里有兩項(xiàng)校驗(yàn)都沒有滿足。

一點(diǎn)擴(kuò)展

我們?cè)谇拔闹姓f(shuō)了使用MediatR的PipelineBehavior可以實(shí)現(xiàn)在CQRS請(qǐng)求前執(zhí)行一些邏輯,其中就包含了日志記錄,這里就把實(shí)現(xiàn)方式也放在下面,在這里我們使用的是Pipeline里的IRequestPreProcessor<TRequest>接口實(shí)現(xiàn),因?yàn)橹魂P(guān)心請(qǐng)求處理前的信息,如果關(guān)心請(qǐng)求處理返回后的信息,那么和前文一樣,需要實(shí)現(xiàn)IPipelineBehavior<TRequest, TResponse>接口并在Handle中返回response對(duì)象:

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

return response;

創(chuàng)建一個(gè)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;

    // 在構(gòu)造函數(shù)中后面我們還可以注入類似ICurrentUser和IIdentity相關(guān)的對(duì)象進(jìn)行日志輸出
    public LoggingBehaviour(ILogger<LoggingBehaviour<TRequest>> logger)
    {
        _logger = logger;
    }

    public async Task Process(TRequest request, CancellationToken cancellationToken)
    {
        // 你可以在這里log關(guān)于請(qǐng)求的任何信息
        _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);
        }
    }
}

如果是實(shí)現(xiàn)IPipelineBehavior<TRequest, TResponse>接口,最后注入即可。

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

如果實(shí)現(xiàn)IRequestPreProcessor<TRequest>接口,則不需要再進(jìn)行注入。

效果如下圖所示:

可以看到日志中已經(jīng)輸出了Command名稱和請(qǐng)求參數(shù)字段值。

總結(jié)

在本文中我們通過(guò)FluentValidation和MediatR實(shí)現(xiàn)了不侵入業(yè)務(wù)代碼的請(qǐng)求參數(shù)校驗(yàn)邏輯,在下一篇文章中我們將介紹.NET開發(fā)中會(huì)經(jīng)常用到的ActionFilters。

參考資料

FluentValidation

How to use MediatR Pipeline Behaviours?

到此這篇關(guān)于.NET 6開發(fā)TodoList應(yīng)用之實(shí)現(xiàn)接口請(qǐng)求驗(yàn)證的文章就介紹到這了,更多相關(guān).NET 6接口請(qǐng)求驗(yàn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • asp.net窗體操作總結(jié)

    asp.net窗體操作總結(jié)

    這些代碼全部寫在和頁(yè)面分離的代碼頁(yè)中(codebehind),如果要嵌入到*.aspx頁(yè)面,可能會(huì)出現(xiàn)問(wèn)題.
    2008-11-11
  • gridview自動(dòng)排序示例分享

    gridview自動(dòng)排序示例分享

    GridView自帶了數(shù)據(jù)排序功能。在設(shè)計(jì)視圖下,只能對(duì)GridView的排序數(shù)據(jù)列和排序方向進(jìn)行靜態(tài)設(shè)置。在后臺(tái)程序中,則需要用Attributes方式對(duì)GridView的這兩個(gè)屬性進(jìn)行動(dòng)態(tài)設(shè)置
    2014-01-01
  • 一個(gè)ASP.Net下的WebShell實(shí)例

    一個(gè)ASP.Net下的WebShell實(shí)例

    一個(gè)ASP.Net下的WebShell,主要完成cmd命令。一般的服務(wù)器設(shè)置,asp.net用戶的權(quán)限都比較高。如果asp的webshell無(wú)法執(zhí)行,可能asp.net的可以執(zhí)行。
    2013-07-07
  • ASP.NET?Core使用自定義日志中間件

    ASP.NET?Core使用自定義日志中間件

    這篇文章介紹了ASP.NET?Core使用自定義日志中間件的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • asp.net gridview指定某一列滾動(dòng)

    asp.net gridview指定某一列滾動(dòng)

    gridview指定某一列滾動(dòng)的asp.net實(shí)現(xiàn)代碼。
    2009-11-11
  • .NET性能優(yōu)化之為集合類型設(shè)置初始大小的方法

    .NET性能優(yōu)化之為集合類型設(shè)置初始大小的方法

    這篇文章主要介紹了.NET性能優(yōu)化之為集合類型設(shè)置初始大小的方法,今天要談的一個(gè)性能優(yōu)化的Tips是一個(gè)老生常談的點(diǎn),但是也是很多人沒有注意的一個(gè)點(diǎn)。在使用集合類型是,你應(yīng)該設(shè)置一個(gè)預(yù)估的初始大小,那么為什么需要這樣做?我們一起來(lái)從源碼的角度說(shuō)一說(shuō)
    2022-05-05
  • 列舉ASP.NET頁(yè)面之間傳遞值的幾種方式

    列舉ASP.NET頁(yè)面之間傳遞值的幾種方式

    這篇文章主要介紹了列舉ASP.NET 頁(yè)面之間傳遞值的幾種方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-03-03
  • 使用 ServiceStack.Text 序列化 json的實(shí)現(xiàn)代碼

    使用 ServiceStack.Text 序列化 json的實(shí)現(xiàn)代碼

    今天發(fā)篇文章總結(jié)下自己使用 ServiceStack.Text 來(lái)序列化 json。它的速度比 Newtonsoft.Json 快很多,在測(cè)試時(shí)發(fā)現(xiàn)比 fastJson 還快些
    2013-06-06
  • .Net Core日志記錄之自定義日志組件

    .Net Core日志記錄之自定義日志組件

    這篇文章介紹了.Net Core日志記錄之自定義日志組件,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • 在 ASP.Net Core 中使用 MiniProfiler的方法

    在 ASP.Net Core 中使用 MiniProfiler的方法

    這篇文章主要介紹了在 ASP.Net Core 中使用 MiniProfiler的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03

最新評(píng)論