为了账号安全,请及时绑定邮箱和手机立即绑定

在 ASP.NET Core 中手动绑定表单数据

在 ASP.NET Core 中手动绑定表单数据

C#
拉丁的传说 2021-11-28 20:03:13
我有一个 web api,其中包含一些应该同时接收数据和文件的操作。为此,我接受 multipart/form-data 而不是 JSON 并使用[FromForm]以下方法绑定到模型:[Authorize(Policy = "MyCustomPolicy")]public async Task<IActionResult> Create([FromForm]MyCustomDto myDto){    // Do some stuff here}public class MyCustomDto{    public int Id { get; set; }    public string Title { get; set; }    public IEnumerable<IFormFile> Attachments { get; set; }}这工作正常并且正确绑定到 DTO。使用 AuthorizationHandler 检查和强制执行策略,它也可以正常工作。在上述 AuthorizationHandler 中,我需要访问一些传递给控制器的东西,例如路由中的 ID 或 DTO。使用 访问路线数据非常容易authContext.RouteData.Values["nameOfIdField"]。但是,对于正文,我创建了一个辅助扩展方法,用于读取正文流并将其反序列化:public static async Task<T> DeserializeBody<T>(this AuthorizationFilterContext context, string name){    var content = string.Empty;    using(var reader = new StreamReader(context.HttpContext.Request.Body, System.Text.Encoding.UTF8, true, 1024, true))    {        content = await reader.ReadToEndAsync();        reader.BaseStream.Seek(0, SeekOrigin.Begin);    }    if (string.IsNullOrWhiteSpace(content))    {        return default(T);    }    return JsonConvert.DeserializeObject<T>(content);}同样,这也很好用。但是,现在我遇到了 DTO 的问题,这些 DTO 不是作为 JSON 传递的,而是 - 正如开头所说的 - 作为表单数据。正文的内容不是可以轻松序列化的 JSON:-----------------------------7e2b13b820d4aContent-Disposition: form-data; name="id"232  -----------------------------7e2b13b820d4aContent-Disposition: form-data; name="title"test  -----------------------------7e2b13b820d4aContent-Disposition: form-data; name="attachments"; filename="C:\Temp\Test.jpg"Content-Type: image/jpeg有什么方法可以轻松地将它绑定到我的 DTO,而无需手动解析它?
查看完整描述

2 回答

?
BIG阳

TA贡献1859条经验 获得超6个赞

你最好在你的操作方法中处理这种情况:


public class SomeController : Controller

{

    private readonly IAuthorizationService _authorizationService;


    public SomeController(IAuthorizationService authorizationService)

    {

        _authorizationService = authorizationService;

    }


    public async Task<IActionResult> Create([FromForm]MyCustomDto myDto)

    {

        var authorizationResult = await _authorizationService.AuthorizeAsync(User, myDto, "MyCustomPolicy");

        if (!authorizationResult.Succeeded)

            return User.Identity.IsAuthenticated ? Forbid() : (IActionResult)Challenge();


        // Do some stuff here

    }

你像这样定义你的授权处理程序:


public class MyCustomDtoAuthorizationHandler : AuthorizationHandler<MyCustomDtoRequirement, MyCustomDto>

{

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, MyCustomDtoRequirement requirement, MyCustomDto resource)

    {

        // your authorization logic based on the resource argument...

    }

}

选择AuthorizeFilter方式的一个大问题是授权过滤器在模型绑定发生之前执行。(只需查看ResourceInvoker类的源代码。)您需要手动绑定模型以访问其中授权所需的信息。然后框架会完成它的工作,导致模型绑定被完成两次,从而导致性能下降。正如前面所描述的那样,这应该并且可以避免。


更新


我刚刚注意到我不小心在 action 方法中留下了一段重要的代码。更正。


查看完整回答
反对 回复 2021-11-28
?
慕哥9229398

TA贡献1877条经验 获得超6个赞

在上述 AuthorizationHandler 中,我需要访问一些传递给控制器的东西,例如路由中的 ID 或 DTO

请不要那样做。您基本上是在复制有关如何从请求中解析参数的现有逻辑。

基本处理程序用于基本情况:例如,只有“BookClub”角色的经过身份验证的成员才能访问这些BooksController方法。那太棒了。

一旦您发现自己需要来自消息本身的信息,请不要手动进行所有解析。让 ASP 做它的事情并根据您给定的约束解析消息,然后当消息完成时,在您获得的对象上调用您的授权逻辑。


查看完整回答
反对 回复 2021-11-28
  • 2 回答
  • 0 关注
  • 346 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信