dimanche 9 octobre 2011

Comment désactiver un validateur en JavaScript (ASP.NET)

Il y a des scénarios où l'on doit valider ou non certaines section d'un formulaire dépendant des choix fait par l'utilisateur. Lorsqu'un utilisateur fait choix qui affecte la validation d'un formulaire, une des méthodes possible est retourner au serveur (Postback) et d'activer ou de désactiver certains validateurs. Par contre lorsque le formulaire comporte beaucoup de champs, cette option peut s’avérer coûteuse car le tout le Viewstate de la page est transféré au serveur. Dans ce cas, il est possible d'activer ou de désactiver certains validateurs en JavaScript, évitant donc un aller/retour au serveur.

Prenons pour exemple un formulaire qui demande à l'utilisateur son prénom, nom et si l'utilisateur coche la case "J'aimerais m'inscrire à la liste de diffusion." et bien nous l’obligeons aussi à saisir son courriel.
Voici le code HTML du formulaire :

<form id="form1" runat="server">

<div>
<span> Prénom : </span>
<asp:TextBox runat="server" ID="TextBoxFirstName" />
</div> <div>
<span>Nom : </span>
<asp:TextBox runat="server" ID="TextBoxLastName" />
</div>
<div><asp:CheckBox ID="CheckBoxMailingList" Text="J'aimerais m'inscrire à la liste de diffusion." runat="server" onclick="ToggleMailingListSection()" /></div> <div id="MailingListSection">
<span>Courriel : </span> <asp:TextBox runat="server" ID="TextBoxEmail" /> <asp:RequiredFieldValidator ID="RequiredFieldValidatorEmail" ControlToValidate="TextBoxEmail" runat="server" ErrorMessage="Le courriel est obligatoire!" />
</div>
<asp:Button Text="Soumettre" runat="server" />
</form>

Rendu du formulaire sans la case cochée :

Rendu du formulaire avec la case cochée :

Lorsque vous cochez la case CheckBoxMailingList, la fonction ToggleMailingListSection est appelée. Voici le code de la fonction:

<script type="text/javascript">
$(document).ready(function () {
ToggleMailingListSection();
});

function ToggleMailingListSection() {
var checkboxMailingList = document.getElementById("CheckBoxMailingList");
var mailingListSection = document.getElementById("MailingListSection");
if (checkboxMailingList.checked) {
mailingListSection.style.display = "block";
}
else {
mailingListSection.style.display = "none";
}
}
</script>

La fonction ToggleMailingListSection sert à cacher ou afficher la section MailingListSection. Même si la section est cachée en CSS, le validateur est encore actif. Pour désactiver un validateur ASP.NET en JavaScript il suffit d'appeler la fonction ValidatorEnable(validator, enable) accessible via WebResource.axd.

<script type="text/javascript">
$(document).ready(function () {
ToggleMailingListSection();
});

function ToggleMailingListSection() {
var checkboxMailingList = document.getElementById("CheckBoxMailingList");
var mailingListSection = document.getElementById("MailingListSection");
var requiredFieldValidatorEmail = document.getElementById("RequiredFieldValidatorEmail");

if (checkboxMailingList.checked) {
mailingListSection.style.display = "block";
ValidatorEnable(requiredFieldValidatorEmail, true);
}
else {
mailingListSection.style.display = "none";
ValidatorEnable(requiredFieldValidatorEmail, false);
}
}
</script>

Voici en ajoutant les deux lignes ValidatorEnabled, on peut maintenant activer ou désactiver le validateur sans avoir à communiquer avec le serveur!

mardi 13 septembre 2011

Opérateur conditionnel (?:) et opérateur de nulle coalescence (??) en C#

L'opérateur conditionnel et l’opérateur de nulle coalescence peuvent s'avérer très utiles pour simplifier votre code et le rendre également plus lisible.

L’opérateur conditionnel

L'opérateur conditionnel (également appelé opérateur ternaire) permet de d'évaluer une condition et ensuite d'évaluer l'une ou l'autre des parties pour en retourner le résultat. La syntaxe est z ? x : y
Donc dans l'exemple ci-dessous, si la condition est (a==1) est vraie, x sera égal à 1 sinon il sera égal à 0.
int x = (a==1) ? 1 : 0;

