Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Avec Workflow Foundation, le changement de nom d'un fichier XAML ou XAMLX n'entraine pas le renommage de l'activité ou du service.

Pour changer le nom, il suffit de :

  1. Ouvrir le Workflow à modifier.
  2. Clicker dans le designer de Workflow sans sélectionner une activité.
  3. Changer le nom dans la fenêtre propriété.

 

Pour une activité, on ne peut changer que le nom de l'activité.

 

Pour un service, on peut aussi changer la configuration WCF utilisée.

Sans contrat établi, un service de Workflow utilise un namespace par défaut « http://tempuri.org/ » et un nom de contrat « IService ».

Quand on utilise l'outil de test WCF, les messages on dont l'aspect suivant :

 

Pour fixer ces éléments, nous avons deux solutions :

  1. Changer la propriété ServiceContractName de chaque activité Receive

 

  1. Ouvrir le Workflow et utiliser la touche de raccourci F7 pour afficher le code XAML. Ensuite on peut remplacer les chaines indésirables via « rechercher /replacer ».

Petit désagrément qui vous a certainement touché si vous avez utilisé le SDK Open XML pour créer des documents Excel :

Le résultat des cellules calculées ne sont pas mis à jour automatiquement.

Ceci vient du fait que le format de fichier ne sert qu’à « porter » la donnée et le format. C’est Excel qui se charge de faire les calculs. Heureusement, le format *.xlsx dispose d’une propriété « ForceFullCalculation »  qui permet de forcer les calculs à l’ouverture d’un classeur.

Exemple d’utilisation :

// Ouverture d'un document
using (SpreadsheetDocument document = SpreadsheetDocument.Open(stream, true))
{
   // Forcer les calculs à l'ouverture
   document.WorkbookPart.Workbook.CalculationProperties.ForceFullCalculation = true;

   // Faire des modification sur le fichier

   // enregistrer le document
   document.WorkbookPart.Workbook.Save();
}

Avec un peu de retards, je souhaitais vous faire part de ma joie de recevoir un nouveau MVP Award. Merci à Microsoft pour cet honneur.

Un grand merci à tous les lecteurs de ce blog qui me sollicitent régulièrement par mail. Oui j'ai des articles en retard, et je vais remonter les manches pour les rédiger !

 

Aux MVP qui ont prévu d'aller au Summit : désolé de ne pas être parmi vous en novembre, ma compagne et moi-même attendons un heureux évènement qui doit se concrétiser à la même époque ;)

Comme disent les admins « Pour débloquer une configuration ratée, rien de mieux que PowerShell » (plus le temps passe, et plus je me fais à l'idée).

Encore faut-il que vous trouviez les commandes qui vont bien. Si comme moi vous n'êtes pas un pro du PowerShell, vous risquez de finir par abandonner au premier message vous disant que la commande n'est pas reconnue… Dommage?!

Il existe pourtant une solution simple : rechercher les modules installés sur votre serveur, et les importer.

 

Par exemple : dans le cadre d'un déploiement du cache partagé de l'AppFabric, je me suis retrouvé dans l'incapacité d'utiliser des commandes basiques telles que Remove-CacheHost ou Unregister-CacheHost. En fait, tout le module de configuration du cache était indisponible.

J'ai donc rendu une petite visite au répertoire Modules de PowerShell (ici en version 1.0 cela donne : %SystemRoot%\System32\WindowsPowerShell\v1.0\Modules\):

 

Ceci m'a permis d'en déduire qu'il me fallait utiliser la commande suivante pour charger le module manquant :

Import-module DistributedCacheConfiguration

Après import, il m'a donc est possible d'utiliser l'ensemble des commandes suivantes :

Le travail pouvait donc commencer ;)

Depuis quelques années, on parle de plus en plus de caches (AppFabric en tête). Malheureusement, une croyance urbaine veut qu'il soit impossible d'avoie le log, quand on active certain type de caches.

Par exemple :

Heureusement même dans ces deux cas, il est possible d'avoir des logs. Plusieurs options simples s'offrent à nous :

  • Coder un Behavior custom pour écrire ces propres logs.
  • Utiliser le MessageLogging.

