如何为多部分/表单数据设置 Web API 控制器

我正在想办法。我的代码没有得到任何有用的错误消息,因此我使用其他代码来生成一些错误消息。我在错误消息后附加了该代码。我已经找到了一个 教程上,但我不知道如何实施它与我有什么。这是我目前拥有的:

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;


}

错误:

对象{ message: “此资源不支持请求实体的媒体类型‘ multipart/form-data’。”“没有 MediaTypeFormatter 可用于读取媒体类型为‘ multipart/form-data’的 obje... om 内容。”例外类型:”系统。网。哈哈。不支持的 MediaTypeException”,stackTrace: “ at System。网。哈哈。HttpContentExtended.ReadAs... atterLogger,CcellationToken CancellationToken)”} exctionMessage: “没有 MediaTypeFormatter 可用于从媒体类型为‘ multipart/form-data’的内容中读取类型为‘ HttpPostedFileBase’的对象。异常类型: 系统。网。哈哈。“信息:”此资源不支持请求实体的媒体类型‘ multipart/form-data’。“ stackTrace:”at System。网。哈哈。HttpContentExtended.ReadAsAsync [ T ](HttpContent content,Type Type,IEnumable < code > 1 format ters,IFormatterLogger format terLogger,CancelationToken CancellationToken) ReadAsAsync (HttpContent 内容,类型,IEnumable 1格式化程序,IFormatterLogger 格式化程序,取消令牌取消令牌)

用于生成错误消息的代码:

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

班级:

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; }
}
190250 次浏览

我通常只在 Mvc 控制器中使用 HttpPostedFileBase参数。在处理 控制器时,尝试检查 当前,请求,文件属性以获取传入文件:

[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“请求实体的媒体类型‘ multipart/form-data’不受此资源的支持。”因为你在请求中没有提到正确的内容类型。

这就解决了我的问题
将以下代码行添加到 WebApiConfig.cs

config.Formatters.XmlFormatter.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("multipart/form-data"));

也许派对已经迟到了。 但是有一个替代的解决方案是使用 表单格式插件。

这个插件帮助你像 ASP.NET Core 一样接收多部分/格式数据内容。

在 github 页面中,已经提供了 demo。

5年后,.NET Core 3.1允许你像下面这样指定媒体类型:

[HttpPost]
[Consumes("multipart/form-data")]
public IActionResult UploadLogo()
{
return Ok();
}

这是 ASP.Net Core 解决这个问题的另一个答案..。

在角度方面,我采用了这个代码示例..。

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 Core 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();


           

}

对于 Asp.net MVC,我需要在保存文件之前进行验证和处理,这样我就可以通过更多的步骤来解决我的问题,将文件交给一个属性。一开始是

HttpContext.Current.Request.Files[i]

是 HttpPostedFile,所以我创建了一个这种类型的属性(我有多个文件,需要更多的属性) ,所以我分配文件属性如下

if (HttpContext.Current.Request.Files.Count>0)
{


var files = HttpContext.Current.Request.Files;
for (int i = 0; i < files.Keys.Count; i++)
{
if (files.Keys[i].ToLower() == "ShenasnameImage".ToLower())
{
model.ShenasnameImage = files[i];
                    

}
if (files.Keys[i].ToLower() == "MelliCardImage".ToLower())
{
model.MelliCardImage = files[i];
                    

}
}
}

然后对文件属性进行验证和处理,最后保存文件。