Importer et exporter des données
au travers d'une application ASP.Net
Ou comment se servir de la sérialisation XML et d'Excel pour ses mises à jour en masse.
Date de publication : 27 octobre 2010 , Date de mise à jour : 27 octobre 2010
Par
Immobilis (accueil)
Dans ce tutoriel, nous allons traiter d'une méthode d'importation et d'exportation de données grâce à Excel 2007.
39 commentaires 
I. Présentation
II. Qu'est-ce que la Sérialisation/Désérialisation XML ?
III. La base de données
IV. Solution
IV-A. Projet d'accès aux données et modèle : la DAL
IV-B. Projet logique métier : Business
IV-C. Projet interface utilisateur : WebApplication
V. Mise en pratique
VI. Pour aller plus loin
VI-A. Utilisation de la généricité pour éviter la duplication du code
VI-B. Utilisation d'une boîte à outils
VII. Conclusion
Remerciements
I. Présentation
Il est parfois nécessaire de permettre aux utilisateurs d'une application d'importer ou d'exporter des données en masse.
Les moyens offerts pour une saisie facile ne sont pas très nombreux. Il en est un qui s'offre comme une évidence : Excel.
Dans la famille des tableurs, Excel 2007 est sans doute la meilleure solution. Excel 2007 permet de saisir plus d'un million de lignes et il permet de travailler avec des fichiers XML de manière très conviviale.
Ce tutoriel va présenter une méthode d'import et d'export de données au format XML grâce à la sérialisation.
II. Qu'est-ce que la Sérialisation/Désérialisation XML ?
Il est possible de lire dans un classeur Excel comme dans une table d'une base de données.
Cette méthode est assez performante à condition que le fichier soit vraiment bien formaté.
C'est un peu risqué car il faut faire beaucoup de vérifications sur le nom des feuilles de calcul,
la position des données dans la feuille et leur type.
Pour renforcer la qualité de l'application, il est préférable d'utiliser un fichier XML.
Grâce au procédé de désérialisation, ce fichier sera formaté de telle sorte qu'il sera validé et interprété
automatiquement par quelques lignes de code.
« La sérialisation XML est le processus qui consiste à convertir des propriétés et champs publics d'un objet
dans un format série (dans ce cas, XML) à des fins de stockage et de transport.
La désérialisation recrée l'objet dans son état d'origine à partir du résultat XML ».
Le programme que nous allons réaliser va nous permettre de transformer les lignes d'une table de notre base de données
en une liste d'objets et cette liste en un fichier XML exploitable par Excel (export).
Il nous permettra aussi de réaliser l'opération inverse (import).
III. La base de données
Elle se compose d'une seule table [Persons] de trois champs :
- [PersonId] : identifiant de l'enregistrement ;
- [LastName] : le nom de famille ;
- [FirstName] : le prénom.
Voici le code permettant de générer la table :
| Code SQL de génération de la table [Person]. |
USE [Excel]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Persons](
[PersonId] [uniqueidentifier] NOT NULL CONSTRAINT [DF_Persons_PersonId] DEFAULT (newid()),
[LastName] [varchar](20) NOT NULL,
[FirstName] [varchar](20) NOT NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
|
IV. Solution
J'utiliserai Visual Studio 2010 et ciblerai le Framework 4. Nous ferons une solution avec trois projets : données/modèle, métier, interface utilisateur. LINQ sera évidement de la partie.
IV-A. Projet d'accès aux données et modèle : la DAL
Pour ce tutoriel, nous irons un peu vite et utiliserons directement les objets mis à disposition par le contexte de données.
 |
Je rappelle que la création d'une classe dédiée à la fourniture de données peut être très utile pour ajouter des requêtes compilées.
|
Ajoutez à la solution un projet librairie de classes. Ajoutez un composant LINQ to SQL et nommez-le "Person.dbml". Ajoutez les tables précédemment créées.
IV-B. Projet logique métier : Business
Ajoutez à la solution un projet librairie de classes. Ajoutez une classe nommée "PersonManager.cs".
Référencez le projet "Data".
Voici tout d'abord la méthode qui nous permettra d'insérer ou de mettre à jour un enregistrement. Elle admet une liste d'objets « Person ». Pour chacun des éléments de la liste, si l'enregistrement existe déjà, on le met à jour sinon, on l'insère.
| Méthode permettant l'insertion ou la mise à jour des enregistrements. |
<summary>
</summary>
<param name="persons"></param>
public static void InsertOrUpdate(IEnumerable<Person> persons)
{
using (PersonDataContext db = new PersonDataContext())
{
foreach (var p in persons)
{
if (p.PersonId == Guid.Empty)
{
p.PersonId = Guid.NewGuid();
db.Persons.InsertOnSubmit(p);
}
else
{
Person person = db.Persons.Where(x => x.PersonId == p.PersonId).FirstOrDefault();
if (person != null)
{
person.LastName = p.LastName;
person.FirstName = p.FirstName;
}
else
{
db.Persons.InsertOnSubmit(p);
}
person = null;
}
db.SubmitChanges();
}
}
}
|
Voici, ci-dessous, la méthode permettant de transformer une liste d'objets « Person » en une chaîne de caractères au format XML :
| Méthode permettant la sérialisation (transformation en XML). |
<summary>
</summary>
<param name="persons"></param>
<param name="page"></param>
public static string SerializeMe(List<Person> persons)
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Person>));
using (MemoryStream mem = new MemoryStream())
{
serializer.Serialize(mem, persons);
return Encoding.UTF8.GetString(mem.ToArray());
}
}
|
L'opération inverse se réalise ainsi :
| Méthode permettant la désérialisation (transformation en liste d'objets). |
<summary>
</summary>
<param name="buffer"></param>
public static List<Person> DeserializeMe(byte[] buffer)
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Person>));
using (MemoryStream mem = new MemoryStream(buffer))
{
XmlTextReader reader = new XmlTextReader(mem);
if (serializer.CanDeserialize(reader))
{
return serializer.Deserialize(reader) as List<Person>;
}
else
{
return null;
}
}
}
|
Une petite surcharge en passant au cas où on aurait besoin d'envoyer une chaîne de caractères à désérialiser.
| Surcharge de la désérialisation admettant une chaine de caractères au format XML. |
<summary>
</summary>
<param name="str"></param>
<returns></returns>
public static List<Person> DeserializeMe(string str)
{
return DeserializeMe(Encoding.UTF8.GetBytes(str));
}
|
Enfin, voici la méthode qui nous permettra d'envoyer le fichier XML au client. Cette méthode admet une référence vers la page en paramètre.
| Méthode permettant l'envoi du fichier XML au client. |
<summary>
</summary>
<param name="s"></param>
<param name="page"></param>
public static void Download(string s, Page page)
{
page.Response.Clear();
page.Response.AddHeader("content-disposition", "attachment; filename=Persons.xml");
page.Response.ContentType = "text/xml";
using (StreamWriter sw = new StreamWriter(page.Response.OutputStream, Encoding.UTF8))
{
sw.Write(s);
}
page.Response.End();
}
|
IV-C. Projet interface utilisateur : WebApplication
Afin de faire fonctionner tout cela, nous allons avoir besoin d'un bouton pour recevoir le modèle du fichier,
d'un contrôle pour sélectionner un fichier, d'un bouton pour l'envoyer au serveur et enfin, d'un bouton pour récupérer le fichier XML
avec les données de la base. La page devrait avoir cette apparence.
Voici le code source de la page « aspx » :
| Code XHTML de la page Default.aspx. |
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication.Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<blockquote>
<fieldset>
<legend>Recevoir</legend><span>Obtenir le fichier Xml vide</span> <asp:Button
ID="Button1" runat="server" Text="Bouton 1" OnClick="Button1_Click" /><br />
</fieldset>
</blockquote>
<blockquote>
<fieldset>
<legend>Envoyer</legend>
<asp:FileUpload ID="FileUpload1" runat="server" /><br />
<span>Envoyer le fichier Xml vers le serveur</span>
<asp:Button ID="Button2" runat="server" Text="Bouton 2" OnClick="Button2_Click" />
</fieldset>
</blockquote>
<blockquote>
<fieldset>
<span>Obtenir le fichier Xml avec les données de la table</span> <asp:Button
ID="Button3" runat="server" Text="Bouton 3" OnClick="Button3_Click" />
</fieldset>
</blockquote>
</form>
</body>
</html>
|
Lors du clic sur le bouton 1, nous allons constituer une liste factice pour fournir un fichier XML avec une structure exploitable.
 |
