Les nouveautés de Visual Studio 2019

L’objectif de cet article est de faire le tour d’horizon des principales nouveautés et améliorations de la prochaine version majeure de Visual Studio, l’outil phare de développement de Microsoft.

IntelliCode

Vous connaissiez certainement IntelliSense, une fonctionnalité très appréciée de Visual Studio, voici la version dopée à l’IA : IntelliCode.
IntelliCode se forme sur votre référentiel de code en créant une hiérarchie entre les modèles de code les plus courants ainsi que le code de vos projets et va partager les résultats avec votre équipe.
Pour générer ses recommandations, IntelliCode s’entraîne sur 2 000 projets open source disponibles dans GitHub.
Au final, cela permet de réduire le nombre de frappes dont vous avez besoin et donc de gagner en productivité.

blog ai3 microsoft-vs-code-intellicode Les nouveautés de Visual Studio 2019

La fonctionnalité de recherche a été optimisée : elle est est désormais plus rapide et plus efficace. De plus, les résultats sont affichés au fur et à mesure de la frappe. Enfin, les raccourcis clavier des commandes courantes sont affichés.

blog ai3 search-feature Les nouveautés de Visual Studio 2019

Optimisations du débogueur

Jamais le débogage n’a été aussi simple et intuitif que dans cette version de Visual Studio.
Vous pouvez examiner plusieurs variables dans l’espion sans avoir besoin de scroller.
De plus, la navigation entre plusieurs mot clés de recherche a été facilitée.
Enfin, une option « Profondeur de la recherche » a été ajoutée (valeur de 1 à 10), cette dernière vous sera utile pour spécifier jusqu’à quelle niveau de profondeur la recherche doit être effectuée dans vos projets.

blog ai3 BasicSearch-1024x380 Les nouveautés de Visual Studio 2019
blog ai3 Navigation-1024x379 Les nouveautés de Visual Studio 2019

Nouvelle interface

L’interface a été mise à jour afin d’avoir la meilleur expérience utilisateur possible.
L’icône principal de l’application a été redesigné en utilisant l’approche Fluent Design System.

blog ai3 new-old-vs-win-icons-1 Les nouveautés de Visual Studio 2019

Le menu de démarrage a été optimisé pour plus de simplicité et une meilleure ergonomie.

blog ai3 command-bar-all-1024x838 Les nouveautés de Visual Studio 2019

Un thème bleu a été ajouté.

blog ai3 Visual-Studo-theme-comparison-1024x638 Les nouveautés de Visual Studio 2019

La barre de commande a été optimisée pour une meilleure productivité.

blog ai3 Visual-Studio-command-shelf-comparison-1024x114 Les nouveautés de Visual Studio 2019

La lisibilité des notifications a été améliorée.

blog ai3 Notifications-2-1024x472 Les nouveautés de Visual Studio 2019

Visual Studio Live Share

Visual Studio Live Share est un service de révision de code en temps réel qui vous permet de partager une base de code avec d’autres développeurs.
N’importe quel développeur autorisé peut travailler à distance en simultané sur vos projets de manière transparente, fluide et sécurisée.

blog ai3 indroducing-visual-studio-live-share Les nouveautés de Visual Studio 2019

Pull Request

La fonctionnalité Pull Request a été améliorée : vous pouvez désormais consulter, exécuter et déboguer les Pull Request de votre équipe sans quitter l’EDI.
Ceci nécessite de télécharger l’extension Pull Requests for Visual Studio à partir de Visual Studio Marketplace.

C#

Visual Studio 2019 ajoute quelques fonctionnalités supplémentaires à C# 8.0 :

  • flux asynchrones,
  • types Range et Index,
  • expressions Switch,
  • modèles récursifs,
  • déclarations using,
  • fonctions locales static.

F#

Améliorations des performances pour les solutions comportant de nombreux projets et corrections de bugs.

Universal Windows Platform (UWP)

Le déploiement sur des périphériques Windows Mobile n’est plus pris en charge dans Visual Studio 2019. Toute tentative de déploiement sur un périphérique Windows 10 Mobile provoquera une erreur indiquant que « Le déploiement sur des périphériques Windows Mobile n’est pas pris en charge dans Visual Studio 2019 ». Si vous devez continuer à travailler sur une application pour les appareils Windows 10 Mobile, continuez à utiliser Visual Studio 2017.

JavaScript/TypeScript

Le débogage JavaScript dans les tests unitaires des projets Node.js a été ajouté.

Prise en charge de .NET Core 3 Preview

Visual Studio 2019 permet la génération d’applications .NET Core 3 pour n’importe quelle plateforme.

blog ai3 dot-net-core-three-dev Les nouveautés de Visual Studio 2019

Pour information le lancement officiel de Visual Studio 2019 aura lieu le 2 avril.

blog ai3 visual Les nouveautés de Visual Studio 2019

Les nouveautés de C# 7

L’objectif de cet article est de présenter aux développeurs les dernières nouveautés de la version 7 de C# en les présentant de manière simple et concise.

Bien entendu, si vous souhaitez avoir plus de détails sur ces nouveautés, je vous invite à vous documenter personnellement pour récupérer les informations qui pourrait vous manquer.

  • La version 7.0

  • Amélioration de la lisibilité du code avec les variables OUT
C# 6 C# 7
string nombreAConvertir = « 7878 »;

int nombre;

if (Int32.TryParse(nombreAConvertir, out nombre))

{

}

string nombreAConvertir = « 7878 »;

if(Int32.TryParse(nombreAConvertir, out int nombre))

{

}

Avec la version 7,  la variable OUT est déclaré au moment où on souhaite l’utiliser, nous ne sommes plus obligés de déclarer préalablement la variable.

  • Amélioration de l’utilisation des tuples
Avant C# 7
Un tuple peut être défini de la façon ci-dessous

Tuple<int, string> tuple = new Tuple<int, string, bool>(1, « pomme »);

Pour accéder aux propriétés du tuples, on le fait simplement avec les propriétés item1, item2… suivant le nombre de propriétés défini dans le tuple.

if (tuple.Item1 == 1) {

Console.WriteLine(tuple.Item1);

}

if (tuple.Item2 == « pomme »){

Console.WriteLine(tuple.Item2);

}

