Archive

Posts Tagged ‘ASP.Net’

CallContext et migration de Framework

Récemment, j’ai été impliqué sur plusieurs projets (c’est le bordel niveau CRA, d’ailleurs ^^).
L’un de ces projets est la migration de Framework : du 2.0 vers le 4.0.

Dans le billet Legacy Applications, j’expliquais mon avis sur le bond technologique, donc je n’y reviendrais pas ici.

Nous avons d’abord eu une démarche d’identifier les Breaking Changes – autrement dit les choses qui deviennent obsolètes ou qui disparaissent – avant de réellement faire la migration.

C’est une bonne chose.

Mais…eh bien oui, il y a toujours un mais.
Mais, donc, il faut bien connaître l’applicatif, bien connaître le code.
Ce qui n’était pas réellement notre (mon, du moins) cas.
Parce que, au final, si on prend la liste des breaking changes, soit on la parcours point par point (ce qui peut s’avérer assez long), soit…on la garde sous le coude.

Mais surtout, il y a des choses qui ne sont pas forcément présentes dans les breaking changes et qui peuvent occasionner des drames (n’ayons pas peur des grands mots ! 🙂 ).

Donc, dans ce billet, on va voir le Grand Méchant (avec majuscules, s’il vous plait) CallContext.

Lire la suite…

Catégories :.Net, ASP.Net, C#, Développement

IIS – WebDeploy

Ça change un peu du codage pur et dur, mais cette semaine, j’ai du faire d’autres opérations.
Les opérations en question, c’est d’installer différents sites Web : répéter les opérations utiles et faire une documentation à destination de l’exploitation.

Du coup, on a un peu tâtonner sur différentes sujets (Build sous TFS, génération d’un package de déploiement…).
Dans le présent billet, je vais uniquement parler de l’installation des sites Web via Web Deploy, sous IIS et les pré-requis pour que ça se passe bien.

Déjà, pour les outils que j’ai utilisé à cette occasion :

  • Visual Studio 2010
  • IIS 7.5
  • Web Deploy

Pour IIS 7.5 et Web Deploy, il faut aller voir sur le site officiel de IIS. Ce sont bien sûr des pré-requis.

 
Lire la suite…

Catégories :.Net, ASP.Net, IIS

SharpDevelop 3.2 et Projet Web

J’ai changé de boîte dernièrement (fin le 31 mai, début le 18 juin) et je commence donc avec un poste de travail sans aucun droit administrateur (mais bon, j’ai un poste de travail ^^).
Du coup, pas possible d’installer Visual Studio ou même les versions Express. De même, pas moyen d’installer le Framework .Net 4.0.
Alors, que faire ? (bon, j’avoue, j’ai l’option « téléphoner au support »…mais c’est trop simple ! :))
Et bien, j’ai décidé de faire joujou avec d’autres outils que d’habitude (et puis c’est bien de voir d’autres choses).

Mon choix s’est porté sur SharpDevelop. Pour la raison exposée plus haut (Framework 3.5 max sur mon poste), j’ai pris la version 3.2.
Une fois installée, je créé un nouveau projet Web.

SharpDevelop – Création d’un projet Web

 
Par défaut, SharpDevelop met un tas de bordel.
Ça commence par une entête de fichier (avant le using), puis des régions et des commentaires pour séparer les blocs (dans quel but ? aucune idée).
Pour les entêtes, c’est simple de les virer : dans le menu Tools -> Options, puis Coding -> Edit Strandard Headers.

Après…et bien, le premier réflexe (pour moi, puisqu’il y a du contenu et une CSS par défaut), c’est de lancer le debug.
Et là, c’est le drame.
SharpDevelop n’embarque pas de Webserver comme le fait Visual Studio.
Du coup…et bien, on peut pleurer un bon coup ou chercher à pallier le problème.

Et notre application héroïque est : CassiniDev.
Ca fait plein de choses, avec, surtout ce qui m’intéresse là maintenant tout de suite : le Webserver.
Donc, on télécharge et on décompresse l’archive (C:\Programs\CassiniDev pour ma part).

