如何解决为什么 autorest 用 Swagger 中的对象替换我的自定义结构?
我创建了一个自定义 readonly
struct
来定义我称之为 TenantId
的不可变值类型:
[DebuggerDisplay("ID={m_internalId.ToString()}")]
[JsonConverter(typeof(TenantIdJsonConverter))]
public readonly struct TenantId : IEquatable<TenantId>
{
private readonly Guid m_internalId;
public static TenantId New => new(Guid.NewGuid());
private TenantId(Guid id)
{
m_internalId = id;
}
public TenantId(TenantId otherTenantId)
{
m_internalId = otherTenantId.m_internalId;
}
...
}
我还定义了一个名为 PurchaseContract
的契约,它是 HTTP 响应的一部分:
[JsonObject(MemberSerialization.OptIn)]
public sealed class PurchaseContract
{
[JsonProperty(PropertyName = "tenantId")]
public TenantId TenantId { get; }
[JsonProperty(PropertyName = "total")]
public double Total { get; }
}
最后,我设置了一个 HTTP 触发函数,它将返回一个 PurchaseContract
实例。目前,它已在 ProducesResponseTypeAttribute
:
[ApiExplorerSettings(GroupName = "Purchases")]
[ProducesResponseType(typeof(PurchaseContract),(int) HttpStatusCode.OK)]
[FunctionName("v1-get-purchase")]
public Task<IActionResult> RunAsync
(
[HttpTrigger(AuthorizationLevel.Anonymous,"GET",Route = "v1/purchases")]
HttpRequest httpRequest,[SwaggerIgnore]
ClaimsPrincipal claimsPrincipal
)
{
// Stuff to do.
return Task.FromResult((IActionResult)new OkResult());
}
在我的 Startup
课上,我设置了这样的 swagger:
private static void ConfigureSwashBuckle(IFunctionsHostBuilder functionsHostBuilder)
{
functionsHostBuilder.AddSwashBuckle(Assembly.GetExecutingAssembly(),options =>
{
options.SpecVersion = OpenApiSpecVersion.OpenApi3_0;
options.AddCodeParameter = true;
options.PrependOperationWithRoutePrefix = true;
options.XmlPath = "FunctionApp.xml";
options.Documents = new []
{
new SwaggerDocument
{
Title = "My API,Version = "v1",Name = "v1",Description = "Description of my API",}
};
});
}
在 swagger UI 页面中,我可以看到它看起来不错:
问题
使用 Autorest 创建 C# 客户端时出现意外结果。不知何故,TenantId
结构被删除并替换为 object
:
为什么会这样,我应该怎么做才能拥有自动生成的 TenantId
,例如客户端中的 PurchaseContract
?
详情
这是版本信息。
- 运行在 netcore3.1 上的函数应用 V3;
- OpenApi 3.0;
- Autorest Core 3.0.6274、autorest.csharp' (~2.3.79->2.3.91) 和 autorest.modeler' (2.3.55->2.3.55);
- NuGet 包 AzureExtensions.Swashbuckle;
解决方法
我开始研究 Swashbuckle.AspNetCore.SwaggerGen 的源代码,以了解如何解释我的 readonly
struct
。这一切都发生在 JsonSerializerDataContractResolver 类中,在 GetDataContractForType
方法中,它为所提供的类型确定 DataContract
:
public DataContract GetDataContractForType(Type type)
{
if (type.IsOneOf(typeof(object),typeof(JsonDocument),typeof(JsonElement)))
{
...
}
if (PrimitiveTypesAndFormats.ContainsKey(type))
{
...
}
if (type.IsEnum)
{
...
}
if (IsSupportedDictionary(type,out Type keyType,out Type valueType))
{
...
}
if (IsSupportedCollection(type,out Type itemType))
{
...
}
return DataContract.ForObject(
underlyingType: type,properties: GetDataPropertiesFor(type,out Type extensionDataType),extensionDataType: extensionDataType,jsonConverter: JsonConverterFunc);
}
我的自定义 struct
TenantId
不符合任何这些条件,因此,它退回到被视为 object
(最后一条语句)。
然后我继续查看现有的 tests 以了解该类的使用方式,并查看是否可以更改任何内容。令人惊讶的是,我发现了一个名为 GenerateSchema_SupportsOption_CustomTypeMappings
(第 356 行)的测试,它展示了一种提供自定义映射的方法(请参阅该方法的第一条语句):
[Theory]
[InlineData(typeof(ComplexType),typeof(ComplexType),"string")]
[InlineData(typeof(GenericType<int,string>),typeof(GenericType<int,"string")]
[InlineData(typeof(GenericType<,>),int>),"string")]
public void GenerateSchema_SupportsOption_CustomTypeMappings(
Type mappingType,Type type,string expectedSchemaType)
{
var subject = Subject(configureGenerator: c => c.CustomTypeMappings.Add(mappingType,() => new OpenApiSchema { Type = "string" }));
var schema = subject.GenerateSchema(type,new SchemaRepository());
Assert.Equal(expectedSchemaType,schema.Type);
Assert.Empty(schema.Properties);
}
就我而言,我希望将我的 TenantId
映射到 string
。为此,我在 Function App 启动时编辑了 SwashBuckle 的配置:
private static void ConfigureSwashBuckle(IFunctionsHostBuilder functionsHostBuilder)
{
functionsHostBuilder.AddSwashBuckle(Assembly.GetExecutingAssembly(),options =>
{
...
options.ConfigureSwaggerGen = (swaggerGenOptions) => swaggerGenOptions.MapType<TenantId>(() => new OpenApiSchema {Type = "string"});
});
}
在这里,TenantId
现在被视为 Swagger 中的 string
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。