Le premier opérande de l'opérateur conditionnel (a==1) doit être une expression d'un type qui peut être converti implicitement en bool ou une expression d'un type qui implémente operator true.
Le type de l’expression conditionnel est déterminé par le deuxième et troisième opérande. En se base sur le modèle suivant :

  • Si y et z sont du même type, il s'agit alors du type de l'expression conditionnelle.
  • Sinon, s'il existe une conversion implicite de X en Y, mais pas de Y en X, Y est alors le type de l'expression conditionnelle.
  • Sinon, s'il existe une conversion implicite de Y en X, mais pas de X en Y, X est alors le type de l'expression conditionnelle.
  • Sinon, le type d'expression ne peut pas être déterminé et une erreur de compilation se produit.

Voir documentation sur MSDN http://msdn.microsoft.com/fr-fr/library/aa691313(v=vs.71).aspx

Donc au lieu d’écrire une expression tel que :
string GetValueName(int value)

{
if (value == 1)
return "Value 1";
else
return "Value 2";
}

On peu tout simplement écrire :
string GetValueName(int value)


{
return (value == 1) ? "Value 1" : "Value 2";
}


L’opérateur de nulle coalescence

Tout d'abord, le mot coalescence signifie grossièrement « Unir 2 parties en une seule, fusionner ». L’opérateur de nulle coalescence vérifie si le premier opérande est non null, si c’est le cas cette valeur est retournée, sinon c’est la valeur du deuxième opérande qui est retourné. La syntaxe est x ?? y
Donc dans l'exemple ci-dessous, si la condition est la variable age n’égale pas à null, la fonction GetAge retournera la valeur de age, sinon elle retournera 0.
int GetAge(Nullable age)

{
return age ?? 0;
}


Vous remarquerez également que la conversion age (Nullable) en int lors du retour de la fonction s’est faite par l’opérateur de nulle coalescence, donc pas besoin de cast.

mardi 12 juillet 2011

Utiliser LINQ to SQL sur une base de données SQL Server Compact Edition (SQL CE)

Il est simple d’utiliser LINQ to SQL afin de se connecter à une base de données SQL Server. Il suffit de faire glisser les tables ou procédures stockées de la fenêtre Server Explorer vers votre fichier DBML. Toutefois lorsque la base de données est de format SQL Server Compact Edition, vous risquez d’avoir un message d’erreur « The selected object(s) use an unsupported data provider. »



Il existe un utilitaire en ligne de commande qui se nomme SqlMetal et qui permet d’outre passer ce problème. Cet outil permet de générer un fichier dbml à partir d’importe quelle base de données (vous devrez vous procurer le provider LINQ to pour les bases de données autres que Microsoft SQL Server). SqlMetal.exe se trouve habituellement dans
C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin


Voici un exemple concret d’utilisation. Nous avons une application avec une base de données HumanResources.sdf qui contient une table Employee. Pour générer notre fichier DBML il suffit d’ouvrir une console de ligne de commande (cmd) et de se positionner dans le dossier de notre projet. Ensuite exécuter la commande

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\SqlMetal.exe" /conn:"Data Source=HumanResources.sdf" /dbml:DataClassesHumanResources.dbml /provider:SQLCompact




Vous pouvez maintenant retourner dans Visual Studio et inclure le fichier dbml généré à votre projet.


Pour plus d'information sur SqlMetal : http://msdn.microsoft.com/fr-fr/library/bb386987.aspx

Vous êtes maintenant prêt à utiliser LINQ to SQL sur votre SQL Server Compact Edition!


Notes

Il est également possible d'automatiser cette procédure pour ne pas avoir à refaire ces étapes lorsque que vous modifiez votre base de données. Une façon de faire est d’appeler SqlMetal dans l’évènement Pre-build de votre projet.