Personnellement, je préfère le MessageLogging car il permet:

  • Une configuration souple et facilement adaptable.
  • Un branchement direct sur System.Diagnostics et donc un log identique à la Trace (encore faut-il l'utiliser)

Et vous, comment tracez-vous vos services ?

Encore une fois, j'exhume un petit peu de code pour répondre à un problème de POO qui semble simple, mais qui peut devenir cauchemardesque dès que l'on y associe WCF et les DataContract.

Le scénario est le suivant :

  • On a prévu d'utiliser une classe (Item) comme argument d'une méthode de service (Service1).
  • Côté client, l'objet réellement manipulé est une instance d'une classe qui hérite d'Item (ItemDerived).
  • Côté client, la classe de base n'est jamais manipulée directement.
  • Chaque classe ou interface est dans un namespace ou un assembly différent

Le diagramme de classe donne ceci

Pour appeler le service on utilise un code tel que celui-ci :

var result = proxy.Process(new ItemDerived());

 

Ou celui-là :

var result = proxy.Process((Item)new ItemDerived());

 

En l'état, les appels au service provoquent systématiquement une exception du style : le type utilisé lors de la sérialisation n'est pas du type attendu

Note : les messages d'exception semblent varier d'une version du Framework à l'autre.

 

Dans les faits, lors de la sérialisation, le DataContractSerializer est perdu :

  • Il attend une classe Item dans un namespace X avec un nom Y avec un DataContract (namespace X, name Y)
  • Il reçoit une classe ItemDerived dans un namespace U avec un nom V sans DataContract (on utilise juste l'héritage).

Il faut donc aider notre DataContractSerializer à s'en sortir. La solution est toute simple : partager une information claire et commune, le contrat.

La classe item est donc modifiée pour exposer deux constantes : le DataContractNamespace et le DataContractName.

Si on ne conserve que les déclarations de classes et des constantes, on obtient ceci :

    
      namespace Demos.Wcf.Base

    
  

    
      {

    
  

    
          // Use a data contract as illustrated in the sample below to add composite types to service operations.
						
    
  

    
          [DataContract(Name = DataContractName, Namespace = DataContractNamespace)]

    
  

    
          public class Item
										
    
  

    
          {

    
  

    
              protected const String DataContractName = "Item";

    
  

    
              protected const String DataContractNamespace = "Datas";

    
  

    
          }

    
  

    
      }

    
  

 

    
      namespace Demos.Wcf.Inherit

    
  

    
      {

    
  

    
          [DataContract(Name = DataContractName, Namespace = DataContractNamespace)]

    
  

    
          public class ItemDerived : Item
												
    
  

    
          {

    
  

    
          }

    
  

    
      }

    
  

 

Note : J'ai découvert par hasard que mes constantes protected pouvaient être utilisées via les attribues de la classe dérivée.

 

En partageant ces informations, on peut maintenant utiliser des classes dérivées avec notre proxy. Il n'y a plus d'exceptions.

Simple comme WCF ;)

 

   

 Heureux propriétaire d'une tablette sous Windows 8 (Asus Vivotab Smart), j'ai vu mes besoins en stockage augmenter (quelle idée folle m'est passée par la tête, quand j'ai installé Visual Studio….). J'ai donc ajouté une carte micro SD à ma tablette. Je dispose maintenant de deux espaces de stockage de 64Gb. Mon objectif étant d'utiliser ma carte SD pour stocker mes données, j'ai voulu déplacer le stockage de l'application SkyDrive (version bureau Windows).

   

 Et là, c'est le drame : Le bouton est grisé, car j'utilise mon compte Microsoft pour me m'identifier. Je ne peux donc pas supprimer le lien SkyDrive.

 

 

Pour pouvoir changer ce lien, et donc le dossier local, il faut désinstaller l'application. On doit donc ouvrir la liste de programmes et supprimer SkyDrive (vive le filtrage des listes via la recherche en haut à droite)

 

 

Vient alors, un nouveau problème : Skydrive n'accepte pour répertoire de stockage local, que des partitions NTFS sur un disque fixe.

Pas de soucis, on peut monter notre carte SD comme dossier NTFS. SkyDrive ne se rendra même pas compte qu'il s'agir d'une carte SD (bien entendu, il est conseillé de ne plus retirer la carte de la tablette).

Il faut donc lancer le gestionnaire de disque. Après récupération des éventuelles données déjà présentes sur la carte, on peut supprimer la ou les partitions déjà existantes. On peut alors créer une nouvelle partition :

 

L'assistant se lance alors.

 

Il faut ensuite choisir « Monter dans le dossier NTFS vide suivant » et cliquer sur « Parcourir »

 

Ceci permet d'ouvrir la fenêtre suivante. Dans mon cas, j'ai choisi de créer ce dossier à l'emplacement suivant « c:\CarteSD »

Après validation des deux boites de dialogue, arrive le choix du nom du volume. NTFS est grisé, ce qui est logique, car on utilise notre partition comme dossier NTFS.

Après formatage, on se retrouve alors avec un affichage des disques similaire à ceci

 

Ma carte est alors disponible via le dossier NTFS. Je peux donc y copier le contenu de mon ancien dossier SkyDrive (en pensant au passage à supprimer l'ancien dossier pour gagner de la place sur C:\)

 

À partir de cet instant, je peux procéder à l'installation de SkyDrive de manière classique, jusqu'au choix du dossier local.

 

Après validation du choix du dossier « c:\CarteSD », je dois confirmer l'utilisation de celui-ci, car il contient déjà mes anciennes données.

 

Une dernière petite vérification sur le chemin affiché par SkyDrive. Si c'est bon, on valide et le tour est joué.

 

Tada !!!

 

Note : Pour mon usage perso, j'ai aussi déplacé mes librairies et mon dossier TFS sur la carte…

 

Via ce billet, je me propose de partager avec vous mon ressenti sur le mode Core+Interface minimale de Windows 2012.

Note : ceci est un avis de Deve qui a besoin d'une infra de tests à la maison qui soit peu gourmande en temps de maintenance et dont le porte-monnaie n'est pas extensible. Ce n'est pas le retour d'un IT pro qui à sa salle blanche sur son lieu de travail.

Introduction

Depuis Windows 2008, Microsoft propose deux modes d'installation pour ses serveurs :

  • Un mode complet (interface windows classique)
  • Un mode core (interface réduite à la console, tout ou presque se fait en ligne de commande)

Les avantages du mode Core sont nombreux, mais n'étant pas IT, je ne vais pas m'appesantir sur la liste de ceux-ci. Je note principalement le fait qu'un serveur Core n'a besoin que de très peu de ressources pour fonctionner correctement (ex : mon contrôleur de domaine de test n'a que 512Mo de Ram).

Côté inconvénient,… dans mon cas, il n'y en a pas beaucoup. Ou plus exactement, avec 2012, il y en a beaucoup moins. Ils se situent principalement au niveau de la liste des produits supportés (ex : aujourd'hui le Framework .net n'est pas complet, les namespaces dédiés à l'interface Windows sont manquant, ce qui est normal). Il faut donc se renseigner avant de se lancer dans une installation.

Pour mon usage, le mode Core avait un gros point noir avant 2012 : sa console (merci de ne pas trop faire attention à mon humour à 2 centimes).

 

Windows 2012 en mode minimal interface

Avec Windows 2012, Microsoft offre une troisième possibilité :

  • Un mode interface minimale avec consoles.

Dans ce mode, on a la console type DOS et le minimum pour utiliser les MMC de Windows 2012. En plus, il est possible de passer d'un mode à l'autre sans réinstaller son serveur (un reboot est nécessaire après chaque changement de mode).

Voici une capture de ma console Server Manager : (comme on peut le voir, je n'ai activé que la feature Graphical management)

Pour revenir à un mode plus classique, il me suffit d'ajouter la feature Desktop Experience et de rebooter mon serveur.

 

Mon usage

Mon objectif étant de simuler un fonctionnement H24 d'une ferme SharePoint ou AppFabric, j'ai choisi de migrer mon serveur Hyper-V qui tournait sous 2008R2 (installation en mode complet). La migration a été faite à la sortie de Windows 20012 RTM avec une simple clé USB et en pilotant l'installation à partir d'un RDP (même pas peur). Après vérification que mon serveur fonctionnait bien sous 2012 (durant une petite semaine), j'ai retiré la feature Desktop Experience. Mon objectif étant d'utiliser le serveur à partir d'un bureau à distance, je n'ai effectué aucune customisation ni ouverture de droits pour utiliser les consoles.

Depuis bientôt un an, mon Hyper-V de test utilise donc un Windows 2012 en mode minimale interface. Pour ajouter/supprimer/configurer mes VM, j'utilise simplement le bureau à distance. Ce qui me permet d'utiliser mon serveur à partir de mon PC ou de ma tablette.

En pratique, mon bureau ressemble à ceci (par défaut, seule la console est ouverte):

 

Mon objectif étant de piloter mon Hyper-V, j'ai créé une MMC avec la Snap-In Hyper-V. Je dispose donc de tout ce qu'il faut pour travailler.

 

Les commandes à connaitre

Vu que l'on ne dispose pas de menu pour lancer ses applications, il faut connaitre quelques commandes :

sconfig (indispensable si on ne veut pas utiliser les mmc et rester en mode Core) :

 

servermanager pour avoir accès la console de gestion du serveur (uniquement possible en mode minimal interface)

 

mmc pour ouvrir une console vide. On peut y ajouter nos snap-in et enregistrer la mmc pour un usage ultérieur.

start cmd pour disposer d'un seconde console.

cd, mkdir.. etc… pour gérer les fichiers, naviguer sur vos volumes (penser à utiliser la touche Tab pour profiter de l'autocomplétion sur les noms de fichiers)

Le raccourci Ctrl+Alt+Fin pour faire un Ctrl+Alt+Supr via RDP (très pratique quand on ferme par erreur sa console, on peut alors ouvrir le gestionnaire de tâches pour lancer cmd).

taskmgr pour avoir accès au gestionnaire de tâches (on peut aussi lancer le moniteur de ressources complet à partir de l'onglet performances)

 

Alors heureux ?

Honnêtement, oui. Je suis très satisfait de mon installation. Je n'ai pas trouvé de réels inconvénients. Mon serveur fonctionne H24, mes VM sont opérationnelles et je peux observer leur fonctionnement en continu (j'ai même quelques VM en mode Core et minimal).

Je recommande fortement ce genre d'installation si vos moyens de virtualisation sont limités.

Pour les développeurs comme moi, j'ai trouvé une paire d'avantages non négligeables :

  • Les performances de mon serveur ne se sont pas dégradées alors que je ne fais rien pour la maintenance.
  • Les mises à jour sont réduites, donc on fait peu de maintenance et de reboots.

J’adore l’AppFabric, mais par moment, il faut savoir s’en passer. Dans ces cas là, il faut sortir des oubliettes de bons vieux codes qui ont fait leurs preuves.

Aujourd’hui je vous propose d’exhumer le System.Web.Caching.Cache. Trop souvent négligé (car rarement présenté en formation, c’est dommage), l’ami System.Web.Caching.Cache n’a pas les possibilités de cache partagées entre plusieurs serveurs de l’AppFabric, mais il peut vous permettre de garder dans un cache serveur des données récurées à un instant T. Son principe d’utilisation est similaire : on a une collection qui permet, d’obtenir, d’ajouter ou de supprimer des données.

Dans le petit exemple que je propose ici, j’ai codé rapidement un Handler qui permet de retourner des images provenant d’une base de données (scénario classique et souvent d’actualité). Les arguments étant l’élément discriminent de la requête, j’utilise le QueryString de celle-ci comme clé pour la mise en cache.

 

public class Handler1 : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        String arg1 = context.Request["arg1"];
        String arg2 = context.Request["arg2"];

        Byte[] data;

        // Récupération de l'objet cache
        Cache cache = context.Cache;

        // Création de la clé utiliser par le cache
        String cacheKey = context.Request.QueryString.ToString();

        // Récupération des données du cache
        Object cachedData = cache.Get(cacheKey);

        if (cachedData == null)
        {
            // 
            // TODO : Ajouter ici la logique pour aller chercher la donnée 
            // data = ...
            //

            try
            {
                cache.Add(cacheKey,
                            data,
                            null,
                            System.Web.Caching.Cache.NoAbsoluteExpiration,
                            System.Web.Caching.Cache.NoSlidingExpiration,
                            CacheItemPriority.Normal,
                            null);
            }
            catch(Exception ex)
            {
                // TODO : faire ce que vous voulez des informations de l'execption
            }

        }
        else
        {
            // Convertir les donnée stockées dans le cache serveur
            data = (Byte[])cachedData;
        }

        // Ecriture de l'image en sortie
        var response = context.Response;
        response.Clear();
        response.ContentType = "image/jpeg";
        response.BinaryWrite(data);
        response.Flush();

        // Gestion du cache http serveur/proxy/client
        response.Cache.SetCacheability(HttpCacheability.Public);
        response.Cache.SetExpires(DateTime.Now.AddDays(7));
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Note : rien à voir  avec System.Web.Caching.Cache, mais dans le cas d’un handler, on peut aussi profiter d’un cache http serveur/proxy/client (dernières lignes de la réponse)

Sans .net 4 ou 4.5, pas de Task, pas d’async/await, attendre un Thread ou le lancer doit donc se faire “à la papa”. Depuis l’arrivée de .net 4, je suis surpris de voir que bon nombre de développeurs ne savent plus faire ce genre d’opératione triviales.

Voici donc un petit code qui vous sera bien utile si vous n’avez que du .net 3.5 sous la main :

namespace MyLib
{
    /// <summary>
    /// Permet de gérer plus facilement des threads
    /// </summary>
    internal static class ThreadingHelperNet35
    {
        /// <summary>
        /// Lance une action sur le Threadpool et fourni un AutoResetEvent pour attendre la fin de l'action 
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        internal static AutoResetEvent Queue(Action action)
        {
            AutoResetEvent e = new AutoResetEvent(false);
            ThreadPool.QueueUserWorkItem(state =>
            {
                try
                {
                    action();
                }
                finally
                {
                    e.Set();
                }
            });
            return e;
        }

        /// <summary>
        /// Lance une action sur le Threadpool et attend la fin de l'action
        /// </summary>
        /// <param name="action"></param>
        internal static void QueueAndWait(Action action)
        {
            AutoResetEvent e = Queue(action);
            e.WaitOne();
        }
    }
}

La méthode Queue() utilise une mécanique simple, mais pourtant bien huilée :

  1. Un AutoResetEvent est instancié, il servira à attendre la fin de l’action.
  2. L’action est lancée via le ThreadPool
  3. À la fin de l’action, on fait un set sur l’AutoResetEvent ce qui met fin à l’attente.

La méthode QueueAndWait() utilise ce mécanisme.

Malheureusement, ce code utilise des particularités de .net 3.0 et 3.5 :

  • System.Action
  • Lambdas

Pour le faire fonctionner sur .net 2.0 il faudra donc passer par une adaptation du code :

  • Déclarer un délégué pour l’action.
  • Remplacer la lambda par une structure.
namespace MyLib
{
    /// <summary>
    /// Permet de gérer plus facilement des threads
    /// </summary>
    internal static class ThreadingHelperNet2
    {
        public delegate void Action();

        /// <summary>
        /// Lance une action sur le Threadpool et fourni un AutoResetEvent pour attendre la fin de l'action 
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        internal static AutoResetEvent Queue(Action action)
        {
            QueuedAction queuedAction = new QueuedAction(action);
            ThreadPool.QueueUserWorkItem(queuedAction.Execute);
            return queuedAction.Event;
        }

        /// <summary>
        /// Lance une action sur le Threadpool et attend la fin de l'action
        /// </summary>
        /// <param name="action"></param>
        internal static void QueueAndWait(Action action)
        {
            AutoResetEvent e = Queue(action);
            e.WaitOne();
        }

        /// <summary>
        /// Stucture permétant d'envelopper l'action à attendre
        /// </summary>
        private struct QueuedAction
        {
            private readonly Action _action;
            private readonly AutoResetEvent _event;

            /// <summary>
            /// Constructeur
            /// </summary>
            /// <param name="action"></param>
            internal QueuedAction(Action action)
            {
                _event = new AutoResetEvent(false);
                _action = action;
            }

            /// <summary>
            /// AutoResetEvent permétant l'attente
            /// </summary>
            internal AutoResetEvent Event { get { return _event; } }

            /// <summary>
            /// Executer l'action
            /// </summary>
            /// <param name="state"></param>
            internal void Execute(Object state)
            {
                try
                {
                    _action();
                }
                finally
                {
                    _event.Set();
                }
            }
        }
    }
}

Et voilà du bon vieux deve “à la papa”. Désolé pour la vue des plus jeunes, .net 2.0 c’était comme ça, ça piquait un peu Clignement d'œil(je n’ai plus ce qu’il faut sous la main pour tester, mais ce code doit aussi être compatible .net 1.0 et 1.1)

Dans un prochain article, on refait des HttpWebRequest à la main pour avoir une couche de service 100% portable (même pas mal)

Voici trois lignes à garder en tête quand vous partez sur l'usage de System.Reflection :

  1. Trop de Reflection tue les performances d'une application.
  2. Pas assez de réflexion tue les performances d'une application.
  3. Moralité : ne jamais utiliser de Reflection sans réflexion !

Signé : un deve qui en a marre de voir des conteneurs IOC là où ça ne sert à rien.

Régulièrement, je reçois des mails, me défiant de fournir un service WCF interopérable. Aux yeux de certains, WCF ne sait pas être compatible avec des clients Java, PHP, JavaScript car il ne respecterait pas les standards. Heureusement, ce n’est pas vrai!

D’expérience, je me suis rendu compte que dans 90% des cas, le Binding n’était pas bien choisi (ou alors il est mal configuré). Dans les 10% restants, c’est le client qui fait mal son travail.

 

Dernièrement, il m’a été communiqué un code JavaScript qui ne fonctionnait pas avec un service WCF utilisant pourtant bien un webHttpBinding.

Avec ce code, on m’a joint la remarque : « WCF ne sait pas lire du json ! »

Après activation modification du fichier de configuration pour que WCF retourne un message d’erreur :

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior>
      <serviceDebug includeExceptionDetailInFaults="true"/>
    </behavior>
  </serviceBehaviors>
</behaviors>

 

Je constate que WCF me dit trouvé un caractère « simple cote » là où il attend un « double cote ». Après recherche sur json, je suis tombé sur un paire d’articles :

JSON : regardons en détail de quoi il s'agit

Request for Comments: 4627

 

Oh la belle surprise, il y a un RFC sur json qui dit qu’une propriété doit être entourées de « doubles cotes ».

Or le client utilise le « simple cote ».

Donc: le code suivant = pas bien !

$.ajax({
  type: "POST",
  url: "/MonService.svc/MaMethode",
  contentType: "application/json; charset=utf-8",
  data: "{‘name’: " + userName + ", ‘firstname’: " + userFirstname + "}",
  success: successCallBack,
  error: ajaxCallBack
})

Le code suivant = bien !

$.ajax({
  type: "POST",
  url: "/MonService.svc/MaMethode",
  contentType: "application/json; charset=utf-8",
  data: "{\"name\": " + userName + ", \"firstname\": " + userFirstname + "}",
  success: successCallBack,
  error: ajaxCallBack
})

Moralité, encore une fois WCF a bien respecté la norme. Dans le cas présent, il la respecte même strictement et n’accepte pas un client non respectueux de celle-ci.

Remarque : Après tests sur un service web ASMX, j’ai constaté que celui-ci était plus permissif et supportait le « simple cote ». D’où les problèmes de migration de certain lors du passage à WCF L

Note : Je poste cet article à titre de pense-bête. Cela fait des années que je me trimballe avec une capture d'écran, car je ne me rappel jamais comment choisir la collation d'un SQL Server pour SharePoint.

Pour SharePoint, il est conseillé de choisir la collation Latin1_General_CI_AS_KS_WS. Ceci ne pouvant être fait qu'à l'installation du SQL Server, il vaut mieux ne pas se rater. Lors du choix de la configuration de notre instance SQL Server, il faut donc aller sur l'onglet « Collation » et cliquer sur le bouton « Customise…

 

Pour obtenir le Latin1_General_CI_AS_KS_WS, on doit :

  • Sélectionner « Latin_General » dans la liste déroulante.
  • Ne pas cocher « Case-sensitive » (ce qui correspond au CI).
  • Cocher « Accent-sensitive » (ce qui correspond au AS).
  • Cocher « Kana-sensitive » (ce qui correspond au KS).
  • Cocher « Width-sensitive » (ce qui correspond au WS).

     

 

Et voilà, le tour est joué :

»

il m'a été demandé, à plusieurs reprises, comment je faisais pour simuler l'envoi de mail lors de mes démos de Workflow Foundation.

Ma solution est plutôt simple : j'utilise la configuration par défaut du SmtpClient et j'oriente les mails vers un dossier local. Dans mes projets de démos et de tests, j'ai toujours la configuration suivante pour mes clients SMTP.

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

  <system.net>

    <mailSettings>

      <smtp deliveryMethod="SpecifiedPickupDirectory">

        <specifiedPickupDirectory pickupDirectoryLocation="D:\mails"/>

      </smtp>

    </mailSettings>

  </system.net>

</configuration>

   

Note : Il faut créer le dossier avant de lancer des tests. Sinon, on obtient un message d'insulte nous disant que le dossier n'existe pas

À partir du moment où j'utilise cette configuration, toutes mes instances de type SmtpClient enverront leurs mails dans mon dossier « D:\mails\ ».

Les avantages sont nombreux :

  • Je peux travailler en déplacement (et sans réseau).
  • Je n'ai rien installé sur mon PC, je n'installerais donc rien sur un serveur de tests.
  • Quand je publie une version en production, la configuration de Release replace cette section (pas besoin de changer le code).
  • Mes projets de tests unitaires peuvent jouer ce code sans polluer ma boite mail.
  • Je peux avoir autant de destinataires que je veux (pour du Workflow, c'est très important).
  • Mes mails ne vont pas inutilement sur internet pour revenir sur mon PC.
  • Je n'attends pas des heures après un mail qui n'arrive pas !

Par une journée de pluie (comme on les aime), un code est tombé de l'étagère d'un collègue. Quand on regarde l'étagère du collègue via Visual Studio, celui-ci est introuvable. Pourtant, il a bien été posé sur l'étagère…

Avec un Visual Studio 2010 sans Power Tools, il est heureusement possible de consulter la liste de Shelvesets de tous les collègues. Pour cela, il suffit de saisir « * », là ou Visual Studio s'attend à voir apparaitre le nom du propriétaire des Shelvesets.

Résultat : un code retrouvé… et une vie sauvée.

Si comme certains, vous vous plaignez de n’avoir plus qu’un graphique affichant l’utilisation globale de vos CPU, sachez qu’il existe une option permettant de revenir à un affichage par CPU.

La mise en œuvre est simple. À partir de l’onglet performance du gestionnaire des tâches, on peut faire un click droit sur le graphique global et on choisit “Processeurs logiques”. 

W8_CPU02

 

Ceci permet d’avoir l’affichage suivant.

W8_CPU03

 

Et pour les amoureux des interfaces minimalistes, l’option “Affichage de résumé du graphique” nous permet d’avoir un boite de dialogue réduite :

W8_CPU04

Elle est pas belle la vie?!

Les ressources de nos très chers serveurs ne sont malheureusement pas illimitées (même dans le cloud). Il arrive toujours un moment où l’on doit se rendre à l’évidence. Soit on joue la guerre à l’armement, soit on se raisonne.

Une fois n’est pas coutume, je vais vous proposer une approche raisonnable. Partons sur un exemple simple. Supposons que vous êtes dans le cas où vous avez créé un service WCF qui accède à une ressource présente sur votre serveur (ex : disques durs, sonde de température, dongle USB, base de données). Vous savez très bien qu’au-delà d’un certain nombre d’utilisations simultané de cette ressource, les performances sont dégradées (voire pire, le matériel n’est plus accessible, ou la base de données passe hors ligne).

Votre esprit s’agite, vous voyez déjà deux ou trois solutions se profiler à l’horizon :

  • Sémaphore
  • Verrous attribués temporairement
  • Mécanisme de synchro maison
  • Singleton pour la gestion du nombre de clients entrants.
  • .. etc…

Mais j’arrive avec mes gros sabots et je dis STOP ! Pourquoi réinventer une roue carrée alors que WCF a de quoi gérer ça via ses behaviors ? (OK : en général quand je dis behavior, tout le monde par en courant)

Qui plus est, il n’y a rien à coder !

Le service doit être lié à un behavior disposant d’un paramètre serviceThrottling. Celui-ci dispose d’un attribut très intéressant, le maxConcurrentInstances (comme sont nom l’indique, il limite le nombre d’instances de votre service).

Par exemple, si mon service ne doit pas avoir plus de 10 instances concurrentes :

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior 
        name="behaviorThrottled">
        <!-- Limite le nombre d'instance du service à 10-->
        <serviceThrottling 
          maxConcurrentInstances="10" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <services>
    <service 
      name="WcfService1.Service1"
      behaviorConfiguration="behaviorThrottled">
      <endpoint 
        binding="netTcpBinding"
        contract="WcfService1.IService1" />
    </service>
  </services>
</system.serviceModel>

Si l’envie vous prend, vous pouvez aussi utiliser les attributs maxConcurrentCalls et maxConcurrentSessions qui peuvent être très pratiques pour limiter l’impact sur le serveur lors de la montée en charge de vos services (ou vous protéger contre des attaques DOS).

Ce matin en voulant installer l'application Windows Phone pour Windows 8, j'ai lancé une petite recherche dans le store :

windows store

Une fois de plus je me suis retrouvé face à une liste bien plus grande que ce dont j'avais besoin. Heureusement, à coup de filtres, j'ai trouvé mon bonheur.

Cette situation ne m'arrivant pas pour la première fois, j'ai beaucoup de mal à comprendre nos "journalistes spécialisés".

Pourquoi s'acharnent-ils encore à dire que le store est vide? (certains auraient-ils peur, de voir baisser la rentabilité de leurs placements boursiers dans une certaine coopérative fruitière?)

Dernièrement, je me suis retrouvé dans une situation absurde. Je ne savais pas où trouver les pack de langues pour un SharePoint Server 2013. Après quelques recherches, je me suis rendu compte que le seul moyen de les télécharger était d’utiliser un abonnement MSDN. Arrivé sur mon espace de téléchargement, j’ai trouvé un beau paquet de fichiers à télécharger… beaucoup trop.

Pour vous éviter de galérer, j’ai pris le temps de faire une petite capture d’écran de ce qu’il faut chercher. A savoir : “Office Server 2013 Language Pack”. Pour l’exemple, j’ai choisi de télécharger le pack “Anglais” et le pack “Français”.

SP2013_Install language pack 01

 

Après téléchargement il suffit de charger l’iso sur son serveur et de lancer le setup.

SP2013_Install language pack 02

 

Il faudra être patient…

SP2013_Install language pack 03

 

Bien entendu, cette patience payera. Mais on sera amené à lancer l’assistant de configuration de SharePoint (là aussi la patience sera de mise)

SP2013_Install language pack 04

 

Quand la configuration de SharePoint est terminée, on peut accéder au panneau de configuration de l’un se ses sites. On peut alors voir apparaitre un lien pour changer la langue du site.

SP2013_Install language pack 05

 

 

Il suffit alors de cocher les langues que l’on veut utiliser. On valider, et le tour est joué. (pour preuve, ma capture d’écran est en français)

SP2013_Install language pack 06

Tada!!!

(Quelles sont loin les galères de WSS)



Les 10 derniers blogs postés

- Après Montréal, ce sera Barcelone, rendez-vous à la European SharePoint Conference 2014 ! par Le blog de Patrick [MVP SharePoint] le 04-19-2014, 09:21

- Emportez votre sélection de la MSDN dans la poche ? par Blog de Jérémy Jeanson le 04-17-2014, 22:24

- [ #Office365 ] Pb de connexion du flux Yammer ajouté à un site SharePoint par Le blog de Patrick [MVP SharePoint] le 04-17-2014, 17:03

- NFluent & Data Annotations : coder ses propres assertions par Fathi Bellahcene le 04-17-2014, 16:54

- Installer un site ASP.net 32bits sur un serveur exécutant SharePoint 2013 par Blog de Jérémy Jeanson le 04-17-2014, 06:34

- [ SharePoint Summit Montréal 2014 ] Tests de montée en charge SharePoint par Le blog de Patrick [MVP SharePoint] le 04-16-2014, 20:44

- [ SharePoint Summit Montréal 2014 ] Bâtir un site web public avec Office 365 par Le blog de Patrick [MVP SharePoint] le 04-16-2014, 18:30

- Kinect + Speech Recognition + Eedomus = Dommy par Aurélien GALTIER le 04-16-2014, 17:17

- [ SharePoint Summit Montréal 2014 ] Une méthodologie simple pour concevoir vos applications OOTB SharePoint de A à Z par Le blog de Patrick [MVP SharePoint] le 04-16-2014, 16:51

- //Lean/ - Apprendre à faire des Apps Windows universelles par Blog de Jérémy Jeanson le 04-16-2014, 12:57