Depuis C# 7
Il est bien entendu toujours possible de déclarer les tuples comme indiqué ci-dessus.

Cependant, d’autres façons de le faire sont maintenant disponible depuis la version 7 de C#.

  • var monTuple = (« test », « test1 »);

monTuple est bien un objet de type Tuple et pour accéder aux valeurs de ce tuple (test et test1), on appellera les propriétés item1 et item2.

  •   (string a, string b) monTuple = (« test », « test1 »);

monTuple est bien un objet de type Tuple et pour accéder aux valeurs de ce tuple(test et test1), on appellera les propriétés a et b.

  •   var monTuple = (a: « test », b: « test1 »);

monTuple est bien une instance d’ objet de type Tuple et pour accéder aux valeurs de ce tuple(test et test1), on appellera les propriétés a et b.

  • Apparition des éléments ignorés avec C# 7
Les éléments ignorés sont des variables temporaires factices utilisées dans le code,

  • n’ayant aucune valeur.
  • défini juste par un underscore (_).

 

Utilisé dans le cadre de la déconstruction d’un tuple
var (_, _, _, a, _, b) = ReturnTuple();

ReturnTuple est une méthode qui retourne un tuple de six éléments.

De tous ces élements retournés, certaines valeurs peuvent être inutilisés car , pas nécessaire. Les éléments ignorés indiqués ci-dessus permettent ainsi de réduire les allocations de mémoire : la methode retourne bien les valeurs du tuple mais du fait que certaines valeurs ne nous intéresse pas, on définit alors des élements ignorés.

  • Apparition du pattern matching avec C# 7
Avant C# 7
  • Le mot-clé is vérifie si un objet est compatible avec un type donné

Exemple : expr is Type

  • Le mot-clé switch est une instruction de sélection qui teste la valeur d’une constante.

Exemple : switch (expr)

case constant:

Après C# 7
  • Le mot-clé is prend en charge en plus
  • Le modèle de type : expr is Type nomVariable
    • is vérifie si expr peut être convertie avec le type Type, et si cela est possible effectue le cast directement.

Exemple : if (o is Employee e)

