Czym jest Workspace API?
Co to jest Workspace?
Workspace reprezentuje solucje w Visual Studio. Klasy więc z tego api będą modelowały układ danej solucji.
Oczywiście rola tych klas nie kończy się tutaj. Przy użyciu tych klas możemy dodawać referencje do projektów i usuwać pliki.
Dla przypomnienia, co to jest solucja w Visual Studio.
Do przykładu użycia tego API stworzyłem solucje z aplikacją konsolową oraz z dwoma projektami WPF i ASP.NET MVC.
Aplikacja konsolowa posiada referencje do aplikacji WPF i ASP.NET MVC.
W tym wpisie zademonstruję, jak przy użyciu Workspace API można przeanalizować daną solucję. Z solucji, w której obecnie pracuję wyświetlę wszystkie projekty w niej zawarte oraz referencje dodane między projektami.
Cały kod wygląda tak:
static void Main(string[] args)
{
var msBuild = MSBuildWorkspace.Create();
var sln = msBuild.OpenSolutionAsync
(@"D:\PanNiebieski\Documents\visual studio 14\Projects\ConsoleApplicationWorkspaces"
+@"\ConsoleApplicationWorkspaces.sln").Result;
var g = sln.GetProjectDependencyGraph();
var ps = g.GetTopologicallySortedProjects();
foreach (var p in ps)
{
var proj = sln.GetProject(p);
Console.WriteLine();
Console.WriteLine(">>Project Name:" + proj.Name);
Console.WriteLine();
foreach (var item in proj.Documents)
{
Console.WriteLine("\t" + item.Name);
}
if (proj.ProjectReferences.Count() > 0)
Console.WriteLine("\tReferences:");
foreach (var item in proj.ProjectReferences)
{
Console.WriteLine("\t - \t"+sln.GetProject(item.ProjectId).Name);
}
}
Console.ReadKey();
}
Używając instancji obiektu klasy “Solution” mogę zrobić dużo rzeczy. Mogę dodać do solucji kolejny projekt. Mogę też uzyskać kolekcję projektów zawartych w danej solucji z właściwości “Projects”.
Korzystając z instancji klasy “ProjectDependencyGraph” zwracanej przez metodę “GetProjectDependencyGraph()”, mogę uzyskać informację na temat zależności pomiędzy projektami.
Mogę zdobyć wszystkie projekty zależne od podanego projektu X.
Korzystając z metody “GetTopologicallSortedProjects” z tego obiektu uzyskuję kolekcję identyfikatorów projektów z solucji, posortowanych od najmniejszej zależności do największej.
var ps = g.GetTopologicallySortedProjects();
Mając reprezentację projektu Visual Studio mogę do niego dodawać referencję i dokumenty.
Obecnie mając kolekcję projektów wyświetlam ich dokumenty oraz referencję do innych projektów, jeśli są
To wszystko, jeśli chodzi o prosty przykład.
Od razu zrodziło mi się pytanie jak połączyć Workspace API z API kompilacyjnym tak, aby tworzyć dll-ki z każdego projektu w solucji.
Poniższy kod nie działa, więc nie jest to takie proste, jak mogłoby się wydawać.
static void Main(string[] args)
{
var msBuild = MSBuildWorkspace.Create();
var sln = msBuild.OpenSolutionAsync
(@"D:\PanNiebieski\Documents\visual studio 14\Projects\ConsoleApplicationWorkspaces"
+@"\ConsoleApplicationWorkspaces.sln").Result;
foreach (var item in sln.Projects)
{
EmitProject(item);
}
Spróbuję uzbierać więcej informacji na ten temat. Według StackOverflow samo polecenie Emit powinno działać, ale to też nie prawda.
public static async void EmitProject(Project proj)
{
var c = await proj.GetCompilationAsync();
var options = new CSharpCompilationOptions
(OutputKind.DynamicallyLinkedLibrary);
c = c.WithOptions(options);
c = c.AddReferences(proj.MetadataReferences);
var r = c.Emit("my" + proj.Name + ".dll");
Console.WriteLine(r.Success);
}