On revient dans SharpDevelop, sur le projet Web et on va dans ses propriétés, onglet Debug :

SharpDevelop - Propriétés du projet Web

SharpDevelop – Propriétés du projet Web

J’ai mis ici uniquement la partie pertinente :

  • Start Action positionné sur Start External, avec le chemin vers le Webserver de CassiniDev.
  • Start Options, avec une command line du type : /port:[le port que je veux] /path: »[chemin vers mon projet web] »

On fait la même chose pour la configuration Release.
Et pis c’est tout.

En parcourant les autres onglets, on voit une étrangeté : sur l’onglet Application, l’Output type est positionné à Class Library.
Ça fait bien bizarre, mais c’est normal.

Voilà, on peut commencer à jouer 🙂

Catégories :.Net, ASP.Net, C#, IDE

[Ext.Net] Helper pour la création d’un GridPanel

Bon, finalement, je l’ai dis mais pas fais, parce que j’ai fais le gros glandeur pendant mes vacances… Mais que c’est bon ! Bref

Série de billets sur les helpers que j’ai réalisés autour d’Ext.Net. Le sommaire référençant les helpers est ici : Présentation des helpers.

Dans ma mission, on a des grilles. Un tas de grilles. Énormément de grilles… De quoi donner un peu la nausée, parfois, mais comme c’est le client qui veut !

La problématique était donc la suivante :

  • On a beaucoup de grilles, on doit pouvoir en faire PLEIN de façon simple
  • Les listes contiennent parfois beaucoup d’objets
  • Chaque objet contient des objets, qui contient des obj…
  • Chaque objet peut avoir un bon nombre de propriétés (parfois des agrégations en fonction d’autres propriétés…)

Résultat des courses, je me colle à faire un composant Ext.NET en lecture seule (ça, c’est important). Qui doit gérer pas mal d’objets avec beaucoup de propriétés. Ces deux points sont importants puisque le tout allant être sérialisé, le premier jet à directement fait planter IE parce que la source HTML était trop grosse (bah oui, Ext.NET sérialise tout ou alors que les propriétés simples à la racine de l’objet…).

Je prends donc mon objet :

public class MySampleObject
{
    public String StringProperty { get; set; }
    public DateTime DateProperty { get; set; }
    public Int32 IntProperty { get; set; }
    public Single FloatProperty { get; set; }
    public String DoNotShowProperty { get; set; }
    public Boolean BoolProperty { get; set; }
    public String Currency { get; set; }
    public MySampleObject InnerObject { get; set; }
    public Dictionary<string, Double> Amount { get; set; }
}

Dans ma grille, je dois pouvoir afficher le montant (propriété Amount, de la forme Amout[« USD »] ou Amount[« EUR »]) en fonction de la monnaie (propriété Currency), mais aussi l’afficher que en Euro.
Dans le même temps, je dois pouvoir aller chercher le libellé correspondant à la monnaire (EUR => Euro; USD => Dollar; BOB => Boliviano ;)).
Je dois aussi pouvoir aller chercher un propriété d’un objet enfant, etc.
En gros, plein plein de cas.

Pour ce faire, j’ai choisis une méthode assez simple : je vais utiliser la réflexion pour créer un dictionnaire de données que je vais binder au contrôle.
Plusieurs avantages :

  • Je ne vais mettre que les données dont j’ai besoin dans le dictionnaire, donc la source sera allégée
  • Je peux conditionner des affichages en fonction d’autres données
  • Je peux formatter mes données en .Net et non plus en JS

Alors, comment ça se passe, en pratique ?

Etape 1 : la configuration de la grille
Cette étape est totalement mutualisable dans le cas de plusieurs grilles. Il faudra UNIQUEMENT redéfinir l’ID des grilles.
Exemple :

ExtGridEntity configuration = new ExtGridEntity("MyGridExtPanel", columns)
{
    AutoExpandColumn = 0,
    ColTooltipIsColName = true,
    Height = 400,
    PageSize = 20,
    PagingPosition = PagingPosition.Both,
    Sortable = true,
    Width = 500
};

