提问人:liamocuz 提问时间:11/9/2023 最后编辑:Renaliamocuz 更新时间:11/9/2023 访问量:41
如何在 ASP NET 中嵌套 [FromHeader] 验证的模型
How to nest [FromHeader] validated models in ASP NET
问:
对于我的 API,我有三个标头,这三个标头几乎都用于所有端点。但是,某些端点不需要这三个端点。但对于每个终结点,它将要求存在任何标头。
我希望能够创建模型来单独验证每个标头,然后创建另一个模型来将它们包装在一起,这样只指定一个模型会很有用,因为大多数端点需要验证所有三个,只有少数需要一两个。
我的目标是使方法签名更干净一些,并避免重复的代码。
// Models
public class MainId
{
[FromHeader(Name = "id")]
[Required]
public string Id { get; set; }
}
public class UserId
{
[FromHeader(Name = "userId")]
[Required]
public string Id { get; set; }
}
public class OtherId
{
[FromHeader(Name = "otherId")]
[Required]
public string Id { get; set; }
}
public class AllHeaders
{
[FromHeader]
public MainId MainId { get; set; }
[FromHeader]
public UserId UserId { get; set; }
[FromHeader]
public OtherId OtherId { get; set; }
}
// Controllers
[ApiController]
public class MyController: ControllerBase
{
[HttpGet("/allThree")]
public string allThree([FromHeader] AllHeaders headers)
{
// be able to access all three headers here
string h1 = headers.MainId.Id;
string h2 = headers.UserId.Id;
string h3 = headers.OtherId.Id;
}
// I know I can do the above like so, but if I ever want to add headers, it just makes the function signature sloppier
[HttpGet("allThreeV2")]
public string allThreeV2([FromHeader] MainId mainId, [FromHeader] UserId userId, [FromHeader] OtherId otherId)
{
// can access all three
string h1 = mainId.Id;
string h2 = userId.Id;
string h3 = userId.Id;
}
[HttpGet("/singleHeader")]
public string oneHeader([FromHeader] MainId mainId)
{
// be able to access the one header here
string h1 = mainId.Id;
}
}
我遇到的错误是 AllHeaders 为 null,如果我在那里省略 [FromHeader],那么控制器将返回 415,因为它正在寻找 AllHeaders 类内部的字段,而不是类内部的字段。
我想知道这种模块化是否可以实现,或者我是否可以以另一种方式构建模型来实现这一点。我希望验证者可以以某种方式扁平化 AllHeaders 类以填充大多数字段。
答:
1赞
scharnyw
11/9/2023
#1
经过一些试验后,可以使用以下设置在 .NET 6 中实现此目的:
// Models
public class MainId
{
[FromHeader(Name = "id")]
[Required]
public string Id { get; set; }
}
public class UserId
{
[FromHeader(Name = "userId")]
[Required]
public string Id { get; set; }
}
public class OtherId
{
[FromHeader(Name = "otherId")]
[Required]
public string Id { get; set; }
}
public class AllHeaders
{
// No FromHeaderAttribute here because the MainId property is not bound from Header - it's the child property that's bound from header
// But RequiredAttribute is necessary here otherwise MainId == null would be a valid setup, violating the invariants expected in controller code
[Required]
public MainId MainId { get; set; }
[Required]
public UserId UserId { get; set; }
[Required]
public OtherId OtherId { get; set; }
}
和控制器动作方法:
[HttpGet("/allThree")]
public string allThree(
// You need the FromHeaderAttribute here to override the default binding logic for complex types, which is from request body for API controllers
[FromHeader] AllHeaders headers)
{
// be able to access all three headers here
string h1 = headers.MainId.Id;
string h2 = headers.UserId.Id;
string h3 = headers.OtherId.Id;
}
评论