Affichage des articles dont le libellé est C#. Afficher tous les articles
Affichage des articles dont le libellé est C#. Afficher tous les articles

17 décembre 2018

C# - Avoir un fichier de app.config différent entre release et debug

C'est natif dans les projets Web mais dans les autres types de projets c'est pas si évident !

J'ai trouvé ce tuto : https://www.linkedin.com/pulse/multi-appconfig-visual-studio-2017-benjamin-davis/
Voici la traduction rapide avec mes notes.

Attention : C'est un peu long, mais ça marche tellement bien que cela vaut le coup. En plus on ne le fait qu'une seule fois par projet.

Prérequis : .NET4.5 (ou plus) et Visual studio 17

1) Charger le projet et ajouter 2 fichiers : App.Debug.config et App.Release.config sans pour l'instant les modifier.

2) Enregistrer et Déchargez le projet

3) Avec un éditeur de texte quelconque éditer le fichier projet (.csproj)

4) Après le dernier bloc XML PropertyGroup Ajouter
<PropertyGroup> <ProjectConfigFileName>App.config</ProjectConfigFileName>
</PropertyGroup>

Sans ce bloc la librairie qui fait la transformation du fichier cherche un fichier "web.config" ! (C'est normal c'est une librairie qui vient des projets Web)

5) Dans le bloc XML qui contient l'inclusion du fichier App.config, modifier comme suit (en orange) afin de lier les fichiers Debug et Release avec le fichier App.config.
<ItemGroup> <None Include="App.config" />
  <!-- Ne pas toucher ce qu'il y a avant --> 
  <None Include="App.Debug.config">     <DependentUpon>App.config</DependentUpon>   </None>   <None Include="App.Release.config">     <DependentUpon>App.config</DependentUpon>   </None>   <!-- Ne pas toucher ce qu'il y a après -->  </ItemGroup>
A noter le fichier App.config a peut être d'autres configurations en fonction du projet : par exemple dans mon projet j'ai :  
<None Include="App.config">
   <SubType>Designer</SubType>
</None>
Ne pas toucher : non plus !

6) Chercher si un nœud XML PropertyGroup existe et contient un nœud VisualStudioVersion si ce n'est pas le cas, il faut le créer sinon il faut y ajouter le noeud VSToolsPath. Ce nœud permet au processus de Build de connaitre le chemin d'accès de la librairie de transformation.
Donc à la fin vous devez avoir :
<PropertyGroup>   <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>   <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
Ne mettez pas d'espace dans de texte du noeud VSToolsPath (pas d'espace avant le $(MSBuild. et après le ...VisualstudioVersion)</VSToolsPath.
Bien sûr il faudra surement ajuster le numéro de version de Visual Studio en fonction de votre version (Je n'ai testé qu'avec un Visual Studio 2017)

7) En fin de fichier après le dernier Import ajouter l'import de la librairie à utiliser
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" 
Condition="'$(VSToolsPath)' != ''" />

8) Ajouter le lancement de la transformation en toute fin de fichier à la racine
<!-- Tout le fichier avant --> 
<Target Name="AfterBuild">    <TransformXml Source="@(AppConfigWithTargetPath)" Transform="$(ProjectConfigTransformFileName)" 
Destination="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')" /> </Target> </Project>

Le Tutorial s'arrête la !
Moi J'ajouterais :

9) Recharger le projet dans Visual Studio. Constater que le fichier App.config peut se déplier et qu'il y a les fichiers App.Debug.config et App.Release.config en dessous.

10) Modifier les fichier Debug et Release en fonction de vos besoins.
Pour ce faire : un peu de lecture de la doc Microsoft et roule ma poule !
https://docs.microsoft.com/fr-fr/previous-versions/dd465326(v=vs.100)

11) Cas d'exemple : Changer la chaîne de connexion en fonction de DEBUG ou RELEASE
Un des choix possible est :
11.a) Dans le App.config
<?xml version="1.0"?>
<configuration>
  <connectionStrings>
     <add name="MonAppli" connectionString="Sera remplace dans le App.Debug.config ou le App.Release.config"/>
  </connectionStrings>
  <appSettings>
    <!--- Suite du fichier --->
  </appSettings>
</configuration>

A noter ici :

  • Le nom de la chaîne de connexion peut changer en fonction de vos besoins
  • Le texte de la chaîne de connexion est non valide : Cela permet de valider que cela fonctionne bien dans les 2 configuration.


11.b) Dans le App.Debug.config ou App.Release.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration  xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <connectionStrings>
    <add name="MonAppli" connectionString="Data Source=ServerBDD;Initial Catalog=MaBase_test;integrated security=SSPI" xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
  </connectionStrings>