La commande de Pre-build pour notre exemple serait :
"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\SqlMetal.exe" /conn:"Data Source=$(ProjectDir)\HumanResources.sdf" /dbml:$(ProjectDir)\DataClassesHumanResources.dbml /provider:SQLCompact


En espérant que cet article vous ait été utile.

vendredi 8 juillet 2011

Comment mocker un DataContext et une Table LINQ to SQL avec Moles

Avez-vous déjà essayés de mocker un DataContext ou une table LINQ to SQL? Cette tâche est ardue à réaliser avec des plateformes de mocking classiques, car le DataContext n’hérite d’aucune interface et la classe Table est sealed. Heureusement, Moles apporte une solution toute simple. Moles est un framework qui permet de détourner n’importe quelle méthode .NET, incluant même les méthodes virtuelles/statiques dans des classes sealed.

Allons-y d’un exemple! Nous avons ici une application WinForms classique contenant un fichier DataClassesEmployee.dbml. Ce fichier contient une table Employee. C’est cette table que l’on va mocker.



Nous avons également une opération EmployeeGetOperation qui se charge de trouver un employé dans la base de données en fonction de son Id.


public class EmployeeGetOperation
{
private Int32 _id = -1;
public Int32 Id
{
get { return _id; }
set { _id = value; }
}

private Employee _result = null;
public Employee Result
{
get { return _result; }
set { _result = value; }
}

DataClassesEmployeeDataContext _context = new DataClassesEmployeeDataContext();
public DataClassesEmployeeDataContext Context
{
get { return _context; }
set { _context = value; }
}

public EmployeeGetOperation(Int32 Id)
{
this.Id = Id;
}

public EmployeeGetOperation(Int32 Id, DataClassesEmployeeDataContext Context)
: this(Id)
{
this.Context = Context;
}

public void Execute()
{
Result = Context.Employees.FirstOrDefault(e => e.ID == Id);
}
}


Nous allons maintenant ajouter un projet de test à notre solution afin de pouvoir créer notre test unitaire. N'oubliez pas d'ajouter la référence System.Data.Linq et celle du projet qui contient votre fichier dbml (MockingLINQtoSQLApp) à votre projet de test. La prochaine étape est de générer un fichier moles pour les 2 références ci-dessus. Pour ce faire vous cliquer droit sur la référence dans votre projet de test et ensuite cliquer sur "Add Moles Assembly". Répéter l'opération pour System.Data.Linq.



Nous voilà rendus au test unitaire. La première étape sera d'instancier un MDataClassesEmployeeDataContext via les nouveaux types générés par Moles, ensuite nous créerons une table d'employé à partir d'une liste fictive et finalement nous détournerons notre propriété Employees de notre nouveau DataContext vers notre table fictive.

Voici maintenant le code de notre test unitaire EmployeeGetOperationTests.


[TestClass]
public class EmployeeGetOperationTests
{
[TestMethod]
[HostType("Moles")]
public void EmployeeGetOperationTests_GetValidUser_ReturnValidUser()
{
//Mock du DataContext
var context = new MDataClassesEmployeeDataContext();

//Liste d'employé fictive à utiliser pour le test
var employees = new List<Employee>()
{
new Employee() { ID = 1, FirstName = "Bud", LastName = "Spencer"},
new Employee() { ID = 2, FirstName = "Terence", LastName = "Hill"}
};

//Créer une table à partir de notre liste fictive
MTable<Employee> employeeMockTable = SetupLinqTable(employees);

//Détourner la propriété Employees de notre context vers notre table fictive
context.EmployeesGet = () => employeeMockTable;

//Appeler notre opération de sélection d'un employé via notre context mocké
EmployeeGetOperation operation = new EmployeeGetOperation(1, context);
operation.Execute();
//Vérifier que l'employé retourné est bien celui que nous attendions
Assert.AreEqual<Int32>(1, operation.Result.ID);
Assert.AreEqual<String>("Bud", operation.Result.FirstName);
Assert.AreEqual<String>("Spencer", operation.Result.LastName);
}

//Fonction qui retourne une Table à partir d'un IEnumerable
private MTable<T> SetupLinqTable<T>(IEnumerable<T> linqList) where T : class
{
MTable<T> tempTable = new MTable<T>();
tempTable.Bind(linqList.AsQueryable());
return tempTable;
}
}


