web-dev-qa-db-de.com

Wie akzeptiere ich eine Datei? POST

Ich verwende asp.net mvc 4 webapi beta, um einen Ruhedienst zu erstellen. Ich muss in der Lage sein, gepostete Bilder/Dateien von Client-Anwendungen zu akzeptieren. Ist das mit dem Webapi möglich? Im Folgenden wird beschrieben, welche Aktion ich derzeit verwende. Kennt jemand ein Beispiel, wie das funktionieren soll?

[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";
}
228
Phil

siehe http://www.asp.net/web-api/overview/formats-and-model-binding/html-forms-and-multipart-mime#multipartmime , obwohl ich denke, der Artikel macht es so etwas komplizierter als es wirklich ist.

Grundsätzlich gilt, 

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; 
} 
161
Mike Wasson

Ich bin überrascht, dass viele von Ihnen Dateien auf dem Server speichern möchten. Die Lösung, um alles im Speicher zu behalten, lautet wie folgt:

[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();
}
342
Gleno

Siehe den nachstehenden Code, angepasst an diesen Artikel , der den einfachsten Beispielcode zeigt, den ich finden konnte. Es enthält sowohl Datei- als auch memory (schnellere) 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);
}
112
Brent Matzelle

Ich habe die Antwort von Mike Wasson verwendet, bevor ich alle NuGets in meinem webapi mvc4-Projekt aktualisiert habe. Danach musste ich die Datei-Upload-Aktion erneut schreiben:

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

Offensichtlich ist BodyPartFileNames nicht mehr im MultipartFormDataStreamProvider verfügbar.

13
Steve Stokes

Hier ist eine schnelle und schmutzige Lösung, die hochgeladene Dateiinhalte aus dem HTTP-Body übernimmt und in eine Datei schreibt. Ich habe ein HTML/JS-Snippet "Bare Bones" für den Dateiupload beigelegt.

Web-API-Methode:

[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-Datei hochladen:

<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>
13
James Lawruk

Der ASP.NET Core-Weg ist jetzt hier :

[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});
}
11
Matt Frear

In die gleiche Richtung schreibe ich ein Client- und ein Server-Snipet, die Excel-Dateien mit WebApi senden. 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
    }
}

Und der 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!"));
    }
}

Und der benutzerdefinierte MyMultipartFormDataStreamProvider, der zum Anpassen des Dateinamens benötigt wird:

PS: Ich habe diesen Code einem anderen Beitrag entnommen 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);
    }
}
10
Daniel Melo
[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);

    }
}
6
user3722373

Es gibt zwei Möglichkeiten, eine Datei zu akzeptieren. Eine Verwendung im Speicheranbieter MultipartMemoryStreamProvider und eine Verwendung von MultipartFormDataStreamProvider , die auf einer Festplatte gespeichert werden. Beachten Sie, dass dies jeweils nur für einen Dateiupload gilt. Sie können dies sicher erweitern, um mehrere Dateien zu speichern. Der zweite Ansatz kann große Dateien unterstützen. Ich habe Dateien über 200 MB getestet und es funktioniert gut. Bei der Verwendung des Arbeitsspeichers müssen Sie nicht auf der Festplatte speichern. Wenn Sie jedoch einen bestimmten Grenzwert überschreiten, wird eine Ausnahme aus dem Arbeitsspeicher ausgelöst.

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

Diese Frage hat auch für .Net Core viele gute Antworten. Ich verwendete beide Frameworks. Die bereitgestellten Codebeispiele funktionieren einwandfrei. Also werde ich es nicht wiederholen. In meinem Fall war es wichtig, wie Sie Datei-Upload-Aktionen mit Swagger wie folgt verwenden: 

 File upload button in Swagger

Hier ist meine Zusammenfassung:

ASP .Net WebAPI 2

  • Um eine Datei hochzuladen, verwenden Sie: MultipartFormDataStreamProvider die Antworten hier
  • Wie man es mit Swagger benutzt

.NET Core

1
Major

Ich hatte ein ähnliches Problem für die Vorschau-Web-API. Portierte diesen Teil noch nicht auf die neue MVC 4-Web-API, aber vielleicht hilft dies:

REST Datei mit HttpRequestMessage oder Stream hochladen?

Bitte lass es mich wissen, kann mich morgen hinsetzen und versuchen, es erneut zu implementieren.

1
Remy

API-Controller:

[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);
}
0
Tiago Medici