如何在WebAPI中使用C#上传包含流的MultipartFormDataContent

huangapple go评论54阅读模式
英文:

Howto upload MultipartFormDataContent which contains a stream using c# in webapi

问题

给定的是以下的webapi HttpPost方法:

使用Microsoft.AspNetCore.Mvc;

/// <summary>
/// Eviget控制器用于上传工件,可以来自teamcity,也可以来自其他文件
/// </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; }
}

以下代码用于上传MultipartFormDataContent:

使用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");
//设置http头为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);
}

默认情况下,响应是400 (Bad Request)

使用以下控制器选项,请求将发送到REST服务器。这个选项只是告诉REST服务器应该忽略null值。

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

流始终为null。(注意:其他值已正确设置)

但是实际上,流是多部分表单数据的一部分(Fiddler输出)。

你需要做什么来确保在这种情况下流被正确映射?

英文:

Given is the following webapi HttpPost method:

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

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

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, &quot;Id&quot;);
StringContent NameStringContent = new StringContent($@&quot;foobar&quot;);
form.Add(NameStringContent, &quot;Name&quot;);

StreamContent TestStream = new StreamContent(GenerateStreamFromString(&quot;test content of my stream&quot;));
TestStream.Headers.ContentDisposition = new ContentDispositionHeaderValue(&quot;form-data&quot;) { Name = &quot;filecontent&quot;, FileName = &quot;test.txt&quot; };
TestStream.Headers.ContentType = new MediaTypeHeaderValue(&quot;application/octet-stream&quot;);
form.Add(TestStream, &quot;filecontent&quot;);
//set http heder to multipart/form-data
http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(&quot;multipart/form-data&quot;));
try
{
    System.Console.WriteLine(&quot;start&quot;);
    var response = http.PostAsync(&quot;http://localhost:5270/api/UploadDemo/Upload&quot;, 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 =&gt; options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true)

The stream is always null. (Note: The other values are properly set)
如何在WebAPI中使用C#上传包含流的MultipartFormDataContent

But the stream is actually part of the multipart form data(fiddler output)
如何在WebAPI中使用C#上传包含流的MultipartFormDataContent

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

答案1

得分: 1

替代使用数据类型 Stream,使用 IFormFile

这样,您可以按以下方式访问属性和文件:

var file = input.filecontent // 这是 IFormFile 文件

要将文件持久化/保存到磁盘,可以执行以下操作:

using (var stream = new FileStream(path, FileMode.Create))
{
    await file.File.CopyToAsync(stream);
}
英文:

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);
}

答案2

得分: 0

这是一个基于ibarcia信息的示例。

我创建了两个WebAPI控制器,允许读取作为MultipartFormDataContent的一部分上传的文件。

第一个方法定义了一个参数,该参数被标记为[FromForm],然后包含一个类型为IFormFile的属性。
在第二个实现中,未指定参数,文件可以通过Request.ReadFormAsync方法读取,然后访问File。

using Microsoft.AspNetCore.Mvc;
/// <summary>
/// 用于上传工件的Eviget控制器
/// 无论是从teamcity还是在杂项文件的情况下
/// </summary>
[Route("api/[controller]/[action]")]
[ApiController]
public class UploadDemoController : ControllerBase
{


    [HttpPost]
    public async Task<IActionResult> UploadWithoutParameter()
    {
        IFormCollection formCollection = await this.Request.ReadFormAsync();
        // 包含id和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("上传成功");
    }

    [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("上传成功");
    }

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

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;
/// &lt;summary&gt;
/// Eviget controller used for uploading artefacts 
/// Either from teamcity or in case of the misc files
/// &lt;/summary&gt;
[Route(&quot;api/[controller]/[action]&quot;)]
[ApiController]
public class UploadDemoController : ControllerBase
{


    [HttpPost]
    public async Task&lt;IActionResult&gt; 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(&quot;upload ok&quot;);
    }

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

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

huangapple
  • 本文由 发表于 2023年2月8日 20:51:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75386068.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定