尽管开放 API 规范 ASP.NET 将每个属性视为强制属性

2023-12-30

我通常直接生成服务器代码https://swagger.io/ https://swagger.io/在线服务

接下来,我决定添加更多自动化功能,因此我决定使用 CLI 工具aspnetcore发电机:https://openapi-generator.tech/docs/generators/aspnetcore https://openapi-generator.tech/docs/generators/aspnetcore

这是其中的重要部分电源外壳触发生成器的脚本:

"openapi-generator-cli generate -g aspnetcore -i $ymlPath -o $outPath " + `
    "--additional-properties=`"packageName=$projectName,nullableReferenceTypes=true,operationResultTask=true," +
    "operationModifier=$opModifier,generateBody=$generateBody,aspnetCoreVersion=5.0`"" | iex

带有模型架构的 YML 部分:

Profile:
  required: [ walletAddress, publicName ]
  properties:
    walletAddress:
      type: string
      example: '0x008F7c856B71190C6E44A51a30A4ec32F68545e0'
    type:
      type: string
      example: 'itemtype'
    id:
      type: string
      example: 'pre_LfeolJ7DINWPTmQzArvT'
    createdAt:
      type: string
      format: date-time
      example: '2022-03-29T16:59:22.9033559Z'  
    publicName:
      type: string
    publicSlugUrl:
      type: string
      format: url
    emailAddress:
      type: string
      format: email
    phoneNumber:
      type: string
    location:
      type: string
    about:
      type: string

生成的 C#:

namespace XxxxXxxxx.WebApi.Models
{ 
    [DataContract]
    public partial class Profile : IEquatable<Profile>
    {
        [Required]
        [DataMember(Name="walletAddress", EmitDefaultValue=false)]
        public string WalletAddress { get; set; }

        [DataMember(Name="type", EmitDefaultValue=false)]
        public string Type { get; set; }

        [DataMember(Name="id", EmitDefaultValue=false)]
        public string Id { get; set; }

        [DataMember(Name="createdAt", EmitDefaultValue=false)]
        public DateTime? CreatedAt { get; set; }

        [Required]
        [DataMember(Name="publicName", EmitDefaultValue=false)]
        public string PublicName { get; set; }

        [DataMember(Name="publicSlugUrl", EmitDefaultValue=false)]
        public string PublicSlugUrl { get; set; }

        [DataMember(Name="emailAddress", EmitDefaultValue=false)]
        public string EmailAddress { get; set; }

        [DataMember(Name="phoneNumber", EmitDefaultValue=false)]
        public string PhoneNumber { get; set; }

        [DataMember(Name="location", EmitDefaultValue=false)]
        public string Location { get; set; }


        [DataMember(Name="about", EmitDefaultValue=false)]
        public string About { get; set; }


        public override string ToString() { //...
        }

        public string ToJson()
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(this, Newtonsoft.Json.Formatting.Indented);
        }

        public override bool Equals(object obj)
        {
            if (obj is null) return false;
            if (ReferenceEquals(this, obj)) return true;
            return obj.GetType() == GetType() && Equals((Profile)obj);
        }

        public bool Equals(Profile other)  { //...
        }

        public override int GetHashCode( { //...
        }

        #region Operators
        // ...
        #endregion Operators
    }
}

OpenAPI 模型的 JSON 版本:

"Profile" : {
  "example" : {
    "createdAt" : "2022-03-29T16:59:22.9033559Z",
    "emailAddress" : "[email protected] /cdn-cgi/l/email-protection",
    "phoneNumber" : "+6563297537",
    "publicName" : "Onxy DAO",
    "about" : "about",
    "publicSlugUrl" : "https://chain.party/onxy_dao",
    "location" : "Germany",
    "id" : "pre_LfeolJ7DINWPTmQzArvT",
    "walletAddress" : "0x008F7c856B71190C6E44A51a30A4ec32F68545e0",
    "type" : "itemtype"
  },
  "properties" : {
    "walletAddress" : {
      "example" : "0x008F7c856B71190C6E44A51a30A4ec32F68545e0",
      "type" : "string"
    },
    "type" : {
      "example" : "itemtype",
      "type" : "string"
    },
    "id" : {
      "example" : "pre_LfeolJ7DINWPTmQzArvT",
      "type" : "string"
    },
    "createdAt" : {
      "example" : "2022-03-29T16:59:22.9033559Z",
      "format" : "date-time",
      "type" : "string"
    },
    "publicName" : {
      "type" : "string"
    },
    "publicSlugUrl" : {
      "format" : "url",
      "type" : "string"
    },
    "emailAddress" : {
      "format" : "email",
      "type" : "string"
    },
    "phoneNumber" : {
      "type" : "string"
    },
    "location" : {
      "type" : "string"
    },
    "about" : {
      "type" : "string"
    }
  },
  "required" : [ "publicName", "walletAddress" ]
}

