以干净的方式在 Asp.Net Core API 中实现 ProblemDetails 的最佳方法

2023-11-27

我需要使用问题详情对于验证错误。它按预期工作。但这里有一个大问题,我必须在所有操作方法中编写类似的代码,我认为这不是一个好主意。

public async Task<ActionResult<SampleResponse>> Post([FromBody] SampleRequest getRateApiRequest)
{
    try
    {
        if (ModelState.IsValid == false)
        {
            ProblemDetails problemDetails = new ProblemDetails();
            problemDetails.Detail = "Detail";
            problemDetails.Instance = "Instance";
            problemDetails.Status = StatusCodes.Status400BadRequest;
            problemDetails.Title = "Title";
            problemDetails.Type = "Type";

            List<FieldCodeMessage> codeMessages = new List<FieldCodeMessage>();
            foreach (var modelState in ModelState)
            {
                if (modelState.Value.ValidationState == Microsoft.AspNetCore.Mvc.ModelBinding.ModelValidationState.Invalid)
                {
                    MemberInfo property = typeof(TradeBookingRequestAPI).GetProperty(modelState.Key);
                    var attribute = property.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().Single();
                    string displayName = attribute.DisplayName;
                    switch (modelState.Key)
                    {
                        case "Property1":
                            codeMessages.Add(new FieldCodeMessage(field: displayName, code: "01", message: modelState.Value.Errors.Select(a => a.ErrorMessage).FirstOrDefault()));
                            break;
                        case "Property2":
                            codeMessages.Add(new FieldCodeMessage(field: displayName, code: "02", message: modelState.Value.Errors.Select(a => a.ErrorMessage).FirstOrDefault()));
                            break;
                        case "Property3":
                            codeMessages.Add(new FieldCodeMessage(field: displayName, code: "03", message: modelState.Value.Errors.Select(a => a.ErrorMessage).FirstOrDefault()));
                            break;
                        case "Property4":
                            codeMessages.Add(new FieldCodeMessage(field: displayName, code: "04", message: modelState.Value.Errors.Select(a => a.ErrorMessage).FirstOrDefault()));
                            break;
                        case "Property5":
                            codeMessages.Add(new FieldCodeMessage(field: displayName, code: "05", message: modelState.Value.Errors.Select(a => a.ErrorMessage).FirstOrDefault()));
                            break;
                        case "Property6":
                            codeMessages.Add(new FieldCodeMessage(field: displayName, code: "06", message: modelState.Value.Errors.Select(a => a.ErrorMessage).FirstOrDefault()));
                            break;
                    }
                }
            }

            problemDetails.Extensions.Add("Invalid Fields", codeMessages);

            return BadRequest(problemDetails);
        }
    }
    catch (Exception)
    {
        ...
    }
}

那么有没有办法在集中的地方(例如中间件或其他东西)来处理这个问题。

预期回应:

{
    "type": "Type",
    "title": "Title",
    "status": 400,
    "detail": "Detail",
    "instance": "Instance",
    "Invalid Fields": [
        {
            "field": "Proprty 1",
            "code": "01",
            "message": "Invalid Proprty 1"
        },
        {
            "field": "Property 2",
            "code": "02",
            "message": "Invalid Property 2"
        }
    ]
}

我已经延长了ValidationAttribute实现所有属性的验证逻辑,下面是实现Property1.

protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
    try
    {
        if (value != null)
        {
            propertyDisplayName = validationContext.DisplayName;
            long property1 = (Int64)value;
            Match match = Regex.Match($"{property1}", @"^\d+$", RegexOptions.IgnoreCase);

            if (!string.IsNullOrWhiteSpace($"{property1}") && match.Success)
            {
                return ValidationResult.Success;
            }
            else
            {
                return new ValidationResult($"Invalid {propertyDisplayName}");
            }

        }
        else
        {
            return new ValidationResult($"Invalid {propertyDisplayName}");
        }
    }
    catch (Exception ex)
    {
        ...
    }
}

如果有办法在扩展中处理这种情况ValidationAttribute课程也对我有用。

Note:目标框架是.Net5


我可以通过使用下面的代码来解决这个问题ConfigureServicesStartup.cs 的方法。

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Latest).ConfigureApiBehaviorOptions(options =>
{
    options.InvalidModelStateResponseFactory = c =>
    {
        ProblemDetails problemDetails = new ProblemDetails();
        problemDetails.Status = StatusCodes.Status400BadRequest;
        problemDetails.Title = "One or more validation errors occurred.";
        problemDetails.Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1";
        
        List<FieldCodeMessage> codeMessages = new List<FieldCodeMessage>();
        foreach (var modelState in c.ModelState)
        {
            if (modelState.Value.ValidationState == Microsoft.AspNetCore.Mvc.ModelBinding.ModelValidationState.Invalid)
            {
                string[] errorMessageCode = modelState.Value.Errors.Select(a => a.ErrorMessage).FirstOrDefault().Split(':');
                string code = errorMessageCode[0];
                string message = errorMessageCode[1];

                codeMessages.Add(new FieldCodeMessage(field: modelState.Key, code: code, message: message));
            }
        }

        problemDetails.Extensions.Add("Invalid Fields", codeMessages);

        return new BadRequestObjectResult(problemDetails);
    };
});

我必须使用一种技巧来通过使用:像这样的分隔符IsValid扩展方法ValidationAttribute.

return new ValidationResult("01:Proprty 1");

如果大家有更好的方法或者建议,欢迎评论留言。我很高兴知道。

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

