Wersja .NET 4.0 zestawu Microsoft.Build zawiera klasę SolutionParser w przestrzeni nazw Microsoft.Build.Construction, która analizuje pliki rozwiązań programu Visual Studio.
Niestety ta klasa jest wewnętrzna, ale zawarłem część tej funkcji w klasie, która używa odbicia, aby uzyskać dostęp do niektórych typowych właściwości, które mogą okazać się pomocne.
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();
}
}
Zauważ, że musisz zmienić platformę docelową na „.NET Framework 4” (nie profil klienta), aby móc dodać odwołanie Microsoft.Build do projektu.
SolutionFile
Microsoft.Build.dll wprowadzono nową klasę publiczną, która jest instalowana z programem Visual Studio 2015 (patrz msdn.microsoft.com/en-us/library/ ... )W programie Visual Studio 2015 istnieje teraz publicznie dostępna
SolutionFile
klasa, której można użyć do analizowania plików rozwiązań:Ta klasa znajduje się w zestawie Microsoft.Build.dll 14.0.0.0 . W moim przypadku znajdował się pod adresem:
Dzięki Philowi za wskazanie tego !
źródło
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
Nie wiem, czy ktoś nadal szuka rozwiązania tego problemu, ale trafiłem na projekt, który wydaje się robić dokładnie to, co jest potrzebne. https://slntools.codeplex.com/ Jedną z funkcji tego narzędzia jest łączenie wielu rozwiązań.
źródło
JetBrains (twórcy Resharper) mają publiczne możliwości parsowania sln w swoich zespołach (nie jest wymagana refleksja). Jest prawdopodobnie bardziej wytrzymały niż sugerowane tutaj istniejące rozwiązania open source (nie mówiąc już o hackach ReGex). Wszystko, co musisz zrobić, to:
JetBrains.Platform.ProjectModel
JetBrains.Platform.Util
JetBrains.Platform.Interop.WinApi
Biblioteka nie jest udokumentowana, ale Reflector (a właściwie dotPeek) jest Twoim przyjacielem. Na przykład:
źródło
Naprawdę nie mogę ci zaoferować biblioteki i przypuszczam, że nie ma takiej, która tam istnieje. Ale spędziłem sporo czasu na zabawie z plikami .sln w scenariuszach edycji wsadowej i odkryłem, że Powershell jest bardzo przydatnym narzędziem do tego zadania. Format .SLN jest dość prosty i można go prawie całkowicie przeanalizować za pomocą kilku szybkich i brudnych wyrażeń. Na przykład
Dołączone pliki projektu.
Nie zawsze jest ładny, ale jest skutecznym sposobem przetwarzania wsadowego.
źródło
rozwiązaliśmy podobny problem automatycznego scalania rozwiązań, pisząc wtyczkę Visual Studio, która utworzyła nowe rozwiązanie, a następnie wyszukała plik * .sln i zaimportowała je do nowego za pomocą:
Nasz problem był nieco inny, ponieważ chcieliśmy, aby VS uporządkował dla nas kolejność kompilacji, więc wtedy, gdy było to możliwe, przekonwertowaliśmy wszelkie odwołania dll na odwołania do projektu.
Następnie zautomatyzowaliśmy to w procesie kompilacji, uruchamiając VS za pośrednictwem automatyzacji COM.
To rozwiązanie było trochę Heath Robinson, ale miało tę zaletę, że VS robił edycję, więc nasz kod nie był zależny od formatu pliku sln. Co było pomocne, gdy przeszliśmy z VS 2005 na 2008 i ponownie na 2010.
źródło
Wszystko jest świetne, ale chciałem również uzyskać możliwość generowania sln - w migawce kodu powyżej analizujesz tylko pliki .sln - chciałem zrobić podobną rzecz, z wyjątkiem możliwości ponownego wygenerowania sln z niewielkimi modyfikacjami z powrotem do pliku .sln . Takimi przypadkami może być na przykład przeniesienie tego samego projektu na inną platformę .NET. Na razie to tylko re-generacja sln, ale później rozszerzę to również na projekty.
Wydaje mi się, że chciałem także zademonstrować potęgę wyrażeń regularnych i natywnych interfejsów. (Mniejsza ilość kodu z większą funkcjonalnością)
Aktualizacja 4.1.2017 Utworzyłem osobne repozytorium svn do parsowania rozwiązania .sln: https://sourceforge.net/p/syncproj/code/HEAD/tree/
Poniżej znajduje się mój własny przykładowy fragment kodu (poprzednik). Możesz używać dowolnego z nich.
Możliwe, że w przyszłości kod parsowania rozwiązania opartego na svn zostanie zaktualizowany z możliwościami generowania.Aktualizacja 4.2.2017 Kod źródłowy w SVN obsługuje również generowanie .sln .
źródło
Wyjaśniłem, ustaliłem, że klasy MSBuild mogą być używane do manipulowania podstawowymi strukturami. Dalszy kod będę miał później na mojej stronie internetowej.
źródło
relativepath
staje się adresem URL, pod którym witryna powinna działać w IISExpress itp.Odpowiedź @ john-leidegren jest świetna. W przypadku wersji przed VS2015 jest to bardzo przydatne. Ale był drobny błąd, ponieważ brakowało kodu do pobierania konfiguracji. Więc chciałem to dodać, na wypadek, gdyby ktoś miał problemy z użyciem tego kodu.
Ulepszenie jest bardzo proste:
Dodatkową pomocą jest zapewnienie prostego kodu do przeglądania właściwości a,
System.Type
zgodnie z sugestią @oasten.źródło
Na co warto, stworzyłem teraz mały projekt do odczytu plików sln i proj dostępnych na nuget:
https://www.nuget.org/packages/ByteDev.DotNet/
źródło
Dzięki @John Leidegren oferuje skuteczny sposób. Piszę klasę hlper, ponieważ nie mogę użyć jego kodu, który nie może znaleźć pliku
s_SolutionParser_configurations
projektów i projektów bez FullName.Kod jest w githubie który może pobrać projekty z FullName.
A kod nie może uzyskać SolutionConfiguration.
Ale kiedy stworzysz vsx, vs powie, że nie można znaleźć
Microsoft.Build.dll
, więc możesz spróbować użyć dte, aby uzyskać wszystkie projekty.Kod, który używa dte do pobierania wszystkich projektów, znajduje się na github
źródło