英文:
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;
/// <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)
But the stream is actually part of the multipart form data(fiddler output)
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;
/// <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; }
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论