Pour une raison qui m'est inconnue, il faut au moins deux éléments dans la liste pour qu'Excel les affiche correctement.
|
| Code behind du bouton n°1. |
protected void Button1_Click(object sender, EventArgs e)
{
List<Person> persons = new List<Person>();
persons.Add(new Person() { PersonId = Guid.Empty, LastName = string.Empty, FirstName = string.Empty });
persons.Add(new Person() { PersonId = Guid.Empty, LastName = string.Empty, FirstName = string.Empty });
PersonManager.Download(
PersonManager.SerializeMe(persons),
this.Page
);
}
|
Lors du clic sur le bouton 2, le code va envoyer le flux binaire du fichier pour qu'il soit désérialisé. La liste obtenue sera envoyée pour que les éléments soient insérés ou mis à jour.
| Code behind du bouton n°2. |
protected void Button2_Click(object sender, EventArgs e)
{
if (FileUpload1.HasFile && FileUpload1.PostedFile.ContentType == "text/xml")
{
PersonManager.InsertOrUpdate(
PersonManager.DeserializeMe(
FileUpload1.FileBytes
)
);
}
}
|
Enfin, le bouton 3 permettra d'envoyer une liste au client, constituée à partir des données en base.
| Code behind du bouton n°3. |
protected void Button3_Click(object sender, EventArgs e)
{
List<Person> persons = PersonManager.Load();
PersonManager.Download(
PersonManager.SerializeMe(persons),
this.Page
);
}
|
V. Mise en pratique
Constatez tout d'abord que votre table est vide.
Lancez l'application et cliquez sur le bouton 1. La page vous propose de télécharger un fichier pour l'ouvrir ou le sauvegarder.
Ce fichier sert de modèle.
Sauvegardez-le. Le code XML contient ceci :
| Contenu du fichier XML vide. |
<?xml version="1.0"?>
<ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Person>
<PersonId>00000000-0000-0000-0000-000000000000</PersonId>
<LastName />
<FirstName />
</Person>
<Person>
<PersonId>00000000-0000-0000-0000-000000000000</PersonId>
<LastName />
<FirstName />
</Person>
</ArrayOfPerson>
|
 |
