Quelques outils que tout bon développeur .Net devrait utiliser sur ses projets

icon Tags de l'article : , , ,

Mai 16, 2018
J'ai entendu dire, il y a longtemps, que Bill Gates avait dit :

"I choose a lazy person to do a hard job. Because a lazy person will find an easy way to do it."

Et c'est vrai. Quelqu'un qui n'aime pas travailler inutilement trouvera toujours des voies pour travailler plus efficacement et supprimer les tâches chiantes inutiles.

Au fil des années, je me suis rendu compte que trop peu de développeurs se posaient une question pourtant évidente : quelle tâche quotidienne et contraignante pourrais-je simplifier dans mon process de développement/test ?

La réponse est souvent : ben merde y'en a plein en fait !!!

Qu'il s'agisse de purger la base de données, de créer un compte utilisateur, de remplir la BDD avec de fausses données... il y a souvent énormément de tâches qu'un développeur pourrait automatiser pour vite gagner un maximum de temps. Et si en plus ce développement est mutualisé entre les développeurs... ben c'est un gain énorme pour toute l'équipe.

Pour ça, je voulais partager avec vous les outils que tout bon développeur .Net devrait utiliser pour ça.

1) Une extension Visual Studio

Coder sa propre extension Visual Studio n'est pas forcément évident... mais ça peut vous permettre de gagner un maximum de temps en ajoutant directement dans VS les choses chiantes que vous devez faire régulièrement.

Quelques exemples (dont certains tirés de l'extension VS de mon poste actuel) :
  • purger la base de données
  • créer un compte utilisateur de test
  • démarrer le noeud Selenium
  • tuer tous les process Chrome Selenium qui restent
  • changer la configuration de la BDD (local / tests de perfs / preprod)
  • etc.

Avoir ces options directement dans votre Visual Studio peut vous faire gagner un temps précieux. Car même juste 2 minutes par jour, sur une année ça représente une journée entière de travail...

2) Le #if DEBUG

En local, on a parfois besoin d'avoir des fonctionnements différents du fonctionnement en production. Que ce soit à cause du cache, de la quantité de données, ou même de l'initialisation de la base de données... on a parfois envie d'avoir un fonctionnement différent, pour se simplifier la vie.

Voici quelques exemples d'actions que j'ai pu automatiser par le passé, grâce au #if DEBUG :
  • au lieu d'aller chercher le catalogue complet de données en BDD (ce qui prenait 2 minutes à chaque lancement de l'application), on le stocke sérialisé sur le disque dur et on l'utilise comme tel (bim, 10 secondes de chargement au lieu de 2 minutes)
  • création automatique d'un compte par défaut si aucun compte n'existe déjà
  • connexion automatique au compte par défaut
  • extraction, anonymisation et stockage sérialisé dans des fichiers de données venant de la production, afin de pouvoir faire des calculs statistiques sans avoir à requêter directement la BDD de prod
  • forcer la connexion à la BDD locale

3) Un dossier de ressources

Là on est dans l'évidence, mais parfois ça ne fait pas de mal de rappeler les évidences : prenez des notes.

Vous galérez à trouver une procédure spécifique ? Notez là quand vous avez enfin trouvé.
Un collègue vous montre une procédure compliquée pour faire quelque chose ? Notez là.
Vous découvrez gadget super cool que vous pourriez avoir à utiliser plus tard ? Mettez le de côté.

Quand on développe, il faut aussi savoir prendre des notes. Personnellement, j'ai toujours un dossier de ressources (personnelles) chiffré.

Qu'est ce qu'on trouve dans le mien ? Enormément de choses :
  • Les logins/mdp pour chaque compte partagé lié à notre application
  • Des scripts windows/powershell pour certaines actions (backup d'une base de données, restauration, création d'un certificat)
  • Comment faire certaines actions simples/complexes dans la solution
  • Des scripts SQL pour certaines actions BDD (purge et réindex Azure, identifier la fragmentation des index, batch de suppression des anciens logs, etc.)
  • Des rappels sur certains concepts qui ont du mal à rentrer (oui, même après plus de 15 ans de dev, ça doit être le grand âge)