On peut donc faire une méthode assez basique qui prend en paramètre un string représentant l’ID et qui renvoit un objet ExtGridEntity.

Etape 2 : lister les colonnes
Le nerf du contrôle, si je puis dire.
Là, on va lister toutes les colonnes, dire où sont les données, comment les récupérer, les formatter…

List<ExtGridColumn> columns = new List<ExtGridColumn>()
{
    new ExtGridColumn("One", "Currency"),
    new ExtGridColumn("Two", "IntProperty", DataType.Int),
    new ExtGridColumn("Three", "FloatProperty", DataType.Float),
    new ExtGridColumn("Four", "DateProperty", DataType.Date),
    new ExtGridColumn("Five", "BoolProperty", DataType.Boolean),
    new ExtGridColumn("Six", "InnerObject.StringProperty"),
    new ExtGridColumn("Seven", "InnerObject.InnerObject.StringProperty"),
    new ExtGridColumn("Eight", "Amount", "Currency", false),
    new ExtGridColumn("Nine", "Amount", "USD", true),
    new ExtGridColumn("Ten", "InnerObject.StringProperty", "<a href='Currency.aspx={One}'>Info of currency: {One}</a>"),
    new ExtGridColumn("Eleven", GetCurrencyLabel, false)
};
columns[1].FormatDataMethod = FormatInt32;
columns[3].FormatDataMethod = FormatDateTime;

Avec les différents constructeurs, on peut par exemple faire en sorte que la colonne Eight affiche le montant de la monnaie courante  (propriété Currency) alors que la colonne Nine affiche toujours le montant en USD.
On peut aussi voir de l’injection de HTML pour créer un lien, l’utilisation d’une méthode pour récupérer les données (colonne Eleven) ou encore des méthodes pour formatter les données (en dehors de la construction de la liste).

Etape 3 : afficher le composant

ExtGridView<MySampleObject> gridPanel = new ExtGridView<MySampleObject>();
gridPanel.SetDataAndConfiguration(configuration, data, GridContainer);

L’objet configuration est celui de l’étape 1. L’objet data est une simple collection (IList<>) contenant les données. Enfin, GridContainer est simplement la div (runat= »server ») dans laquelle insérer la grille.
Le tout est à placer dans un évènement du type Page_Load ou autre et…le tour est joué !

On obtient donc une grille avec toutes nos données, bien formattée et tout !

Catégories :.Net, ASP.Net, C#, Ext.Net

[Ext.Net] Helper pour la création d’une ComboBox

Série de billets sur les helpers que j’ai réalisés autour d’Ext.Net. Le sommaire référençant les helpers est ici : Présentation des helpers.

Avec Ext.Net, il y a plusieurs types de Combobox disponibles.
Pour ma part, j’ai pris la plus simple : celle qui affiche le contenu d’une liste dont le contenu est connu avant la création de la combo.

En pratique, cela veut dire que, dans la page, j’ organise le code comme il suit :

Etape 1 : déclaration des combobox comme propriétés de la page (du user control)

private ExtComboBox combo1;

Etape 2 : configurer la combobox

private ExtComboEntity GetConfigComboBox(int id)
{
    return new ExtComboEntity()
    {
        ComboID = String.Concat("Combobox", id),
        Resizable = true,
        DisplayField = "StringProperty",
        ValueField = "IntProperty",
        EmptyText = "Select value...",
        AllowRemove = true
    };
}

Note : normalement, la propriété EmptyText doit pointer vers une ressource (*.resx / *.resources), mais pour les exemples, je suis passé outre (voir solution d’exemples).

Etape 3 : dans l’évènement OnInit : création du contrôle (constructeur et appel de la méthode SetDataAndConfiguration)

combo1 = new ExtComboBox();
combo1.SetDataAndConfiguration(GetConfigComboBox(1), data.Take(10).ToList(), Combobox1Container);

Etape 4 : dans l’évènement Page_Load : présélection des champs

combo1.SelectedText = "I am property number 9";