{return (e.Name);

  • Le modèle de variable : expr is var varName
    • Is vérifie si expr peut être assigné dans la variable varName, et si cela est possible effectue l’assignation directement.

Exemple : if (item is var obj){}

  • Le mot-clé switch prend en charge en plus
    • Tout expression de correspondance non null (IEnumerable, ICollection, Array, Int…).
    • L’apparition de la clause when sur la même ligne d’un case.

Exemple : case Shape shape when shape == null:

  • Apparition des fonctions locales avec C# 7

Une fonction locale est une méthode définie à l’intérieur d’une autre méthode. Cette fonctionnalité a été créé dans le but d’avoir plus de facilité de compréhension dans la lecture du code.

Exemple de fonction locale
private static string GetText(string path, string filename)

{

var sr = File.OpenText(AppendPathSeparator(path) + filename);

var text = sr.ReadToEnd();

return text;

// Ci-dessous, vous trouverez la fonction locale

string AppendPathSeparator(string filepath)

{

if (! filepath.EndsWith(@ »\ »))

filepath += @ »\ »;

return filepath;

}

}

  • Généralisation des expressions-bodied dans C# 7

Les expressions-bodied sont apparus dans la version 6 de C#. En C# 7, elles ont été généralisées au niveau des constructeurs et ses accesseurs.

Exemple d’expression-bodied en C# 7
// Accesseurs

public string Label

{

get => label;

set => this.label = value ?? « Default label »;

}

// Constructeur

public ExpressionMembersExample(string label) => this.Label = label;

  • Valeurs de retour de référence et variables locales de référence en C# 7
Variables de retour de référence
Une valeur de retour de référence permet à une méthode de retourner à un appelant une référence à une variable, plutôt qu’à une valeur.

Exemple :

public ref Person GetContactInformation(string fname, string lname)

{

return ref p;

}

On peut s’apercevoir que la méthode retourne une référence à un objet Person nommé p.

Variables locales de référence
Une variable locale de référence est une variable qui va recevoir une affectation de données ( généralement une méthode) non par par valeur mais par référence.

Exemple :

Person p = contacts.GetContactInformation(« Scott », « Hanselman »);

Ci-dessus, nous avons faire face à une variable locale : la valeur de p est copié à partir de la méthode GetContactInformation, si on modifie p par la suite, la valeur renvoyé par GetContactInformation ne sera pas impactée.

Ref Person p = contacts.GetContactInformation(« Scott », « Hanselman »);

Ci-dessus, nous avons faire face à une variable locale de référence : la valeur de p est désormais un alias de la valeur retournée par GetContactInformation, si on modifie p par la suite, la valeur renvoyée par GetContactInformation sera impactée.

  • Types de retours async généralisés
Nouveautés de C# 7
Au niveau asynchronisme, je ne m’étendrais pas dans cet article sur les mot-clés async et await. Je précise juste que les types de retour retournés dans le cadre d’utilisation de ces mots clés peuvent être Task,Task<TResult> ou void. Pour simplifier tout cela, C#7 permet d’utiliser maintenant un type globale, utilisable dés qu’une méthode est awaitable.

System.Threading.Tasks.ValueTask<TResult>

using System;

using System.Threading.Tasks;

class Program

{

static Random rnd;

static void Main()

{

Console.WriteLine($ »You rolled {GetDiceRoll().Result} »);

}

private static async ValueTask<int> GetDiceRoll()

{

int roll1 = await Roll();

int roll2 = await Roll();

return roll1 + roll2;

}

private static async ValueTask<int> Roll()

{

if (rnd == null)

rnd = new Random();

await Task.Delay(500);

int diceRoll = rnd.Next(1, 7);

return diceRoll;

}

}

  • Amélioration de la syntaxe litérale numérique
Nouveautés de C# 7
Avec C# 7, il est possible désormais d’utiliser  des séparateurs de chiffres pour une meilleure compréhension du code dans la lecture de constantes numériques.

public const int SixtyFour = 0b0100_0000;

public const long BillionsAndBillions = 100_000_000_000;

public const double AvogadroConstant = 6.022_140_857_747_474e23;

public const decimal GoldenRatio = 1.618_033_988_749_894_848_204_586_834_365_638_117_720 ;


  • La version 7.1

  • Expressions littérales par défaut
Nouveautés de C# 7
Dans l’optique de toujours plus simplifier le code, le mot-clé default pourra être utilisé de manière littérale pour initialiser des variables, des paramètres de méthodes où bien des instructions de retour.

Cela initialise la chaine à la valeur par défaut d’une string, à savoir null.

string maChaine=default ;

L’utilisation du mot clé dans un paramètre de méthode.

public LabeledPoint(double x, double y, string label = default)

{

X = x;

Y = y;

Label = label;

}

L’utilisation du mot clé en retour d’une méthode.

public static LabeledPoint MovePoint(LabeledPoint source,

double xDistance, double yDistance)

{

// return a default value:

if (source == null)

return default;

return new LabeledPoint(source.X + xDistance, source.Y + yDistance,

source.Label);

}

  • Async dans main
Le mot-clé async pourra être utilisé dans une méthode main.
  • Simplification de fonctionnalité de tuple
  • var monTuple = (a: « test », b: « test1 »);

monTuple est bien un objet de type Tuple et pour accéder aux valeurs de ce tuple(test et test1), on appellera les propriétés a et b.

Cependant en version C# 7.1, la définition du tuple  peut être redéfini de la façon suivante, toujours pour des raisons de simplification de code.

string a= « test »,

string b= »test1″,

  • var monTuple = (a, b);

  • La version 7.2

  • Apparition de private protected
  • Private protected :  cela veut dire qu’un membre pourra être accessible depuis les classes dérivés du même assembly de la classe principale
  • Arguments nommés non placés à la position de fin
Depuis C#4 sont apparus les arguments nommés (exemple ci-dessous)

PrintOrderDetails(orderNum: 31, productName: « Red Mug », sellerName: « Gift Shop »);

Les arguments nommés améliorent la lisibilité du code en identifiant ce que chaque argument représente.

Il ne faut pas les confondre avec des arguments de position (exemple ci-dessous)

PrintOrderDetails(orderNum, productName, sellerName);

 

Depuis la version C# 7.2, nous avons la possibilité de mixer les deux types d’arguments dans l’appel de la méthode.

PrintOrderDetails(orderNum :31, « Red Mug » , sellerName: « Gift Shop » );


  • La version 7.3

  • Prise en charge des opérateurs d’égalité et d’inégalité avec les tuples
Depuis la version 7.3, nous avons la possibilité dorénavant d’utiliser les opérateurs d’égalité == et d’inégalité. Le mode de fonctionnement est basique, il compare chaque membre de l’argument de gauche à chaque membre de l’argument de droite.
Exemple :
var test= (a: 5, b: 10);
var test1= (a: 5, b: 10);
Console.WriteLine(test== test1); // Le résultat sera True
  • Réaffectation des variables locales Ref
Il est désormais maintenant possible de pouvoir réaffecter une variable local Ref , qui était déjà un pointeur vers une autre variable.
Exemple :
ref VeryLargeStruct refLocal = ref veryLargeStruct;
refLocal = ref anotherVeryLargeStruct;On voit bien ci-dessus que la variable qui était un pointeur vers l’objet veryLargeStruct sur la première ligne, est désormais un nouveau pointeur vers l’objet anotherVeryLargeStruct sur la deuxième ligne.
  • Amélioration des tableaux stackalloc
Le mot-clé stackalloc est utilisé dans un contexte de code unsafe pour allouer un bloc de mémoire sur la pile. Avec la version 7.3, ce mot-clé peut dorénavant être utilisé avec des tableaux

Avant 7.3
var arr = new int[3] {1, 2, 3};
var arr2 = new int[] {1, 2, 3};
Depuis 7.3
int* pArr = stackalloc int[3] {1, 2, 3};
int* pArr2 = stackalloc int[] {1, 2, 3};
Span<int>arr = stackalloc [] {1, 2, 3};

  • D’autres types pour l’instruction fixed
L’instruction fixed définit un pointeur un pointeur vers une variable managée et épingle cette variable pendant l’exécution de l’instruction.

À compter de C# 7.3, l’instruction fixed s’applique à d’autres types au-delà des tableaux, chaînes, mémoires tampons de taille fixe ou variables non managées.

 

Blazor : Framework Web .NET

Introduction

Depuis les premiers navigateurs, Javascript a beaucoup évolué pour permettre de développer des applications web plus complexes. L’émergence récente des Web Assembly ouvre la possibilité de compiler du code que les navigateurs pourront exécuter directement sans avoir à parser le code source. Ceci offre une alternative à Javascript pour les développeurs qui souhaitent dynamiser leurs applications avec des langages comme C, C++ ou C#.

Web Assembly est un standard W3C qui consiste en un bytecode s’exécutant dans une sandbox compatible avec Javascript. L’objectif est d’exécuter du code à une vitesse proche du natif avec des fonctionnalités avancées tout en conservant la sécurité et la rétrocompatibilité. L’écosystème Web Assembly est toujours en développement et il est supporté par la plupart des navigateurs web.

Présentation

Microsoft a publié plusieurs versions beta de Blazor, un Framework Web .NET qui s’exécute au sein du navigateur. Blazor se base sur le moteur de rendu Razor pour simplifier la création d’application web monopage aussi appelée Single Page Application.

Frontend

Blazor s’appuie sur les technologies HTML et CSS, mais le C# vient remplacer le Javascript. En effet, la runtime C# .NET est embarquée dans le WASM (Web Assembly) et le navigateur exécute le bytecode du WASM. Il comporte toutes les fonctionnalités d’un Framework moderne tel que le modèle de composant, le routage, la mise en page, l’injection de dépendances, le rendu côté serveur, le débogage .NET et le rechargement à chaud pendant le développement.

blog ai3 Blazor_frontend-300x275 Blazor : Framework Web .NET

Backend

Si le navigateur ne supporte pas Web Assembly, Blazor permet de faire fonctionner l’application dans un environnement asm.js. L’exécution de Blazor côté serveur vous permettra d’écrire votre application web entièrement en C# avec ASP.NET Core, mais il présente quelques inconvénients. Chaque interaction avec l’UI gérée par SignalR nécessite un saut réseau, ceci implique que l’application ne fonctionnera pas hors-ligne et qu’il pourrait y avoir quelques latences en fonction du nombre de connexion.

blog ai3 blazor_backend Blazor : Framework Web .NET

Get started

Prérequis

Votre première application

Ouvrir Visual Studio puis Fichier -> Nouveau -> Projet…
Sélectionner Web et ASP.NET Core Web Application

blog ai3 blazor_tuto1 Blazor : Framework Web .NET

Sélectionnez le template Blazor et compiler la solution.

blog ai3 blazor_tuto2 Blazor : Framework Web .NET

Lancer l’application, vous devez avoir l’écran ci-dessous dans votre navigateur.

blog ai3 blazor_tuto3 Blazor : Framework Web .NET

Ouvrir la page Counter où l’incrémentation dynamique est effectuée en C#.

blog ai3 blazor_tuto4 Blazor : Framework Web .NET

Vous pouvez regarder l’implémentation dans le fichier Counter.cshtml

blog ai3 blazor_tuto5 Blazor : Framework Web .NET

Créer un nouveau fichier Todo.cshtml dans le dossier Pages avec l’implémentation suivante :

Ouvrir le fichier NavMenu.cshtml et ajouter les lignes suivantes :

Créer une classe TodoItem.cs à la racine du projet avec le code suivant :

blog ai3 blazor_tuto9 Blazor : Framework Web .NET

Vous pouvez compiler et relancer votre application, vous venez de coder une todolist avec Blazor !

blog ai3 blazor_tuto10 Blazor : Framework Web .NET

Conclusion

Le projet Blazor est open source et disponible sur Github. Bien que le Framework soit encore au stade expérimental, son approche est vraiment intéressante. Il ne s’agit pas de concurrencer ASP.NET MVC ou Javascript, mais de proposer une nouvelle solution full-stack .NET pour développer des « Single Page Application ».

Sources :
https://blazor.net/index.html
https://blogs.msdn.microsoft.com/webdev/2018/07/25/blazor-0-5-0-experimental-release-now-available/

 

LINQ Expressions

What is it ?

Compiled Expressions, Lambda Expressions, Expression Trees… LINQ Expressions can be named in many ways. This object describes a tree of members, operators, calls, conditions… that can be, during runtime, either read/parsed or compiled into a delegate.

EntityFramework

If you’re using EntityFramework, you’ll find that this C# instruction :

will execute this SQL query :

Well, the SQL query clearly does what we wanted it to do. But how did it know what to do ?

looks like a simple lambda, which would be a C# call to a C# method. Yet the call is not made in C#. It is included in the SQL query. The thing is you’re not using the extension method

but the extension method

The syntax when using both methods is exactly the same. However, the first method’s parameter is a lambda whereas the second method’s parameter is a lambda expression which means the code is not compiled with the app. Instead, it contains the expression tree :

  • We have a parameter named u of type User.
  • We access the property LastName of the parameter.
  • We call the method string.StartsWith on this property, with the parameter « F ».

This expression tree can be accessed and read at runtime. That way, the Where implementation will be able to convert some C# code we wrote into SQL.

Creating a LINQ expression at runtime

Let’s say you want to get, for a given object, the value of a property, which name you got as a string. You can do it with reflection. That’s quite easy. However, it is very slow. Yet, LINQ expressions can be compiled into lambdas, which is about as fast a if you wrote the code directly.

The easiest way to start is to write the lambda you would want :

And then decompose it :

  • You have a parameter of type User.
  • You access a property of this parameter.
  • The lambda type is Func<User, string>.

So here is the detailed code to create the expression :

All you need is calling the right static method of the Expression class.

Once you have the expression, you can compile it with the Compile() method.

A concrete example : an object mapper

In a multi-layer application, you often have more than one class for the same business concept. For example, you might have a UserEntity that matches what you have in your database and a UserDto that only contains the information you want to display.

Both those entities will have some identical properties (same type, same name). Some libraries enable you to automatically map those identical properties from one object to the other (AutoMapper being a famous one). Let’s do our own simple yet fast one.

Let’s imagine those objects :

The goal is to fill a UserDto from a UserEntity.

We will create OurOwnMapper class :

Then we will create a method to prepare the mapping from one class to another. Its prototype will be quite simple :

This method will have to find the matching properties :

Each property will be set from one object to another via a lambda that we will create with LINQ expressions. So, for each (TFrom, TTo) couple, we will have lamba array. However, the lambda array type will be different for each (Type, Type) couple. If you want to save all lambda arrays into the same Dictionary, I see 2 choices :

  • Use a Dictionary<(Type, Type), object[]> and cast the delegate into their real types when needed.
  • Use a Dictionary<(Type, Type), Action<object, object>[]> and do the cast inside the delegate.

I will use the second solution. That means my lambdas should look like that :

Now we add the code to create such lambdas :

Then we add the lambdas collection into a dictionary :

The only thing left to do is the Map method. For that, we just have to get the lambdas for the from and to types, then call all of them on the two objects :

Now, you can use your class like this :

Here is the full code for the OurOwnMapper class :

Not so complicated, is it ?

 

Envoyer un rapport SSRS au format MHTML, en tant que corps de mail

On peut avoir besoin d’envoyer un rapport Sql Server Reporting Services (SSRS) dans un mail. En général pour cela, on génère un fichier au format choisi (PDF, Excel, Word…), qui est ajouté en pièce jointe au mail. Ceci dit on peut aussi avoir besoin d’envoyer ce rapport en tant que corps du mail, en utilisant un export au format html. A première vue ça a l’air assez basique, mais la solution technique ne l’est pas tant que ça, et on peut trouver des bouts de solutions, mais jamais la solution complète. Elle existe pourtant, et je vais la détailler.

Mais d’abord un petit rappel sur la manière dont on génère un rapport dans du code, cette génération se fait en utilisant le web service « ReportExecution2005.asmx » présent sur le serveur de rapports. Voici un exemple de code C# :

Le paramètre « format » correspond au format d’export (ici PDF), à choisir parmi les formats disponibles. Il ne reste plus qu’à écrire le contenu de la valeur de retour « results » dans un fichier avec la bonne extension, et c’est bon.

Maintenant pour générer un email avec un rapport en tant que corps de mail, le but va être de faire un rendu du rapport au format html, pour intégrer ce rendu en tant que corps d’un mail.

Reporting services supporte 2 types de format html, qui sont « HTML4.0 » et « MHTML ». Le premier format nous donne un code html compréhensible et utilisable, mais si le rapport contient des images, elles sont fournies comme des liens vers le serveur de rapport, ce qui n’est pas acceptable, les images doivent être intégrées dans l’email. On va donc se diriger vers le format « MHTML », qui contient toutes les données et est normalement adapté à ce genre d’usage.

Ceci dit en essayant de générer un rapport en MHTML, on se rend compte que le contenu est encodé en base64, et s’il peut être ouvert dans un navigateur, ce contenu n’est pas reconnu par les clients email et il ne peut donc pas être envoyé tel quel.

On peut essayer de décoder ce contenu (c’est assez complexe), mais il existe une solution beaucoup plus simple si on s’intéresse au paramètre « deviceInfo » de la fonction de rendu du web service SSRS. Ce paramètre, souvent passé à null pour avoir des valeurs par défaut, est en fait un descriptif au format XML, permettant de positionner certaines valeurs pour le rendu. Parmi ces valeurs, il y a l’attribut « MHTMLFragment » qui permet de déterminer si on doit générer le html avec les tags html et body, ou s’il est intégré dans un tag table, et surtout l’attribut « OutlookCompat » qui a l’air intéressant dans le cadre d’une utilisation pour un email.

On peut donc essayer de générer le rapport au format MHTML, en utilisant la valeur de deviceInfo :

<DeviceInfo><OutlookCompat>True</OutlookCompat><MHTMLFragment>True</MHTMLFragment></DeviceInfo>

En regardant le résultat, on voit enfin du html utilisable, mais les images ne sont pas présentes. Ceci dit les références à ces images dans le html sont sous la forme « cid:a64b27da3c7a464d9102053b5fa7e8d1 », qui ressemble bien à ce qu’on trouve dans un email html, on approche. Reste à trouver à quoi correspond cette valeur, et où trouver l’image en question. La piste se trouve en regardant le contenu de la variable de sortie streamIDs, récupérée dans la fonction de rendu du rapport. Cette variable contient en fait la liste des codes correspondant aux liens vers les images du rapport, bingo ! il reste ensuite à récupérer le contenu de ces images à partir de ces streamIDs, pour pouvoir les intégrer au mail. Ceci se fait grâce à une autre fonction du web service de SSRS : « RenderStream ».

On a donc le html, les images et la liaison entre les deux grâce à ces ID, il ne reste plus qu’à construire un mail avec toutes ces données ! Si on utilise la classe « MailMessage » du Framework .NET, il va nous falloir passer par un objet de type « AlternateView », qui permet de définir des ressources liées au mail telles les images insérées. Voici donc un exemple de code final en C# qui permet de générer un tel mail :

Il faut juste rajouter certaines données à l’email (expéditeur, destinataire, sujet…), et il est prêt à être envoyé !

La procédure n’est pas très compliquée, mais reste mal documentée, j’espère que ce petit article sera utile.

Introduction a Microsoft Azure Profiler

Au menu du jour, une présentation de Azure Profiler qui est un nouveau service proposé par Microsoft, en mode preview, permettant de mettre en place une solution de profilage de vos applications Web. Ce service permet de faire des analyses poussées d’une application, et d’explorer les métriques remontés afin de trouver les causes de problèmes que peuvent rencontrés vos applications. Pour faire un parallèle avec un produit du marché, Azure Profiler propose des fonctionnalités proche de ANTS performance Profiler.

Pour fonctionner, cette solution s’articule autour de trois éléments principaux :

  • Un agent permettant de collecter les données de votre application.
  • Un compte de stockage Azure utilisé pour stocker les informations récoltées par l’agent Profiler.
  • Une application Web qui vous permettra d’accéder aux informations récoltées par l’agent.

Pour pouvoir créer une nouvelle instance de ce service, il vous faudra vous rendre à l’adresse suivante: https://www.azureserviceprofiler.com/ . Vous devrez ensuite vous connectez avec un compte possédant un abonnement Azure et pouvant manipuler des comptes de stockage.

Une fois connecté vous arriverez sur l’écran d’accueil du service.

blog ai3 Azure-Profiler-Portal Introduction a Microsoft Azure Profiler

A partir de cet écran vous pourrez soit créer un nouveau Data Cube, soit utilisez un wizard de création d’une nouvelle instance de profiler, en cliquant sur le lien « Get started » se trouvant sur la page d’accueil du portail. C’est cette seconde option que nous allons voir dans la suite de cet article pour mettre en place notre première instance de service Azure Profiler.

Le premier niveau de configuration concerne le choix de l’abonnement sur lequel vous désirez travailler. Au cours de mes tests je n’ai pas pu changer l’abonnement sur lequel je voulais déployer un agent. L’application me remonte tout le temps le premier de mes abonnements.

blog ai3 Azure-Profiler-Create-Data-Cube-Step1 Introduction a Microsoft Azure Profiler

Vous devez ensuite choisir l’application sur laquelle vous désirez mettre en place votre agent. Si votre application est en mode PAAS, il  faudra au minimum que votre application se trouve dans un App Service de type B1, et quel’option Always On soit activée. Vous pouvez apporter ces modifications, si nécessaire, directement depuis le portail de configuration de votre Cube, ou alors effectuer celles-ci à partir le portail Azure, et revenir ensuite finir la mise en place de votre agent. Tant que ces prérequis ne sont pas remplis vous ne pouvez pas aller plus loin au niveau de la configuration.

blog ai3 Azure-Profiler-Create-Data-Cube-Step2 Introduction a Microsoft Azure Profiler

Dès que tous les prérequis sont respectés, vous pouvez alors sélectionner votre application Web.

blog ai3 Azure-Profiler-Create-Data-Cube-Step3 Introduction a Microsoft Azure Profiler

L’étape de sélection de l’application étant effectuée, l’étape suivante consiste à choisir soit de vous appuyez sur un cube existant, soit de créer un nouveau cube. Si vous décidez de créer un nouveau cube, il vous faudra alors sélectionné un compte de stockage de votre abonnement Azure pour héberger les données en provenance de l’agence. Il est important de noté qu’un compte de stockage ne peut être lié qu’à une seule instance de cube. Si vous décidez de créer un nouveau cube, et d’utiliser un compte de stockage déjà lié à un cube, toutes les données seront écrasées par votre nouvelle instance de cube.

blog ai3 Azure-Profiler-Create-Data-Cube-Step4 Introduction a Microsoft Azure Profiler

Votre cube est maintenant créé. Il ne reste plus qu’à déployer le nécessaire au niveau de l’application Web afin de pouvoir la monitorer et c’est ce que nous allons voir lors de l’étape suivante.

blog ai3 Azure-Profiler-Create-Data-Cube-Step5 Introduction a Microsoft Azure Profiler

Comme vous pouvez le voir au niveau de la copie d’écran ci-dessous, un certain nombre d’opérations vont être effectuées afin de pouvoir déployer le nécessaire à la mise en place de l’agent de monitoring au niveau de votre application. durant cette opération les opérations suivantes vont être réalisées :

  • Une extension permettant à Azure Profiler de fonctionner va être publier au niveau de votre application web.
  • Une chaine de connexion va être rajouter aux settings de votre application web, afin que l’agent puisse sauvegarder les informations concernant votre application.
  • Une instance de Web Job va être ajoutée. Ce Web Job hébergera l’agent.

Afin de lancer le déploiement de votre service profiler, veuillez cliquer sur le bouton « Deploy ».

blog ai3 Azure-Profiler-Create-Data-Cube-Step6 Introduction a Microsoft Azure Profiler

Vous allez alors arriver sur une page vous informant sur l’avancée de l’installation et de la configuration des différents éléments. la dernière opération consistant à l’instanciation d’un service de type Web Job prenant un certain temps, vous pouvez aller boire un petit café et revenir. Il arrive dès fois que l’information concernant l’avancée de l’installation du Web Job soit erronée (statut reste toujours à en cours), dans ce cas là rafraichissez l’écran.

blog ai3 Azure-Profiler-Create-Data-Cube-Step7 Introduction a Microsoft Azure Profiler

 

Une fois toutes les opérations terminées vous pourrez revenir à la page de gestion des Data Cubes afin d’accéder au cube que vous venez de créer. Vous pourrez voir que votre cube a été correctement créé, que l’agent est en cours d’exécution et que la collecte des données relatives à votre application est effective.

blog ai3 Azure-Profiler-Create-Data-Cube-Step8 Introduction a Microsoft Azure Profiler

Afin de vérifier la bonne installation du Web Job, vous pouvez vous connecter au portail Azure, et ouvrir le groupe de ressources concernant votre application Web. En allant dans le détails de celle-ci vous pourrez voir qu’une instance de Web Job a été ajoutée.

blog ai3 Azure-Profiler-Create-Data-Cube-Step9 Introduction a Microsoft Azure Profiler

Votre profiler est maintenant opérationnel, vous allez maintenant pouvoir analyser votre application, et pouvoir trouver les potentiels problèmes pouvant exister au niveau de celle-ci. Pour se faire connectez vous au portail Azure Profiler à l’adresse suivante : https://www.azureserviceprofiler.com/. Au niveau de la page d’accueil cliquez sur le cube afin d’aller sur l’écran de détails. Vous pouvez maintenant explorer votre application, et accéder aux informations récoltés par votre agent.

blog ai3 Azure-Profiler-App Introduction a Microsoft Azure Profiler

Vous pouvez ensuite aller sur le détails de chacune de vos requête, et voir les portions de code qui consomme le plus de ressources en cliquant sur le lien « show hotpath ».

blog ai3 Azure-Profiler-App1 Introduction a Microsoft Azure Profiler

 

Voilà cette introduction à Azure Profiler touche à sa fin. N’hésitez surtout pas à faire des tests par vous même et à approfondir les possibilités de ce service. Celui-ci étant encore en preview il est sur que des ajouts de fonctionnalités seront effectuées pour enrichir encore plus le produit.

David Moïsa.

 

Pièges en C# – Episode 2

Parce qu’un article ne peut être nommé « Episode 1 » que s’il y a un épisode 2, voici le successeur de son prédécesseur. Comme tout épisode 2 qui se respecte, on reprend la recette du 1, mais avec des pièges encore plus inattendus et encore plus mortels.

Double (ou float) et arrondi

Le problème

Bien évidemment, 1.000001 - 0.000001, ça fait 1. Pourtant, result est false

La raison

En C#, la valeur d’un float ou un double se calcule ainsi :

Le calcul se fait donc en base 2. Les valeurs décimale de d1 et d2 n’ont pas de valeurs binaires exactes. Ces deux arrondis aboutissent à ce qui semble être une erreur de calcul.

Cet arrondi en valeurs binaires est similaire à celui de 1/3 en valeur décimale.

La solution

Il est possible d’accepter une marge d’erreur :

Il est également possible d’utiliser decimal à la place de double. Ce type se base sur des valeurs décimales. On y stocke donc de manière exacte toute valeur décimale. En revanche, un decimal est deux fois plus gros en mémoire, et les calculs sont plus lents. Vraiment plus lents. Genre entre 20 et 100 fois plus lents (selon les opérations).

Si on veut faire des calculs monétaires, on ne peut pas se permettre un arrondi. On utilise donc forcément du decimal. Sinon, double convient tout-à-fait dans la plupart des cas.

Surcharge² – override et overload

Le problème

Child.MyMethod(int semble évidemment être le meilleur candidat. Pourtant, c’est Child.MyMethod(object) qui est appelé.

La raison

La surcharge (override) d’une méthode remplace le comportement de la méthode du parent, mais ne déclare pas une méthode dans la classe enfant. La classe Child elle-même ne déclare qu’une seule méthode : MyMethod(object). Pour trouver le meilleur candidat lors d’un appel, la surcharge (overload) va commencer par chercher les méthodes déclarées sur la classe. Si aucune ne correspond, il recherche sur la classe parente, et ainsi de suite jusqu’à rechercher sur System.Object.

La solution

Le plus simple est de ne pas mixer les deux (override et overload). Pour cela, soit on nomme différemment Child.MyMethod(object), soit on remplace override sur Child.MyMethod(int) par new (attention, cela masque la méthode du parent, mais ne modifie pas son comportement).

L’autre solution est d’appeler MyMethod(integerValue) sur une référence de type Parent. Ainsi, la seule méthode disponible est Parent.MyMethod(int), surchargée (donc dont le comportement est remplacé) par Child.MyMethod(int).

Variables externes dans une lambda

Le problème

Et là, plutôt que d’obtenir toutes les valeurs de 0 à 9, j’obtiens 10 fois la valeur 10.

La raison

Dans une lambda (ou de manière plus générale, une méthode anonyme), lorsqu’on utilise une variable externe, c’est la variable elle-même qui est capturée, et non sa valeur. Lors de l’exécution des actions, la variable i a la valeur 10 puisqu’il s’agit de la condition de sortie de la boucle et qu’on se trouve après celle-ci.

« Mais si la lambda capture la variable et non la valeur, puisque la variable i est déclarée dans le bloc for, elle ne devrait donc plus exister après ! »

Très bonne remarque ! On peut remercier le compilateur C# qui est très intelligent et remarque que la variable i est utilisée dans une lambda. Et là, il va bosser ! Il va créer une classe cachée contenant une méthode correspondant à la lambda, va créer dans cette classe un champ public de type int pour sauvegarder i, va remplacer la déclaration de i par la création d’un objet de la classe en question et enfin va remplacer chaque occurrence de i dans le code par un accès au champ de l’objet qu’il vient de créer. i ayant été remplacé par le champ d’une classe, elle se trouve dans la heap et sa désallocation sera faite normalement par le garbage collector quand plus aucune référence à l’objet en question n’existera.

La solution

Il suffit de ne pas utiliser la même variable dans chaque lambda, mais d’utiliser une variable différente, initialisée à la valeur courante de i à l’intérieur de la boucle. Pour cela, un simple int val = i; entre les lignes 4 et 5, et un remplacement de i par val dans le Console.WriteLine(i); et le tour est joué. A chaque itération, val correspond à une nouvelle allocation, donc chaque action a sa val.

++ et threads

Le problème

Et là, j’affiche bien un mil… ah non, 453622… Entre les double et les incrémentations, on dirait que le C# ne sait pas compter.

La raison

L’incrémentation, même si c’est un simple opérateur, englobe 3 actions :

  • On récupère la valeur de la variable
  • On ajoute 1
  • On sauvegarde la nouvelle valeur

Celles-ci ne sont pas atomiques, c’est-à-dire que plusieurs threads concurrents peuvent entremêler ces actions. Prenons un cas extrême : le calcul est réparti sur un million de threads. Chacun demande la valeur de la variable : 0. Ensuite, chacun ajoute 1 : 0+1 = 1. Enfin, chacun sauvegarde sa nouvelle valeur : 1.

La solution

La solution la plus générique consiste à rendre l’opération atomique via un lock :

Cependant, pour certaines opérations simples (incrémentation, décrémentation, somme…), il existe la classe statique Interlocked permettant d’effectuer ces opérations atomiquement bien plus rapidement qu’avec un lock :

Appels synchrones sur une méthode asynchrone

Le problème

 

XAML : Récupérer un chemin vectoriel à partir d’une image ou d’une icône

Bonjour à tous,

Pour les logos de type flat il est intéressant d’utiliser un chemin vectoriel au lieu d’une image. Ceux-ci prennent moins de place et peuvent être utilisés  sur toutes les tailles sans problème de pixellisation ou de perte de détail. Par exemple avec ceux-ci pas besoin d’avoir différentes icônes en fonction de la résolution d’écran de votre utilisateur.

Voici un simple exemple d’utilisation d’une image vectoriel

<ViewBox>
<Path Fill="Black" 
Data="m 47.5625 330.9375 0 -264.375 343.125 0 343.125 0 0 264.375 0 264.375 -132.1875 0 -132.1875 0 0 -26.71875 0 -26.71875 105.46875 0 105.46875 0 0 -210.9375 0 -210.9375 -289.6875 0 -289.6875 0 0 210.9375 0 210.9375 105.46875 0 105.46875 0 0 26.71875 0 26.71875 -132.1875 0 -132.1875 0 0 -264.375 z m 316.875 130.55176 0 -132.88574 -33.52243 33.51273 -33.52243 33.51273 -18.50579 -18.52317 -18.5058 -18.52317 65.15322 -65.14816 65.15323 -65.14817 65.15323 65.14817 65.15322 65.14816 -18.5058 18.52317 -18.50579 18.52317 -33.52243 -33.51273 -33.52243 -33.51273 0 132.88574 0 132.88574 -26.25 0 -26.25 0 0 -132.88574 z"
/>
</ViewBox>

Si vous travaillez avec des designers vous pouvez demander à ceux-ci de vous fournir une image au format svg.

 

Pour récupérer le chemin vectoriel j’utilise l’outil inkscape que vous pouvez récupérer gratuitement https://inkscape.org/fr/telecharger/windows/ :

  1. Ouvrez votre fichier vectoriel (format .svg) avec inkscape
  2. Enregistrez-sous au format xaml microsoft
  3. Ouvrez le fichier extrait et récupérez le path que vous pourrez réutiliser dans votre xaml

blog ai3 svg-1024x626 XAML :  Récupérer un chemin vectoriel à partir d'une image ou d'une icône

Si vous disposez uniquement  de l’image au format png il faut ajouter quelques étapes :

  1. Ouvrez votre fichier image avec inkscape (pour un bon résultat prévoyez une grande image simple)
  2. Clic droit sur l’image, vectoriser le bitmap
  3. Si vous le souhaitez, vous pouvez configurer la vectorisation puis valider
  4. Cliquer à nouveau sur l’image et supprimer l’image
  5. Vous aurez ensuite au premier plan votre image vectoriel et n’aurez qu’à l’exporter comme dans le premier exemple

blog ai3 vectoriser-1024x640 XAML :  Récupérer un chemin vectoriel à partir d'une image ou d'une icône

Plus d’excuse pour avoir des icônes pixelisées dans vos applications !

Thierry

Build 2016 : les nouveautés UWP que vous avez peut-être manquées

Bonjour à tous,

La Build 2016 de Microsoft est maintenant passée avec son lot de grandes nouveautés annoncées aux conférences principales.

En parallèle de nombreuses nouveautés ont été présentées lors des conférences annexes, voici celles qui ont attiré mon attention et que vous avez peut-être manquées. Certaines sont déjà en places et d’autres sont en phase de test et ne sont pas encore accessibles, n’hésitez pas à visionner les replay des conférences de la build et plus précisément celui-ci pour de plus amples détails.

La composition et ses effets enrichis

blog ai3 1_graphicIsland Build 2016 : les nouveautés UWP que vous avez peut-être manquées

Afin de permettre des effets visuels plus poussés et plus performants de nombreuses mise à jour ont été apportées à la composition.

  • Nouveaux effets tels que les effets de lumière, d’ombre et de flou.
  • Possibilité de lier une animation à une propriété d’un élément graphique (scroll, position…)
  • Simplification des effets de continuités entre deux pages

L’équipe travaille activement sur la composition et de nombreuses nouveautés arriveront dans le futur à ce niveau. La composition se confirme comme la nouvelle technologie sur laquelle travailler si l’on veut des effets complexes et performants.

Possibilité de lier son application à un type d’url

La solution actuelle pour lancer votre application depuis une autre application est d’utiliser un lien avec un format propre. La limitation de ce système est que seuls les propriétaires de l’application pourront ouvrir ce lien. Ceux qui n’ont pas l’application d’installée sur leur smartphone seront redirigés vers le store.

Il sera maintenant possible de lier votre application à un type d’url internet. Par exemple si vous avez l’application viadeo installée et que vous recevez un mail contenant un lien vers un profil, le clic sur ce lien n’ouvrira pas le site internet de viadeo mais l’application vers le profil de l’utilisateur. Une très bonne nouvelle donc.

Nombreuses améliorations au niveau de l’accessibilité

Entre autre il vous sera maintenant possible de débuguer votre application en mode narrateur. Dans ce cas votre écran sera noir, affichant uniquement les cadres des éléments sélectionnables avec le texte du narrateur pour chaque élément.

Simplification du background audio et plus de liberté sur les applications en background

blog ai3 task Build 2016 : les nouveautés UWP que vous avez peut-être manquées

Il ne faudra plus qu’une seule tache pour gérer la lecture audio en arrière-plan. Une annonce également de simplification du multi-threading avec moins d’utilisation des task sans plus de détail… à suivre.

Il sera notamment possible, spécialement dans le cas où l’appareil est connecté à un chargeur, de forcer son application à ne jamais passer en background. On peut imaginer de nombreux cas d’utilisation (gps, client de téléchargement, traitement de données…).

Appx le nouveau format d’installation des applications Windows

Conscient des limitations des installeurs actuels Microsoft pousse les appx comme le nouveau format d’installation des programmes Windows.

Plus besoin de lancer un script powershell, double cliquer sur un appx lancera directement l’installation de l’application, si l’appx est signée par un certificat de confiance il sera possible d’installer votre application sans passer par le store microsoft.

Grâce au projet centenial il sera possible de convertir les installeurs classiques en appx facilement et d’ainsi déployer des applications et jeux classique sur le store Microsoft. Les appx permettent une plus grande propreté lors de l’installation et de la désinstallation. Fini les clefs de registres, dll et fichiers obsolètes après une désinstallation. Le processus de mise à jour s’en trouve également simplifié pour les utilisateurs.

Le projet Rome et la synchronisation multi-device

blog ai3 rome-1024x518 Build 2016 : les nouveautés UWP que vous avez peut-être manquées

Avec une même application installée sur plusieurs appareils (Windows Phone, Xbox, Iphone…) par le même utilisateur il sera maintenant possible de facilement échanger entre les différentes applications. Par exemple un utilisateur ayant lancé une vidéo sur son Iphone, une fois rentré chez soi, pourra lancer depuis son Iphone le lecteur vidéo de sa Xbox et ainsi reprendre sa vision sans interruption.

Enrichissement des tuiles et des notifications

De nombreuses nouveautés à ce niveau, commençons par les notifications :

  • Possibilité de personnaliser les groupes de notifications avec logo, grande image…
  • Plus d’actions sont disponibles directement depuis les notifications
  • Plus de templates sont également disponibles pour celles-ci

Pour les tuiles :

  • Plus de templates et de libertées disponible, même si évoquées les tuiles xaml ne sont toujours pas possibles.
  • Possibilité de garder le contexte d’une tuile lorsque l’on clic sur celle-ci. Par exemple si vous cliquer sur une tuile alors qu’une image est affichée il est possible de récupérer le nom de l’image dans les arguments de lancement de l’application.

Pour finir des compteurs peuvent maintenant être affiché sur l’icône d’une application épinglée à la barre des tâches et il sera très simple de synchroniser l’ensemble des indicateurs sur les tuiles et notifications en temps réel.

 

J’espère que vous avez pu découvrir de nouvelles fonctionnalités, cet article n’est pas exhaustif et de nombreuses autres évolutions ont été annoncées.

Thierry,

UWP : Empêcher les ContentDialog de prendre tout l’écran

Bonjour à tous,

Une petite astuce au niveau du comportement des ContentDialog.

Celles-ci ont un comportement par défaut qui peut s’avérer gênant. En fonction de la hauteur de la fenêtre elles vont :

blog ai3 content-dialog-1024x356 UWP : Empêcher les ContentDialog de prendre tout l'écran

-Être centrées

-Être fixées en haut

-Prendre toute la hauteur disponible

Le dernier comportement (qui peut être forcé avec la propriété FullSizeDesired) peut être gênant avec parfois deux tiers de contenu vide dans son content dialog.

Le workaround pour éviter ce comportement :

Lors de l’initialisation de votre contentdialog définissez la MaxHeight de celle-ci à la taille de la fenêtre actuelle moins trente:

[pastacode lang= »cpp » message= » » highlight= » » provider= »manual »]

[/pastacode]

La limite de ce workaround est si l’utilisateur change la hauteur de la fenêtre.

Thierry,