Ca peut sembler idiot, car souvent en 2/3 minutes sur stackoverflow on peut retrouver la solution... mais :
1) Ca permet d'avoir du spécifique pour notre situation
2) Si nos fichiers sont bien triés et nommés, on gagne du temps même par rapport à stackoverflow
3) Ca peut vous sauver la vie si vous devez refaire une opération compliquée (prévue à l'origine comme un one-shot, vous savez, le célèbre "ne t'en fais pas, c'est juste pour cette fois" d'il y a 6 mois)

4) Les tests unitaires

Bon, je ne vais pas insister sur l'importance des tests unitaires dans un projet, mais sachez ceci : vous pouvez très bien utiliser des tests unitaires pour automatiser certaines actions de dev/debug.

Quelques exemples :
  • Tester la connectionstring du projet
  • Vérifier que toutes les procédures stockées appelées sont bien présentes dans la BDD
  • Tester une procédure stockée
  • Vérifier qu'une convention de codage est bien respectée sur le projet (quand on a des règles spécifiques)

Ou même encore : créer des données en dur en base. Après tout pourquoi pas ?

5) Un logiciel d'automatisation dans le navigateur

Lorsqu'on fait du dev web, on a souvent besoin de remplir des formulaires pour tester certaines choses. Et remplir 10 fois d'affilée les même 10 champs... ben ça fatigue très vite.

Or... il existe une solution simple : les extensions Chrome/Firefox d'automatisation. Par exemple iMacros.

Ces extensions permettent d'enregistrer un enchainement d'actions faites dans le navigateur pour les reproduire ensuite. Grâce à ça, vous pourrez créer un compte, vous logger, remplir en formulaire, etc... en un seul clic.

6) Les tests Selenium

Même si les tests Selenium sont, à la base, conçus pour tester votre application, vous pouvez les utiliser pour de nombreuses choses pas forcément évidentes à première vue :
  • Tester une API
  • Tester l'interconnexion entre 2 applications
  • Aller vérifier l'état d'un autre service en ligne
  • Créer une surcouche de monitoring (quand vous n'avez qu'un board figé de monitoring et pas d'API)
  • ...

7) Les macros de Notepad++

Si vous ne les avez jamais utilisé, sachez que Notepad++ permet d'enregistrer toutes les actions produites sur une ligne, pour ensuite les reproduire sur toutes les lignes d'un fichier.

Vous avez un fichier où le format ne va pas du tout, vous devez passer un bloc à gauche, supprimer quelques caractères et rajouter un morceau à la fin ? Record => modifications => Fin => Jouer en boucle jusqu'à la fin => terminé.

Voilà, je pense que ça fait déjà pas mal,

Je vous ai épargné les grands classiques, comme les environnements d'intégration continue, car si vous n'en avez pas déjà, il y a de fortes chances que ce soit indépendant de votre volonté (je voulais concentrer cet article sur ce que les développeurs peuvent faire eux-même, sur leur poste).

J'espère que cet article vous a plu, bonne journée et bon dev à tous et toutes !

Le célèbre bug du cookie ASP.Net qui disparait

icon Tags de l'article : , ,

Septembre 18, 2015
Tout le monde se fait avoir, et ça vient de m'arriver.

Alors que je développais tranquillement ma solution, je me suis rendu compte que ma connexion à l'application cassait juste après que je me sois connecté.

Après vérification, il s'avérait que mon cookie disparaissait sans raison dès que je faisais la moindre action après ma connexion.

J'ai tout vérifié, mon code de création de cookie était bon :

Response.Cookies["UserSettings"]["IdUser"] = user.Id.ToString();
Response.Cookies["UserSettings"]["Token"] = user.Token;
Response.Cookies["UserSettings"]["Name"] = user.FirstName + " " + user.LastName;

Response.Cookies["UserSettings"].Expires = DateTime.UtcNow.AddDays(WebAppConstants.COOKIE_LIFETIME);

D'où ça vient ? C'est très simple : je devais probablement faire un Response.Cookies à un endroit au lieu d'un Request.Cookies pour lire le contenu de mon cookie.

Et effectivement c'était le cas, à un endroit où j'essayais de lire mon cookie :
if(Response.Cookies["UserSettings"] != null && Response.Cookies["UserSettings"]["Name"] != null) 
{
     //...
}

