如何接受文件POST

Phi*_*hil 242 c# asp.net-mvc-4

我正在使用asp.net mvc 4 webapi beta来构建休息服务.我需要能够从客户端应用程序接受POSTed图像/文件.这可能使用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";
}
Run Code Online (Sandbox Code Playgroud)

Gle*_*eno 364

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

[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();
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您不想花费磁盘空间,将文件保留在内存中会很有用.但是,如果您允许上传大文件然后将其保留在内存中,则意味着您的网络服务器将耗尽大量内存,而这些内存不能用于保留其他请求的内容.这将导致在高负载下工作的服务器出现问题. (32认同)
  • @ W.Meints我理解想要存储数据的原因,但我不明白为什么有人想将上传的数据存储在服务器磁盘空间上.您应始终将文件存储与Web服务器隔离 - 即使对于较小的项目也是如此. (20认同)
  • `File.WriteAllBytes(filename,buffer);`将其写入文件 (8认同)
  • 不幸的是,如果你想读取表单数据,MultipartMemoryStreamProvider也无济于事.想要创建类似于MultipartFormDataMemoryStreamProvider的东西,但aspnetwebstack内部有很多类和辅助类:( (3认同)
  • @GaryDavies的默认上限是4MB.不知道从哪里得到64k ...... (2认同)

Mik*_*son 165

请参阅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; 
} 
Run Code Online (Sandbox Code Playgroud)

  • MultipartFormDataStreamProvider不再具有BodyPartFileNames属性(在WebApi RTM中).见http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2 (47认同)
  • `MultipartFormDataStreamProvider`不再公开`BodyPartFileNames`属性,我使用`FileData.First().LocalFileName`代替. (9认同)
  • 文件保存为**BodyPart_8b77040b-354b-464c-bc15-b3591f98f30f**.它们不应该像*pic.jpg*一样保存在客户端吗? (6认同)
  • 使用Task只读取一个文件有什么好处?真正的问题,我刚开始使用任务.根据我目前的理解,这段代码非常适合在上传多个文件时正确吗? (5认同)
  • 伙计们,请大家详细说明为什么我们不能简单地使用HttpContext.Current.Request.Files访问文件,而是需要使用这个花哨的MultipartFormDataStreamProvider?完整的问题:http://stackoverflow.com/questions/17967544. (5认同)

Bre*_*lle 118

请参阅下面的代码,该代码改编自本文,它演示了我能找到的最简单的示例代码.它包括文件和内存(更快)上传.

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);
}
Run Code Online (Sandbox Code Playgroud)

  • 当WebAPI托管在自托管容器OWIN中时,HttpContext.Current为null. (26认同)
  • 除非绝对必须,否则不要在WebAPI中使用System.Web. (6认同)
  • 当然,System.Web与IIS紧密耦合.如果您在OWIN piple line或.Net Core中工作,那么在linux下运行或自托管时,这些API将无法使用. (3认同)
  • 很好的答案。只有一个细节:如果您从 HTML 页面上传,&lt;input type="file" /&gt; 标签*必须*具有“名称”属性,否则该文件将不会出现在 HttpContext.Current.Request.Files 中。 (3认同)

Mat*_*ear 15

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});
}
Run Code Online (Sandbox Code Playgroud)


Jam*_*ruk 14

这是一个快速而肮脏的解决方案,它从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";
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

  • @Tom是什么意思? (3认同)

Ste*_*kes 13

在我更新webapi mvc4项目中的所有NuGets之前,我使用了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;
    }
Run Code Online (Sandbox Code Playgroud)

显然,MultipartFormDataStreamProvider中不再提供BodyPartFileNames.


小智 10

朝着同样的方向,我发布了一个使用WebApi发送Excel文件的客户端和服务器snipets,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
    }
}
Run Code Online (Sandbox Code Playgroud)

和服务器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!"));
    }
}
Run Code Online (Sandbox Code Playgroud)

自定义MyMultipartFormDataStreamProvider,需要自定义文件名:

PS:我从另一篇文章中获取此代码http://www.codeguru.com/csharp/.net/uploading-files-asynchronously-using-asp.net-web-api热媒

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

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

    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为用户需要一些解释......! (6认同)

Maj*_*jor 5

即使对于 .Net Core,这个问题也有很多很好的答案。我正在使用这两个框架,提供的代码示例工作正常。所以我就不重复了。就我而言,重要的是如何通过Swagger使用文件上传操作,如下所示:

Swagger 中的文件上传按钮

这是我的回顾:

ASP .Net WebAPI 2

.NET核心