在 .NET 7 中使用过滤器

2024-03-03

自从 .NET 6 中发布以来,我一直在使用 Minimal API。为了进行验证,我一直使用手动方法,如下所示:

app.MapPost("api/user", async ([FromService] IValidator<UserDto> validator, [FromBody] UserDto user) => 
{
   var validationResult = await validator.ValidateAsync(user);

   if (!validationResult.IsValid)
   {
      return Results.BadRequest(string.Join("/n", validationResult.Errors));
   }
  
  ...
})

随着 .NET 7 新版本的发布,包括Filters https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/min-api-filters?view=aspnetcore-7.0。我已经继续实现了一些功能。我创建了自定义验证过滤器,如下所示:

public class ValidationFilter<T> : IEndpointFilter where T : class
{
 private readonly IValidator<T> _validator;

 public ValidationFilter(IValidator<T> validator)
 {
    _validator = validator;
 }

 public async ValueTask<object> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
 {
    var obj = context.Arguments.FirstOrDefault(x => x?.GetType() == typeof(T)) as T;

    if (obj is null)
    {
        return Results.BadRequest();
    }
    
    var validationResult = await _validator.ValidateAsync(obj);

    if (!validationResult.IsValid)
    {
        return Results.BadRequest(string.Join("/n", validationResult.Errors));
    }

    return await next(context);
  }
}

我现在可以通过调用使用上面的内容AddEndPointFilter<T>()所以像这样:

app.MapPost("api/user", (..) => { ... }).AddEndPointFilter<ValidationFilter>();

上面的效果很好。不过,我有一些RuleSet()在我的 FluentValidation 中,我将其包含在PUT要求。所以我的问题是,如何将规则集传递给我的ValidationFilter?


一种方法是利用为端点提供元数据的能力。沿着这样的思路:

public class RuleSetMetadata<T>
{
    public RuleSetMetadata(string ruleSet)
    {
        RuleSet = ruleSet;
    }

    public string RuleSet { get; set; }
}

Setup:

app.MapPost("api/user", (Example e) =>  e)
    .AddEndpointFilter<ValidationFilter<Example>>()
    .WithMetadata(new RuleSetMetadata<Example>("Test"))

以及实施方面的变化:

public class ValidationFilter<T> : IEndpointFilter where T : class
{
    // ...

    public async ValueTask<object> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
    {
        string? ruleSet = null;
        if (context.HttpContext.GetEndpoint()?.Metadata.GetMetadata<RuleSetMetadata<T>>() is {} meta)
        {
            ruleSet = meta.RuleSet;
        }

        var validationResult = ruleSet is null
            ? await _validator.ValidateAsync(obj)
            : await _validator.ValidateAsync(obj, options => options.IncludeRuleSets(ruleSet));

        // ...
    }
}

另一种方法是查看AddEntpointFilterFactory并通过属性实现一些参数处理(可以使用 和这个结合var grp = app.MapGroup(""); grp.AddEndpointFilterFactory(...)).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 .NET 7 中使用过滤器 的相关文章