En effet, en ASP.Net, dès qu'on essaie de lire un cookie avec Response.Cookies, un cookie qui sera automatiquement renvoyé au navigateur est créé.

Or comme on ne spécifie pas la date d'expiration du cookie... il s'agit du 01/01/0001. Et du coup, quand le navigateur recevra ce cookie, il se dira que son cookie existant est obsolète... et le supprimera.

Donc rappelez-vous en : dès qu'un cookie disparait sans raison après avoir été créé, il y a de fortes chances que vous ayez essayé d'y accéder en passant par Response.Cookies au lieu de Request.Cookies !

Un petit outil pour compter le nombre de lignes de code de son projet .Net

icon Tags de l'article : ,

Septembre 17, 2015
Parce que ça fait longtemps, et que c'est toujours marrant ce genre de chiffres :)

Voici un petit morceau de code à mettre dans une application Console et qui va aller compter le nombre de lignes de code C# et JavaScript d'un de vos projets.

Son fonctionnement est simple, il va parcourir récursivement tous les dossiers de la solution, récupérer les fichiers .cs et .js, filtrer les lignes inutiles (vides, commentaires, accolades, ...) et vous renvoyer le total de lignes pour chaque langage.

Sur mon projet, on est à 52000 lignes de C# pour 53000 lignes de JavaScript. Le JS l'emporte de peu !

Voici le code :

// on récupère récursivement tous les fichiers du dossier de la solution
var allfiles = System.IO.Directory.GetFiles(
    @"/path/to/solution",
    "*.*",
    System.IO.SearchOption.AllDirectories);

// on récupère uniquement les fichiers CS
var csFiles = allfiles.Where(e => e.EndsWith(".cs"));

int cptCs = 0;
foreach (var csFile in csFiles)
{
    // pour chaque fichier on vire les tabulations et \r, et on split sur les \n
    var parts = File.ReadAllText(csFile).Replace("\r", "").Replace("\t", "").Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
    // on ne garde que les morceaux non vides et qui ne sont pas une simple accolade ou un commentaire
    parts =
        parts.Where(e => e.Trim() != "" && e.Trim() != "{" && e.Trim() != "}" && !e.Contains("//"))
            .ToArray();
    // on additionne le nombre de lignes récupérées au compteur
    cptCs += parts.Count();
}

// on récupère uniquement les fichiers JS
var jsFiles = allfiles.Where(e => e.EndsWith(".js"));
// on exclut le dossier de libraries
jsFiles = jsFiles.Where(e => !e.Contains(@"/fichier/de/librairies/js/à/exclure"));

int cptJs = 0;
foreach (var jsFile in jsFiles)
{
    // même traitement que pour le C#
    var parts = File.ReadAllText(jsFile).Replace("\r", "").Replace("\t", "").Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
    parts =
        parts.Where(e => e.Trim() != "" && e.Trim() != "{" && e.Trim() != "}" && !e.Contains("//"))
            .ToArray();
    cptJs += parts.Count();
}

Console.WriteLine(cptCs + " lines of code in C#");
Console.WriteLine(cptJs + " lines of code in JS");
Console.Read();

Relax your eyes

icon Tags de l'article : , ,

Avril 16, 2015
Hello les gens,

Comme beaucoup de développeurs, j'ai la mauvaise habitude de passer plusieurs heures sur le PC sans faire de pauses.

