vendredi 24 octobre 2008
Failure adding assembly to the cache: Access denied.
Ce matin j'ai eu besoin d'enregistrer ma Dll signée dansle GAC de notre serveur de build qui est sous Windows 2008.
Manipulation super simple en principe puisque qu'un simple drag and drop de la Dll dans le répertoire %WINDIR%\Assembly\ et hop ! Ou alors, on peut aussi utiliser (et c'est recommandé) l'utilitaire gacutil.
Mais avec Windows 2008 (il semble qu'on observe la même chose sous Vista) le drag and drop tout comme le gacutil vous renvoi un message d'erreur Failure adding assembly to the cache: Access denied. Très désagréable et surprenant au premier abord lorsqu'on a les droits d'administrateur.
L'astuce est donc de démarrer la ligne de commande MS-DOS en faisant "clique droit -> run as Administrator" pour utiliser gacutil. Et la c'est tout bon, la dll est enregistrée dans le GAC.
Je n'ai pas le temps aujourd'hui de fouiller plus que ça les principes qui régissent ce fonctionnement mais si quelqu'un a une explication ou un lien pour aider à la compréhension, n'hésitez pas à laisser un commentaire.
Edit le 24/10/2008 à 15:00 :
En posant la question à des collègues de l'exploitation j'ai eu une réponse. En fait c'est lié au "nouveau " fonctionnement de la sécurité dans Windows Vista et 2008. Tout utilisateur ayant les droits d'administration, peut accéder aux fonctionnalités des administrateurs mais doivent explicitement indiquer qu'ils souhaitent réaliser une action en tant qu'administrateur en utlilisant le menu "clique droit -> Run as Administrator".
C'est plus clair comme ça, non ?
vendredi 19 septembre 2008
Petite introduction sur DbPro de Visual Studio Team System
Voici, après quelques heures d'utilisation, ce que propose DbPro.
Grace à DbPro nous pouvons "aspirer" le modèle de notre base de données existante et Visual Studio nous créer un projet DbPro qui cohabite avec nos autres projets de la solution et qui contient les scripts de tous les objets de notre base de données (table, vues, user, procédures...). Assez génial ! Du coup tous les scripts de la base de données sont sauvegardés dans le serveur de code source de la même manière qu'un fichier CS ou VB. Fini l'écrasement accidentel et la perte définitive d'une procédure stockée qui à prit 5 jours de réalisation, tout est dans le serveur de code source !
DbPro va encore plus loin car il permet d'éditer tous les objets de la base de données dans Visual Studio (plus besoin de Sql Manager Studio, ou presque) et surtout, génère le script de déploiement vers la base de données cible. Ici Microsoft facilite un autre point crucial dans le cycle de développement qu'est le recensement des modifications apportées à une base de données durant une phase de développement.
Dans un contexte d'intégration continu on peut bien sur envisager le déploiement automatique des modifications de base de données à chaque check-in. Il suffit de modifier un peu la déclaration de son serveur de build Team System pour que ce dernier compile le projet Dbpro et déploie les modifications sur le serveur d'intégration ! C'est exactement ce que je mets en place actuellement. C'est plutôt simple à réaliser et les MSDN documentent assez bien le sujet.
Dans mon prochain article je vais ajouter quelques liens pour la mise en oeuvre de DbPro avec Team Build, plus quelques petit tips que j'aurais découvert.
Bien à vous.
lundi 4 août 2008
Déploiement de clé de registre avec valeur par défaut dans un MSI
Exemple :
Je veux créer une clé de registre avec comme valeur par défaut "toto va au marcher".
Si j'ajoute simplement une string value à ma clé et que je lui donne comme nom (Default), on pourrait croire que ça marchera mais en fait non. Le MSI va créer 2 clés de registre avec le nom (Default), une avec ma valeur "toto va au marcher" et une sans valeur.
Résolution :
Et la où c'est pas terrible c'est que le designer ne propose pas de solution évidente à part une manipulation sordide trouvé dans les MSDN : http://msdn.microsoft.com/fr-fr/library/xkfz6802(en-us).aspx. En voici un extrait au cas où Microsoft décide de fermer la page... par honte du contenu :
...
To specify a default value :
- Select a value name in the right-hand
pane of Registry Editor.
- Right-click the value name and then click Rename.
- On the Edit menu, click Delete.
- Press ENTER. The name is replaced
with '(Default)'.
...
Le plus moche c'est que cette manipulation n'a pas fonctionné pour moi...
La solution qui a marcher pour moi c'est de créer un fichier .reg à partir de l'éditeur de base de registre et de l'importer ensuite dans le designer de Visual Studio. (Clique droit sur Registry Target Machine -> Import)
Bonne programmation à tous.
mercredi 30 juillet 2008
Créer des tâches personnalisées pour un Team Build
But
Créer une tâche personnalisée qui sera exécutable par un serveur de build Team System.Pré requis
Configuration de la machine de développement :La création de build custom task se fait en VB ou en C# dans Visual Studio et se base sur l'API de Team System. Donc il faut un Visual Studio + l'installation du SDK Team System ou plus simple, Visual Studio Team System.
Configuration du serveur de build (Team Build) :
Pour que le serveur de build puisse compiler la documentation du code en se basant sur SandCastle, il faut bien sur installer SandCastle... Logique non ? Allez voir sur http://www.codeplex.com pour avoir la dernière version.
Ensuite il faut installer SandCastleBuilder sur le serveur de build (l'application qui permettra de compiler l'aide grâce à des projets de documentation), voir aussi sur http://www.codeplex.com pour le téléchargement.
Scénario 1 :
Le serveur de build exécute les tâches qui sont définies dans le fichier tfsbuild.proj. Le format de ce fichier de projet est écrit dans le standard MSBuild et propose différentes choses, dont notamment la possibilité d'exécuter une ligne de commande. On va donc pouvoir compiler la documentation de notre code avec SandCastleBuilder (voir pré requis dans le scénario 2) en l'appelant depuis le fichier de projet du team build.
Le code de l'exemple :
<target name="GenerateDocumentation">
<propertygroup>
<sandcastlebuidlerpath>C:\Program Files\EWSoftware\Sandcastle Help File Builder\SandcastleBuilderConsole.exe</sandcastlebuidlerpath>
<sandcastlebuilderprojectfile>..\Sources\DemoDocumentation\DemoDocumentation.shfb</sandcastlebuilderprojectfile>
<sandcastlebuilderarguments>-OutputPath="$(OutDir)\"</sandcastlebuilderarguments>
</propertygroup>
<exec command="">
</exec>
Scénario 2 :
On étudie ici l'ajout d'une tâche qui consiste à compiler la documentation du code avec SandCastleBuilder, après la compilation du code.
Le serveur de build va donc exécuter les tâches dans l'ordre suivant :
- prendre la dernière version des sources
- compiler la solution (sln)
- exécuter les tests unitaires existants
- compiler la documentation du code compilé en 1
Création de la custom task :
Une custom task est encapsulée dans une Dll .Net qui sera référencée dans le fichier de projet du Team Build (tfsbuild.proj). Pour rappel ce fichier de projet est un fichier type MSBuild, donc pour plus d'informations sur ce format rechercher MSBuild dans Google.
- Nous créons un projet de type ClassLibrary dans Visual Studio
- Nous lui ajoutons les références aux assemblies de Team System :
- . Microsoft.Build.Framework
- . Microsoft.TeamFoundation.Client
- . Microsoft.TeamFoundation.Build.Common
- . Microsoft.Build.Framework
- On supprime Class1.cs qui ne sert à rien...
- On ajoute notre nouvelle classe qui va nous permettre de compiler la documentation de code. Je vais l'appeler BuildHelp.
- Microsoft nous propose 2 manières d'implémenter une classe tâche de build. Soit hériter de la classe Microsoft.Build.Utilities.Task ou alors implémenter l'interface Microsoft.Build.Framework.ITask. Dans notre exemple nous prendrons la première solution, plus rapide à implémenter.
- La classe Task est une classe abstraite et définie la méthode Execute() comme abstraite, nous la surchargeons donc dans notre classe BuildHelp. C'est cette méthode qui sera invoquée par le serveur de build pour déclencher le travail de notre custom task.
- Le code de notre fonction Execute() est plutôt simple puisqu'il consiste à appeler le programme SandCastleBuilderConsole.exe en lui passant en paramètres, le projet SandCastleBuilder qui contient tous les paramètres de génération de documentation.
Voici du code simple (pour l'exemple) pour faire ceci :
public override bool Execute()
{
// Création du processInfo
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(@"SandcastleBuilderConsole.exe");
psi.Arguments = "monProjet.shfb";
psi.RedirectStandardOutput = true;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
System.Diagnostics.Process sandCastleBuilder = null;
// La fonction Log.LogCommandLine() est fournie par Team System et permet d'écrire dans le journal de build
Log.LogCommandLine(MessageImportance.Low, @"SandcastleBuilderConsole.exe" + " " + "monProjet.shfb");
sandCastleBuilder = System.Diagnostics.Process.Start(psi); // Démarre le programme de compilation de la documentation
sandCastleBuilder.WaitForExit(MAX_WAITING_TIME);
return true;
}
La valeur que retourne la fonction Execute() permet au serveur de build de connaitre le résultat de la tâche qu'il a démarré. True la tâche s'est déroulée avec succès, sinon false.
9- Pour ajouter la custom task au serveur de build, on édite le fichier projet du serveur de build, le fameux fichier tfsbuild.proj. On lui ajoute notre tâche à la fin après la dernière balise <ItemGroup>:
<usingtask taskname="Reseaux.TeamSystem.Build.CustomTask.BuildHelp" assemblyfile="$(SolutionRoot)\\DemoDocumentation\\Reseaux.TeamSystem.Build.CustomTasks.dll">10- Pour pouvoir exécuter notre custom task, le serveur de build doit pourvoir la trouver, donc on peut la mettre dans le répertoire de la solution (il y a d'autres méthodes, voir dans Google et/ou les MSDN). On ajoute donc la Dll générée qui contient notre custom task, dans le contrôle de code source Team System, à coté du fichier sln que notre serveur de build compile.
<target name="GenerateDocumentation">
<buildhelp>
</buildhelp>
11- On archive tout (le fichier projet du TeamBuild, la Dll de la customTask) et on démarre un nouveau build.
En principe dans le répertoire de sortie définit par le projet SandCastleBuilder, vous devriez y trouver l'aide compilée.
Si ce n'est pas le cas aller voir dans le fichier de log du serveur de build et rechercher l'appel à votre custom task pour voir si une erreur est remontée.
Ajouter l'output de SandCastleBuilder : Bon aller il y a de grandes chances pour que le shfb qui tourne en local se comporte autrement sur le serveur de build, donc ça serait cool d'avoir l'output de SansCastleBuilderConsole dans le fichier de log du serveur de build. Pour faire ça, on remplace le code de notre Custom Task pour obtenir ceci :
public override bool Execute()
{
bool result = false;
string applicationName = @"SandcastleBuilderConsole.exe";
string parameters = "monProjet.shfb";
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(applicationName);
psi.Arguments = parameters;
psi.RedirectStandardOutput = true;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
System.Diagnostics.Process sandCastleBuilder = null;
try
{
Log.LogCommandLine(MessageImportance.Low, applicationName + " " + parameters);
sandCastleBuilder = System.Diagnostics.Process.Start(psi);
}
catch (ObjectDisposedException e)
{
Log.LogErrorFromException(e, true);
}
catch (InvalidOperationException e)
{
Log.LogErrorFromException(e, true);
}
catch (ArgumentNullException e)
{
Log.LogErrorFromException(e, true);
}
catch (Win32Exception e)
{
Log.LogErrorFromException(e, true);
}
finally
{
if (sandCastleBuilder != null)
sandCastleBuilder.WaitForExit(MAX_WAITING_TIME);
}
try
{
string errorMessage = string.Empty;
string logMessage = string.Format("No output available for {0}", applicationName);
if (sandCastleBuilder.HasExited)
{
string applicationOutput = sandCastleBuilder.StandardOutput.ReadToEnd();
if (sandCastleBuilder.StandardOutput != null)
logMessage = string.Format("See {0} output bellow :\r\n{1}", applicationName, applicationOutput);
if (applicationOutput.IndexOf("Fatal error") != -1)
errorMessage = "See previous error in application output";
else
result = true;
}
Log.LogMessage(logMessage); // Affiche la sortie de l'outil
if (errorMessage.Length > 0)
Log.LogError(errorMessage, null);
}
catch (InvalidOperationException e)
{
Log.LogErrorFromException(e, true);
}
catch (Win32Exception e)
{
Log.LogErrorFromException(e, true);
}
catch (NotSupportedException e)
{
Log.LogErrorFromException(e, true);
}
return result;
}
Rendre les arguments de notre custom task paramétrables, dans le fichier projet Team Build :
Ce qui est pratique c'est qu'on peut facilement définir des paramètres à notre classe custom task. Ces paramètres sont automatiquement lus dans le fichier projet et envoyé à notre custom task par le serveur de build.
Il faut donc ajouter une propriété publique à notre classe BuildHelp. Cette propriété doit portée l'attribut [Required].
Par exemple on peut définir le nom et l'emplacement du fichier projet de documentation à compiler (.shfb)
[Required]
public string SandCastleBuilderProjectFile
{
get { return _sandCastleBuilderProjectFile; }
set { _sandCastleBuilderProjectFile = value; }
}
Et dans le fichier projet, on ajoute le paramètre :
<buildhelp sandcastlebuilderprojectfile=""..\Sources\DemoDocumentation\DemoDocumentation.shfb" ">
</buildhelp></target>/<usingtask></target>
Voilà pour l'essentiel.
Sur mes projets, à ce jour j'ai préféré n'utiliser que la configuraion du fichier TFSBuild.proj en faisant appel aux outils externes via la commande <exec.../> utilisable dans les fichiers MSBUILD. Ca me permet de faire ce dont j'ai besoin (compilation de la documentation de code, regroupement de Dll en une seule et packaging dans un MSI) sans avoir à maintenir de code supplémentaire qui serait induit par l'utilisation de custom task codée en C# ou VB.
J'espère que ça vous aidera à démarrer sur le sujet.
Bien sur, Google est très parlant sur le sujet.
jeudi 17 juillet 2008
TeamSystem : Comment supprimer définitivement un WorkItem
La commande tfpt.exe fait partie des PowerTools de Team System :
Télécharger les ici http://msdn2.microsoft.com/en-us/tfs2008/bb980963.aspx
Ajouter vos assemblies dans la boite de dialogue "Add References" de Visual Studio
Quoi de plus chouette lorsqu'on distribue sa/ses Dll, que de la voir apparaitre dans la fenêtre "Add References" de Visual Studio ?
Certainement plein de choses, mais ce petit tips fait bon effet et peut faciliter la vie des clients de votre Dll.
Il suffit d'ajouter une clé de registre ici HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\ avec comme valeur le chemin vers le répertoire contenant votre / vos Dll.
Exemple :
- je veux ajouter les Dll contenues dans le dossier C:\Program Files\Common Files\MonProduit, il faut ajouter la clé suivante dans la base de registre :
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\MonProduit
@="C:\\Program Files\\Common Files\\MonProduit"
La modification sera prise en compte lors du démarrage d'une nouvelle instance de Visual Studio.
Voilà ! Et bon codage.
mercredi 23 avril 2008
Ouverture du blog
Voici quelques temps déjà que je réfléchi à faire un blog. En effet un blog c'est bien mais il s'agit d'y mettre un peu de contenu attrayant. Alors après avoir pensé à diverses sujets (toujours autour de l'informatique bien sûr) j'ai décidé de limiter le champ et de le consacrer au développement Miscrosoft .NET.
C'est un sujet déjà très vaste en soit et il y aura toujours pleins de choses intéressantes à en dire, sans compter que c'est un des sujets que je maîtrise le mieux. Quitte à partager de l'information autant qu'elle soit de bonne qualité et éclairé par un point de vue (certe subjectif) mais expérimenté.
J'en profite pour me présenter ce qui vous aidera à mieux me connaitre : je fais du développement depuis plus de 6 ans dont 4 en C\C++ et 3 en .Net.