Utiliser les requêtes multipart en ASP.NET Core 1.0
Les requêtes multipart sont des requêtes Http qui permettent d’envoyer plusieurs contenus différents dans la même requête. Cela permet donc d’envoyer par exemple le contenu d’un fichier, mais également un objet JSON, une valeur brute … La mise en place de ce système permet donc de réduire les échanges entre vos applications, quand il est possible de faire une action en une seule requête.
Comment ça fonctionne côté client ?
Lorsque vous voulez créer un contenu multipart, celui-ci doit d’abord être spécifié dans les entêtes de la requête. Pour cela, il est nécessaire d’avoir un type Mime “multipart” pour prévenir le serveur que le contenu de votre requête est de type multipart, car le contenu est différent d’un contenu classique (application/json, text/plain …) et il doit être lu d’une manière spécifique. En C#, pour créer un contenu multipart, vous pouvez utiliser une classe dérivée de MultipartContent, présente dans le System.Net.Http.
Dans mon exemple ci-dessous, j’utilise la classe MultipartFormDataContent, pour envoyer à mon serveur 2 contenus différents, un fichier et un objet JSON.
public async Task Add(Dictionary<string, object> values, byte[] content, string fileName) { using (var formDataContent = new MultipartFormDataContent()) { formDataContent.Add(new ByteArrayContent(content), "files", fileName); formDataContent.Add(new StringContent(JsonConvert.SerializeObject(values), Encoding.UTF8, "application/json"), "myJsonObject"); using (HttpClient httpClient = new HttpClient()) { HttpResponseMessage response = await httpClient.PostAsync("", formDataContent); await EnsureResponse(response); } } }
Il est possible d’ajouter autant de contenus différents que souhaités. La seule limite se situe côté serveur avec la taille maximale que celui-ci accepte pour une requête entrante.
Comment ça fonctionne côté serveur ?
Côté serveur, pour obtenir le contenu envoyé par une requête multipart, il suffit d’utiliser la requête courante et notamment la collection de form qu’elle expose pour obtenir les différents contenus envoyés.
Pour les contenus classiques de type text, ceux-ci sont directement exposés dans la collection de Form portée par la requête et peuvent être obtenus via leur clé. Pour les contenus de type fichier, ils sont exposés dans la collection de fichiers appelée “Files” présente dans la collection de Form.
Voici l’exemple pour obtenir l’object JSON et le fichier précédemment envoyés par la requête cliente ci-dessus,
public ActionResult CreateDocument() { if(!Request.Form.ContainsKey("myJsonObject") || (Request.Form.Files == null || !Request.Form.Files.Any())){ // Dans notre exemple l'objet et le fichier sont obligatoires return BadRequest(); } var jsonModel = Request.Form.First(f => f.Key == "myJsonObject").Value; var myJsonObject = JsonConvert.DeserializeObject<Dictionary<string, object>>(await new StringReader(jsonModel).ReadToEndAsync()); IFormFile myFile = Request.Form.Files.First(); string myFileName = myFile.Name; byte[] myFileContent; using (var memoryStream = new MemoryStream()) { await myFile.CopyToAsync(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); myFileContent = new byte[memoryStream.Length]; await memoryStream.ReadAsync(myFileContent, 0, myFileContent.Length); } // Faire ce que l'on souhaite avec le fichier et l'object Json return Ok(); }
Avec cet exemple, Il est possible de rendre le code serveur générique pour directement obtenir le contenu dans les paramètres de l’action notamment en créant un formatter qui se chargerait de cette logique.
Mais pour une utilisation unique, ce bout de code est suffisant.
Commentaires