如何为 multipart/form-data 设置 Web API 控制器
How to set up a Web API controller for multipart/form-data
我正在努力解决这个问题。我的代码没有收到任何有用的错误消息,所以我使用了其他东西来生成一些东西。我在错误消息后附加了该代码。我在上面找到了一个 tutorial 但我不知道如何用我现有的实现它。这是我目前拥有的:
public async Task<object> PostFile()
{
if (!Request.Content.IsMimeMultipartContent())
throw new Exception();
var provider = new MultipartMemoryStreamProvider();
var result = new { file = new List<object>() };
var item = new File();
item.CompanyName = HttpContext.Current.Request.Form["companyName"];
item.FileDate = HttpContext.Current.Request.Form["fileDate"];
item.FileLocation = HttpContext.Current.Request.Form["fileLocation"];
item.FilePlant = HttpContext.Current.Request.Form["filePlant"];
item.FileTerm = HttpContext.Current.Request.Form["fileTerm"];
item.FileType = HttpContext.Current.Request.Form["fileType"];
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var user = manager.FindById(User.Identity.GetUserId());
item.FileUploadedBy = user.Name;
item.FileUploadDate = DateTime.Now;
await Request.Content.ReadAsMultipartAsync(provider)
.ContinueWith(async (a) =>
{
foreach (var file in provider.Contents)
{
if (file.Headers.ContentLength > 1000)
{
var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
var contentType = file.Headers.ContentType.ToString();
await file.ReadAsByteArrayAsync().ContinueWith(b => { item.FilePdf = b.Result; });
}
}
}).Unwrap();
db.Files.Add(item);
db.SaveChanges();
return result;
}
错误:
Object {message: "The request entity's media type 'multipart/form-data' is not supported for this resource.", exceptionMessage: "No MediaTypeFormatter is available to read an obje…om content with media type 'multipart/form-data'.", exceptionType: "System.Net.Http.UnsupportedMediaTypeException", stackTrace: " at System.Net.Http.HttpContentExtensions.ReadAs…atterLogger, CancellationToken cancellationToken)"}exceptionMessage: "No MediaTypeFormatter is available to read an object of type 'HttpPostedFileBase' from content with media type 'multipart/form-data'."exceptionType: "System.Net.Http.UnsupportedMediaTypeException"message: "The request entity's media type 'multipart/form-data' is not supported for this resource."stackTrace: " at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
↵ at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable
1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
用于生成错误消息的代码:
[HttpPost]
public string UploadFile(HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(HttpContext.Current.Server.MapPath("~/uploads"), fileName);
file.SaveAs(path);
}
return "/uploads/" + file.FileName;
}
Class:
public class File
{
public int FileId { get; set; }
public string FileType { get; set; }
public string FileDate { get; set; }
public byte[] FilePdf { get; set; }
public string FileLocation { get; set; }
public string FilePlant { get; set; }
public string FileTerm { get; set; }
public DateTime? FileUploadDate { get; set; }
public string FileUploadedBy { get; set; }
public string CompanyName { get; set; }
public virtual ApplicationUser User { get; set; }
}
我通常只在 Mvc Controllers 中使用 HttpPostedFileBase 参数。在处理 ApiControllers 时,请尝试检查传入文件的 HttpContext.Current.Request.Files 属性:
[HttpPost]
public string UploadFile()
{
var file = HttpContext.Current.Request.Files.Count > 0 ?
HttpContext.Current.Request.Files[0] : null;
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(
HttpContext.Current.Server.MapPath("~/uploads"),
fileName
);
file.SaveAs(path);
}
return file != null ? "/uploads/" + file.FileName : null;
}
你可以使用这样的东西
[HttpPost]
public async Task<HttpResponseMessage> AddFile()
{
if (!Request.Content.IsMimeMultipartContent())
{
this.Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/temp/uploads");
var provider = new MultipartFormDataStreamProvider(root);
var result = await Request.Content.ReadAsMultipartAsync(provider);
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
if (key == "companyName")
{
var companyName = val;
}
}
}
// On upload, files are given a generic name like "BodyPart_26d6abe1-3ae1-416a-9429-b35f15e6e5d5"
// so this is how you can get the original file name
var originalFileName = GetDeserializedFileName(result.FileData.First());
var uploadedFileInfo = new FileInfo(result.FileData.First().LocalFileName);
string path = result.FileData.First().LocalFileName;
//Do whatever you want to do with your file here
return this.Request.CreateResponse(HttpStatusCode.OK, originalFileName );
}
private string GetDeserializedFileName(MultipartFileData fileData)
{
var fileName = GetFileName(fileData);
return JsonConvert.DeserializeObject(fileName).ToString();
}
public string GetFileName(MultipartFileData fileData)
{
return fileData.Headers.ContentDisposition.FileName;
}
检查你的 WebApiConfig 并添加这个
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
您收到 HTTP 415 "The request entity's media type 'multipart/form-data' is not supported for this resource." 因为您没有在请求中提及正确的内容类型。
这就是解决我问题的方法
将以下行添加到 WebApiConfig.cs
config.Formatters.XmlFormatter.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("multipart/form-data"));
也许聚会迟到了。
但是还有一个替代解决方案是使用 ApiMultipartFormFormatter 插件。
此插件可帮助您像 ASP.NET Core 一样接收 multipart/formdata 内容。
在github页面中,已经提供了demo
5 年后,.NET Core 3.1 允许您像这样指定媒体类型:
[HttpPost]
[Consumes("multipart/form-data")]
public IActionResult UploadLogo()
{
return Ok();
}
这是 ASP.Net 这个问题的核心解决方案的另一个答案...
在 Angular 方面,我采用了这个代码示例...
https://stackblitz.com/edit/angular-drag-n-drop-directive
... 并将其修改为调用 HTTP Post 端点:
prepareFilesList(files: Array<any>) {
const formData = new FormData();
for (var i = 0; i < files.length; i++) {
formData.append("file[]", files[i]);
}
let URL = "https://localhost:44353/api/Users";
this.http.post(URL, formData).subscribe(
data => { console.log(data); },
error => { console.log(error); }
);
有了这个,下面是我在 ASP.Net 核心 WebAPI 控制器中需要的代码:
[HttpPost]
public ActionResult Post()
{
try
{
var files = Request.Form.Files;
foreach (IFormFile file in files)
{
if (file.Length == 0)
continue;
string tempFilename = Path.Combine(Path.GetTempPath(), file.FileName);
System.Diagnostics.Trace.WriteLine($"Saved file to: {tempFilename}");
using (var fileStream = new FileStream(tempFilename, FileMode.Create))
{
file.CopyTo(fileStream);
}
}
return new OkObjectResult("Yes");
}
catch (Exception ex)
{
return new BadRequestObjectResult(ex.Message);
}
}
非常简单,但我必须从几个(几乎正确的)来源拼凑示例才能使其正常工作。
我就是这样工作的,希望对你有帮助!
[HttpPost("AddProduct")]
public async Task<IActionResult> AddProduct( IFormFile files)
{
string fileGuid = Guid.NewGuid().ToString();
var pathImage = Path.Combine(_hostEnvironment.ContentRootPath, "Images", fileGuid);
var streamImage = new FileStream(pathImage, FileMode.Append);
await files.CopyToAsync(streamImage);
return Ok();
}
我正在努力解决这个问题。我的代码没有收到任何有用的错误消息,所以我使用了其他东西来生成一些东西。我在错误消息后附加了该代码。我在上面找到了一个 tutorial 但我不知道如何用我现有的实现它。这是我目前拥有的:
public async Task<object> PostFile()
{
if (!Request.Content.IsMimeMultipartContent())
throw new Exception();
var provider = new MultipartMemoryStreamProvider();
var result = new { file = new List<object>() };
var item = new File();
item.CompanyName = HttpContext.Current.Request.Form["companyName"];
item.FileDate = HttpContext.Current.Request.Form["fileDate"];
item.FileLocation = HttpContext.Current.Request.Form["fileLocation"];
item.FilePlant = HttpContext.Current.Request.Form["filePlant"];
item.FileTerm = HttpContext.Current.Request.Form["fileTerm"];
item.FileType = HttpContext.Current.Request.Form["fileType"];
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var user = manager.FindById(User.Identity.GetUserId());
item.FileUploadedBy = user.Name;
item.FileUploadDate = DateTime.Now;
await Request.Content.ReadAsMultipartAsync(provider)
.ContinueWith(async (a) =>
{
foreach (var file in provider.Contents)
{
if (file.Headers.ContentLength > 1000)
{
var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
var contentType = file.Headers.ContentType.ToString();
await file.ReadAsByteArrayAsync().ContinueWith(b => { item.FilePdf = b.Result; });
}
}
}).Unwrap();
db.Files.Add(item);
db.SaveChanges();
return result;
}
错误:
Object {message: "The request entity's media type 'multipart/form-data' is not supported for this resource.", exceptionMessage: "No MediaTypeFormatter is available to read an obje…om content with media type 'multipart/form-data'.", exceptionType: "System.Net.Http.UnsupportedMediaTypeException", stackTrace: " at System.Net.Http.HttpContentExtensions.ReadAs…atterLogger, CancellationToken cancellationToken)"}exceptionMessage: "No MediaTypeFormatter is available to read an object of type 'HttpPostedFileBase' from content with media type 'multipart/form-data'."exceptionType: "System.Net.Http.UnsupportedMediaTypeException"message: "The request entity's media type 'multipart/form-data' is not supported for this resource."stackTrace: " at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable
1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken) ↵ at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable
1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)
用于生成错误消息的代码:
[HttpPost]
public string UploadFile(HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(HttpContext.Current.Server.MapPath("~/uploads"), fileName);
file.SaveAs(path);
}
return "/uploads/" + file.FileName;
}
Class:
public class File
{
public int FileId { get; set; }
public string FileType { get; set; }
public string FileDate { get; set; }
public byte[] FilePdf { get; set; }
public string FileLocation { get; set; }
public string FilePlant { get; set; }
public string FileTerm { get; set; }
public DateTime? FileUploadDate { get; set; }
public string FileUploadedBy { get; set; }
public string CompanyName { get; set; }
public virtual ApplicationUser User { get; set; }
}
我通常只在 Mvc Controllers 中使用 HttpPostedFileBase 参数。在处理 ApiControllers 时,请尝试检查传入文件的 HttpContext.Current.Request.Files 属性:
[HttpPost]
public string UploadFile()
{
var file = HttpContext.Current.Request.Files.Count > 0 ?
HttpContext.Current.Request.Files[0] : null;
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(
HttpContext.Current.Server.MapPath("~/uploads"),
fileName
);
file.SaveAs(path);
}
return file != null ? "/uploads/" + file.FileName : null;
}
你可以使用这样的东西
[HttpPost]
public async Task<HttpResponseMessage> AddFile()
{
if (!Request.Content.IsMimeMultipartContent())
{
this.Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/temp/uploads");
var provider = new MultipartFormDataStreamProvider(root);
var result = await Request.Content.ReadAsMultipartAsync(provider);
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
if (key == "companyName")
{
var companyName = val;
}
}
}
// On upload, files are given a generic name like "BodyPart_26d6abe1-3ae1-416a-9429-b35f15e6e5d5"
// so this is how you can get the original file name
var originalFileName = GetDeserializedFileName(result.FileData.First());
var uploadedFileInfo = new FileInfo(result.FileData.First().LocalFileName);
string path = result.FileData.First().LocalFileName;
//Do whatever you want to do with your file here
return this.Request.CreateResponse(HttpStatusCode.OK, originalFileName );
}
private string GetDeserializedFileName(MultipartFileData fileData)
{
var fileName = GetFileName(fileData);
return JsonConvert.DeserializeObject(fileName).ToString();
}
public string GetFileName(MultipartFileData fileData)
{
return fileData.Headers.ContentDisposition.FileName;
}
检查你的 WebApiConfig 并添加这个
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
您收到 HTTP 415 "The request entity's media type 'multipart/form-data' is not supported for this resource." 因为您没有在请求中提及正确的内容类型。
这就是解决我问题的方法
将以下行添加到 WebApiConfig.cs
config.Formatters.XmlFormatter.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("multipart/form-data"));
也许聚会迟到了。 但是还有一个替代解决方案是使用 ApiMultipartFormFormatter 插件。
此插件可帮助您像 ASP.NET Core 一样接收 multipart/formdata 内容。
在github页面中,已经提供了demo
5 年后,.NET Core 3.1 允许您像这样指定媒体类型:
[HttpPost]
[Consumes("multipart/form-data")]
public IActionResult UploadLogo()
{
return Ok();
}
这是 ASP.Net 这个问题的核心解决方案的另一个答案...
在 Angular 方面,我采用了这个代码示例...
https://stackblitz.com/edit/angular-drag-n-drop-directive
... 并将其修改为调用 HTTP Post 端点:
prepareFilesList(files: Array<any>) {
const formData = new FormData();
for (var i = 0; i < files.length; i++) {
formData.append("file[]", files[i]);
}
let URL = "https://localhost:44353/api/Users";
this.http.post(URL, formData).subscribe(
data => { console.log(data); },
error => { console.log(error); }
);
有了这个,下面是我在 ASP.Net 核心 WebAPI 控制器中需要的代码:
[HttpPost]
public ActionResult Post()
{
try
{
var files = Request.Form.Files;
foreach (IFormFile file in files)
{
if (file.Length == 0)
continue;
string tempFilename = Path.Combine(Path.GetTempPath(), file.FileName);
System.Diagnostics.Trace.WriteLine($"Saved file to: {tempFilename}");
using (var fileStream = new FileStream(tempFilename, FileMode.Create))
{
file.CopyTo(fileStream);
}
}
return new OkObjectResult("Yes");
}
catch (Exception ex)
{
return new BadRequestObjectResult(ex.Message);
}
}
非常简单,但我必须从几个(几乎正确的)来源拼凑示例才能使其正常工作。
我就是这样工作的,希望对你有帮助!
[HttpPost("AddProduct")]
public async Task<IActionResult> AddProduct( IFormFile files)
{
string fileGuid = Guid.NewGuid().ToString();
var pathImage = Path.Combine(_hostEnvironment.ContentRootPath, "Images", fileGuid);
var streamImage = new FileStream(pathImage, FileMode.Append);
await files.CopyToAsync(streamImage);
return Ok();
}