以干净的方式在 Asp.Net Core API 中实现 ProblemDetails 的最佳方法 的相关文章

  • 尝试了解使用服务打开对话框

    我已经阅读了有关使用 mvvm 模式打开对话框的讨论 我看过几个使用服务的示例 但我不明白所有部分如何组合在一起 我发布这个问题寻求指导 以了解我应该阅读哪些内容 以更好地理解我所缺少的内容 我将在下面发布我所拥有的内容 它确实有效 但从我
  • 在 CPP 类中将 C 函数声明为友元

    我需要在 C 函数中使用类的私有变量 我正在做这样的事情 class Helper private std string name public std getName return name friend extern C void in
  • Grpc - 将消息从一个客户端发送到连接到同一服务器的另一个客户端

    是否可以将消息从一个客户端发送到连接到同一服务器的另一个客户端 我想将数据从一个客户端发送到服务器然后发送到特定客户端 我想我需要获取客户端 ID 但我不知道如何获取此 ID 以及如何从服务器将此消息发送到该客户端 我这里有一个样本 这是一
  • Rx.NET 中是否有一个Subject 实现,其功能类似于BehaviourSubject,但仅在值发生更改时才发出?

    有没有Subject https learn microsoft com en us previous versions dotnet reactive extensions hh229699 v vs 103 Rx NET 中的实现在功能
  • 转换 const void*

    我有一个函数返回一个const void 我想用它的信息作为char 我可以将它投射为 C 风格的罚款 char variable但是当我尝试使用reinterpret cast like reinterpret cast
  • 如何在类文件中使用 Url.Action() ?

    如何在 MVC 项目的类文件中使用 Url Action Like namespace 3harf public class myFunction public static void CheckUserAdminPanelPermissi
  • 按扩展名过滤搜索文件返回太多结果

    我正在开发一个 C 控制台应用程序 它必须管理 Windows 操作系统上的文件 我需要获取具有特定扩展名的文件名 列表 我找到了很多解决方案 最建议的是以下一种 HANDLE hFind WIN32 FIND DATA data hFin
  • MVC3中设置下拉列表中的所选项目

    我必须为视图中的下拉列表设置所选项目 但它不起作用 View div class editor label Html LabelFor model gt model Gender div div class editor field Htm
  • 当事件button.click发生时,如何获取按钮名称/标签?

    我以编程方式制作按钮并将它们添加到堆栈面板中 以便每次用户导航到页面时按钮都会发生变化 我正在尝试做这样的事情 当我单击创建的按钮时 它将获取按钮的标签并转到正确的页面 但是 我无法使用 RoutedEventHandler 访问按钮元素
  • extern 声明和函数定义都在同一文件中

    我只是浏览了一下gcc源文件 在gcc c 我发现了类似的东西 extern int main int char int main int argc char argv 现在我的疑问是extern是告诉编译器特定的函数不在这个文件中 但可以
  • cpp.react库的C++源代码中奇怪的“->* []”表达式

    这是我在文档中找到的 C 片段cpp react 库 https github com schlangster cpp react implicit parallelism auto in D MakeVar 0 auto op1 in g
  • 如果输入被重定向则执行操作

    我想知道如果我的输入被重定向 我应该如何在 C 程序中执行操作 例如 假设我有已编译的程序 prog 并且我将输入 input txt 重定向到它 我这样做 prog lt input txt 我如何在代码中检测到这一点 一般来说 您无法判
  • 不可变类与结构

    以下是类与 C 中的结构的唯一区别 如果我错了 请纠正我 类变量是引用 而结构变量是值 因此在赋值和参数传递中复制结构的整个值 类变量是存储在堆栈上的指针 指向堆上的内存 而结构变量作为值存储在堆上 假设我有一个不可变的结构 该结构的字段一
  • 模板外部链接?谁能解释一下吗?

    模板名称具有链接 3 5 非成员函数模板可以有内部链接 任何其他模板名称应具有外部链接 从具有内部链接的模板生成的实体与在其他翻译单元中生成的所有实体不同 我知道使用关键字的外部链接 extern C EX extern C templat
  • 在 C# 中为父窗体中的子窗体控件添加事件处理程序

    我有两种形式 一种是带有按钮和文本框的父表单 单击该按钮时 将打开一个对话框 该子窗体又包含一个文本框和一个按钮 现在我想要的是 每当子表单文本框中的文本更改时 父表单文本框中的文本会自动更改 为了获得这个 我所做的是 Form3 f3 n
  • memcpy/memmove 到联合成员,这是否设置“活动”成员?

    重要说明 一些评论者似乎认为我是从工会抄袭的 仔细看memcpy 它从普通旧地址复制uint32 t 它不包含在联合中 另外 我正在复制 通过memcpy 到工会的特定成员 u a16 or u x in a union 不直接到整个联盟本
  • 比较:接口方法、虚方法、抽象方法

    它们各自的优点和缺点是什么 接口方法 虚拟方法 抽象方法 什么时候应该选择什么 做出这一决定时应牢记哪些要点 虚拟和抽象几乎是一样的 虚方法在基类中有一个实现 可以选择重写 而抽象方法则没有 并且must在子类中被覆盖 否则它们是相同的 在
  • C++:二叉树所有节点值的总和

    我正在准备面试 我被一个二叉树问题困住了 我们如何计算二叉树所有节点中存在的值的总和 优雅的递归解决方案 伪代码 def sum node if node NULL return 0 return node gt value sum nod
  • 了解 Lambda 表达式和委托 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我已经尝试解决这个问题很长一段时间了 阅读在线博客和文章 但到目前为止还没有成功 什么是代表 什么是 Lambda 表达式 两者的优点
  • 在 System.Type 上使用条件断点时出错

    这是函数 public void Init System Type Type this Type Type BuildFieldAttributes BuildDataColumns FieldAttributes 我在第一行设置了一个断点

随机推荐