asp.net 在www.example中发送对象和文件 www.example.com 通过单个请求,不带IFormFile属性

wkyowqbh  于 2023-05-02  发布在  .NET
关注(0)|答案(1)|浏览(99)

我有一个负责CRUD操作的简单控制器,一个Pet模型,我使用fetch API向端点发送JavaScript请求。请求的主体是一个包含文件和模型的FormData对象,但这似乎不起作用,因为我得到错误代码“400 Bad Request”。我也用Postman做了同样的事情,结果是一样的。在检查响应体时,在错误部分中,我得到

"errors": {
    "model.Name": [
        "The Name field is required."
    ]
 }

我想在一个请求中同时发送我的模型和文件。我在网上找到了一些解决方案,但是人们在他们的模型中添加了一个类型为“IFormFile”的额外属性,而我不想接触我的模型并将它们绑定到IFormFile,因为它们也应该在Web环境之外使用。
我有以下模型:

public class Pet
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

PetsController中的PUT控制器方法如下所示:

[HttpPut("{id:guid}")]
    public ActionResult EditPet(Guid id, [FromForm]Pet model)
    {
        ArgumentNullCheck(model);
        try
        {
            _logger.LogInformation($"Request recieved to edit pet with id {id}");
            //Update model in repo
            if (Request.Form.Files.Count != 0)
            {
                IFormFile file = Request.Form.Files[0];
                //Store file locally.
            }
            return StatusCode(StatusCodes.Status200OK);
        }
        catch (Exception e)
        {
            _logger.LogError($"Error: {e.Message} when attempting to edit pet with id {id}");
            return UnprocessableEntity();
        }
    }

我认为这对于PostMan请求来说已经足够了,但为了以防万一,我的fetch请求看起来像这样:

class Pet
    {
         name : string;
         id : string;
         constructor()
         {
             this.name = "";
             this.id = "";
         }
    }

    let model = new Pet();
    model.id = //some GUID;
    model.name = "Cheddar";
    let payLoad = new FormData();
    payLoad.append("model", JSON.stringify(model));
    let file = getFileSomehow();
        if (file)
        {
            payLoad.append("file", file);
        }
    let response: Response; 

        try
        {
            response = await fetch("../Pets/model.id",
                {
                    method: 'PUT',
                    headers: {
                        'Content-type': "multipart/form-data"
                    },
                    body: payload
                });
        }
        catch (err)
        {
            console.error(`Error processing update request, ${err}`);
            return;
        }

我想到的一个变通方法是发送两个单独的请求,但我宁愿保持内容完整,理想情况下-一次性发送它们。任何建议都很感激(:.

ccgok5k5

ccgok5k51#

我找到了解决方案,它包括使用请求。窗体来访问File并反序列化模型的值,该值也是从Request中检索的。因此,考虑到这一点,控制器应该看起来像这样:

[HttpPut("{id:guid}")]
public ActionResult EditPet(Guid id)
{
    Pet model = JsonConvert.DeserializeObject<Pet>(Request.Form["model"]);
    ArgumentNullCheck(model);
    try
    {
        _logger.LogInformation($"Request recieved to edit pet with id {id}");
        //Update model in repo
        if (Request.Form.Files.Count != 0)
        {
            IFormFile file = Request.Form.Files[0];
            //Store file locally.
        }
        return StatusCode(StatusCodes.Status200OK);
    }
    catch (Exception e)
    {
        _logger.LogError($"Error: {e.Message} when attempting to edit pet with id {id}");
        return UnprocessableEntity();
    }
}

相关问题