logo JULIENCORIOLAND.NET

2/28/2013 - [ASPNET Web API] Upload de fichier avec le HttpClient

Il est fréquent qu’un service http est besoin de récupérer un fichier envoyé par l’utilisateur. ASP.NET Web API permet bien entendu de mettre en place ce type de scénario.

Code côté Serveur

Côté serveur, il s’agit d’un contrôleur ASP.NET Web API tout à fait classique qui va exploiter une multipart provider pour pouvoir télécharger et enregistrer le fichier. Si vous ne connaissez pas les multipart provider, je vous invite à lire cet article que j’ai posté il y a quelques temps.

public class FileUploadController : ApiController
{
    public async Task<HttpResponseMessage> Post()
    {
        //si la requête n'est pas en multipart/form-data
        if (!Request.Content.IsMimeMultipartContent("form-data"))
        {
            return Request.CreateErrorResponse(HttpStatusCode.UnsupportedMediaType, "non supporté");
        }

        //création du multipart provider fournit avec Web API et qui permet d'enregistrer les fichiers
        //sur le file system (ici dans un répertoire temporaire)
        var multipartFileStreamProvider = new MultipartFileStreamProvider(Path.GetTempPath());

        //récupération des fichiers
        var files = await Request.Content.ReadAsMultipartAsync(multipartFileStreamProvider).ContinueWith(task =>
        {
            if (task.IsFaulted)
                throw task.Exception;

            return task.Result.FileData.ToList();
        });

        //travail sur les fichiers
        foreach (var file in files)
        {
            //chemin du fichier en local :
            string path = file.LocalFileName;

            //nom du fichier envoyé :
            string fileName = file.Headers.ContentDisposition.FileName;
        }

        return Request.CreateResponse(HttpStatusCode.OK);
    }
}

Code côté client

Côté client, pour envoyer un fichier, nous allons utiliser une application console et la classe HttpClient. Il est nécessaire d’ajouter une référence vers System.Net.Http.dll :

image

Ensuite, il faut tout d’abord créer un FileStream sur le fichier à Upload, puis un StreamContent. Ce StreamContent est alors rajouté à un MultipartFormDataContent, qui représente le contenu qui sera envoyé par le client http, en mode multipart/form-data.

Il suffit alors de créer un HttpClient et de poster le contenu à l’adresse adéquate.

private static async Task UploadAsync()
{
    int bufferSize = 1024;

    //création du file stream
    using (var fs = new FileStream("Fichier à envoyer.txt", FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, true))
    {
        //création d'un stream StreamContent qui représente le fichier
        StreamContent streamContent = new StreamContent(fs, bufferSize);

        //création d'un MultipartFormDataContent et ajout du fichier
        MultipartFormDataContent formDataContent = new MultipartFormDataContent();
        formDataContent.Add(streamContent, "fichier", "Fichier à envoyer.txt");

        //création du http client
        HttpClient client = new HttpClient();

        var uri = new Uri("http://localhost:17831/api/fileupload");

        //envoie de la requête HTTP POST
        HttpResponseMessage response = await client.PostAsync(uri, formDataContent);

        //récupération du status
        if (response.StatusCode == System.Net.HttpStatusCode.OK)
        {
            Console.WriteLine("fichier envoyé");
        }
        else
        {
            string description = await response.Content.ReadAsStringAsync();
            Console.WriteLine("une erreur s'est produite : " + description);
        }

        Console.ReadLine();
    }
}

Et voilà, le tour est joué ! Le code source de démonstration est dispo ici : http://juliencoriolandblog.blob.core.windows.net/publicfiles/UploadHttpSample.zip

Enjoy Winking smile

Julien

2/6/2013 - [ASP.NET MVC] Utilisation des préfixes pour la génération des noms et id des champs

Il n’est pas rare d’avoir plusieurs formulaires sur une même page HTML, et d’autant plus lorsque l’on compose une vue dynamiquement à partir de vues partielles. Du coup, il est vite possible de se retrouver avec des inputs qui possèdent les mêmes noms et mêmes id. Dans ce cas, c’est l’arrachage de cheveux assuré lors du debug de la manipulation du DOM avec jQuery Smile 

Heuresement, la nature ASP.NET MVC est bien fait ! Il est en effet possible de préciser un préfixe à appliquer lors de la génération des inputs à l’aide des html helpers. Au sein d’une action de contrôleur, il suffit d’affecter la propriété HtmlFieldPrefix de la propriété TemplateInfo du ViewData, comme suivant :

