23

I'm trying to send a image and text fields to an API endpoint but I'm received

Unsupported content type 'multipart/form-data; boundary=---------------------------81801171514357

This is a ASP.NET Core 2.1 Web API. I have this:

[HttpPost("/api/account"), Authorize]
public void SaveUser(UserModel info)

And my model:

    [JsonProperty(PropertyName = "avatar")]
    [DataType(DataType.Upload)]
    public IFormFile Avatar { get; set; }

    [JsonProperty(PropertyName = "name")]
    [DataType(DataType.Text)]
    public string Name { get; set; }

Then I use axios:

    var formData = new FormData();
    formData.append("avatar", imageFile);
    formData.append("name", name);
    axios.post("/api/account", formData);

I expected this method to run, not throw an exception. But how? I have tried to add:

[Consumes("application/json", "multipart/form-data")]

But no success.

Then I tried:

[HttpPost("/api/account"), Authorize]
public void SaveUser([FromForm]UserModel info)

The method runs, but the properties is empty on info object :(

UPDATE: Solution, don't use JsonProperty PropertyName. Use the variable name.

5
  • 1
    You should use public void SaveUser(IFormCollection collection) when uploading a file with detail. Follow this stackoverflow.com/questions/53825794/… Commented Jan 29, 2019 at 5:30
  • Is there any demo to reproduce your issue? I made a test with your current code, it wokrs correctly. Commented Jan 29, 2019 at 6:40
  • I have another method: [HttpPost("/api/avatar"), Authorize] public void SaveAvatar(IFormFile avatar) There is no problem. But when i add IFormFile and properties in a model, then i get "Unsupported content type 'multipart/form-data". Commented Jan 29, 2019 at 8:50
  • Now, i found that i cant use the JsonProperty name, i must use Avatar and Name (the property names). Then it works fine. Is that possible to set the name of the properties? Commented Jan 29, 2019 at 12:01
  • This is the solution.[stackoverflow.com/questions/60275185/… Commented Mar 15, 2020 at 7:43

4 Answers 4

32

Maybe you should try decorate controller input and model with [FromForm] attribute? See more info here: web api parameters binding.

In given example your controller action should look like this:

[HttpPost("/api/account"), Authorize]
public void SaveUser([FromForm]UserModel info)

In model:

[FromForm(Name="avatar")]
public IFormFile Avatar { get; set; }

[FromForm(Name="name")]
public string Name { get; set; }
Sign up to request clarification or add additional context in comments.

7 Comments

Yes, i have try to add, [FromForm] then all the properties in my model is null.
Try to add this attribute on model properties.
i found that i cant use the JsonProperty name, i must use Avatar and Name (the property names). Then it works fine. Is that possible to set the name of the properties?
Use should use [FromForm] attribute in Controller action and in model definition. At least that worked to me.
This just saved my day! I was up all night with this issue. Thank you so much @joostas
|
4

1 - Receive multi part file:

[HttpPost, Route("postimagenews")]
public IActionResult PostImageNews([FromForm] IFormFile file)
{
    try
    {
        if (file == null || file.Length == 0)
        {
            return BadRequest("Please send a photo");
        }
        // Create unique name for file.
        var fileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName);

        // Set file url.
        var savePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/images/news", fileName);

        using (var stream = new FileStream(savePath, FileMode.Create))
        {
            file.CopyTo(stream);
        }
        
        return Ok(fileName);
    }
    catch
    {
        return BadRequest("Error in image upload");
    }
}

2 - Send multi part file in C#:

public static async Task<string> PostImage(string apiEndPoint, IFormFile data)
{
    // Warning: use a proper way to get the HttpClient. Following code may exhaust socket ports,
    // see https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines
    using (var httpClient = new HttpClient())
    {
        var multipartContent = new MultipartFormDataContent();
        var fileContent = new ByteArrayContent(GetFileArray(data));
        fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
        multipartContent.Add(fileContent, "file", data.FileName);
        var resultUploadImage = await httpClient.PostAsync(apiEndPoint, multipartContent);
        if (resultUploadImage.IsSuccessStatusCode)
        {
            var fileName = (await resultUploadImage.Content.ReadAsStringAsync()).Replace("\"", "");
            return fileName;
        }
        return "";
    }
}
        
public static byte[] GetFileArray(IFormFile file)
{
    using (var ms = new MemoryStream())
    {
        file.CopyTo(ms);
        return ms.ToArray();
    }
}

3 - Send multi-part encoded file with Postman:

enter image description here

2 Comments

Isn't your point one actually receive the file and your point two send the file?
I have adjusted this and also added a warning about proper usage of the HttpClient.
0

Note that as mentioned in this question/answer, when using [FromForm] binding, it does not work automatically with application/json content (i.e. the object is not parsed). For example from the current answer, if you replace string Name with something like NameInfo Name:

[HttpPost("/api/account"), Authorize]
public void SaveUser([FromForm]UserModel info)

// In model:
[FromForm(Name="avatar")]
public IFormFile Avatar { get; set; }

[FromForm(Name="name")]
public NameInfo Name { get; set; }

Then it would NOT be parsed successfully. You either have to put it as string and use JsonSerializer.Deserialize(info.Name) by yourself or use custom binding like in the linked answer.

Comments

-3

Here is a working example for what you are looking for

Controller:

[HttpPost]
public async Task<IActionResult> SaveFile([FromForm] IFormFile file) {
  // Your code here
}

And inside your model:

public IFormFile File { get; set; }

Change async Task<IActionResult> if you don't need it...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.