我应该能够仅使用两个必填字段来发布此有效负载,但我在所有其他字段上收到验证错误:

{
    "errors": {
        "id": [
            "The Id field is required."
        ],
        "about": [
            "The About field is required."
        ],
        "location": [
            "The Location field is required."
        ],
        "publicName": [
            "The PublicName field is required."
        ],
        "phoneNumber": [
            "The PhoneNumber field is required."
        ],
        "emailAddress": [
            "The EmailAddress field is required."
        ],
        "publicSlugUrl": [
            "The PublicSlugUrl field is required."
        ]
    },
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "00-42995fb014cad1fbb999645cb61e4cf9-ade43e222f9917ae-00"
}

该应用程序的配置方式如下:

using System.Reflection;
using ChainParty.WebApi.Filters;
using ChainParty.WebApi.Formatters;
using ChainParty.WebApi.OpenApi;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services
    .AddMvc(opts => opts.InputFormatters.Insert(0, new InputFormatterStream()))
        .ConfigureApplicationPartManager(apm => {
            var originals = apm.FeatureProviders.OfType<ControllerFeatureProvider>().ToList();
            foreach (var original in originals)
                apm.FeatureProviders.Remove(original);
            apm.FeatureProviders.Add(new DefaultControllerFeatureProvider());
        })
        .AddNewtonsoftJson(opts => {
            opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            opts.SerializerSettings.Converters.Add(new StringEnumConverter
            {
                NamingStrategy = new CamelCaseNamingStrategy()
            });
        });


// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services
    .AddSwaggerGen(c => {
        c.SwaggerDoc("2.0.0", new OpenApiInfo
        {
            Title = "ChainParty",
            Description = "ChainParty (ASP.NET Core 3.1)",
            TermsOfService = new Uri("https://github.com/openapitools/openapi-generator"),
            Contact = new OpenApiContact
            {
                Name = "OpenAPI-Generator Contributors",
                Url = new Uri("https://github.com/openapitools/openapi-generator"),
                Email = "[email protected] /cdn-cgi/l/email-protection"
            },
            License = new OpenApiLicense
            {
                Name = "NoLicense",
                Url = new Uri("http://localhost")
            },
            Version = "2.0.0",
        });
        c.CustomSchemaIds(type => type.FriendlyId(true));
        c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{Assembly.GetEntryAssembly().GetName().Name}.xml");

        // Include DataAnnotation attributes on Controller Action parameters as OpenAPI validation rules (e.g required, pattern, ..)
        // Use [ValidateModelState] on Actions to actually validate it in C# as well!
        c.OperationFilter<GeneratePathParamsValidationFilter>();
    });
builder.Services
        .AddSwaggerGenNewtonsoftSupport();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
    app.UseDeveloperExceptionPage();
    app.UseSwagger(c => {
        c.RouteTemplate = "openapi/{documentName}/openapi.json";
    })
    .UseSwaggerUI(c => {
        // set route prefix to openapi, e.g. http://localhost:8080/openapi/index.html
        c.RoutePrefix = "openapi";
        //TODO: Either use the SwaggerGen generated OpenAPI contract (generated from C# classes)
        c.SwaggerEndpoint("/openapi/2.0.0/openapi.json", "ChainParty");

        //TODO: Or alternatively use the original OpenAPI contract that's included in the static files
        // c.SwaggerEndpoint("/openapi-original.json", "ChainParty Original");
    });
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.UseRouting();
app.MapControllers();

app.Run();

唯一的定制是控制器名称解析。

非常感谢任何帮助,最诚挚的问候


As 这个文件 https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/nullable-reference-types#create-the-application-and-enable-nullable-reference-types said:

从 .NET 6 开始,新项目包括<Nullable>enable</Nullable>项目文件中的元素。一旦 功能打开后,现有的引用变量声明变为不可为 null 的引用类型.