</configuration>

A noter ici :

  • Le NameSpace ajouté au nœud configuration est obligatoire
  • Le nom de la chaîne de connexion est le même que dans le fichier App.config (c'est important voir ci-dessous)
  • La chaîne dans l'attribut ConnectionString (en rose) est a adapter en fonction du fichier et de la base à laquelle se connecter quand on est en Debug ou en Release.
  • L'attribut xdt:Locator permet d'indiquer, à l'aide d'une requête XPath, dans le fichier App.config, sur quel ou quels nœuds XML la transformation va s'appliquer. Ici on Matche sur l'attribut name c'est à dire tous les nœuds du fichier App.config qui ont le chemin XML suivant : configuration/ConnectionStrings/add[name="MonAppli"]
  • L'attribut xdt:Transform permet d'expliquer quelle transformation appliquer (Ici remplacement de tous les attributs du ou des nœuds trouvés.

12) Compilez et Enjoy !






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é.


   


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 !

31 octobre 2016

ServiceStack DataAnotation

ServiceStack est une librairie fort utile que je ne presente pas ici...
Petit mémo de la partie DataAnotation qui permet de faire un mapping Relationnel / Objet très simplement.


L'attribut :  [Alias("")] : Permet de mapper une table (s'il est mis sur une classe) ou une colonne s'il est mis sur une propriété.
La propriété doit toujours être de la forme : public [type] [propriété] { get; set;}
Attention aux types mappés : n'utiliser que les types valeur de base (int, double, decimal (pour les money  Sql Server), string, bool).
Vous pouvez utilisez les types nullables (int?, double?, decimal?, string, bool?)


L'attribut : [Ignore] : Permet d'ajouter des propriétés à l'objet sans les mapper à une colonne.
Exemple pour les enum je câble souvent une propriété :

public enum ValeursPossible
{
   val1 = 1,
   val2 = 2,
  ....
}

[Alias("maColonne")]
public int MonEnumInt {get; set;}

[Ignore]
public ValeursPossible MonEnum
{
   get
   {
      return (ValeurPossible)this.MonEnumInt;
   }
   set
  {
     this.MonEnumInt = (int)value;
  }
}

L'attribut : [Autoincr] est très important pour la propriété qui mappe une colonne auto-incrémentée de Sql Server : A ne pas oublier !


Enfin : Très utile !!
L'attribut : [Schema("xxx")] permet de mapper des tables qui ne sont pas dans le schéma par défaut (DBO pour Sql Server).



06 décembre 2015

Expressions régulières pour parser du XLM

J'ai voulu de manière simple mettre en surbrillance une string XML pour un rendu dans une page HTML !


Bon même y a pleins de plug-in c# ou JS, voir des supers convertisseurs en ligne... je préfère me braquer cela à la main : voici ma proposition...

Il y a plusieurs types de "balises" à détecter, entourer dans le texte d'origine ces balises de <span class="Type Balise">xx</span> pour gérer cela avec du CSS.

Voici les expressions régulières associées aux types de balises :

