WorkspaceCzęść NR.5

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.

ConsoleApplicationWorkspaces

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”.

Solution

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.

GetProjectDependencyGraph

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.

Project

Obecnie mając kolekcję projektów wyświetlam ich dokumenty oraz referencję do innych projektów, jeśli są

SLN

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);
}