Il est maintenant temps de rouler le test.



Voilà! Nous avons créé un test unitaire en mockant la couche d'accès aux données (LINQ to SQL) grâce à Moles!

lundi 15 novembre 2010

Référencer en CSS 2.0 des éléments sans id ni classe

Un de mes collègues m’a montré un cas assez spécial aujourd’hui dans SharePoint. Il a construit un formulaire de saisie dans SharePoint avec l’objet InputFormSection qui est un Template User Control. Bref en résumé cet objet génère en html un objet avec un tag <tr> et des <td> pour chacune des sections.

Le problème est survenu lorsqu’il a ajouté le contrôle PeoplePicker de SharePoint dans une des sections. Le code html généré par le PeoplePicker crée automatiquement un espace à droite de 10 pixels ainsi qu’une ligne en dessous. Ce qui n’était pas très élégant pour l’affichage du formulaire. Le défi est donc de cacher la cellule de 10 pixels ainsi que la ligne qui a été rajoutée en dessous du contrôle PeoplePicker.

Le PeoplePicker est un WebControl, ce qui veut dire qu’il est compilé dans un assembly, donc pas facilement modifiable.
Après réflexion je ne vois que deux solutions pour cacher ces deux éléments : soit via CSS ou Javascript.

J’ai donc choisi la première solution.

Pour rajouté à la tâche, les deux éléments n’ont aucun ID ni aucune class CSS. Ils sont donc assez difficiles à référencer.
Voici un exemple de code, différent de l’original, mais qui démontre bien la situation.



<table id="tblMyTable">
<tr class="myTrClass">
<td class="myTDClass1">Data 1</td>
<td class="myTDClass1">Data 2</td>
<td width="10">&nbsp;</td> <%--To be removed--%>
</tr>
<tr> <%--To be removed--%>
<td> </td>
<td><img src="Line.jpg" height="5" width="200"/></td>
<td> </td>
</tr>
</table>


Je cherchais un moyen de référencer le 3e tag TD afin de lui appliquer le style « Display: none; ». J’ai donc discuté mon collègue Sébastien qui connait bien le CSS. Il m’a donc parlé du symbole « + » en CSS 2.0 qui permet de référencer l’objet qui succède directement à l’élément précédent.
J’ai donc créé le style suivant dans le tag « Head » de la page afin de cacher le tag TD :


<style type="text/css">
#tblMyTable .myTDClass1 + .myTDClass1 + td
{
display: none;
}
</style>

Le code ci-dessus sélectionne le tag avec la classe « myTDClass1 » dans la table dont le id est « tblMyTable » (1er TD), ensuite il sélectionne l’objet qui lui succède directement et qui a également la classe « myTDClass1 » (2e TD) et ensuite le TD qui lui succède directement c'est-à-dire le 3e TD.

Même principe pour cacher le 2e TR.


<style type="text/css">
#tblMyTable .myTrClass + tr
{
display: none;
}
</style>

En résumé, vive le CSS!

dimanche 14 novembre 2010

Utilisation du mot-clé yield pour palier aux variables de retour temporaire

Il vous est surement arrivé de devoir retourner un IEnumerable dans une de vos méthodes. La façon classique, est de se déclarer une variable temporaire afin de pouvoir ajouter le contenu désiré et ensuite retourner la collection.

Voici un exemple qui affiche les nombres pairs entre dans un intervalle donné:


public IEnumerable<int> GetPairNumber(int From, int To)
{
List<int> retVal = new List<int>();


for (int indexNumber = From; indexNumber < To; indexNumber++)
{
if (indexNumber % 2 == 0)
{
retVal.Add(indexNumber);
}
}
return retVal;
}


