NSwag:如何在C#-> Swagger-> C#客户端中使用自定义值对象类型?

时间:2019-09-19 08:06:59

标签: c# swagger swagger-codegen nodatime nswag

我有一个在输入和输出中都使用Noda Time类型的API。使用默认的Noda Time序列化格式(基本上是ISO-8601格式)将类型序列化为JSON中的字符串。

我有一个看起来像这样的对象:

<>apple

这通常会导致以下Swagger JSON:

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; }
}

这使得在C#客户端中无法转换回正确的Noda Time类型。除了具有完全相同的格式("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" } } } )的许多不同类型使映射成为不可能之外,某些类型还具有不幸的定义。 "date-time"的结果是DateInterval的数组,因为它是"date"的可枚举,但是简单的开始/结束日期格式会更好。使用LocalDate创建了其他方法,以非常复杂的对象包含绝对不感兴趣的字段。请注意,所有这些都应该序列化为简单的字符串(可以说不是间隔)。

我能够创建自己的类型映射器,并将其添加到$ref中,如下所示:

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;
    });
}

这允许使用与现有格式("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" } } } "date-time""date""time")相同的格式,但是我不能因为喜欢上帝知道如何使"time-span"使用这些格式正确地转换回相应的Noda时间类型。我通常会丢失某些东西吗?还是目前无法做到这一点?

1 个答案:

答案 0 :(得分:0)

我没有Swagger json问题的解决方案,但是我可以为C#客户端生成部分提供帮助。

我们将使用NSwagStudio使用反射来生成客户端,而不是从NSwag json生成客户端。我正在使用“运行时将Web API通过反射”设置为“默认”:

enter image description here

此生成器“使用.NET反射来分析ASP.NET Web API或ASP.NET Core控制器”。当然,您的里程可能会有所不同-还有一个“ .NET程序集”选项和/或您可能需要显式设置运行时。

在右侧窗格上,单击“ CSharp Client”,然后切换到“ CSharp Client”标签:

enter image description here

在上面的屏幕快照中可以看到第一份秘密酱料:我们将NodaTime添加为其他名称空间。

进一步,我们需要让NSwagStudio生成DTO类,这是非常重要的-,可以通过将它们添加到“排除的类型名称”列表中来生成任何NodaTime类型:

enter image description here

我使用的类型排除字符串是:DateInterval,DateTimeZone,Duration,Instant,Interval,IsoDayOfWeek,LocalDate,LocalDateTime,LocalTime,Offset,OffsetDate,OffsetDateTime,OffsetTime,Period,ZonedDateTime,CalendarSystem,Era

您还需要查看许多其他选项。完成此操作后,按Generate Outputs,将生成您的C#客户端。


将客户端粘贴到引用NodaTime的项目中,我们可以看到使用了NodaTime类型:

enter image description here

我的测试使用了您的课程NodaTimeDataStructure和该控制器:

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

出于本测试/演示的目的,我将其内置到针对.NET 4.8并使用ASP.NET Core 2.2的库中。