在 .NET 6 中必须要求不可为 null 的属性,否则 ModelState 将无效。

为了达到您的要求,您可以删除<Nullable>enable</Nullable>从您的项目文件中。

另一种方法是您可以添加?允许可为空:

[DataContract]
public partial class Profile : IEquatable<Profile>
{
    [Required]
    [DataMember(Name="walletAddress", EmitDefaultValue=false)]
    public string WalletAddress { get; set; }

    [DataMember(Name="type", EmitDefaultValue=false)]
    public string Type { get; set; }

    [DataMember(Name="id", EmitDefaultValue=false)]
    public string? Id { get; set; }

    [DataMember(Name="createdAt", EmitDefaultValue=false)]
    public DateTime? CreatedAt { get; set; }

    [Required]
    [DataMember(Name="publicName", EmitDefaultValue=false)]
    public string? PublicName { get; set; }
    //other proerpties..
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

尽管开放 API 规范 ASP.NET 将每个属性视为强制属性 的相关文章

  • 在实体框架拦截器中向 DbScanExpression 添加内部联接

    我正在尝试使用实体框架 CommandTree 拦截器通过 DbContext 向每个查询添加过滤器 为了简单起见 我有两个表 一个称为 User 有两列 UserId 和 EmailAddress 另一个称为 TenantUser 有两列
  • FileStream 构造函数和默认缓冲区大小

    我们有一个使用 NET 4 用 C 编写的日志记录类 我想添加一个构造函数参数 该参数可以选择设置文件选项 WriteThrough http msdn microsoft com en us library system io fileo
  • 更改 Qt OpenGL 窗口示例以使用 OpenGL 3.3

    我正在尝试更改 Qt OpenGL 示例以使用更现代的 opengl 版本 330 似乎合适 所以我做了 在 main cpp 上设置版本和配置文件 设置着色器版本 更改着色器以使用统一 它现在构建没有任何错误 但我只看到一个空白窗口 我错
  • 读取 C# 中的默认应用程序设置

    我的自定义网格控件有许多应用程序设置 在用户范围内 其中大部分是颜色设置 我有一个表单 用户可以在其中自定义这些颜色 并且我想添加一个用于恢复默认颜色设置的按钮 如何读取默认设置 例如 我有一个名为的用户设置CellBackgroundCo
  • 防止 boost::asio::io_context 在空轮询调用时停止

    此代码调用发布的句柄 boost asio io context ioc boost asio post ioc std cout lt lt lol lt lt std endl ioc poll 而这并没有 boost asio io
  • 根据 N 个值中最小的一个返回不同的结果

    不确定如何使标题更具描述性 所以我只是从一个例子开始 我使用下面的代码位 它从枚举中选择一个方向 具体取决于四个轴中哪一个与给定方向相比形成最小角度 static Direction VectorToDirection Vector2 di
  • 与 Qt 项目的静态链接

    我有一个在 Visual Studio 2010 Professional 中构建的 Qt 项目 但是 当我运行它 在调试或发布模式下 时 它会要求一些 Qt dll 如果我提供 dll 并将它们放入 System32 中 它就可以工作 但
  • 找不到 assimp-vc140-mt.dll ASSIMP

    我已经从以下位置下载了 Assimp 项目http assimp sourceforge net main downloads html http assimp sourceforge net main downloads html Ass
  • ASP.Net Core 内容配置附件/内联

    我正在从 WebAPI 控制器返回一个文件 Content Disposition 标头值自动设置为 附件 例如 处置 附件 文件名 30956 pdf 文件名 UTF 8 30956 pdf 当它设置为附件时 浏览器将要求保存文件而不是打
  • 时间:2019-03-17 标签:c#ThreadSafeDeepCopy

    我一直在阅读很多其他问题以及大量谷歌搜索 但我一直无法找到明确的解决方案 根据我读过的一些最佳实践 类的静态方法应该创建线程安全的 并且实例成员应该将线程安全留给消费者 我想为该类实现深度复制方法 该类本身还有其他引用类型成员 有没有什么方
  • 单例模式和 std::unique_ptr

    std unique ptr唯一地控制它指向的对象 因此不使用引用计数 单例确保利用引用计数只能创建一个对象 那么会std unique ptr与单例执行相同 单例确保只有一个实例属于一种类型 A unique ptr确保只有一个智能指针到
  • Visual Studio Code:如何配置 includePath 以获得更好的 IntelliSense 结果