随机推荐

  • pdf.js 只适用于某些 pdf 文件吗?

    我正在尝试使用将 pdf 页面转换为画布pdf js 我使用了答案使用 pdf js 和 ImageData 将 pdf 渲染到单个 Canvas https stackoverflow com questions 15341010 ren
  • 在 pandas 数据框中添加缺失的时间

    我有一个pandas DataFrame在列中带有时间戳 这些值以纪元为单位 间隔 0 1 秒 价值观如1488771900 100000 1488771900 200000等等 但是 存在缺失值 所以我有1488794389 500000
  • 将文件编码为 Base64 时内存不足

    使用 Apache commons 中的 Base64 public byte encode File file throws FileNotFoundException IOException byte encoded try FileI
  • C++:C 字符串集

    我想创建一个 以便我可以使用 set find 检查某个单词是否在集合中 然而 C 字符串是指针 因此默认情况下该集合将通过指针值来比较它们 为了正确运行 必须取消引用它们并比较字符串 我可以只向构造函数传递一个指向 strcmp 函数的指
  • Python Moviepy安装问题(Windows 7x64)

    美好的一天 我在为 python 64 位和 Windows 64 位安装 moviepy 时遇到问题 库安装成功 文件ffmpeg下载 每次我运行它或使用 video VideoFileClip path OSError WinError
  • FirebaseobserveSingleEvent 保留在内存中

    我的应用程序相当多地使用 firebase 的observeSingleEventOfType 我开始意识到我的应用程序的内存随着时间的推移而增加 我已经注释掉了所有代码 除了调用以下函数的测试按钮 func loadPostsTest F
  • Windows 版 Git 中的文件名太长

    我在用着Git 1 9 0 preview20140217对于 Windows 据我所知 这个版本应该可以解决文件名太长的问题 但不适合我 我肯定做错了什么 我做错了git config core longpaths true and gi
  • OnTriggerEnter() 未调用

    我有一个玩家 球体 和 4 个敌人 胶囊 所有敌人都添加了角色控制器 它们还有一个子 GameObject 它具有一个 RigidBody 无质量 无重力 和一个附加的 Box Collider 盒子碰撞器足够大 因此您可以看到盒子内部的球
  • yocto 中的机器特定层

    我想为一台新机器 称之为 A 添加一些从上游获取的层 主要是为了使用这些层提供的机器 A 配置文件 内核和 u boot 然而 新层有几个 bbappend 文件 还有 bb 文件 其版本与我的 yocto 项目中其他机器的层不同 例如 机
  • 如何让 Org-mode 在当前窗口中打开像 [[file://file.org]] 这样的链接而不是在其他窗口中默认打开?

    我希望使用 C c C o 打开一个链接 例如 file filename org filename 在当前窗口中 而不是在其他窗口中的默认值 如何更改此组织模式默认行为 似乎是默认的 C u C c C o 是在其他窗口中强制打开链接 这
  • 从具有相同方法签名的多个接口继承的类

    假设我有三个接口 public interface I1 void XYZ public interface I2 void XYZ public interface I3 void XYZ 继承这三个接口的类 class ABC I1 I
  • 在 bookdown 文档中使用 R/exams(特别是 HTML 输出)

    我使用 bookdown 创建了一本 书 我希望能够添加交互式测验 而不需要闪亮等 是否可以使用 R exams http www R exams org http www R exams org 与预订 我主要对 HTML 输出感兴趣 P
  • 仅当索引为日期和时间时,如何根据时间选择 pandas 数据框中的行

    我有一个如下所示的数据框
  • Excel VBA如何从网络读取文本文件(未缓存)?

    我一直在使用以下代码从网络读取文本文件 import the text file into a string Function DownloadTextFile URL As String As String On Error GoTo E
  • R - 根据位置将纬度/经度点的巨大数据帧分组

    我是 R 新手 但我听说使用它确实是一个坏主意for循环 我有使用它们的工作代码 但我想改进它 因为它对于大数据来说非常慢 我已经有了一些如何改进算法的想法 但我不知道如何对其进行矢量化 或者在没有for loops 我只是将纬度 经度点分
  • .Net 属性网格。有没有办法让网格以不同的方式操作对象

    据我了解 属性网格被赋予一个对象 它可以通过使用反射提取其属性来操作该对象 我的问题是我有一组在运行时确定的参数 因此我无法静态地组成一个具有属性的类来表示这组参数 我有两个想法来解决这个问题 但这两个想法都很复杂 并且可能会消耗大量时间
  • 如果当天的闹钟时间已过,android会阻止立即触发闹钟服务

    警报管理器的参考资料说 如果指定的触发时间已经过去 则会触发警报 立即地 我在我的应用程序中面临这个问题 这是我的警报管理器代码 Intent myIntent new Intent getActivity DinnerAlarmRecei
  • Emacs:修复某些窗口的高度

    有没有办法像这样固定某个窗口的高度 汇编 缓冲区使用编译窗口高度 有window size fixed http www delorie com gnu docs elisp manual 21 elisp 441 html IDX1477
  • 沙盒解决方案似乎严重受损

    我正在学习 SharePoint 以及您可以部署的不同类型的解决方案 从我正在观看的培训来看 您似乎应该尽可能使用沙盒解决方案 这是因为农场解决方案可能会把事情搞得一团糟 但是 沙盒解决方案不支持我使用 WebPart 执行的两项主要操作
  • 在 .NET 7 中使用过滤器

    自从 NET 6 中发布以来 我一直在使用 Minimal API 为了进行验证 我一直使用手动方法 如下所示 app MapPost api user async FromService IValidator