Le problème, c'est que mes yeux n'aiment vraiment pas, et qu'en plus les années passent, en plus ma myopie s'amplifie (et je suis sûr et certain que c'est à cause de mes trop longues sessions devant le PC).

Du coup, afin de me forcer à faire des pauses, j'ai décidé de développer un tout petit logiciel qui verrouille ma session 3 minutes toutes les heures. Ca peut sembler radical, mais c'est ce que j'ai trouvé de mieux. J'avais testé EyeDefender, plus complet, mais trop gentil (on appuie sur Echap et hop, la pause est terminée).

Le code source est disponible sur GitHub.

Et le zip est disponible ici.

L'application, ultra simpliste (pour le moment), ressemble à ça :



3 minutes avant la pause, elle affichera une infobulle d'alerte :



Et si vous êtes vraiment sur une tâche critique, vous pouvez décaler la pause de 3 minutes (mais une seule fois !) :



Enfin, vous pouvez la lancer avec l'argument -autostart pour qu'elle se lance automatiquement, ce qui peut être pratique si, comme moi, vous voulez la mettre au démarrage.

Bon dev et bonne journée à tous !

Afficher des bulles de notification dans la barre des tâches en C#

icon Tags de l'article : , ,

Avril 16, 2015
Hello,

Un besoin qui revient souvent en C#, pour des appli Winforms simples : pouvoir afficher des notifications dans la barre des tâches en C#.

Pour cela, j'utilise toujours la même méthode : un notifyIcon et l'appel à la méthode ShowBalloonTip :

this.notifyIconFormMain.Visible = true;
this.notifyIconFormMain.BalloonTipIcon = ToolTipIcon.Info;
this.notifyIconFormMain.BalloonTipTitle = "Relax your eyes";
this.notifyIconFormMain.BalloonTipText = string.Format("You will have to relax your eyes in {0} minutes.", minutes);
this.notifyIconFormMain.ShowBalloonTip(4); // 4 = le nombre de secondes d'affichage du message

Et voilà, une bulle apparaitra dans le coin de votre écran pour afficher votre message pendant 4 secondes !



Bon dev à tous !

Verrouiller une session en C#

icon Tags de l'article : , , ,

Avril 15, 2015
Hello,

Juste un mini article : comment verrouiller une session en C#.

La réponse est simple, à l'aide de ce petit morceau de code qui utilise user32.dll :

private const int WmSyscommand = 0x0112;
private const int ScMonitorpower = 0xF170;
private const int HwndBroadcast = 0xFFFF;
private const int ShutOffDisplay = 2;
[DllImport("user32.dll")]
private static extern void LockWorkStation();
[DllImport("user32.dll", SetLastError = true)]
private static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

Voilà, vous n'avez plus qu'à appeler la jolie méthode LockWorkStation qui s'occupera de verrouiller la session utilisateur ! Pensez juste à faire attention quand vous testez, car si vous mettez ça dans une boucle vous risquez d'être bloqué... [oui, ça sent le vécu]

Bon dev!

source

Une classe de base pour manipuler SQLite facilement en C#

icon Tags de l'article : ,

Avril 03, 2015
Hello à tous,

Aujourd'hui je vais vous parler de SQLite. Lors d'un projet récent, j'ai eu à manipuler une BDD SQLite en C#. Pour cela j'ai créé une classe qui peut vous intéresser.

La première étape, pour manipuler du SQLite, est d'installer le package Nuget SQLite (et ses prérequis).

Ensuite, j'ai créé cette classe abstraite :

using System;
using System.Collections.Generic;
using System.Data.SQLite;

public abstract class BaseDA<T>
{
	public string ConnectionString { get; set; }

	public BaseDA(string connectionString)
	{
		this.ConnectionString = connectionString;
	}

	protected T GetUniqueItem(string sql, Func<SQLiteDataReader, T> mappingMethod)
	{
		var connection = new SQLiteConnection(this.ConnectionString);

		try
		{
			var command = new SQLiteCommand(sql, connection);

			var reader = command.ExecuteReader();

			if (reader.Read())
			{
				return mappingMethod(reader);
			}
		}
		finally
		{
			connection.Close();
		}

		return default(T);
	}

	protected IEnumerable<T> GetItems(string sql, Func<SQLiteDataReader, T> mappingMethod)
	{
		var connection = new SQLiteConnection(this.ConnectionString);

		try
		{
			var command = new SQLiteCommand(sql, connection);

			var reader = command.ExecuteReader();

			var result = new List<T>();

			while (reader.Read())
			{
				result.Add(mappingMethod(reader));
			}

			return result;
		}
		finally
		{
			connection.Close();
		}
	}

	protected int ExecuteNonQuery(string sql)
	{
		var connection = new SQLiteConnection(this.ConnectionString);

		try
		{
			var command = new SQLiteCommand(sql, connection);

			return command.ExecuteNonQuery();
		}
		finally
		{
			connection.Close();
		}
	}
}

Comme vous le voyez, cette classe contient 3 méthodes basiques me permettant de requêter facilement ma BDD SQLite.

Je n'ai plus qu'à créer une classe qui hérite de cette classe abstraite, pour, par exemple, gérer mes utilisateurs :

using ApiManager.BusinessEntities;
using System.Collections.Generic;
using System.Data.SQLite;

public class UserDA : BaseDA<UserBE>
{
	public UserDA(string connectionString) : base(connectionString)
	{
	}

	public UserBE GetUserByLogin(string login)
	{
		var sql = string.Format("SELECT * FROM User WHERE Login='{0}'", login);

		return GetUniqueItem(sql, this.MapUser);
	}

	public IEnumerable<UserBE> GetUsers()
	{
		var sql = "SELECT * FROM User";

		return (IEnumerable<UserBE>)GetItems(sql, this.MapUser);
	}

	public bool AddUser(UserBE user)
	{
		var sql = string.Format("INSERT INTO User VALUES ('{0}', '{1}', {2})", user.Login, user.Password, user.IsAdmin ? "1" : "0");

		return ExecuteNonQuery(sql) == 1;
	}

	public bool DeleteUser(int idUser)
	{
		var sql = string.Format("DELETE FROM User WHERE Id = {0}", idUser);

		return ExecuteNonQuery(sql) == 1;
	}

	private UserBE MapUser(SQLiteDataReader reader)
	{
		return new UserBE()
		{
			Id = (int)reader["Id"],
			Login = reader["Login"].ToString(),
			IsAdmin = (bool)reader["IsAdmin"],
			Password = reader["Password"].ToString()
		};
	}
}

Voilà, en résumé :
  • Ma classe mère, BaseDA, contient 3 méthodes pour requêter la BDD à partir de la connection string passée dans le constructeur.
  • Ensuite on crée une classe qui hérite de BaseDA et qui appelera le constructeur de cette dernière.
  • Enfin, on n'a plus qu'à appeler les méthodes de la classe mère avec le SQL désiré (et la méthode de mapping reader => objet dans le cas des méthodes de Get)

Voilà, on ne sait jamais, ça vous servira peut-être un jour !

Bonne journée à tous... Et bon weekend !

Comment stocker ses mots de passe en .Net

icon Tags de l'article : , ,

Novembre 24, 2014
Il existe de nombreuses façons de stocker les mots de passe pour une application ou un site web. La triste nouvelle, c'est que la majorité des sites et des applications n'utilisent pas les bonnes.

Aujourd'hui nous allons voir comment bien faire les choses.

Déjà, voici les différentes façons de faire, de la plus ridicule à la plus paranoïaque :

  • Niveau 0 : tout en clair. Rien de bien compliqué, aucune sécurité, la moindre fuite de données et on doit demander à nos utilisateurs de changer de mots de passe... Vraiment pas top pour l'image. Sécurité : 0%

  • Niveau 1 : mots de passe hashés avec une clef en dur. Pourquoi pas, sauf que... ça ne sert à rien. Le hacker n'aura qu'à générer des rainbow tables à partir de votre clef, et il aura les correspondances en clair pour tous les mots de passe hashés en base. Sécurité : 1%

  • Niveau 2 : on hashe les mots de passe avec un sel, généré aléatoirement pour chaque utilisateur. Un petit peu mieux. Seul bémol : il suffit de régénérer des Rainbow Tables, une par utilisateur, et ... on a tous les mots de passe. Sécurité : 5%

  • Niveau 3 : on hashe les mots de passe avec un sel, généré aléatoirement pour chaque utilisateur, à l'aide d'un algorithme lent : BlowFish. Ici on corrige le principal problème du niveau 2 : générer des Rainbow Tables pour chaque utilisateur peut prendre des jours, voire des mois... Sécurité : 80%

  • Niveau 4 : on utilise un module physique pour hasher les mots de passe. Si quelqu'un essaye de le déplacer ou d'y accéder, il effacera automatiquement toutes les données. Vous l'avez compris, il s'agit du mode paranoïaque ! Sécurité : 99%

Vous l'aurez compris, on va surtout s'intéresser au niveau 3, facilement réalisable et ne demandant pas, lui, d'investissements financiers. La clef repose sur le fait d'avoir un sel généré unique par utilisateur, et d'utiliser l'algorithme lent BlowFish. A l'échelle d'un site web, le temps de hash de l'algorithme est court. Mais lorsqu'on fait du bruteforce, le temps pour générer un dictionnaire entier de mots de passe est gigantesque !

La mise en place est plutôt simple :

Il faut d'abord créer deux entrées dans notre base, une pour le mot de passe hashé, et une pour le sel. Il ne faut jamais stocker ni déplacer le mot de passe non hashé. Si vous voulez bien faire les choses, utilisez HTTPS et stockez le sel ailleurs.



Ensuite, il faut ajouter BCrypt.Net à notre projet (via NuGet) :



Cette implémentation de l'algorithme BlowFish offre 2 méthodes : GenerateSalt et HashPassword, à utiliser comme suit :



Maintenant vous n'avez plus qu'à implémenter la bonne logique dans votre code :
  • Lorsque l'utilisateur s'inscrit, on génère et stocke un salt aléatoire pour lui, puis on se sert de ce salt pour hasher son mot de passe.
  • Lorsqu'il se connecte, on récupère le salt, et on hashe le mot de passe saisi à l'aide du salt pour ensuite comparer les deux hashs générés.
  • Lorsqu'il a perdu son mot de passe, on génère un mot de passe et un salt aléatoires, pour ensuite lui envoyer un mail avec son nouveau mot de passe.

Voilà, j'espère que ce petit article vous a plu,

Bonne soirée à tous !

Un petit outil pour gérer ses fichiers de traduction en PHP

icon Tags de l'article : , ,

Septembre 17, 2014
Hello,

Juste pour ceux que ça intéresse, voici un petit outil très simple que j'ai développé pour moi afin de gérer les traductions dans mes applications en PHP.

Resmanager (sur Github)

Le fonctionnement est très simple :
  • on remplit le fichier resources.lng avec nos traductions
  • on lance le petit exécutable ResourcesSplitter.exe
  • ce dernier va générer automatiquement des fichiers PHP avec nos traductions, un fichier par langue
  • on n'a plus qu'à inclure/utiliser ces fichiers dans nos applications

Le petit exe est fait en .Net, il est très simple et son code source est également présent sur le repository (fichier ResourcesSplitter.cs).

Voilà, on ne sait jamais, ça vous servira peut-être ! Si vous avez des questions n'hésitez pas !

Bon développement à tous !

(Et oui, pour ceux qui se demandent, je m'en sert pour la nouvelle version à venir de MyCryptoChat :)

Tests unitaires, présentation

icon Tags de l'article : , ,

Mars 25, 2014
Aujourd'hui, je vais vous parler de tests unitaires.

On teste tous nos développements. Que ce soit en compilant et regardant rapidement si ça marche, en déroulant un cahier de tests, en faisant n'importe quoi pour voir si on arrive à planter l'application, etc.

Sauf qu'assez peu de gens font des tests unitaires.

C'est triste, car il s'agit du meilleur moyen d'améliorer considérablement la qualité de vos développements, mais aussi d'anticiper sur les différents bugs à venir.

En effet, beaucoup de développeurs auront tendance à considérer les tests unitaires comme une perte de temps, voire un truc plutôt gadget qui coute toujours plus que ce qu'il apporte.

Ce n'est pas vrai.

De vrais bons tests unitaires auront effectivement un cout assez lourd au départ, mais ce cout sera vite amorti si vous passez du temps sur votre application.

Ca peut sembler idiot, mais c'est vrai.

A chaque développement, il y a un risque de coder un ou plusieurs bug. Voire même de faire réapparaître un ancien bug. Les tests unitaires permettent d'éliminer 90% des bugs.

Le vrai problème qui se pose est donc : comment bien faire mes tests unitaires ?

Nous verrons cela très bientôt, dans de futurs articles :
  • Quand faire des tests unitaires ?
  • Les tests de connectivité
  • Présentation des tests unitaires pour la couche d'accès aux données
  • Présentation des tests unitaires pour la couche métier

Bonne soirée !