如何接受文件POST

我正在使用asp.net mvc 4 webapi beta来构建一个休息服务。我需要能够接受张贴的图像/文件从客户端应用程序。这可能使用webapi吗?下面是如何行动,我目前正在使用。有人知道一个例子吗?

[HttpPost]
public string ProfileImagePost(HttpPostedFile profileImage)
{
string[] extensions = { ".jpg", ".jpeg", ".gif", ".bmp", ".png" };
if (!extensions.Any(x => x.Equals(Path.GetExtension(profileImage.FileName.ToLower()), StringComparison.OrdinalIgnoreCase)))
{
throw new HttpResponseException("Invalid file type.", HttpStatusCode.BadRequest);
}


// Other code goes here


return "/path/to/image.png";
}
474949 次浏览

我在预览Web API时遇到了类似的问题。还没有将这部分移植到新的MVC 4 Web API,但这可能会有所帮助:

REST文件上传HttpRequestMessage或Stream?< / >

请让我知道,可以坐下来,明天再试着实施它。

请参阅http://www.asp.net/web-api/overview/formats-and-model-binding/html-forms-and-multipart-mime#multipartmime,尽管我认为这篇文章使它看起来比实际情况更复杂。

基本上,

public Task<HttpResponseMessage> PostFile()
{
HttpRequestMessage request = this.Request;
if (!request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}


string root = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/uploads");
var provider = new MultipartFormDataStreamProvider(root);


var task = request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(o =>
{


string file1 = provider.BodyPartFileNames.First().Value;
// this is the file name on the server where the file was saved


return new HttpResponseMessage()
{
Content = new StringContent("File uploaded.")
};
}
);
return task;
}

在我更新webapi mvc4项目中的所有nuget之前,我使用了Mike Wasson的答案。一旦我这样做了,我必须重写文件上传操作:

    public Task<HttpResponseMessage> Upload(int id)
{
HttpRequestMessage request = this.Request;
if (!request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.UnsupportedMediaType));
}


string root = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/uploads");
var provider = new MultipartFormDataStreamProvider(root);


var task = request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(o =>
{
FileInfo finfo = new FileInfo(provider.FileData.First().LocalFileName);


string guid = Guid.NewGuid().ToString();


File.Move(finfo.FullName, Path.Combine(root, guid + "_" + provider.FileData.First().Headers.ContentDisposition.FileName.Replace("\"", "")));


return new HttpResponseMessage()
{
Content = new StringContent("File uploaded.")
};
}
);
return task;
}

显然BodyPartFileNames在MultipartFormDataStreamProvider中不再可用。

朝着同样的方向,我发布了一个客户端和服务器片段,使用WebApi, c# 4发送Excel文件:

public static void SetFile(String serviceUrl, byte[] fileArray, String fileName)
{
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (var content = new MultipartFormDataContent())
{
var fileContent = new ByteArrayContent(fileArray);//(System.IO.File.ReadAllBytes(fileName));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = fileName
};
content.Add(fileContent);
var result = client.PostAsync(serviceUrl, content).Result;
}
}
}
catch (Exception e)
{
//Log the exception
}
}

服务器的webapi控制器:

public Task<IEnumerable<string>> Post()
{
if (Request.Content.IsMimeMultipartContent())
{
string fullPath = HttpContext.Current.Server.MapPath("~/uploads");
MyMultipartFormDataStreamProvider streamProvider = new MyMultipartFormDataStreamProvider(fullPath);
var task = Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith(t =>
{
if (t.IsFaulted || t.IsCanceled)
throw new HttpResponseException(HttpStatusCode.InternalServerError);


var fileInfo = streamProvider.FileData.Select(i =>
{
var info = new FileInfo(i.LocalFileName);
return "File uploaded as " + info.FullName + " (" + info.Length + ")";
});
return fileInfo;


});
return task;
}
else
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "Invalid Request!"));
}
}
和自定义MyMultipartFormDataStreamProvider,需要自定义文件名:

PS:我从另一个帖子http://www.codeguru.com/csharp/.net/uploading-files-asynchronously-using-asp.net-web-api.htm

取了这个代码
public class MyMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public MyMultipartFormDataStreamProvider(string path)
: base(path)
{


}


public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
{
string fileName;
if (!string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName))
{
fileName = headers.ContentDisposition.FileName;
}
else
{
fileName = Guid.NewGuid().ToString() + ".data";
}
return fileName.Replace("\"", string.Empty);
}
}

我很惊讶你们很多人似乎都想把文件保存在服务器上。将所有内容保存在内存中的解决方案如下:

[HttpPost("api/upload")]
public async Task<IHttpActionResult> Upload()
{
if (!Request.Content.IsMimeMultipartContent())
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);


var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
foreach (var file in provider.Contents)
{
var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
var buffer = await file.ReadAsByteArrayAsync();
//Do whatever you want with filename and its binary data.
}


return Ok();
}

请看下面的代码,改编自这篇文章,它演示了我能找到的最简单的示例代码。它包括文件和内存(更快)上传。

public HttpResponseMessage Post()
{
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count < 1)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}


foreach(string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName);
postedFile.SaveAs(filePath);
// NOTE: To store in memory use postedFile.InputStream
}