Il est toute fois possible d'éviter la déclaration et l'utilisation de la variable retVal. Pour ce faire, on peut utiliser les mots-clés yield return dans un bloc itérateur.
Le mot-clé yield indique au compilateur que la méthode dans laquelle il apparait est un bloc itérateur. Le compilateur génère une classe pour implémenter le comportement exprimé dans le bloc itérateur. Dans le bloc itérateur, le mot clé yield est utilisé avec le mot clé return pour fournir une valeur à l'objet énumérateur. C'est donc cette valeur qui est retournée.


L'exemple ci-dessous reprend effectue exactement la même opération, mais en évitant la variable retVal.



public IEnumerable<int> GetPairNumber(int From, int To)
{
for (int indexNumber = From; indexNumber < To; indexNumber++)
{
if (indexNumber % 2 == 0)
{
yield return indexNumber;
}
}
}


Ok ça ne changera pas le monde, mais c’est un petit truc intéressant à savoir :)

jeudi 15 juillet 2010

Contrôler l'arrêt d'un service Windows perso (.NET)

Lorsqu'on développe un service Windows, il est essentiel de contrôler le moment où le service s'arrêtera surtout lorsqu'il s'agit d'un traitement en lot. Vous ne voudriez probablement pas que votre service s'arrête en plein traitement, car un utilisateur à lancer la commande net stop votre_service.

Prenons par exemple un service qui roule en continu et qui vérifie toutes les 15 secondes les enregistrements qui ont été ajoutés à une base de données afin de pouvoir les traiter. Dans cet exemple, le service ne doit pas s'arrêter tant qu'il n'a pas fini de traiter les nouveaux enregistrements.

Seul le code servant au contrôle du service sera présenté dans cette publication

Voici le code du service ServiceData (ServiceData.cs)


public partial class ServiceData : ServiceBase
{
Thread dataProcessingThread = null;

public ServiceData()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
dataProcessingThread = new Thread(DataProcessing.ProcessPendingData);
dataProcessingThread.Start();
}

protected override void OnStop()
{
DataProcessing.ResetEvent.Set();
while (dataProcessingThread.IsAlive)
{
this.RequestAdditionalTime(5000);
Thread.Sleep(5000);
}
}
}


Lors du démarrage du service, nous lançons, dans l'évènement OnStart, un thread qui va s'exécuter tout au long du service. Nous verrons la classe DataProcessing un peu plus loin... Regardons tout d'abord l'arrêt du service. Dans la fonction OnStop la commande
DataProcessing.ResetEvent.Set();
sert à déclencher l'évènement d'arrêt du service. La boucle while sert ensuite à attendre que les enregistrements restant à traiter se terminent. La commande suivante
this.RequestAdditionalTime(5000);
sert à avertir le Service Control Manager (SCM) que le service requiert 5 secondes de plus pour s'arrêter. Si nous omettons cette commande, le SCM croira que le service ne répond plus. Cette boucle vérifie en fait à tout les 5 secondes si le travail du thread est terminé.


Voici le code de la classe DataProcessing (DataProcessing.cs)


public static class DataProcessing
{
private static ManualResetEvent resetEvent = new ManualResetEvent(false);
public static ManualResetEvent ResetEvent
{
get { return resetEvent; }
set { resetEvent = value; }
}

public static void ProcessPendingData()
{
do
{
//All stuff here will not be interrupted until they finish
}
while (!ResetEvent.WaitOne(15000));
}
}


Le code suivant
private static ManualResetEvent resetEvent = new ManualResetEvent(false);
public static ManualResetEvent ResetEvent
{
get { return resetEvent; }
set { resetEvent = value; }
}

définit le ResetEvent qui sert à avertir le thread qu'un événement est survenu.
public static void ProcessPendingData()
{
do
{
//All stuff here will not be interrupted until they finish
}
while (!ResetEvent.WaitOne(15000));
}
La méthode statique ProcessPendingData sert à traiter les enregistrements. Tout ce qui se trouve à l'intérieur du do-while ne sera pas interrompu par un arrêt de service.
Donc la boucle va s'exécuter toutes les 15 secondes tant et aussi longtemps qu'une demande d'arrêt n'a pas été formulée. Votre lot d'enregistrements pourra donc être traité sans être interrompu!