Gridview et DetailView avec ASP.NET AJAX
Le but de cet article est de construire une page AJAX contenant une gridView et une detailView du genre master/detail.
Les pré-requis sont :
- Visual studio 2005
- asp.net ajax 1.0 beta2
L'installation de asp.net ajax fournit un ensemble d'outils supplémentaires dans la toolbox :
- Timer : permet le rafraichissement partiel et périodique d'une page
- ScriptManager : objet de base qui permet d'éviter le postback (à condition de positionner à true la propriété EnablePartialRendering
- ScriptManagerProxy (gestion du scriptmanager dans des pages complexes avec des frames par exemple)
- UpdatePanel : permet de définir une entité (un panel) pour le rafraîchissement partiel
L'installation permet également de disposer d'un template de projet et de page pour asp.net ajax.
Pour commencer :
- construire un nouveau site Web Ajax : File-->New-->Web site et choisir Asp.Net Ajax Enabled Web Site
- Le template génère une page par défaut (Default.aspx) blanche qui contient le code suivant :
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server"> <title>Untitled Page</title>
</head>
<body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server" /> <div> </div> </form>
</body>
</html>
CODE HTML COMPLET DE LA PAGE
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="comptes.aspx.cs" Inherits="comptes" %> <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %> <!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>Consultation des comptes</title> <link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true"> </asp:ScriptManager> <div id="header" style="width: 678px; height: 65px"> <br /> <asp:Menu ID="Menu1" runat="server" BackColor="#E0E0E0" DynamicHorizontalOffset="2" Font-Names="Arial" Font-Size="Large" ForeColor="#0000C0" Orientation="Horizontal" StaticSubMenuIndent="10px" Width="780px"> <StaticMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" /> <DynamicHoverStyle BackColor="#7C6F57" ForeColor="White" /> <DynamicMenuStyle BackColor="#F7F6F3" /> <StaticSelectedStyle BackColor="#5D7B9D" /> <DynamicSelectedStyle BackColor="#5D7B9D" /> <DynamicMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" /> <Items> <asp:MenuItem NavigateUrl="~/Default.aspx" Text="Accueil" Value="Accueil"></asp:MenuItem> <asp:MenuItem NavigateUrl="~/comptes.aspx" Text="Comptes" Value="Comptes"></asp:MenuItem> <asp:MenuItem NavigateUrl="~/mouvements.aspx" Text="Mouvements" Value="Mouvements"></asp:MenuItem> <asp:MenuItem Text="Données personnelles" Value="Données personnelles" NavigateUrl="~/client.aspx"></asp:MenuItem> <asp:MenuItem Text="Etats" Value="Etats"></asp:MenuItem> </Items> <StaticHoverStyle BackColor="#7C6F57" ForeColor="White" /> </asp:Menu> </div> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <asp:ObjectDataSource ID="comptesDS" runat="server" SelectMethod="getComptesForClient" TypeName="bankdemoBL.Operations"> <SelectParameters> <asp:SessionParameter Name="idclient" SessionField="idclient" Type="Int64" /> </SelectParameters> </asp:ObjectDataSource> <div style="text-align: center"> <table> <tr> <td style="width: 500px; height: 210px;"> <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" BackColor="White" BorderColor="#999999" BorderStyle="Solid" BorderWidth="1px" CellPadding="3" DataKeyNames="id" DataSourceID="comptesDS" ForeColor="Black" GridLines="Vertical" SelectedIndex="0" Width="347px"> <FooterStyle BackColor="#CCCCCC" /> <Columns> <asp:CommandField ShowSelectButton="True" /> <asp:BoundField DataField="id" Visible="False" /> <asp:BoundField DataField="numcompte" /> <asp:BoundField DataField="libcompte" /> </Columns> <SelectedRowStyle BackColor="#000099" Font-Bold="True" ForeColor="White" /> <PagerStyle BackColor="#999999" ForeColor="Black" HorizontalAlign="Center" /> <HeaderStyle BackColor="Black" Font-Bold="True" ForeColor="White" /> <AlternatingRowStyle BackColor="#CCCCCC" /> </asp:GridView> </td> <td style="width: 850px; height: 210px;"> <asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False" CellPadding="4" DataSourceID="compteDS" ForeColor="#333333" GridLines="None" Height="50px" Width="265px"> <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" /> <CommandRowStyle BackColor="#E2DED6" Font-Bold="True" /> <EditRowStyle BackColor="#999999" /> <RowStyle BackColor="#F7F6F3" ForeColor="#333333" /> <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" /> <Fields> <asp:BoundField DataField="id" HeaderText="id" SortExpression="id" /> <asp:BoundField DataField="numcompte" HeaderText="N° compte" SortExpression="numcompte" /> <asp:BoundField DataField="libcompte" HeaderText="Libellé" SortExpression="libcompte" /> <asp:BoundField DataField="datecreat" DataFormatString="{0:dd/MM/yyyy}" HeaderText="Date création" HtmlEncode="False" SortExpression="datecreat" /> </Fields> <FieldHeaderStyle BackColor="#E9ECF1" Font-Bold="True" /> <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" /> <AlternatingRowStyle BackColor="White" ForeColor="#284775" /> </asp:DetailsView> <asp:ObjectDataSource ID="compteDS" runat="server" SelectMethod="getFicheCompte" TypeName="bankdemoBL.Operations"> <SelectParameters> <asp:ControlParameter ControlID="GridView1" Name="idcompte" PropertyName="SelectedValue" Type="Int64" /> </SelectParameters> </asp:ObjectDataSource> </td> </tr> </table> </div> </ContentTemplate> </asp:UpdatePanel> </form> </body>
</html>
Custom membership provider minimaliste appelant une fonction métier
- Nous allons voir comment mettre en place une authentification pour un site WEB en utilisant les outils Microsoft et en customisant un MembershipProvider.
Par défaut, les fonctions d'authentification et de gestion des rôles peuvent être délèguer au provider par défaut (AspnetMembership provider). Celui-ci va lire les données dans une base SQL. Cette manière de faire pose des problèmes d'architecture et de sécurité car : la couche présentation accède directement à la couche DATA.
Nous allons donc construire notre propre fournisseur pour l'authentification qui respectera les règles habituelles.
Pour cela :
- Identifier la fonction métier qui réalise l'authentification : ici ce sera l'interface IOperations via la fonction authentifie
System.Int64 op.authentifie(string username, string password);
- Créer une classe (par exemple MonMembershipProvider qui dérive de la classe MembershipProvider)
public class MonMembershipProvider : MembershipProvider
Il faut ensuite surcharger les nombreuses méthodes et propriétés.
- Au minimum, il faut implémenter :
- la propriété Name (nom du provider)
public override string Name
{
get
{
return "MonMembershipProvider";
}
}
- la méthode ValidateUser
- public override bool ValidateUser(string username, string password)
- {
- IOperations op = new Operations();
- Int64 res = op.authentifie(username, password);
- if (res != 0)
- {
- HttpContext.Current.Session.Add("idclient", res.ToString());
- return true;
- }
- else
- return false;
- Modifier le fichier Web.config
<authentication mode="Forms">
<forms loginUrl="login.aspx" timeout="20">
</forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
<membership defaultProvider="MonMembershipProvider">
<providers>
<add name="MonMembershipProvider"
passwordFormat="Hashed"
minRequiredPasswordLength="2"
minRequiredNonalphanumericCharacters="0"
requiresQuestionAndAnswer="False"
requiresUniqueEmail="True"
type="bankdemoAJAX.MonMembershipProvider"/>
</providers>
</membership>
Il ne reste plus qu'à faire glisser sur la page login.aspx un contrôle "Login" et modifier la propriété membershipProvider à MonMembershipProvider. Voilà c'est fini. Pour aller plus loin, il est possible de surcharger CreateUser, ChangePassword ...
Quelques astuces rails
Rails NomAppli
(dans script) ruby generate migration nomTable
Dans dbmigrate
Présentation de RoR
Introduction :
RoR (Ruby On Rails) est un framework léger pour le développement d'applications n-tiers. Il s'appuie sur le langage Ruby; Rails étant un framework MVC. RoR privilégie la productivité du développeur, la plupart des tâches techniques (accès aux données, marshalling des objets ...) étant gérées directement par le framework lui-même. Le développeur se concentre donc sur l'implémentation du code fonctionnel et de l'IHM.
Deux avantages indéniables :
- De part la nature de Rails, les développeurs sont obligés de respecter le pattern MVC pour la partie présentation;
- L'accès aux données et les opérations CRUD sont directement implémentés dans le framework via le pattern Active Record.
Ce qui rend alors le développement très productif !
Installation :
Plusieurs modes d'installation. Personnellement, je recommande de télécharger "InstantRails" sous Windows (programme d'installation packagé qui installe Ruby, Gems, Rails, Apache, MySql et PHP.
Sur le même site, consulter la rubrique "Getting started" pour les tâches post-installation et la FAQ.
Tutoriels :
Les sites suivants sont précieux pour la prise en main du framework :
http://jurassicgeek.blogspot.com/
http://sl33p3r.free.fr/tutorials/rails/wiki/wiki-fr.html
Autrement, les sites de référence :
Une DAO générique avec VS2005 et le framework CASTLE
Les genrics dans .NET 2.0 permettent de factoriser le code; parfois de façon spectaculaire.
Par exemple, un DAO expose les méthodes CRUD pour accéder aux classes métier. En général,
il faut écrire une classe DAO par entité métier.
Avec les générics, c'est fini :
///*********************************************************************************************************
///Classe DAOGeneric
///*********************************************************************************************************
///Classe utilisant Hibernate, Castle(Active Record) pour la persistance
using System;
using System.Collections.Generic;
using System.Text;
using Appliref.domain;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Queries;
using NHibernate;
namespace Appliref.Dao
{ public class daoGenerics<T,U,V>
{ public daoGenerics()
{ } /// ///Recherche un objet par clé
public T getObject(U ID)
{ return ((T)(ActiveRecordMediator.FindByPrimaryKey(typeof(T), ID)));
} /// ///Récupère la collection d'un type donné public T[] getObjects()
{ return ((T[])(ActiveRecordMediator.FindAll(typeof(T))));
} /// ///Supprime un objet /// public bool deleteObject(T objet)
{ try
{
ActiveRecordMediator.Delete(objet);
return true;
} catch (Exception e)
{ return false;
} } /// ///Vide une table /// public bool deleteAllObjects()
{ try
{
ActiveRecordMediator.DeleteAll(typeof(T));
return true;
} catch (Exception e)
{ return false;
} } /// ///Mise à jour d'un objet /// public T updateObject(T objet)
{ try
{
ActiveRecordMediator.Save(objet);
return objet;
} catch(Exception e)
{ return default(T);
} } /// ///Création d'un nouvel objet /// public T newObject(T objet)
{ try
{
ActiveRecordMediator.Create(objet);
return objet;
} catch (Exception e)
{ return default(T);
} } /// ///Exécute une requête de sélection (HQL) public V[] executeQuery(SimpleQuery q)
{ return (V[])ActiveRecordMediator.ExecuteQuery(q);
} } }
Benchmark Java 5 et .NET 1.1 2.0 sur des opérations XML
http://www.process64.com/articles/xmlmark1/
Les résultats d'un bench (XML Mark revisited).
Exemple XMLENCRYPT
XmlEncrypt est un standard qui permet d'échanger des données chiffrées au format xml.
L'exemple ci-dessous permet de chiffrer une partie d'un fichier xml dans un programme de type console
et de déchiffrer dans un autre programme de type Winform.
Programme console de chiffrement
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
namespace cryptage
{ class Program
{
static void Main(string[] args)
{ XmlDocument xmlDoc = new XmlDocument();
// Charge le fichier XML en clair dans un objet XmlDocument.
try
{
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load("c:\\crypto\\test.xml");
} catch (Exception e)
{ Console.WriteLine(e.Message);
} // Création d'un clé RSA. Cette clé servira à chiffrer la clé symétrique qui sera embarquée,
// dans le fichier xml.
RSA rsaKey = new RSACryptoServiceProvider();
XmlDocument xmlKey = new XmlDocument();
xmlKey.LoadXml(rsaKey.ToXmlString(true));
xmlKey.Save("c:\\crypto\\key.xml");
try
{
// Chiffrement de l'élément XML.
Encrypt(xmlDoc, "creditcard", rsaKey, "rsaKey");
// Sauvegarde du fichier chiffré xmlDoc.Save("c:\\crypto\\test2.xml"); ;
} catch (Exception e)
{ Console.WriteLine(e.Message);
} finally
{
// Clear the RSA key.
rsaKey.Clear();
}
}
public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, RSA Alg, string KeyName)
{ // Contrôle des arguments.
if (Doc == null)
throw new ArgumentNullException("Doc");
if (ElementToEncrypt == null)
throw new ArgumentNullException("ElementToEncrypt");
if (Alg == null)
throw new ArgumentNullException("Alg");
////////////////////////////////////////////////
// Recherche de l'élément à chiffrer
////////////////////////////////////////////////
XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;
if (elementToEncrypt == null)
{ throw new XmlException("The specified element was not found");
} //////////////////////////////////////////////////
//Création d'une nouvelle instance EncryptedXml pour chiffrer l'XmlElement
// avec une clé symétrique aléatoire.
//////////////////////////////////////////////////
// Création d'une clé de 256 bits.
RijndaelManaged sessionKey = new RijndaelManaged();
sessionKey.KeySize = 256; EncryptedXml eXml = new EncryptedXml();
byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
////////////////////////////////////////////////
// Construction d'un objet EncryptedData et renseignement des informations de chiffrement
////////////////////////////////////////////////
EncryptedData edElement = new EncryptedData();
edElement.Type = EncryptedXml.XmlEncElementUrl;
// Creation d'une EncryptionMethod
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
//Chiffrement de la clé de session et rajout à l'élément EncryptedKey
EncryptedKey ek = new EncryptedKey();
byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false);
ek.CipherData = new CipherData(encryptedKey);
ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
// Create a new KeyInfoName element.
KeyInfoName kin = new KeyInfoName();
// Specify a name for the key.
kin.Value = KeyName;
// Add the KeyInfoName element to the
// EncryptedKey object.
ek.KeyInfo.AddClause(kin);
// Add the encrypted key to the
// EncryptedData object.
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
// Add the encrypted element data to the
// EncryptedData object.
edElement.CipherData.CipherValue = encryptedElement;
////////////////////////////////////////////////////
// Replace the element from the original XmlDocument
// object with the EncryptedData element.
////////////////////////////////////////////////////
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
} } } Programme Winform de déchiffrement using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Security.Cryptography; using System.Security.Cryptography.Xml; using System.Xml; namespace clnCrypto
{ public partial class Form1 : Form { public Form1()
{ InitializeComponent(); } private void Form1_Load(object sender, EventArgs e)
{ RSA rsaKey = new RSACryptoServiceProvider();
XmlDocument xmlkey = new XmlDocument();
xmlkey.Load("c:\\crypto\\key.xml");
rsaKey.FromXmlString(xmlkey.OuterXml); XmlDocument xmlDoc = new XmlDocument();
// Load an XML file into the XmlDocument object. //xmlDoc.PreserveWhitespace = true; xmlDoc.Load("c:\\crypto\\test2.xml");
this.richTextBox1.Text = xmlDoc.InnerXml;
Decrypt(xmlDoc, rsaKey, "rsaKey");
this.richTextBox2.Text = xmlDoc.InnerXml;
} private static void Decrypt(XmlDocument Doc, RSA Alg, string KeyName)
{ // Check the arguments. if (Doc == null)
throw new ArgumentNullException("Doc");
if (Alg == null)
throw new ArgumentNullException("Alg");
if (KeyName == null)
throw new ArgumentNullException("KeyName");
// Create a new EncryptedXml object. EncryptedXml exml = new EncryptedXml(Doc);
exml.AddKeyNameMapping(KeyName, Alg); // Decrypt the element using the symmetric key. try { exml.DecryptDocument(); } catch (System.Security.Cryptography.CryptographicException e)
{ Console.WriteLine(e.Message);
} } } } Fichier xml en clair <?xml version="1.0" encoding="utf-8" ?>
<root>
<creditcard>
<number>19834209</number>
<expiry>02/02/2002</expiry>
</creditcard>
</root> fichier xml chiffré <?xml version="1.0" encoding="utf-8"?>
<root>
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#"><EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#"><EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><KeyName>rsaKey</KeyName></KeyInfo><CipherData><CipherValue>PbpKLi/EBGoh6qTxUJyRPYat/u+1Rj5g+H6IxIWRXJ3E6cODsKxJbFokzg980+OBFKh6ZAagmrwxATRElX1LMgDZfatCBEW3jIaESG12N0HnPPlntmY5PViqZpny3lm7XltAISeFE7ovxShKFcxU9749uC+Zj+eONlhJUGt5DPQ=</CipherValue></CipherData></EncryptedKey></KeyInfo><CipherData><CipherValue>9fFBfVMGS50njNrt+vJtWKrgEgciG93Py+RkVnW4IWyRzvDx9VoDrEEs7kRPqN5PCAgIt2Y9TnExX6e+eWQM9JlReTAKlJ+RFY3No2oc1APElYcH2JJdpkj4V2XpOLduYOIwK108p2eGJiliO2L1bw==</CipherValue></CipherData></EncryptedData>
</root>
Mapping O/R : PUZZLE
Un framework intéressant : Puzzle.
Puzzle comprend :
- ObjectMapper : Outil permettant de générer les POCOs et la couche de persistance avec NPersist ou
NHibernate;
- NPersist : un framework O/R mapping;
- NPath : query sur les graphes en mémoire (objets);
- NAspect : un framework AOP
- NFactory
Tout cela en Opensource et téléchargeable sur le site :
http://www.puzzleframework.com/
Site sur WCF (Indigo)
Microsoft vient d'ouvrir un site dédié à WCF.
http://windowscommunication.net/
Il y a pas mal d'articles intéressants dont des exemples pour débuter.