return Request.CreateResponse(HttpStatusCode.Created);
}
[HttpPost]
public JsonResult PostImage(HttpPostedFileBase file)
{
try
{
if (file != null && file.ContentLength > 0 && file.ContentLength<=10485760)
{
var fileName = Path.GetFileName(file.FileName);


var path = Path.Combine(Server.MapPath("~/") + "HisloImages" + "\\", fileName);


file.SaveAs(path);
#region MyRegion
////save imag in Db
//using (MemoryStream ms = new MemoryStream())
//{
//    file.InputStream.CopyTo(ms);
//    byte[] array = ms.GetBuffer();
//}
#endregion
return Json(JsonResponseFactory.SuccessResponse("Status:0 ,Message: OK"), JsonRequestBehavior.AllowGet);
}
else
{
return Json(JsonResponseFactory.ErrorResponse("Status:1 , Message: Upload Again and File Size Should be Less Than 10MB"), JsonRequestBehavior.AllowGet);
}
}
catch (Exception ex)
{


return Json(JsonResponseFactory.ErrorResponse(ex.Message), JsonRequestBehavior.AllowGet);


}
}

下面是一个快速而简单的解决方案,它从HTTP正文中获取上传的文件内容并将其写入文件。我为文件上传包含了一个“骨架”HTML/JS片段。

Web API方法:

[Route("api/myfileupload")]
[HttpPost]
public string MyFileUpload()
{
var request = HttpContext.Current.Request;
var filePath = "C:\\temp\\" + request.Headers["filename"];
using (var fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
{
request.InputStream.CopyTo(fs);
}
return "uploaded";
}

HTML文件上传:

<form>
<input type="file" id="myfile"/>
<input type="button" onclick="uploadFile();" value="Upload" />
</form>
<script type="text/javascript">
function uploadFile() {
var xhr = new XMLHttpRequest();
var file = document.getElementById('myfile').files[0];
xhr.open("POST", "api/myfileupload");
xhr.setRequestHeader("filename", file.name);
xhr.send(file);
}
</script>

ASP。NET Core方式现在是在这里:

[HttpPost("UploadFiles")]
public async Task<IActionResult> Post(List<IFormFile> files)
{
long size = files.Sum(f => f.Length);


// full path to file in temp location
var filePath = Path.GetTempFileName();


foreach (var formFile in files)
{
if (formFile.Length > 0)
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
await formFile.CopyToAsync(stream);
}
}
}


// process uploaded files
// Don't rely on or trust the FileName property without validation.


return Ok(new { count = files.Count, size, filePath});
}

这里有两种接受文件的方法。一个使用内存提供程序MultipartMemoryStreamProvider,另一个使用保存到磁盘的MultipartFormDataStreamProvider。注意,这一次只针对一个文件上传。您可以扩展它来保存多个文件。第二种方法可以支持大文件。我测试过超过200MB的文件,它工作得很好。使用内存方法不需要保存到磁盘,但如果超过一定的限制,将抛出内存外异常。

private async Task<Stream> ReadStream()
{
Stream stream = null;
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
foreach (var file in provider.Contents)
{
var buffer = await file.ReadAsByteArrayAsync();
stream = new MemoryStream(buffer);
}


return stream;
}


private async Task<Stream> ReadLargeStream()
{
Stream stream = null;
string root = Path.GetTempPath();
var provider = new MultipartFormDataStreamProvider(root);
await Request.Content.ReadAsMultipartAsync(provider);
foreach (var file in provider.FileData)
{
var path = file.LocalFileName;
byte[] content = File.ReadAllBytes(path);
File.Delete(path);
stream = new MemoryStream(content);
}


return stream;
}

这个问题甚至对于。net Core也有很多好的答案。我使用这两个框架提供的代码示例工作良好。我就不重复了。在我的例子中,重要的事情是如何使用< a href = " https://swagger。io/" rel="nofollow noreferrer">Swagger . io/" rel="nofollow noreferrer">的文件上传动作,就像这样:

文件上传按钮在Swagger

以下是我的概述:

2 . asp.net WebAPI

net核心

API控制器:

[HttpPost]
public HttpResponseMessage Post()
{
var httpRequest = System.Web.HttpContext.Current.Request;


if (System.Web.HttpContext.Current.Request.Files.Count < 1)
{
//TODO
}
else
{


try
{
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
BinaryReader binReader = new BinaryReader(postedFile.InputStream);
byte[] byteArray = binReader.ReadBytes(postedFile.ContentLength);


}


}
catch (System.Exception e)
{
//TODO
}


return Request.CreateResponse(HttpStatusCode.Created);
}

补充Matt Frear的回答-这将是一个asp.net Core的选择,直接从流读取文件,而不保存&

public ActionResult OnPostUpload(List<IFormFile> files)
{
try
{
var file = files.FirstOrDefault();
var inputstream = file.OpenReadStream();


XSSFWorkbook workbook = new XSSFWorkbook(stream);


var FIRST_ROW_NUMBER = \{\{firstRowWithValue}};


ISheet sheet = workbook.GetSheetAt(0);
// Example: var firstCellRow = (int)sheet.GetRow(0).GetCell(0).NumericCellValue;


for (int rowIdx = 2; rowIdx <= sheet.LastRowNum; rowIdx++)
{
IRow currentRow = sheet.GetRow(rowIdx);


if (currentRow == null || currentRow.Cells == null || currentRow.Cells.Count() < FIRST_ROW_NUMBER) break;


var df = new DataFormatter();


for (int cellNumber = \{\{firstCellWithValue}}; cellNumber < \{\{lastCellWithValue}}; cellNumber++)
{
//business logic & saving data to DB
}
}
}
catch(Exception ex)
{
throw new FileFormatException($"Error on file processing - {ex.Message}");
}
}