可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I\'m using asp.net mvc 4 webapi beta to build a rest service. I need to be able to accept POSTed images/files from client applications. Is this possible using the webapi? Below is how action I am currently using. Does anyone know of an example how this should work?
[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\";
}
回答1:
see http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2, although I think the article makes it seem a bit more complicated than it really is.
Basically,
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;
}
回答2:
I\'m surprised that a lot of you seem to want to save files on the server. Solution to keep everything in memory is as follows:
[HttpPost, Route(\"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();
}
回答3:
See the code below, adapted from this article, which demonstrates the simplest example code I could find. It includes both file and memory (faster) uploads.
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);
}
回答4:
Here is a quick and dirty solution which takes uploaded file contents from the HTTP body and writes it to a file. I included a \"bare bones\" HTML/JS snippet for the file upload.
Web API Method:
[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 File Upload:
<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>
回答5:
I used Mike Wasson\'s answer before I updated all the NuGets in my webapi mvc4 project. Once I did, I had to re-write the file upload action:
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;
}
Apparently BodyPartFileNames is no longer available within the MultipartFormDataStreamProvider.
回答6:
Toward this same directions, I\'m posting a client and server snipets that send Excel Files using WebApi, c# 4:
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
}
}
And the server webapi controller:
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!\"));
}
}
And the Custom MyMultipartFormDataStreamProvider, needed to customize the Filename:
PS: I took this code from another post 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);
}
}
回答7:
The ASP.NET Core way is now here:
[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});
}
回答8:
[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);
}
}
回答9:
Here are two ways to accept a file. One using in memory provider MultipartMemoryStreamProvider and one using MultipartFormDataStreamProvider which saves to a disk. Note, this is only for one file upload at a time. You can certainty extend this to save multiple-files. The second approach can support large files. I\'ve tested files over 200MB and it works fine. Using in memory approach does not require you to save to disk, but will throw out of memory exception if you exceed a certain limit.
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;
}
回答10:
I had a similar problem for the preview Web API. Did not port that part to the new MVC 4 Web API yet, but maybe this helps:
REST file upload with HttpRequestMessage or Stream?
Please let me know, can sit down tomorrow and try to implement it again.
回答11:
This question has lots of good answers even for .Net Core. I was using both Frameworks the provided code samples work fine. So I won\'t repeat it. In my case the important thing was how to use File upload actions with Swagger like this:
Here is my recap:
ASP .Net WebAPI 2
- To upload file use: MultipartFormDataStreamProvider see answers here
- How to use it with Swagger
.NET Core
- To upload file use: IFormFile see answers here or MS documentation
- How to use it with Swagger
回答12:
API Controller :
[HttpPost]
public HttpResponseMessage Post()
{
HttpRequestMessage request = this.Request;
if (!request.Content.IsMimeMultipartContent() || System.Web.HttpContext.Current.Request.Files.Count < 1)
{
//TODO
}
else
{
string root = System.Web.HttpContext.Current.Server.MapPath(\"~/App_Data\");
var provider = new MultipartFormDataStreamProvider(root);
try
{
Request.Content.ReadAsMultipartAsync(provider);
List<String> payload = new List<string>();
foreach (var file in provider.FileData)
{
var path = file.LocalFileName;
byte[] byteArray = File.ReadAllBytes(path);
}
}
catch (System.Exception e)
{
//TODO
}
}
return Request.CreateResponse(HttpStatusCode.Created);
}