    我是使用 Visual Studio Code 的完全初学者 我不知道我在做什么 我已经四处搜索 也许还不够 但我找不到像我这样的人如何配置的简单解释c cpp properties json每当我单击带有绿色波浪线下划线的行旁边的黄色灯泡
  • 如何在标准 WPF ListView 中启用 UI 虚拟化

    我正在使用 NET 4 5 VS2012 并且我有一个 ListView 看起来像这样
  • 无法在内存位置找到异常源:cudaError_enum

    我正在尝试确定 Microsoft C 异常的来源 test fft exe 中 0x770ab9bc 处的第一次机会异常 Microsoft C 异常 内存位置 0x016cf234 处的 cudaError enum 我的构建环境是 I
  • 运行选定的代码生成器时出错:“未将对象引用设置到对象的实例。”错误?

    我已经尝试了所有解决方案 例如修复 VS 2013 但没有用 当您通过右键单击控制器文件夹来创建控制器并添加控制器时 然后右键单击新创建的控制器的操作并选择添加视图 当我尝试创建视图时 就会发生这种情况 它不是一个新项目 而是一个现有项目
  • 如何通过 JsonConvert.DeserializeObject 在动态 JSON 中使用 null 条件运算符

    我正在使用 Newtonsoft 反序列化已知的 JSON 对象并从中检索一些值 如果存在 关键在于对象结构可能会不断变化 因此我使用动态来遍历结构并检索值 由于对象结构不断变化 我使用 null 条件运算符来遍历 JSON 代码看起来像这
  • 了解使用 Windows 本机 WPF 客户端进行 ADFS 登录

    我已经阅读了大量有关 ADFS 与 NodeJS Angular 或其他前端 Web 框架集成以及一般流程如何工作的文献 并通过 Auth0 Angular 起始代码构建了概念证明 但我不明白如何这可以与本机 WPF Windows 应用程
  • 每个数据库多个/单个 *.edmx 文件

    我有一个通过 ADO net 数据服务与数据库交互的项目 数据库很大 近 150 个具有依赖关系的表 该项目几年前开始 当时使用的是数据集 现在我们正在转向实体模型关系 由于我们添加了更多需要使用的表 该模型正在不断增长 这是管理这一切的正
  • 矩阵到数组 C#

    这将是转换方阵的最有效方法 例如 1 2 3 4 5 6 7 8 9 into 1 2 3 4 5 6 7 8 9 in c 我在做 int array2D new int 1 2 3 4 5 6 7 8 9 int array1D new
  • 在简单注入器中解析具有自定义参数的类

    我正在使用以下命令创建 WPF MVVM 应用程序简易注射器作为 DI 容器 现在 当我尝试从简单注入器解析视图时遇到一些问题 因为我需要在构造时将参数传递到构造函数中 而不是在将视图注册到容器时 因此这不是适用的 简单注入器将值传递到构造

随机推荐

  • 内存映射文件长度

    我正在处理内存映射文件 有没有办法知道内存映射文件内容的长度 我想要的是附加现有的内存映射文件 在文件中附加字节很容易 但我希望附加字符串 我们可以检查 CAPACITY 属性 但它返回我认为的字节大小 为了更清楚地说明 我正在解释这个场景
  • 如何在 UIWebView 中暂停媒体播放

    我目前正在开发一款支持 iPad 上多个选项卡的浏览器 问题是 iOS 不允许多个选项卡同时播放音频 视频 尝试这样做会导致出现问题 例如所有音频停止且无法返回 我注意到 Google Chrome 浏览器实际上会停止非活动选项卡中的媒体
  • 如何在GIT中将一个分支合并到另一个分支?

    让我详细解释一下这个问题 我有一个主 git 分支 在上面创建了一个新的侧分支 bug10101010 现在我不想将 bug10101010 合并到主分支 到目前为止一切都很好 现在我有同一产品的不同分支 名为legacy 我不想将 bug
  • 如何使用 Apache HttpClient 启用 SSLv3?

    Apache 中禁用了 SSLv3Http客户端 https hc apache org从 4 3 6 版本开始 但我使用的是 4 5 版本 这开发人员写道 https hc apache org news html 希望继续使用 SSLv
  • Android 中的视频录制格式(.3gp 或 mp4)?

