我正在使用 ASP.NET 创建 Web API。为了向用户公开我的数据库模型,我创建了数据模板对象,以便我可以显示/隐藏 swagger 架构中的属性。
问题是,如果我想区分 POST 和 GET 方法,我认为这是不可扩展的。
假设我有一个博客模型,其中有标识符、名称和创建者。当我创建一个新博客时,我只想设置博客的名称。另一方面,我想在发送 GET 请求时读取其他属性。
public class Blog
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[ForeignKey("CreatorId")]
public Users Creator { get; set; }
public int CreatorId { get; set; }
}
public class BlogDto
{
public int Id { get; set; }
public string Name { get; set; }
public Users Creator { get; set; }
}
现在,如果我运行此代码,发布请求会要求我设置所有创建者对象,以及博客 ID(应由实体框架设置)。
我发现我可以通过设置
[SwaggerSchema(ReadOnly = true)]
来隐藏标识符字段。不幸的是,此属性不适用于我的 Creator 属性。
也就是说,如果我将 BlogDto 设置为:
public class BlogDto
{
[SwaggerSchema(ReadOnly = true)]
public int Id { get; set; }
public string Name { get; set; }
[SwaggerSchema(ReadOnly = true)]
public Users Creator { get; set; }
}
我希望请求正文只是:
{
"name": "string"
}
(仅当属性 SwaggerSchema 位于我创建的对象上时才会触发此问题)。
我尝试过自定义 Json 序列化器、更改 SchemaFilter、使用
[JsonIgnore]
、[ReadOnly(true)]
。我发现的解决方法是创建一个仅包含 string Name { get; set; }
属性的 BlogPostDto 和包含所有三个属性的 BlogGetDto,但我想知道是否可以仅使用一个 Dto 来实现这一点。
终于找到解决方案了。
swagger 存储库中也报告了此问题(嵌套对象上的只读),但我无法理解 Asp.Net 的等效项。
但是我尝试将
[SwaggerSchema(ReadOnly = true)]
添加到课程本身。我不知道为什么这会起作用,或者即使它在其他地方产生问题。无论如何,这是我的方法,因为我在这里无法收到任何其他回复。
简单来说,我所做的是为用户模型添加一个新的数据模板对象:
[SwaggerSchema(ReadOnly = true)]
public class UserDto
{
[SwaggerSchema(ReadOnly = true)]
public int Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
}
请注意,我将 SwaggerSchema 属性添加到该类中。然后我可以删除 BlogDto Creator 属性的属性:
public class BlogDto
{
[SwaggerSchema(ReadOnly = true)]
public int Id { get; set; }
public string Name { get; set; }
public UserDto Creator { get; set; }
}
我想我必须将该属性添加到我为项目创建的每个 DTO 中。
我仍然愿意进一步讨论。
谢谢。
我回顾了 Swashbuckle.AspNetCore.Annotations 中的 AnnotationsSchemaFilter
我找不到任何地方从架构中删除属性(schema.Properties.Remove(excludedName))
我创建了另一个过滤器并在 Swashbuckle.AspNetCore.Annotations 中使用 SwaggerSchemaAttribute
public class SwaggerIgnoreFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (schema?.Properties == null)
{
return;
}
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
var memberList = context.Type
.GetFields(bindingFlags).Cast<MemberInfo>()
.Concat(context.Type.GetProperties(bindingFlags));
var excludedList = memberList
.Where(m => m.GetCustomAttribute<SwaggerSchemaAttribute>() != null)
.Select(m => m.GetCustomAttribute<JsonPropertyAttribute>()?.PropertyName ?? m.Name.ToCamelCase());
foreach (var excludedName in excludedList)
{
if (schema.Properties.ContainsKey(excludedName))
schema.Properties.Remove(excludedName);
}
}
}
public static class StringExtension
{
public static string ToCamelCase(this string str)
{
if (!string.IsNullOrEmpty(str) && str.Length > 1)
{
return char.ToLowerInvariant(str[0]) + str.Substring(1);
}
return str.ToLowerInvariant();
}
}
并在program.cs中添加以下内容
builder.Services.AddSwaggerGen(options =>
{
options.SchemaFilter<SwaggerIgnoreFilter>();
}
工作完美