public class ClientController : Controller
{
    public ActionResult Ajouter()
    {
        ViewData.TemplateInfo.HtmlFieldPrefix = "AjouterClient";
        return View(new Client());
    }
}

Du coup, en utilisant correctement les Html Helpers pour générer les champs de formulaires (TextBox, CheckBox, DropDownList, Editor etc…), ASP.NET MVC tient compte de ce préfixe pour nommer les champs.

@model MvcApplication2.Models.Client

@{
    ViewBag.Title = "Ajouter un client";
}

<h2>Ajouter un client</h2>

@using (Html.BeginForm()) {

    <div class="editor-label">
        @Html.LabelFor(model => model.Prenom)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Prenom)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.Nom)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Nom)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.Adresse)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Adresse)
    </div>

    <p>
        <input type="submit" value="Create" />
    </p>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Le template razor précédent génère alors le markup HTML qui suit :

<div class="editor-field">
    <input id="AjouterClient_Prenom" name="AjouterClient.Prenom" type="text" value="" />
</div>
<div class="editor-label">
    <label for="AjouterClient_Nom">Nom :</label>
</div>
<div class="editor-field">
    <input id="AjouterClient_Nom" name="AjouterClient.Nom" type="text" value="" />
</div>
<div class="editor-label">
    <label for="AjouterClient_Adresse">Adresse :</label>
</div>
<div class="editor-field">
    <input id="AjouterClient_Adresse" name="AjouterClient.Adresse" type="text" value="" />
</div>

Comme vous pouvez le remarquer, les attributs name et id ont bien été préfixés.

Se pose maintenant le problème de la résolution du modèle par le ModelBinder d’ASP.NET MVC lorsque le formulaire sera posté. En effet, par défaut le ModelBinder va chercher dans les champs postés des propriétés nommées exactement comme les propriétés de l’objet que l’on récupère en paramètre de l’action (ici un Client). Du coup, il est nécessaire d’indiquer au ModelBinder qu’un préfixe a été utilisé. Ceci se fait à l’aide de l’attribut Bind, comme le montre le code ci-dessous :

[HttpPost]
public ActionResult Ajouter([Bind(Prefix="AjouterClient")]Client client)
{
    //ajout du client
    return View("Index");
}

Et voilà, le tour est joué, le ModelBinder retombe sur ses pattes :

sample-binder-prefix

Enjoy Winking smile

Julien

2/1/2013 - [Techdays 2013] Quoi de neuf dans ASP.NET MVC 4 et Introduction à Windows Phone 8

L’info ne vous a surement pas échapée, les Techdays 2013 commencent dans un peu plus d’une semaine maintenant, le 12 Février ! Smile

J’aurais la chance d’animer deux sessions lors de cette nouvelle édition :

  • Introduction au développement Windows Phone 8 : avec Jean-Sébastien Dupuy (Microsoft), nous vous donnerons tous les pointeurs pour bien démarrer vos applications Windows Phone ! De l’installation des outils, en passant par la création d’un premier projet jusqu’à la création de votre compte développeur et à la publication d’une application sur le Windows Phone store, nous essayerons de vous donner une bonne vue d’ensemble de la plateforme Windows Phone, pour les développeurs !
  • Quoi de neuf dans ASP.NET MVC 4 : avec Léonard Labat (Infinite Square), nous ferons un tour d’horizon des nouveautés d’ASP.NET MVC 4, avec de nombreuses démonstrations au programme : async/await, templates mobile, bundling, open auth et bien d’autres ! Un coktail de démos pour bien prendre en main toutes ces nouveautés !

 

 

Rendez-vous au Palais des Congrès le 12 !

Julien

12/21/2012 - [ASPNET MVC] Utilisation du plugin jQuery BBQ pour la gestion du bouton back et la navigation par fragment dans une SPA

Lorsque l’on développe une Single Page Application (SPA) en JavaScript, il est souvent recommandé de mettre en place la gestion du bouton back pour l’historique de navigation, ainsi que de la navigation par fragment, permettant de conserver des URL propres à chaque ressource et permettant ainsi aux utilisateur d’utiliser la SPA comme n’importe qu’elle autre application.

Comprendre la navigation par fragment