    我用Intent MediaStore ACTION VIDEO CAPTURE视频录制方法 默认情况下 录制的视频存储为 3gp文件 我想将视频录制并存储为 mp4 file 这可能吗 Yes Set the MediaRecorder
  • 将触摸焦点转移到另一个视图

    这个问题问得有点尴尬 是否可以将一个视图的触摸焦点转移到另一个视图 基本上 假设您有一个选择第一个的视图ACTION DOWN触摸事件 然后立即想要将所有触摸事件的焦点转移到另一个视图来处理它onTouchEvent MotionEvent
  • 将分配器添加到 C++ 类模板以创建共享内存对象

    简而言之 我的问题是 如果你有课 MyClass
  • jQuery:使用预定义函数添加更改事件处理程序

    所以我有以下内容 var change handler function element do some fancy stuff 现在 我想将其附加到一个元素 哪种方法更好 最好或更正确 element selector change ch
  • Maven 3.3.1 ECLIPSE:未设置-Dmaven.multiModuleProjectDirectory 系统属性

    我刚刚在 Mac OS X 上安装了 Maven 3 3 1 并且使用 Eclipse 构建 Maven 项目时出现以下错误 Dmaven multiModuleProjectDirectory system property is not
  • 在哪里设置 celery 任务的task_id?

    我无法找到使用我自己的 task id 设置 task id 的任何示例 沿着这些思路的东西 def testview1 request for i in xrange 0 1000 result add delay i 4 task id
  • Win32 中消息队列如何工作?

    我读了一些关于 Win32 以及消息循环如何工作的内容 但有一些东西我仍然不清楚 消息队列中到底存储了什么 对应于消息的整数值 WM COMMAND WM CREATE等 或指向MSG包含消息整数值和其他内容的结构 例如wParam lPa
  • Google Drive API 中缩略图的永久链接

    我正在使用 Google Drive API PHP 将一些照片上传到我的云端硬盘 当文件上传时 会出现一个Google DriveFile响应中返回对象以确认传输成功 它包括一个名为thumbnailLink 可通过getThumbnai
  • 安装 scrapy 时出现 gcc failed 错误

    当我安装 scrapy 时 我收到以下错误 命令 gcc 失败 退出状态为 1 我正在使用 Centos 是的 我安装了最新版本的 gcc 但我不确定为什么会收到此错误 我尝试用谷歌搜索但找不到解决方案 OpenSSL crypto cry
  • UIViewController 中的插座 viewdidload 中为零

    我有一个带有 tableView 出口的 UIViewController IBOutlet weak var tableView UITableView 当我尝试访问 tableView 变量时viewDidload它抛出一个错误 说 t
  • 表单提交错误后如何保留文件输入值?

    我有一个似乎相当基本的问题 想确认如何最好地处理它 我有一个带有多个输入的表单 其中一个是文件输入 提交表单时 PHP 中会进行许多验证检查 以确认所有必需的字段均已按应填写的方式填写 如果没有 则通知用户填写其余部分并再次向他们显示表单而
  • 使用 JavaScript 计算文本宽度

    我想使用 JavaScript 来计算字符串的宽度 是否可以在不使用等宽字体的情况下实现这一点 如果它不是内置的 我唯一的想法是为每个字符创建一个宽度表 但这非常不合理 特别是支持Unicode http en wikipedia org
  • 检查点在 Apache Spark 上有什么作用?

    检查点对 Apache Spark 有何作用 它是否会影响 RAM 或 CPU 来自 Apache 流媒体文档 http spark apache org docs latest streaming programming guide ht
  • 小型 Ajax JavaScript 库 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个非常小的 单行 Ajax JavaScript 库来添加到小脚本的第一行来发出一些请求 我已经尝试过 jx http www
  • 如何在一个云形成到另一个云形成模板之间传递参数

    如何在aws中将一个云形成模板文件之间的参数传递到另一个云形成模板文件 我不是在谈论嵌套模板 因为我知道它们只是一个 CFT 内的单独资源块 如果我错了 请纠正我 查看跨堆栈参考的官方文档 https docs aws amazon com
  • 尽管开放 API 规范 ASP.NET 将每个属性视为强制属性

    我通常直接生成服务器代码https swagger io https swagger io 在线服务 接下来 我决定添加更多自动化功能 因此我决定使用 CLI 工具aspnetcore发电机 https openapi generator