Brandon Turpy
Brandon Turpy

Reputation: 921

400 Bad Request when trying to send api request with IFormFile in request object

I am having a hard time figuring out how to send an IFormFile object part of the request. It is an API call to upload an image. I have found a few resources and have tried each suggestion but I always get a 400 Bad Request response when I try and hit the API. Both the API and client are ASP.NET Core 2.1

Call to the API

public async Task<ApiResponse<ImageDto>> AddImageToWebsite(AddImageToWebsiteRequest request)
{
      try
      {
        HttpClient client = new HttpClient();
        var url = $"{_apiInfo.Url}/portal/AddImageToWebsite";
        byte[] data;
        using (var br = new BinaryReader(request.Image.OpenReadStream()))
        {
          data = br.ReadBytes((int) request.Image.OpenReadStream().Length);
        }

        var bytes = new ByteArrayContent(data);
        MultipartFormDataContent multiContent = new MultipartFormDataContent();    

        multiContent.Add(bytes, "file", request.Image.FileName);
        multiContent.Add(new StringContent(request.WebsiteId.ToString()), "WebsiteId");
        multiContent.Add(new StringContent(request.AltText), "AltText");

        // BREAKS AFTER THIS POST CALL
        var apiResponse = await client.PostAsync(url, multiContent);

        // DESERIALIZE RESPONSE TO RESPONSE OBJECT HERE

      }
      catch (Exception ex)
      {
        Log.Error(ex, "Error calling api");
        return ApiResponse.InternalError<ImageDto>(ex.Message);
      }
}

AddImageToWebsiteRequest

public class AddImageToWebsiteRequest
{
    public int WebsiteId { get; set; }
    public IFormFile Image { get; set; }
    public string AltText { get; set; }
}

API CALL

[HttpPost]
[Route("AddImageToWebsite")]
public async Task<JsonResult> AddImageToWebsite(AddImageToWebsiteRequest request)
{
  return await this.HandleRequest(async () =>
  {
    var website = _dataAccess.GetWebsite(request.WebsiteId);

    if (website == default(Website))
    {
      return ApiResponse.NotFound<ImageDto>("Website not found");
    }

    // UPLOAD IMAGE CODE HERE
  }
}

It does not even hit the API call. I also tried posting it as follows, and it worked as long as I did not have an image in the serialized object.

Another Attempt

var stringContent = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
var apiResponse = await client.PostAsync(url, stringContent);

// DESERIALIZE RESPONSE TO RESPONSE OBJECT HERE

I have tried so many different recommendations online and none seem to work.

Upvotes: 0

Views: 2529

Answers (2)

CryptoChrisJames
CryptoChrisJames

Reputation: 53

How are you sending this from the view? If you are using a form, you can just give it the multipart/form-data type, give the input type of file and then bind it to the IFormFile in the parameter.

View:

<form id="fileupload" action="yourpath/AddImageToWebsite/" method="POST" enctype="multipart/form-data">
  <button type="submit" class="btn btn-primary start">
  </button>
  <input type="file" name="YourFile"/>
  <!--Whatever other things you need to input, use hidden fields-->
</form> 

Controller:

[HttpPost]
[Route("AddImageToWebsite")]
public async Task<JsonResult> AddImageToWebsite(IFormFile YourFile)
{
  //Do what you need....
}

Upvotes: 0

Chris Pratt
Chris Pratt

Reputation: 239290

IFormFile is only for multipart/form-data encoded POST requests, i.e. a traditional form post. If you're sending JSON, your "upload" needs to be a Base64 string and you need to bind to a byte[]:

public class AddImageToWebsiteRequest
{
    public int WebsiteId { get; set; }
    public byte[] Image { get; set; }
    public string AltText { get; set; }
}

JsonConvert.SerializeObject will automatically convert byte[]s into Base64 strings.

Upvotes: 3

Related Questions