web-dev-qa-db-fra.com

Comment accepter un fichier POST

J'utilise asp.net mvc 4 webapi beta pour créer un service de repos. Je dois pouvoir accepter les images/fichiers POSTés des applications clientes. Est-ce possible d'utiliser le webapi? Vous trouverez ci-dessous les actions que j'utilise actuellement. Est-ce que quelqu'un sait d'un exemple comment cela devrait fonctionner?

[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

voir http://www.asp.net/web-api/overview/formats-and-model-binding/html-forms-and-multipart-mime#multipartmime , bien que je pense que l'article en fait un semblant un peu plus compliqué qu'il ne l'est réellement.

Fondamentalement, 

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

Je suis surpris que beaucoup d'entre vous semblent vouloir enregistrer des fichiers sur le serveur. La solution pour tout garder en mémoire est la suivante:

[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

Voir le code ci-dessous, adapté de cet article , qui illustre l'exemple de code le plus simple que j'ai trouvé. Il inclut les téléchargements de fichiers et memory (plus rapides).

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

J'ai utilisé la réponse de Mike Wasson avant de mettre à jour tous les NuGets de mon projet webapi mvc4. Une fois que je l'ai fait, j'ai dû réécrire l'action de téléchargement de fichier:

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

Apparemment, BodyPartFileNames n'est plus disponible dans MultipartFormDataStreamProvider.

13
Steve Stokes

Voici une solution rapide et incorrecte qui extrait le contenu du fichier téléchargé du corps HTTP et l’écrit dans un fichier. J'ai inclus un extrait de code HTML/JS "bare bones" pour le téléchargement du fichier.

Méthode de l'API Web:

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

Téléchargement de fichier 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>
13
James Lawruk

La manière d'ASP.NET Core est maintenant ici :

[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

Dans la même direction, je publie des extraits de client et de serveur qui envoient des fichiers Excel à l'aide de 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
    }
}

Et le contrôleur webapi du serveur:

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

Et le Custom MyMultipartFormDataStreamProvider, nécessaire pour personnaliser le nom de fichier:

PS: J'ai pris ce code dans un autre article 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

Voici deux manières d'accepter un fichier. Un utilisant le fournisseur de mémoire MultipartMemoryStreamProvider et l'autre utilisant MultipartFormDataStreamProvider qui enregistre sur un disque. Notez que ceci n’est valable que pour un téléchargement de fichier à la fois. Vous pouvez certainement étendre cela pour sauvegarder plusieurs fichiers. La seconde approche peut prendre en charge des fichiers volumineux. J'ai testé des fichiers de plus de 200 Mo et cela fonctionne bien. L'utilisation de la méthode en mémoire ne nécessite pas l'enregistrement sur disque, mais une exception de mémoire insuffisante est générée si vous dépassez une certaine limite.

        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
Filix Mogilevsky

Cette question a beaucoup de bonnes réponses, même pour .Net Core. J'utilisais les deux cadres, les exemples de code fournis fonctionnaient bien. Donc je ne vais pas le répéter. Dans mon cas, l’important était de savoir comment utiliser les actions de téléchargement de fichiers avec Swagger comme ceci: 

 File upload button in Swagger

Voici mon récapitulatif:

ASP .Net WebAPI 2

  • Pour télécharger un fichier, utilisez: MultipartFormDataStreamProvider voir les réponses ici
  • Comment l'utiliser avec Swagger

.NET Core

1
Major

J'ai eu un problème similaire pour l'aperçu de l'API Web. N'a pas encore porté cette partie à la nouvelle API Web MVC 4, mais peut-être que cela aide:

REST téléchargement de fichier avec HttpRequestMessage ou Stream?

Faites-le moi savoir, je peux m'asseoir demain et essayer de le réappliquer.

1
Remy

Contrôleur d'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);
}
0
Tiago Medici