Les commentaires : (?<comment><!--(\w|\W)*?-->)
Les tags : (<|</)(?<tag>\w*?)([>\s])
Les attributs : ((<\w*?\s*?)|(("|')\s*?))(?<attr>\w*)=("|')
Les valeurs des attributs : (=(?<quote>"|'))(?<attvalue>(\w|\W)*?)?(\k<quote>) 
Les valeurs des tags : (?<value>(\w|\W)*?)<   [Penser à éliminer les valeurs vide ici]
Les séparateurs : (?<sep><|>|=|"|')


Détecter les infos dans l'ordre et éliminer des résultats les infos dont le texte est déjà dans un groupe précédent (Par exemple pour éviter de mettre en surbrillance un tag dans un commentaire).


La suite quand j'ai le c# qui marche !!

10 mars 2015

SQL et c# Jour de la semaine

Pour avoir le jour de la semaine avec SQL Server il faut utiliser la fonction DATEPART avec le paramètre WEEKDAY :  SELECT DATEPART(WEEKDAY, GETDATE()) pour avoir le numéro du jour d'aujourd'hui. Le résultat est un nombre entre 1 et 7. Soit :

  • 1 = Lundi
  • 2 = Mardi
  • 3 = Mercredi
  • 4 = Jeudi
  • 5 = Vendredi
  • 6 = Samedi
  • 7 = Dimanche

Attention le résultat est fonction de la variable @@DATEFIRST qui permet d'ajuster le nombre voulu pour le résultat.

Voir la doc SQL Server pour plus de détail ; ici

En C# la propriété DayOfWeek d'un type DATETIME renvoie une énumération qui une fois casté en int renvoie des valeurs entre 0 et 6 !!
Evidement c'est pas les mêmes que SQL Server, mais pas trop loin
  • 1 = Lundi
  • 2 = Mardi
  • 3 = Mercredi
  • 4 = Jeudi
  • 5 = Vendredi
  • 6 = Samedi
  • 0 = Dimanche
Bon pour uniformiser tout cela est simplifier l'utilisation et le transfert des infos entre les deux technos je propose la formule ci dessous qui renvoie toujours les données au format c# quelque soit la configuration SQL Server.

SELECT (DATEPART(WEEKDAY, ma_date) +  @@DATEFIRST - 1) % 7 AS jour_semaine
FROM ...

Explications : Le DATEPART renvoie le jour de la semaine pour SQL Server, L'ajout du @@DateFirst -1 permet de retomber sur un nombre qui avec le Modulo (%) 7 sera toujours identique quelque soit la valeur du @@DATEFIRST et toujours compris entre 0 et 6 c'est ce qu'il faut pour c#

Enjoy !


17 avril 2014

C# : Requête SQL qui remonte du XML

Si vous voulez pouvoir utiliser le générateur de XML de SQL Server directement en C#, je vous propose cette petite procédure qui permet exécuter le SQL et de retourner directement un XElement.

    public XElement ExecuteRequeteGetXml(string sql, params SqlParameter[] commandParameters)
    {
      StringBuilder res = new StringBuilder();
      SqlCommand cmd = this.GetSqlCommand(CommandType.Text, sql, commandParameters);
      using (XmlReader xmlr  = cmd.ExecuteXmlReader())
      {
        xmlr.Read();
        while (xmlr.ReadState != System.Xml.ReadState.EndOfFile)
        {
          res.Append(xmlr.ReadOuterXml());
        }
      }

      if (res.Length > 0)
      {
        return XElement.Parse(res.ToString());
      }
      else
      {
        return null;
      }
    }

On récupère le reader, puis on lit jusqu’à la fin du flux XML et on recopie l'info dans un StringBuilder qui est parsé en XElement à la fin.
Utile aussi la procédure GetSqlCommand : Qui suppose que la chaîne de connexion est dans le fichier de configuration avec la clé "Base".

    private SqlCommand GetSqlCommand(CommandType typeCommande, string requeteSql, params SqlParameter[] commandParameters)
    {
      SqlCommand command = new SqlCommand();
      string connexionString = ConfigurationManager.ConnectionStrings["Base"].ConnectionString;
      SqlConnection connexion = new SqlConnection(connexionString);
      connexion.Open();
      command.Connection = connexion;
      command.CommandText = requeteSql;
      command.CommandType = typeCommande;

      if (commandParameters != null)
      { // les paramètres de la commande
        foreach (SqlParameter p in commandParameters)
        {
          if (p != null)
          { // Check for derived output value with no value assigned
            if ((p.Direction == ParameterDirection.InputOutput || p.Direction == ParameterDirection.Input) && p.Value == null)
            {
              p.Value = DBNull.Value;
            }

            command.Parameters.Add(p);
          }
        }
      }

      return command;
    }


31 janvier 2014

c# Améliorer la visualisation d'une classe dans le debugger

Afin d'améliorer la vision d'un objet dans le débogueur VISUAL STUDIO, il existe un attribut qui peut s'avérer bien pratique : DebuggerDisplay qui prend en paramètre une chaîne de formatage des propriétés de l'objet à afficher.

Exemple :
  [DebuggerDisplay("Rubrique ={Code} = {Valeur}")]
  public class FicheSimple
  {
    /// <summary>
    /// Initialise une nouvelle instance de la classe <see cref="FicheSimple"/>
    /// </summary>
    /// <param name="rub">Le code de la rubrique</param>
    public FicheSimple(string rub)
    {
      this.Code = rub.ToLower();
      this.Valeur = "";
    }

    #region Properties
    /// <summary>
    /// Le code de la rubrique (forcé en minuscule)
    /// </summary>
    public string Code { get; private set; }

    /// <summary>
    /// La valeur mémorisée
    /// </summary>
    public string Valeur { get; set; }
    #endregion
  }

La chaîne de format, prend entre accolades les propriétés à afficher.
Cela peut être pratique pour certain débogage un peu longs.

Ah : Penser à ajouter le bon using : using System.Diagnostics;


Voir la doc pour plus de détails ;-)

Enjoy