简体   繁体   English

NSwag:你如何使用自定义值 Object 类型 C# -> Swagger -> ZD7EFA19FBE7D23D772FDZ客户端560FBE7D23D7724客户端?

[英]NSwag: How do you Use Custom Value Object Types in C# -> Swagger -> C# client?

I have an API that uses Noda Time types in both input and output.我有一个 API 在输入和 output 中都使用Noda Time类型。 The types are serialized to strings in the JSON using the default Noda Time serialization format (which basically is the ISO-8601 format).这些类型使用默认的 Noda Time 序列化格式(基本上是 ISO-8601 格式)序列化为 JSON 中的字符串。

I have an object looking something like this:我有一个 object 看起来像这样:

public class NodaTimeDataStructure
{
    public System.DateTime DateTime { get; set; }
    public DateInterval DateInterval { get; set; }
    public DateTimeZone DateTimeZone { get; set; }
    public Duration Duration { get; set; }
    public Instant Instant { get; set; }
    public Interval Interval { get; set; }
    public IsoDayOfWeek IsoDayOfWeek { get; set; }
    public LocalDate LocalDate { get; set; }
    public LocalDateTime LocalDateTime { get; set; }
    public LocalTime LocalTime { get; set; }
    public Offset Offset { get; set; }
    public OffsetDate OffsetDate { get; set; }
    public OffsetDateTime OffsetDateTime { get; set; }
    public OffsetTime OffsetTime { get; set; }
    public Period Period { get; set; }
    public ZonedDateTime ZonedDateTime { get; set; }
}

This will normally result in the following Swagger JSON:这通常会导致以下 Swagger JSON:

"NodaTimeDataStructure": {
  "type": "object",
  "additionalProperties": false,
  "required": [
    "dateTime", "duration", "instant", "interval", "isoDayOfWeek", "localDate", "localDateTime",
    "localTime", "offset", "offsetDate", "offsetDateTime", "offsetTime", "zonedDateTime"
  ],
  "properties": {
    "dateTime":       { "type": "string", "format": "date-time" },
    "instant":        { "type": "string", "format": "date-time" },
    "zonedDateTime":  { "type": "string", "format": "date-time" },
    "offsetDateTime": { "type": "string", "format": "date-time" },
    "localDateTime":  { "type": "string", "format": "date-time" },
    "localDate":      { "type": "string", "format": "date" },
    "localTime":      { "type": "string", "format": "time" },
    "duration":       { "type": "string", "format": "time-span" },
    "dateInterval":   { "type": "array", "items": { "type": "string", "format": "date" } },
    "dateTimeZone":   { "$ref": "#/definitions/DateTimeZone" },
    "interval":       { "$ref": "#/definitions/Interval" },
    "isoDayOfWeek":   { "$ref": "#/definitions/IsoDayOfWeek" },
    "offset":         { "$ref": "#/definitions/Offset" },
    "offsetDate":     { "$ref": "#/definitions/OffsetDate" },
    "offsetTime":     { "$ref": "#/definitions/OffsetTime" },
    "period":         { "$ref": "#/definitions/Period" }
  }
}

This makes it impossible to convert back to the right Noda Time types in a C# client.这使得无法在 C# 客户端中转换回正确的 Noda Time 类型。 Apart from the many different types having the exact same format ( "date-time" ) making a mapping impossible, certain types have unfortunate definitions.除了具有完全相同格式( "date-time" )的许多不同类型使得映射不可能之外,某些类型具有不幸的定义。 A DateInterval results in an array of "date" , since it's an enumerable of LocalDate , but a simple start/end date format would work much better. DateInterval产生一个"date"数组,因为它是LocalDate的可枚举,但简单的开始/结束日期格式会更好。 Other methods are created with a $ref to very elaborate objects containing fields of absolutely no interest.其他方法是使用$ref创建的,用于非常复杂的对象,其中包含绝对不感兴趣的字段。 Be aware that all of these should be serialized as simple strings (arguably not the intervals).请注意,所有这些都应该序列化为简单的字符串(可以说不是间隔)。

I am able to create my own Type Mappers and adding them to a AspNetCoreToSwaggerGeneratorSettings like this:我可以创建自己的类型映射器并将它们添加到AspNetCoreToSwaggerGeneratorSettings中,如下所示:

var nodaTimeTypeMappers = new[]
{
    CreateTypeMapper(typeof(DateInterval), "date-interval"),
    CreateTypeMapper(typeof(DateTimeZone), "date-time-zone"),
    CreateTypeMapper(typeof(Duration), "duration"),
    CreateTypeMapper(typeof(Instant), "instant"),
    CreateTypeMapper(typeof(Interval), "interval"),
    CreateTypeMapper(typeof(IsoDayOfWeek), "iso-day-of-week"),
    CreateTypeMapper(typeof(LocalDate), "local-date"),
    CreateTypeMapper(typeof(LocalDateTime), "local-date-time"),
    CreateTypeMapper(typeof(LocalTime), "local-time"),
    CreateTypeMapper(typeof(Offset), "offset"),
    CreateTypeMapper(typeof(OffsetDate), "offset-date"),
    CreateTypeMapper(typeof(OffsetDateTime), "offset-date-time"),
    CreateTypeMapper(typeof(OffsetTime), "offset-time"),
    CreateTypeMapper(typeof(Period), "period"),
    CreateTypeMapper(typeof(ZonedDateTime), "zoned-date-time"),
};

foreach (var typeMapper in nodaTimeTypeMappers)
{
    settings.TypeMappers.Add(typeMapper);
}

PrimitiveTypeMapper CreateTypeMapper(Type type, string name)
{
    return new PrimitiveTypeMapper(type, s =>
    {
        s.Type = JsonObjectType.String;
        s.Format = "noda-time-" + name;
    });
}

to get something like this:得到这样的东西:

"NodaTimeRequest": {
  "type": "object",
  "additionalProperties": false,
  "required": [
    "dateTime", "duration", "instant", "interval", "isoDayOfWeek", "localDate", "localDateTime",
    "localTime", "offset", "offsetDate", "offsetDateTime", "offsetTime", "zonedDateTime"
  ],
  "properties": {
    "dateTime":       { "type": "string", "format": "date-time" },
    "dateInterval":   { "type": "string", "format": "noda-time-date-interval" },
    "dateTimeZone":   { "type": "string", "format": "noda-time-date-time-zone" },
    "duration":       { "type": "string", "format": "noda-time-duration" },
    "instant":        { "type": "string", "format": "noda-time-instant" },
    "interval":       { "type": "string", "format": "noda-time-interval" },
    "isoDayOfWeek":   { "type": "string", "format": "noda-time-iso-day-of-week" },
    "localDate":      { "type": "string", "format": "noda-time-local-date" },
    "localDateTime":  { "type": "string", "format": "noda-time-local-date-time" },
    "localTime":      { "type": "string", "format": "noda-time-local-time" },
    "offset":         { "type": "string", "format": "noda-time-offset" },
    "offsetDate":     { "type": "string", "format": "noda-time-offset-date" },
    "offsetDateTime": { "type": "string", "format": "noda-time-offset-date-time" },
    "offsetTime":     { "type": "string", "format": "noda-time-offset-time" },
    "period":         { "type": "string", "format": "noda-time-period" },
    "zonedDateTime":  { "type": "string", "format": "noda-time-zoned-date-time" }
  }
}

This allows the formats to be used just like the existing formats ( "date-time" , "date" , "time" , "time-span" ), but I can't for the love of God figure out how to make the swagger2csclient use those formats to properly convert back to the corresponding Noda Time types.这允许格式像现有格式一样使用( "date-time""date""time""time-span" ),但看在上帝的份上,我无法弄清楚如何制作swagger2csclient使用这些格式正确转换回相应的 Noda Time 类型。 Am I generally missing something or is this currently not possible?我通常会遗漏一些东西还是目前不可能?

I don't have a solution for the Swagger json problem, but I can help with the C# client generation part.我没有 Swagger json 问题的解决方案,但我可以帮助解决 C# 客户端生成部分。

Instead of generating the client from NSwag json, what we will do is have NSwagStudio generate the client using reflection.我们不会从 NSwag json生成客户端,而是让 NSwagStudio 使用反射生成客户端。 I'm using "Web API via reflection" with Runtime set to "Default":我正在使用“通过反射的 Web API”,运行时设置为“默认”:

在此处输入图像描述

This generator "uses .NET reflection to analyze ASP.NET Web API or ASP.NET Core controllers". This generator "uses .NET reflection to analyze ASP.NET Web API or ASP.NET Core controllers". Your mileage may vary of course - there is also a ".NET assembly" option and/or you might need to set the Runtime explicitly.当然,您的里程可能会有所不同 - 还有一个“.NET 程序集”选项和/或您可能需要明确设置运行时。

On the right hand pane, click "CSharp Client" and switch to the "CSharp Client" tab:在右侧窗格中,单击“CSharp Client”并切换到“CSharp Client”选项卡:

在此处输入图像描述

The first serving of secret sauce is visible in the above screenshot: we add NodaTime as an additional namespace.在上面的屏幕截图中可以看到第一份秘制酱汁:我们将NodaTime添加为一个额外的命名空间。

Further down, we need to have NSwagStudio generate DTO classes and - here's the really important thing - not generate any of the NodaTime types by adding them to the "Excluded Type Names" list:再往下,我们需要让 NSwagStudio 生成 DTO 类,并且——这是真正重要的事情——不要通过将 NodaTime 类型添加到“排除的类型名称”列表中来生成它们:

在此处输入图像描述

The type exclusion string I used is: DateInterval,DateTimeZone,Duration,Instant,Interval,IsoDayOfWeek,LocalDate,LocalDateTime,LocalTime,Offset,OffsetDate,OffsetDateTime,OffsetTime,Period,ZonedDateTime,CalendarSystem,Era .我使用的类型排除字符串是: DateInterval,DateTimeZone,Duration,Instant,Interval,IsoDayOfWeek,LocalDate,LocalDateTime,LocalTime,Offset,OffsetDate,OffsetDateTime,OffsetTime,Period,ZonedDateTime,CalendarSystem,Era

There are numerous other options you will want to look at.您还想查看许多其他选项。 Once you've done that, press Generate Outputs and your C# client will be generated.完成后,按Generate Outputs并生成 C# 客户端。


Pasting the client in to a project which references NodaTime, we can see that the NodaTime types are used:将客户端粘贴到引用 NodaTime 的项目中,我们可以看到使用了 NodaTime 类型:

在此处输入图像描述

My test utilised your class NodaTimeDataStructure and this controller:我的测试使用了你的 class NodaTimeDataStructure和这个 controller:

[Route("api/[controller]")]
[ApiController]
public class NodaTimeController
{
    [HttpGet]
    public NodaTimeDataStructure Get() => new NodaTimeDataStructure();
}

For the purposes of this test/demo, I built this into a library which targets .NET 4.8 and uses ASP.NET Core 2.2.出于此测试/演示的目的,我将其构建到一个库中,该库针对 .NET 4.8 并使用 ASP.NET Core 2.2。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C# NSwag 和带有枚举的 swagger-codegen - C# NSwag and swagger-codegen with Enums ASP NET Boilerplate>使用swagger codegen工具(nswag)生成C#swagger客户端无法正常工作 - ASP NET Boilerplate > Generating C# swagger client using swagger codegen tool (nswag) not working 使用 NSwag for C# 我们如何在同一个客户端项目中为不同的 API 创建多个客户端类 - With NSwag for C# how do we create multiple client classes for different API in the same client project 如何使用MongoDB C#序列化器序列化值类型? - How do you serialize value types with MongoDB C# serializer? 如何在NSwag生成的C#代码中包含自定义语句/指令? - How to include custom statements/directive in C# code generated by NSwag? 如何在堆上存储 int 或其他“C# 值类型”(使用 C#)? - How do you store an int or other “C# value types” on the heap (with C#)? 如何使用 NSwag 和 C# 指定“scheme”元素? - How do I specify the "scheme" element using NSwag and C#? 如何在C#中更新自定义DateTime对象? - How do you update a custom DateTime object in C#? C# Swagger 生成客户端如何验证和使用自动生成的代码 - C# Swagger generated client how to authenticate and use autogenerated code 在 NSwag 中是否可以只生成 C# 客户端接口并使用一些自定义属性注释它们的方法? - Is it possible in NSwag to generate just C# client interfaces and annotate their methods with some custom attributes?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM