Comment puis-je analyser les fichiers de la solution Visual Studio (SLN) dans .NET? Je voudrais écrire une application qui fusionne plusieurs solutions en une seule tout en enregistrant l'ordre de construction relatif.
la source
Comment puis-je analyser les fichiers de la solution Visual Studio (SLN) dans .NET? Je voudrais écrire une application qui fusionne plusieurs solutions en une seule tout en enregistrant l'ordre de construction relatif.
La version .NET 4.0 de l'assembly Microsoft.Build contient une classe SolutionParser dans l'espace de noms Microsoft.Build.Construction qui analyse les fichiers de solution Visual Studio.
Malheureusement, cette classe est interne, mais j'ai intégré une partie de cette fonctionnalité dans une classe qui utilise la réflexion pour accéder à certaines propriétés courantes que vous pourriez trouver utiles.
public class Solution
{
//internal class SolutionParser
//Name: Microsoft.Build.Construction.SolutionParser
//Assembly: Microsoft.Build, Version=4.0.0.0
static readonly Type s_SolutionParser;
static readonly PropertyInfo s_SolutionParser_solutionReader;
static readonly MethodInfo s_SolutionParser_parseSolution;
static readonly PropertyInfo s_SolutionParser_projects;
static Solution()
{
s_SolutionParser = Type.GetType("Microsoft.Build.Construction.SolutionParser, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
if (s_SolutionParser != null)
{
s_SolutionParser_solutionReader = s_SolutionParser.GetProperty("SolutionReader", BindingFlags.NonPublic | BindingFlags.Instance);
s_SolutionParser_projects = s_SolutionParser.GetProperty("Projects", BindingFlags.NonPublic | BindingFlags.Instance);
s_SolutionParser_parseSolution = s_SolutionParser.GetMethod("ParseSolution", BindingFlags.NonPublic | BindingFlags.Instance);
}
}
public List<SolutionProject> Projects { get; private set; }
public Solution(string solutionFileName)
{
if (s_SolutionParser == null)
{
throw new InvalidOperationException("Can not find type 'Microsoft.Build.Construction.SolutionParser' are you missing a assembly reference to 'Microsoft.Build.dll'?");
}
var solutionParser = s_SolutionParser.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(null);
using (var streamReader = new StreamReader(solutionFileName))
{
s_SolutionParser_solutionReader.SetValue(solutionParser, streamReader, null);
s_SolutionParser_parseSolution.Invoke(solutionParser, null);
}
var projects = new List<SolutionProject>();
var array = (Array)s_SolutionParser_projects.GetValue(solutionParser, null);
for (int i = 0; i < array.Length; i++)
{
projects.Add(new SolutionProject(array.GetValue(i)));
}
this.Projects = projects;
}
}
[DebuggerDisplay("{ProjectName}, {RelativePath}, {ProjectGuid}")]
public class SolutionProject
{
static readonly Type s_ProjectInSolution;
static readonly PropertyInfo s_ProjectInSolution_ProjectName;
static readonly PropertyInfo s_ProjectInSolution_RelativePath;
static readonly PropertyInfo s_ProjectInSolution_ProjectGuid;
static readonly PropertyInfo s_ProjectInSolution_ProjectType;
static SolutionProject()
{
s_ProjectInSolution = Type.GetType("Microsoft.Build.Construction.ProjectInSolution, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
if (s_ProjectInSolution != null)
{
s_ProjectInSolution_ProjectName = s_ProjectInSolution.GetProperty("ProjectName", BindingFlags.NonPublic | BindingFlags.Instance);
s_ProjectInSolution_RelativePath = s_ProjectInSolution.GetProperty("RelativePath", BindingFlags.NonPublic | BindingFlags.Instance);
s_ProjectInSolution_ProjectGuid = s_ProjectInSolution.GetProperty("ProjectGuid", BindingFlags.NonPublic | BindingFlags.Instance);
s_ProjectInSolution_ProjectType = s_ProjectInSolution.GetProperty("ProjectType", BindingFlags.NonPublic | BindingFlags.Instance);
}
}
public string ProjectName { get; private set; }
public string RelativePath { get; private set; }
public string ProjectGuid { get; private set; }
public string ProjectType { get; private set; }
public SolutionProject(object solutionProject)
{
this.ProjectName = s_ProjectInSolution_ProjectName.GetValue(solutionProject, null) as string;
this.RelativePath = s_ProjectInSolution_RelativePath.GetValue(solutionProject, null) as string;
this.ProjectGuid = s_ProjectInSolution_ProjectGuid.GetValue(solutionProject, null) as string;
this.ProjectType = s_ProjectInSolution_ProjectType.GetValue(solutionProject, null).ToString();
}
}
Notez que vous devez modifier votre infrastructure cible en «.NET Framework 4» (pas le profil client) pour pouvoir ajouter la référence Microsoft.Build à votre projet.
SolutionFile
introduite dans Microsoft.Build.dll qui est installée avec Visual Studio 2015 (voir msdn.microsoft.com/en-us/library/… )Avec Visual Studio 2015, il existe désormais une
SolutionFile
classe accessible au public qui peut être utilisée pour analyser les fichiers de solution:Cette classe se trouve dans l' assembly Microsoft.Build.dll 14.0.0.0 . Dans mon cas, il était situé à:
Merci à Phil pour l' avoir signalé !
la source
Add-Type -Path "C:\Program Files (x86)\Reference Assemblies\Microsoft\MSBuild\v14.0\Microsoft.Build.dll"
$slnFile = [Microsoft.Build.Construction.SolutionFile]::Parse($slnPath);
$slnFile.ProjectsInOrder
Je ne sais pas si quelqu'un cherche encore des solutions à ce problème, mais j'ai rencontré un projet qui semble faire exactement ce qu'il faut. https://slntools.codeplex.com/ Une des fonctions de cet outil est de fusionner plusieurs solutions ensemble.
la source
JetBrains (les créateurs de Resharper) ont des capacités d'analyse des sln publics dans leurs assemblages (aucune réflexion n'est nécessaire). C'est probablement plus robuste que les solutions open source existantes suggérées ici (sans parler des hacks ReGex). Tout ce que vous avez à faire est:
JetBrains.Platform.ProjectModel
JetBrains.Platform.Util
JetBrains.Platform.Interop.WinApi
La bibliothèque n'est pas documentée, mais Reflector (ou en fait, dotPeek) est votre ami. Par exemple:
la source
Je ne peux pas vraiment vous offrir une bibliothèque et je suppose qu'il n'y en a pas une qui existe là-bas. Mais j'ai passé beaucoup de temps à jouer avec des fichiers .sln dans des scénarios d'édition par lots et j'ai trouvé que Powershell était un outil très utile pour cette tâche. Le format .SLN est assez simple et peut être presque complètement analysé avec quelques expressions rapides et sales. Par exemple
Fichiers de projet inclus.
Ce n'est pas toujours joli, mais c'est un moyen efficace de traiter par lots.
la source
nous avons résolu un problème similaire de fusion automatique des solutions en écrivant un plugin Visual Studio qui a créé une nouvelle solution puis recherché le fichier * .sln et les importé dans la nouvelle en utilisant:
Notre problème était légèrement différent dans la mesure où nous voulions que VS trie l'ordre de construction pour nous, nous avons donc converti toutes les références dll en références de projet lorsque cela était possible.
Nous avons ensuite automatisé cela dans un processus de construction en exécutant VS via l'automatisation COM.
Cette solution était un peu Heath Robinson, mais avait l'avantage que VS faisait l'édition donc notre code ne dépendait pas du format du fichier sln. Ce qui a été utile lorsque nous sommes passés de VS 2005 à 2008 et de nouveau à 2010.
la source
Tout est génial, mais je voulais aussi obtenir la capacité de génération de sln - dans l'instantané de code ci-dessus, vous ne faites qu'analyser les fichiers .sln - je voulais faire quelque chose de similaire, sauf pour pouvoir régénérer sln avec de légères modifications dans le fichier .sln . De tels cas pourraient être par exemple le portage du même projet pour une plate-forme .NET différente. Pour l'instant, ce n'est que la re-génération de sln, mais plus tard, je l'étendrai également aux projets.
Je suppose que je voulais aussi démontrer la puissance des expressions régulières et des interfaces natives. (Une plus petite quantité de code avec plus de fonctionnalités)
Mise à jour 4.1.2017 J'ai créé un référentiel svn séparé pour l'analyse de la solution .sln: https://sourceforge.net/p/syncproj/code/HEAD/tree/
Voici mon propre extrait de code (prédécesseur). Vous êtes libre d'utiliser l'un d'entre eux.
Il est possible qu'à l'avenir, le code d'analyse d'une solution basée sur svn soit également mis à jour avec des capacités de génération.Le code source de la mise à jour 4.2.2017 dans SVN prend également en charge la génération .sln.
la source
J'ai expliqué, déterminé que les classes MSBuild peuvent être utilisées pour manipuler les structures sous-jacentes. J'aurai plus de code sur mon site Web plus tard.
la source
relativepath
devient l'URL sous laquelle le site doit s'exécuter dans IISExpress, etc.La réponse de @ john-leidegren est géniale. Pour pré-VS2015, c'est d'une grande utilité. Mais il y avait une erreur mineure, car le code pour récupérer les configurations manquait. Je voulais donc l'ajouter, au cas où quelqu'un aurait du mal à utiliser ce code.
L'amélioration est très simple:
Comme aide supplémentaire, fournir un code simple pour parcourir les propriétés d'un
System.Type
comme suggéré par @oasten.la source
Pour ce que ça vaut, j'ai maintenant créé un petit projet pour lire les fichiers sln et proj disponibles sur nuget:
https://www.nuget.org/packages/ByteDev.DotNet/
la source
Merci @John Leidegren il offre un moyen efficace. J'écris une classe hlper car je ne peux pas utiliser son code qui ne trouve pas le
s_SolutionParser_configurations
et les projets sans FullName.Le code est dans github qui peut obtenir les projets avec le FullName.
Et le code ne peut pas obtenir SolutionConfiguration.
Mais quand tu devras un vsx, le vs dira que je ne peux pas trouver
Microsoft.Build.dll
, vous pouvez donc essayer d'utiliser dte pour obtenir tous les projets.Le code qui utilise dte pour obtenir tous les projets est dans github
la source