Il s’agit en fait des éléments que l’on rajoute à une URL de page, après le caractère “#”. On parle aussi d’ancre dans la page. Par exemple, le lien suivant http://www.monsite.com/page1.html#menu, permet de rediriger l’utilisateur directement vers une section de le page.

Ce système existant dans HTML depuis de nombreuses années a été ré-exploité en JavaScript pour de la navigation par fragment. Par exemple, l’équivalent de la page http://www.monsite.com/customers/32, qui affiche le détail du client ayant 32 pour id, peut se retrouver sous la forme de http://www.monsite.com/#/customers/32 afin d’être exploité directement depuis du code JavaScript. Les éléments qui suivent le caractère “#” représente le “hash” de l’URL.

Il suffit donc d’avoir un mécanisme en JavaScript pour détecter les changements de hash et permettre à l’utilisateur de passer de ressource en ressource à l’aide des boutons précédent / suivant du navigateur, de mettre une ressource en favoris, d’envoyer une ressource par mail à un autre utilisateur, etc…

C’est ce que permet de faire le plugin jQuery BBQ : http://benalman.com/projects/jquery-bbq-plugin/

Mise en place de jQuery BBQ

Commencez par télécharger les sources du plugin ici ou (en version “minified”). Ajoutez ensuite le fichier à votre projet de développement et référencez le dans la/les page(s) dans la(les)quelle(s) vous souhaitez l’utiliser.

<script src="/Scripts/jquery.ba-bbq.js"></script>

Une fois ceci fait, il est possible de s’abonner à un événement “hashchange” sur la window. Cet événement sera levé à chaque fois que le hash de l’URL sera modifié :

<div id="menu">
    <ul>
        <li>@Html.ActionLink("Clients", "Index", "Customers", null, new { @class = "menu-link" })</li>
        <li>@Html.ActionLink("Achats", "Index", "Orders", null, new { @class = "menu-link" })</li>
    </ul>
</div>

<div id="contentDiv">

</div>

<div id="currentFragment"></div>

@section scripts{
    <script type="text/javascript">
        $(document).ready(function () {
            $(window).bind("hashchange", function (e) {
                //récupération du fragment
                var fragment = e.fragment;
                $("#currentFragment").html("<p>" + fragment + "</p>");
            });
        });
    </script>
}

Dès lors, dès que le fragment change dans l’URL, le hash est affiché sur la page, dans le conteneur “currentFragment” :

image

A présent, il suffit de remplacer les liens directs des différentes sections de l’application par des liens fragmentés :

$(".menu-link").each(function(index, item) {
    var href = $(item).attr("href");
    var newHref = thisUrl + "#" + href;
    $(item).attr("href", newHref);
});

Et de charger le contenu représenter par le fragment lorsque le hash change :

$(window).bind("hashchange", function (e) {
    //récupération du fragment
    var fragment = e.fragment;
    $("#currentFragment").html("<p>" + fragment + "</p>");

    //chargement du contenu
    $("#contentDiv").load(fragment);
});

Enfin, pour faire en sorte que le contenu soit également chargé lorsque l’utilisateur accède directement à votre application web via une URL fragmentée, il est nécessaire de forcer l’évènement “hashchange” sur le document ready :

$(window).trigger("hashchange");

Et voilà, le tour est joué. Vous pouvez récupérer les sources de l’exemple ici.

Enjoy Clignement d'œil

Julien

12/20/2012 - Utilisez Razor dans vos scripts JavaScript

Dans certains cas, il peut être intéressant de pouvoir formater du JavaScript avec Razor, pour tirer profit des données du modèle directement dans vos scripts JavaScript.

Pour cela, il suffit d’utiliser la notation “<text></text>” comme ci-dessous :

<script type="text/javascript">

    //code JavaScript
    var customers = new Array();

    //code Razor/C#
    @foreach(var customer in Model.Customers)
    {
        //code javascript + razor/c#
        <text>
            customers.push({
                name: "@customer.Name",
                firstname: "@customer.FirstName",
                birth: "@customer.BirthDate"
            });
        </text>
    }

    $(document).ready(function(){
        //ect...
    });

</script>

Et voilà : simple, mais efficace !

A+

Julien

RECHERCHER

A PROPOS

Julien Corioland

Développeur ASP.NET MVC, Windows Azure, Windows Phone (entre autres...) chez Infinite Square

MVP ASP.NET IIS

Nokia Developer Champion

TAGS

TWITTER

chargement du flux twitter...