1

Given is the following webapi HttpPost method:

using Microsoft.AspNetCore.Mvc;
/// <summary>
/// Eviget controller used for uploading artefacts 
/// Either from teamcity or in case of the misc files
/// </summary>
[Route("api/[controller]/[action]")]
[ApiController]
public class UploadDemoController : ControllerBase
{

    [HttpPost]
    public IActionResult Upload([FromForm] UploadContent input)
    {
        return Ok("upload ok");
    }
}

public class UploadContent
{
    public string Id { get; set; }
    public string Name { get; set; }
    public Stream filecontent { get; set; }
}

The following code is used to upload a MultipartFormDataContent

using System.Net.Http.Headers;

HttpClient http = new HttpClient();
MultipartFormDataContent form = new MultipartFormDataContent();

StringContent IdStringContent = new StringContent(Guid.NewGuid().ToString());
form.Add(IdStringContent, "Id");
StringContent NameStringContent = new StringContent($@"foobar");
form.Add(NameStringContent, "Name");

StreamContent TestStream = new StreamContent(GenerateStreamFromString("test content of my stream"));
TestStream.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "filecontent", FileName = "test.txt" };
TestStream.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
form.Add(TestStream, "filecontent");
//set http heder to multipart/form-data
http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("multipart/form-data"));
try
{
    System.Console.WriteLine("start");
    var response = http.PostAsync("http://localhost:5270/api/UploadDemo/Upload", form).Result;
    response.EnsureSuccessStatusCode();
}
catch (System.Exception ex)
{
    System.Console.WriteLine(ex.Message);
}

By default, the response is 400 (Bad Request).

With the following controller option, the request is sent to the rest server. This option just says the rest server should ignore null values.

 builder.Services.AddControllers(options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true)

The stream is always null. (Note: The other values are properly set) enter image description here

But the stream is actually part of the multipart form data(fiddler output) enter image description here

What do i need to do that the Stream is properly mapped in this case?

2 Answers 2

1

Instead of using the data type Stream, use IFormFile.

So then you can access the properties and the file as follows:

var file = input.filecontent // This is the IFormFile file

To persist/save the file to disk you can do the following:

using (var stream = new FileStream(path, FileMode.Create))
{
    await file.File.CopyToAsync(stream);
}
Sign up to request clarification or add additional context in comments.

3 Comments

When using IFormFile, i'm able to read the content and everything seems to work. Any Idea why this doesn't work when using Stream?
If you are using "multipart/form-data" you need to use IFormFile, otherwise, you must use Stream data type.
Microsoft has documentation around this if you want to stream the file and save memory/disk space rather than buffer the file - learn.microsoft.com/en-us/aspnet/core/mvc/models/…
0

This is a sample based on the information from ibarcia.

I've created two webapi controller which allow to read files uploaded as part of a MultipartFormDataContent.

One method defines a parameter which is attributed with [FromForm] and which then contains a property of type IFormFile. In the second implementation, no parameter is specified and the file can be read via Request.ReadFormAsync and then accessing the File


using Microsoft.AspNetCore.Mvc;
/// <summary>
/// Eviget controller used for uploading artefacts 
/// Either from teamcity or in case of the misc files
/// </summary>
[Route("api/[controller]/[action]")]
[ApiController]
public class UploadDemoController : ControllerBase
{


    [HttpPost]
    public async Task<IActionResult> UploadWithoutParameter()
    {
        IFormCollection formCollection = await this.Request.ReadFormAsync();
        //contains id and name
        foreach (var form in formCollection)
        {
            System.Console.WriteLine(form.Key);
            System.Console.WriteLine(form.Value);
        }
        foreach (var file in formCollection.Files)
        {
            System.Console.WriteLine(file.FileName);
            System.Console.WriteLine(file.Length);
        }
        return Ok("upload ok");
    }

    [HttpPost]
    public async Task<IActionResult> Upload([FromForm] UploadContent input)
    {
        System.Console.WriteLine(input.Id);
        System.Console.WriteLine(input.Name);
        using (var stream = new FileStream(@"c:/temp/neutesttext.txt", FileMode.Create))
        {
            await input.filecontent.CopyToAsync(stream);
        }
        return Ok("upload ok");
    }

    public class UploadContent
    {
        public string Id { get; set; }
        public string Name { get; set; }
        // public Stream filecontent { get; set; }
        public IFormFile filecontent { get; set; }
    }
}

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.