簡體   English   中英

NSwag 中接口上鑒別器的 KnownType 等價物

[英]KnownType equivalent for discriminator on Interfaces in NSwag

當我們需要告訴 NSwag 和生成的 OpenAPI 3.0 文檔,抽象的 class 應該在客戶端轉換為某種具體類型時,我使用[KnownType]和鑒別器並且效果很好:

using Newtonsoft.Json;
using NJsonSchema.Converters;

namespace Xyz.common.objects
{
    [JsonConverter(typeof(JsonInheritanceConverter), "discriminator")]
    [KnownType(typeof(DeviceTemplate))]
    [KnownType(typeof(PersonelTemplate))]
    public abstract class AbstractResourceTemplate
    {
    }
}

我遇到的問題是[KnownType]不能在接口上使用。 所以這無法編譯:

using Newtonsoft.Json;
using NJsonSchema.Converters;

namespace Xyz.common.objects
{
    [JsonConverter(typeof(JsonInheritanceConverter), "discriminator")]
    [KnownType(typeof(DeviceTemplate))] // Can't put KnownType on interfaces
    [KnownType(typeof(PersonelTemplate))]
    public interface IResourceTemplate
    {
    }
}

是否有等效的代碼可以放在界面上讓 NSwag 知道區分對象應該是什么?

對於上下文,這是接口的使用方式:

public class DeviceTemplateReponse {
    // In this class, Template is always going to be a DeviceTemplate, if that helps.
    [WhatGoesHere???(typeof(DeviceTemplate))]
    public IResourceTemplate Template { get; set; }
}

我想有一種方法可以通知 NSwag 在 DeviceTemplateReponse 中,Template 始終是具體類型 DeviceTemplate,因此不要在 OpenAPI 文檔中使用 IResourceTemplate。 這很重要,否則我會在客戶端收到此錯誤:

無法實例化抽象 class 'IResourceTemplate'。

此外,似乎TypeMapper在這里會有所幫助,但我無法找到有關如何在此處實現類似內容的文檔或示例。

我發現的一些解決方法是將接口轉換為抽象類,或者編寫我自己的僅使用具體類的對象版本。 但如果不是必須的話,我真的寧願不弄亂這樣的代碼。

接口的問題在於單個類型可以實現多個接口,但類型本身仍將實現一個公共基礎。 更重要的是,我們可以顯式重載接口屬性並為同一屬性公開多個值。

在客戶端,如果我們允許這樣做,那么接口中未定義的字段的默認值是多少? 序列化器是否應該允許所有元數據通過基類型的另一端,或者它應該被屏蔽並僅限於接口上定義的屬性。 當服務器端類型具有接口的顯式屬性時,具有不同的值,您希望將哪個值發送給客戶端,應該發送哪個值?

public interface ITest1
{
    int Test { get;set; }
}
public interface ITest2
{
    int Test { get;set; }
}
public class TestCase : ITest1, ITest2
{
    public int Test { get;set; } = 0;
    int ITest1.Test { get;set; } = 1;
    int ITest2.Test { get;set; } = 2;
}

在 NSwag 中,多態性是通過直接 inheritance 來簡化和管理的,而不是通過接口的組合。 請參閱NJsonSchema - Inheritance和相關的 PR,在當前實現中僅在內部檢查直接基類型,因此您在接口定義上的屬性將被完全忽略。

它對我來說並不經常出現,出於習慣,我嘗試 map 我所有的 API 端點到該資源的特定 DTO,並且如果需要的話,不同結構有不同的端點,任何聚合端點故意使用直接 inheritance 主要是因為那是我使用的其他框架(如 EF 和 OData)的要求。

當它確實出現時,我只是創建一個實現接口的抽象 class,將它用於此端點,然后在邏輯中我們仍然可以將其轉換回去,然后它變成了一個非常小的干預。

using Newtonsoft.Json;
using NJsonSchema.Converters;

namespace Xyz.common.objects
{
    public interface IResourceTemplate
    {
    }

    [JsonConverter(typeof(JsonInheritanceConverter), "discriminator")]
    [KnownType(typeof(DeviceTemplate))]
    [KnownType(typeof(PersonelTemplate))]
    public abstract class ResourceTemplateBase : IResourceTemplate
    {
    }
}
public class DeviceTemplateReponse {
    [KnownType(typeof(DeviceTemplate))]
    public ResourceTemplateBase Template { get; set; }
}

這很煩人嗎,嗯,是的,當它出現時......但是你可以使用隱式類型轉換或顯式輔助方法或像 AutoMapper 這樣的工具它是否足以簡化將邏輯實例設置到響應的Template屬性中,應該對您的代碼庫的開銷非常小,您只需編寫一次。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM