Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

LINQ to Visual Studio Solution

4.20/5 (7 votes)
1 Dec 2009CPOL3 min read 29K   224  
Search properties of projects within a solution using LINQ.

Image 1

A screenshot from LINQPad showing an example use of this code.

Introduction

In attempting to write software for Windows Mobile using Visual Studio C# Express or SharpDevelop, I found that there is some common code that is generated by the designers which does not work on Windows Mobile. Instead of fixing it by hand every time I changed something on the form, I wanted to write a general refactoring tool that I could run from the command line (or the "Tools" menu) and fix the problem code.

I got something very ugly working, using (or misusing) the NRefactory library from SharpDevelop. However, I found that sometimes I needed to use Reflection, and so I needed to know which libraries were referenced in the project. At this point, I had never used LINQ, but I started to see how LINQ to XML could save a lot of code.

Then, as I was working on it, the code to get project properties evolved into the general purpose LINQ to Visual Studio solution that I present here. There is nothing in this code that deals with refactoring. It does read only property queries against Visual Studio projects. Hopefully, at some point, my refactoring code will be at a decent stage and I can post an article on that.

Background

As I already stated, I had never used LINQ until a few days ago. Not all of this code is very pretty, and there may be a simpler/better way to implement some of the features in this code. If there is, I would appreciate advice. Having said that, when I ran a series of queries against the many solution files / projects on my computer, it performed very well.

Using the Code

To use the demo application, simply start it from the command line, passing a directory you want to scan recursively for solution files and projects. It outputs a summary of each solution/project to output.txt in the application directory. In the code for the demo application, there are several other queries you can try that are commented out. I recommend that you look at those to see some of the possibilities of this library.

Add a reference to LinqToVisualStudioSolution.dll that is found in the demo download. Add a using directive for the LinqToVisualStudioSolution namespace. Now, you are ready to use the code.

C#
using System;
using LinqToVisualStudioSolution;

class Program
{
   static void Main(string[] args)
   {
       // Change the path to a real solution file.
       Solution solution = new Solution(@"D:\temp\Test.sln");

       var projects = (from project in solution
                       where project.OutputType == OutputType.Library
                       select project);

       foreach (var project in projects)
       {
         
            Console.Write("Project: ");
            Console.WriteLine(project.ProjectName);

            // OutputPathToAssemblyFull is a calculated property from 
            // OutputPathFull (another calculation), AssemblyName, and OutputType.

            Console.WriteLine(project.OutputPathToAssemblyFull);
            Console.WriteLine();
            if (project.Errors.Count > 0)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                foreach (string err in project.Errors)
                {
                    Console.WriteLine(err);
                }
                Console.ResetColor();
            }
       }
   }
}

Points of Interest

The hardest part of my code was getting the Element(s) and Attribute(s) features working so that the user can access any property in the project, not only the common ones. I had to create a class, PElement, that inherits from XElement. The reason for this is to keep the user from having to include the namespace in his queries. So instead of writing the following:

C#
XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";

var projects = (from project in solution
                where project.Element(ns + "PropertyGroup") != null &&
                project.Element(ns + "PropertyGroup")
                .Element(ns + "AssemblyName") != null &&
                project.Element(ns + "PropertyGroup")
                .Element(ns + "AssemblyName").Value == "Test"
                select project); 

you can forget about the XNamespace altogether.

In order to accomplish this, I had to write a couple of extension methods for the IEnumerable<PElement> class. These can be found at the beginning of the PElement.cs file.

I also wrote an extension method for the IEnumerable<Reference> class so I could have a custom Contains method. Now, you can search for projects that contain certain references.

C#
var projects = (from project in solution
                 where project.References.Contains("mscorlib")
                 select project);

Conclusion

I had fun writing this code and learned a lot from it, including how powerful LINQ is. Hopefully, this will be of some use to others.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)