31 octobre 2017

Les tests en C#

Après quelques mise en place de tests unitaires sur des solutions, voici un compte rendu de mes points de réflexions sur la mise en place de les tests unitaire en c#


J'ai utilise les outils de base de visual studio


1) Une classe de test par classe testée : le nom de la classe de tests doit être d'une forme dérivée de la classe testée. Par exemple :  Test[Nom de la classe testée]

Cela permet de s'y retrouver.

2) Une méthode de test (au moins) par méthode testée. Le nom de la méthode doit être d'une forme dérivée de la méthode testée. Par exemple : Test[Nom de la méthode testée]

Cela permet de s'y retrouver.

3) Chaque appel à Assert.xxx doit renvoyer un message personnalisé.
Le message doit être clair sur : la classe testée, la méthode testé,  le contexte du test et ce qui n'a pas marché.


   


27 juillet 2017

Les Cursors SQL

Cela sert à parcourir de manière itérative des données.
Voici la séquence de bouts de code à utiliser :

Etape 1) Les variables des données à manipuler (ici un int et un Varchar(50)
DECLARE @a INT, @b VARCHAR(50);

Etape 2) déclaration du curseur
DECLARE variable_cursor CURSOR FOR 
SELECT  x, y FROM ...
;

  • Adapter le SELECT en fonction des besoins, les colonnes remontées correspondent aux variables de l'étape 1)
  • Le nom de la variable du curseur ne comporte pas de @ !


Etape 3) ouverture du curseur et remplissage des variables
OPEN variable_cursor;
FETCH NEXT FROM variable_cursor INTO @a, @b;

On voit bien ici qu'il faut une adéquation des variables aux colonnes du SELECT !

Etape 4) Boucle tant que c'est pas fini
WHILE (@@FETCH_STATUS <> -1)
BEGIN
  --- Faire ici le traitement utilisant nos variables remplies @a et @b

Etape 5) Fin de boucle
  FETCH NEXT FROM variable_cursor INTO @a, @b;
END

Etape 6) Nettoyage : Très très important : ne pas oublier

CLOSE variable_cursor;
DEALLOCATE variable_cursor;


Enjoy

13 juillet 2017

Shrink des logs d'un BDD SQL Server

Voici un script pour réduite la taille du journal des transactions

DECLARE @size INT;
SET @size = 10;   --- Taille du log à la fin en MegaBytes

DECLARE @database VARCHAR(200);
SET @database = DB_NAME();  --- Obtient le nom de la base en cours

--- le shrink des logs
DECLARE @sqlShrink VARCHAR(MAX);
SET @sqlShrink = '
DECLARE @logfilename NVARCHAR(200);

USE [' + @database + '];
ALTER DATABASE ['+ @database +'] SET RECOVERY SIMPLE;

DECLARE crsor CURSOR FOR
SELECT [name] FROM [sys].[database_files] 
WHERE [type] = 1;
OPEN crsor 
  FETCH crsor  INTO @logfilename
  WHILE @@FETCH_STATUS = 0
  BEGIN
    DBCC SHRINKFILE (@logfilename, '+CONVERT(VARCHAR(20), @size)+');
    FETCH crsor INTO @logfilename
  END
CLOSE crsor
DEALLOCATE crsor

ALTER DATABASE [' + @database + '] SET RECOVERY FULL;


USE master;
';
EXEC (@sqlShrink);


Dans le principe :
1) On passe la base en cours dans le mode Recovery Simple
2) Pour chaque fichier de log (LDF) on fait un DBCC SHRINKFILE
3) On remet la base dans le mode Recovery Full

Il doit surement pouvoir être amélioré mais bon ça fait le job !

Merci aux auteurs initaux du script ;-)

12 février 2017

Web services avec ServiceStack

Ci dessous la procédure de mise en oeuvre (minimale) de web services avec la librairie ServiceStack.

1) Télécharger les librairies qui vont bien : un NuGet en cherchant : "ServiceStack.ServiceInterface".

2) Dans un namespace de votre lib ou du site Web : Fichier AppHost.cs
  Classe qui dérive de AppHostBase et qui permet l'initialisation des web Services
  Le constructeur à surcharger fait tout le boulot en une ligne !
      public AppHost()
      : base("Ma librairie HttpListener", typeof(AppHost).Assembly)
    {
    }

3) Dans AppHost Toujours : override de la méthode Configure pour définir le comportement des Web services : Ajout de chaînes de connexions aux bases, entête http, compression, ...

4) Les web services : Je fais toujours un dossier par Web Service avec 3 classes : La classe Request, la classe Response, la classe web service

 5) La request : Classe qui gère les paramètres d'appel à un ou plusieurs Web services
  doit contenir les attributs suivants :

  •    [Api("Nom de l'api")]  pour indiquer dans quel groupe d'api se trouve le web service
  •    [Route("Url du Web service avec paramètres obligatoires", vers = "GET, POST, PUT, ...")] pour indiquer l'url du web service et les verbes auquel il doivent répondre :