Si vous n'assignez pas les propriétés « nullables », elles n'apparaîtront pas dans le XML.
|
Ouvrez le fichier avec Excel. Ce dernier devrait vous proposer de l'ouvrir en tant que « Tableau XML ». Acceptez.
Confirmez la boîte de dialogue suivante.
Le tableau s'affiche directement ainsi :
Remplissez les deux lignes.
Ne sauvegardez pas le fichier, il faut l'exporter. Faites un clic droit sur le tableau, Menu XML > Exporter.
Exportez le fichier au format XML en écrasant la version que vous venez de télécharger.
Retournez sur l'application Web, sélectionnez votre fichier grâce au contrôle « FileUpload ». Cliquez sur le bouton 2.
Le fichier est téléchargé et désérialisé. Un point d'arrêt nous permet de constater que nos objets sont bien là.
Une fois le processus terminé nous pouvons constater que la table n'est plus vide.
Il reste à cliquer sur le bouton 3 pour obtenir le fichier XML rempli des données de la base.
À la différence du premier, les éléments ont une valeur.
| Contenu du fichier XML rempli avec les données de la base. |
<?xml version="1.0"?>
<ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Person>
<PersonId>ad55a71d-f204-466a-ab54-1dd53c409e27</PersonId>
<LastName>VERSAIRE</LastName>
<FirstName>Annie</FirstName>
</Person>
<Person>
<PersonId>73f61362-ffbe-4fb0-aac0-aaea373a8c8f</PersonId>
<LastName>TERIEUR</LastName>
<FirstName>Alex</FirstName>
</Person>
</ArrayOfPerson>
|
VI. Pour aller plus loin
VI-A. Utilisation de la généricité pour éviter la duplication du code
Peut-être qu'en regardant ce code et notamment les méthodes de sérialisation vous vous êtes dit que tout cela n'est pas très optimisé. Vous avez raison. En l'état, il faut adapter les méthodes de sérialisation et désérialisation pour chaque type d'objets. Ce serait très long et très improductif.
Pour résoudre ce petit inconvénient, une toute petite modification suffira. Nous allons rendre ces méthodes génériques. Il faut tout d'abord créer une nouvelle classe que nous nommerons « GenericSerializer ». Voici son code :
| La classe GenericSerializer. |
public static class GenericSerializer<T>
{
}
|
Notez bien le « T ». Cela va nous permettre de préciser dynamiquement le type utilisé par la classe.
Ajoutons la méthode de sérialisation :
| Code de la méthode SerializeMe |
public static string SerializeMe(List<T> list)
{
XmlSerializer serializer = new XmlSerializer(typeof(List<T>));
using (MemoryStream mem = new MemoryStream())
{
serializer.Serialize(mem, list);
return Encoding.UTF8.GetString(mem.ToArray());
}
}
|
Remarquez une nouvelle fois l'utilisation du « T ».
 |