En terme de fonctionnement interne, la liste passée en paramètre est transformée en une liste générique de type AnonymousObject.
En effet, j’ai dis à l’occasion de la présentation du helper pour le store que TOUT l’objet est sérialisé.
Dans mon exemple (voir le code sur GitHub), j’utilise un objet MySampleObject qui contient quatre propriétés. Si je laisse Ext.Net le sérialiser, j’aurais dans ma source les quatre propriétés.
A mon sens, cela pose deux problèmes majeurs : le poids de la page qui est chargée inutilement et, plus grave, une possible faille de sécurité.
Donc, avec un peu de réflexion (dans tous les sens du terme), il est possible de transformer, mon proxy est donc pas mal allégé.

new Ext.data.PagingMemoryProxy(
	[
	{"Text":"I am property number 0","Value":"0"},
	{"Text":"I am property number 1","Value":"1"},
	{"Text":"I am property number 2","Value":"2"},
	{"Text":"I am property number 3","Value":"3"}
	[...]

Au lieu de :

new Ext.data.PagingMemoryProxy(
	[
	{"StringProperty":"I am property number 0","DateProperty":"1946-01-15T10:13:50","IntProperty":0,"DoNotShowProperty":"I am the hidden one."},
	{"StringProperty":"I am property number 1","DateProperty":"1982-09-13T22:33:58","IntProperty":1,"DoNotShowProperty":"I am the hidden one."},
	{"StringProperty":"I am property number 2","DateProperty":"1960-02-21T22:15:14","IntProperty":2,"DoNotShowProperty":"I am the hidden one."},
	{"StringProperty":"I am property number 3","DateProperty":"1944-01-20T09:34:41","IntProperty":3,"DoNotShowProperty":"I am the hidden one."},
	[...]
Catégories :.Net, ASP.Net, C#, Ext.Net

[Ext.Net] Présentation des helpers

Ce billet sera relativement court, il a pour but premier de poser la problématique autour de laquelle tournera les suivants.

Sommaire des billets :

Les sources et exemples d’utilisations peuvent être trouvés sur Github.

J’ai déjà brièvement parlé d’Ext.Net, mais je vais faire un rappel ici.

Donc, Ext.Net se base sur le Framework Javascript ExtJS. Il a pour but de mettre à disposition des composants utilisables aisément afin de créer des interfaces web riches. Il suffit simplement de référencer les DLL qui conviennent et c’est tout, rien de plus simple.
Au sein du code, on va donc manipuler des balises à l’instar des balies <asp:…/>.

Voici deux exemples simplistes :

    <ext:ImageButton
        runat="server"
        ImageUrl="button.gif"
        OverImageUrl="overButton.gif"
        DisabledImageUrl="disabled.gif"
        PressedImageUrl="pressed.gif">
        <DirectEvents>
            <Click OnEvent="Button_Click" />
        </DirectEvents>
    </ext:ImageButton>

 

<ext:SpinnerField ID="SpinnerField1" runat="server" FieldLabel="Age" />

Comme on peut le voir, c’est assez simple (simpliste).
Par contre, dès que l’on veut utiliser des composants un peu plus complexes, comme un GridPanel, alors le code ASPX est bien plus long à faire.

La problématique qui s’est posée à moi était simple : sur un projet faisant la part belle au reporting sous forme de tableaux, j’avais un nombre assez considérable de GridPanel. Et comme je suis d’un naturel assez fainéant, j’ai préféré investir un peu de temps à créer un helper.
L’avantage est de pouvoir créer un nombre très important de GridPanel sans gros efforts et surtout de tout gérer dans le code C#, ce qui me permet donc de satisfaire à d’autres besoins qui sont, entre autres, d’avoir un même tableau avec les mêmes données, mais des colonnes affichées ou masquées suivant qui les voit.

Catégories :.Net, ASP.Net, C#, Ext.Net

[Ext.Net] Helper pour la création du store

Série de billets sur les helpers que j’ai réalisés autour d’Ext.Net. Le sommaire référençant les helpers est ici : Présentation des helpers.

La première chose à créer, lorsque l’on veut créer des composants avec des données, c’est le store.

Déjà, qu’est ce que c’est le store.
Le store, c’est comme une DataSource, ça permet de stocker les données (dans notre cas, des données sérialisées).
L’inconvénient, c’est que TOUT le store est stocké dans la page.

Prenons un exemple.
Je souhaite utiliser un GridPanel pour afficher les données d’une liste générique de type :

    public class MySampleObject
    {
        public String StringProperty { get; set; }
        public DateTime DateProperty { get; set; }
        public Int32 IntProperty { get; set; }
        public String DoNotShowProperty { get; set; }
    }

Dans la source de la page, on aura :

		[...Extrait partiel...]

this.MainContent_MyGridExtPanelStoreId=new Ext.ux.data.PagingStore(
	{
	proxyId:"MainContent_MyGridExtPanelStoreId",
	autoLoad:true,
	reader:new Ext.data.JsonReader(
		{
		fields:[
			{name:"StringProperty"},
			{name:"IntProperty",type:"int"},
			{name:"DateProperty",type:"date",dateFormat:"Y-m-dTh:i:s"}
			]
		}),
	directEventConfig:{},
	proxy:new Ext.data.PagingMemoryProxy(
		[
		{"StringProperty":"I am property number 0","DateProperty":"1988-03-01T06:53:34","IntProperty":746583876,"DoNotShowProperty":"I am the hidden one."},
		{"StringProperty":"I am property number 1","DateProperty":"1944-04-13T21:10:31","IntProperty":1822087014,"DoNotShowProperty":"I am the hidden one."},
		{"StringProperty":"I am property number 2","DateProperty":"2000-06-22T14:37:03","IntProperty":1922942219,"DoNotShowProperty":"I am the hidden one."}

		[...Extrait partiel...]

Expliquons un peu cet extrait :
J’ai créé un store (type : PagingStore; id : MainContent_MyGridExtPanelStoreId).
Le reader utilisé est un JsonReader, c’est lui qui s’occupe de la lecture des données.
Au sein du reader, on référence trois colonnes (fields) , se sont les propriétés à afficher :  StringProperty, IntProperty (de type int dans la grille) et DateProperty (de type date dans la grille et avec le format spécifié).
Enfin, les données à proprement parlées sont stockée dans la page (PagingMemoryProxy, à moins de faire appel à un handler).

Mon objet contient plus de champ, il y a la propriété DoNotShowProperty que je ne souhaite pas afficher.
Mais comme c’est l’objet ENTIER qui est sérialisé, il convient de faire TRES attention aux objets utilisés (au même titre q’une page d’erreur affichant du code, cela peut être une faille de sécurité).

Ainsi, je conseillerais d’utiliser des objets « présentation », c’est à dire des objets minimalistes avec uniquement les champs que l’on souhaite afficher (mais qui n’hérite pas des objets métiers, sinon on en revient au même problème…).

Le deuxième effet kiss cool, c’est que comme l’objet est sérialisé (et ça, on y peut rien), il faut bien prévoir que toutes les propriétés de l’objet puissent être sérialisée.

A noter que l’attribut XmlIgnore n’est pas pris en compte.

Pour créer le store, j’utilise donc la classe suivante :

public class StoreFactory
{
    public static Ext.Net.Store Create(String id, JsonReader jsonReader, IList data, String groupByField)
    {
        // Création du Store
        Ext.Net.Store store = new Ext.Net.Store();
        store.ID = id;
        store.Reader.Add(jsonReader);
        store.SerializationMode = SerializationMode.Complex;
        // Groupement sur les entrées
        if (!String.IsNullOrEmpty(groupByField))
            store.GroupField = groupByField;

        store.AutoLoad = true;
        store.AutoDataBind = true;
        store.RemoteSort = false;
        store.RemotePaging = false;

        store.DataSource = data;
        store.DataBind();

        return store;
    }
    public static Ext.Net.Store Create(String id, JsonReader jsonReader, IList data)
    {
        return Create(id, jsonReader, data, null);
    }
}
Catégories :.Net, ASP.Net, C#, Ext.Net