Les 2 attributs sont dans le name space : ServiceStack.ServiceHost
L'attribut Route peut être mis autant de fois que nécessaire (Permet d'avoir différentes URL en fonction des besoins, ou rendre des paramètres obligatoires en fonction du verbe utilisé)
Les paramètres obligatoires de l'URL doivent être entre accolades exemple :
[Route("/commandeGet/{ApiKey}/", Verbs = "GET")] ici ApiKey doit correspondre à une propriété de la classe request.
Il faudra programmer une méthode pour chaque verbe Http déclaré ici dans la classe service.

De plus il est pas mal (mais optionnel) d'indiquer ce que retourne le Web Service en ajoutant l'interface IReturn<>
  public class MaClasseRequest : IReturn<MaClasseResponse>
 
6) La response : Classe qui contient les données de la réponse. Rien à signaler de plus sur cette classe !

7) Le service : Classe qui contient les méthodes de traitement des Web Services :
Exemple : public object Get(MaClasseRequest request)
Le nom de la méthode est le nom du verbe HTTP utilisé (Attention à la casse : dans le Request c'est en majuscule, ici c'est en Camel Upper Name)
Le paramètre de la méthode est le nom de la classe Request définie
Le type de retour est object car on retourne soit une Response soit une HttpErrror !

La classe service doit dériver de la classe Service  de ServiceStack.ServiceInterface

24 janvier 2017

c# Service Stack et transactions

Je me suis fait avoir récemment donc pour ne pas oublier : Voici comment utiliser les transactions avec la librairie ServiceStack.


Une classe Tache à une méthode InsertToDb qui à pour but d’insérer l'objet et ses fils des Actions dans une base de données.

  private void InsertToDb(IDbConnection cnx)
    {
      this.Id = Convert.ToInt32(cnx.Insert<Tache>(this, selectIdentity: true));

      // insertion des actions
      foreach (Action act in this.Actions)
      {
        act.TacheId = this.Id;
        act.ToDB(cnx);
      }
    }

Pour rendre le code transactionnel il faut lancer une transaction : le réflexe est la méthode BeginTransaction() de la classe IDbConnection.
Et bien avec ServiceStack ça marche pas avec le  select identity, il semble que la transaction soit mal initialisée. Pour y arriver facilement il faut utiliser la méthodes d'extension : OpenTransaction() Qui fait la même chose sans générer d'erreur !

     using (FConnexion cnn = new FConnexion())
      {
        var tran = cnn.Db.OpenTransaction();
        try
        {
          // mettre en base la tâche
          t.ToDB(cnn.Db);
          tran.Commit();
        }
        catch (Exception ex)
        {
          tran.Rollback();
          throw ex;
        }
      }

Ne pas oublier le using qui va bien :
using ServiceStack.OrmLite;

La classe FConnection gère une propriété IDbConnection Db et se charge d'ouvrir la connexion à la base.
using System;
using System.Data;
using ServiceStack.OrmLite;
using ServiceStack.OrmLite.SqlServer;

  /// <summary>
  /// Class base pour gestion connexion.
  /// </summary>
  public class FConnexion : IDisposable
  {
    /// <summary>
    /// Initialise une nouvelle instance de la classe <see cref="FConnexion" />.
    /// </summary>
    public FConnexion()
    {
      var dbfactory = new OrmLiteConnectionFactory(System.Configuration.ConfigurationManager.ConnectionStrings["MaBase"].ToString(), SqlServerOrmLiteDialectProvider.Instance);
      this.Db = dbfactory.Open();
      this.Db.Open();
    }

    /// <summary>
    /// Obtient ou définit La connexion
    /// </summary>
    public IDbConnection Db { get; private set; }

    /// <summary>
    /// Libère les ressources de l'objet de connexion.
    /// </summary>
    public void Dispose()
    {
      this.Db.Dispose();
    }
  }


Enjoy !

23 janvier 2017

SQL : Premier jour du mois et dernier jour du mois

Voici ce que j'utilise pour trouver le premier jour du mois d'une date donnée :

DECLARE @dt DATE = '2017-02-17'

SELECT  @dt, DATEADD(DAY, 1 - DATEPART(DAY, @dt), @dt)

Ou
SELECT  @dt, DATEADD(MONTH, DATEDIFF(MONTH, 0, @dt), 0)


Ce qui donne dans les deux cas :
17/02/2017     01/02/2017

Dans le premier exemple : on retire le nombre de jour moins 1 à la date en cours.
Dans le second : on ajoute à la date "0" la différence de mois entre "0" et la date fournie



Voici ce que j'utilise pour trouver le dernier jour du mois d'une date donnée :

DECLARE @dt DATE = '2017-02-17'
SELECT  @dt, DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, @dt) + 1, 0))


Ce qui donne  :
17/02/2017     28/02/2017

Explication : on ajoute un mois au premier jour du mois et on retire un jour.


MAJ 05/2021 : Sinon pour de le dernier jour du mois, il existe a maintenant (depuis SQL Server 2014!) la fonction EOMONTH().
On lui donne un jour dans le mois, elle renvoie le dernier jour du mois, simple, Merci SQL Server ! 

Enjoy !