N'importe quelle lettre fera l'affaire. La lettre « T » est pratique car elle correspond à l'initiale de « Type ».
|
Et enfin la méthode de désérialisation.
| Code de la méthode DeserializeMe |
public static List<T> DeserializeMe(byte[] buffer)
{
XmlSerializer serializer = new XmlSerializer(typeof(List<T>));
using (MemoryStream mem = new MemoryStream(buffer))
{
XmlTextReader reader = new XmlTextReader(mem);
if (serializer.CanDeserialize(reader))
{
return serializer.Deserialize(reader) as List<T>;
}
else
{
return null;
}
}
}
|
Voici un exemple d'utilisation lors de l'insertion :
| Exemple d'utilisation lors de l'appel de la méthode InsertOrUpdate |
public static void InsertOrUpdate(IEnumerable<Person> persons)
{
string str = GenericSerializer<Person>.SerializeMe(persons as List<Person>);
}
|
VI-B. Utilisation d'une boîte à outils
La méthode « Download » permettant l'envoi d'un fichier au client n'est pas propre à la classe « PersonManager ». Celle-ci est dédiée à la gestion du type « Person ». Il faut donc déplacer la méthode « Download » dans une nouvelle classe. Nous l'appellerons « Tools ». Voici son code :
| Code de la boîte à outils. |
public static class Tools
{
<summary>
</summary>
<param name="s"></param>
<param name="page"></param>
public static void Download(string s, Page page)
{
page.Response.Clear();
page.Response.AddHeader("content-disposition", "attachment; filename=Persons.xml");
page.Response.ContentType = "text/xml";
using (StreamWriter sw = new StreamWriter(page.Response.OutputStream, Encoding.UTF8))
{
sw.Write(s);
}
page.Response.End();
}
}
|
Il suffira de l'utiliser ainsi :
| Utilisation de la boîte à outils. |
protected void Button3_Click(object sender, EventArgs e)
{
List<Person> persons = PersonManager.Load();
Tools.Download(
GenericSerializer<Person>.SerializeMe(persons),
this.Page
);
}
|
VII. Conclusion
Vous voici maintenant bien outillé pour faire vos exports et imports dans votre base de données.
Remerciements


Les sources présentées sur cette page sont libres de droits
et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation
constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ©
2010 Julien. Aucune reproduction,
même partielle, ne peut être faite de ce site et de l'ensemble de son contenu :
textes, documents, images, etc. sans l'autorisation expresse de l'auteur.
Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 €
de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.
Cette page est déposée.