29

Does anyone know of a way to programmatically read the list of References in a VS2008 csproj file? MSBuild does not appear to support this functionality. I'm trying to read the nodes by loading the csproj file into an XmlDocument but, the XPath search does not return any nodes. I'm using the following code:

System.Xml.XmlDocument projDefinition = new System.Xml.XmlDocument();
        projDefinition.Load(fullProjectPath);

        System.Xml.XPath.XPathNavigator navigator = projDefinition.CreateNavigator();

        System.Xml.XPath.XPathNodeIterator iterator = navigator.Select(@"/Project/ItemGroup");
        while (iterator.MoveNext())
        {
            Console.WriteLine(iterator.Current.Name);
        }

If I can get the list of ItemGroups I can determine whether it contains Reference information or not.

Igor Kustov
  • 3,228
  • 2
  • 34
  • 31

3 Answers3

47

The XPath should be /Project/ItemGroup/Reference, and you have forgot the namespace. I'd just use XLINQ - dealing with namespaces in XPathNavigator is rather messy. So:

    XNamespace msbuild = "http://schemas.microsoft.com/developer/msbuild/2003";
    XDocument projDefinition = XDocument.Load(fullProjectPath);
    IEnumerable<string> references = projDefinition
        .Element(msbuild + "Project")
        .Elements(msbuild + "ItemGroup")
        .Elements(msbuild + "Reference")
        .Select(refElem => refElem.Value);
    foreach (string reference in references)
    {
        Console.WriteLine(reference);
    }
Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
  • That was much easier. Thanks for the help. –  Jul 28 '09 at 14:53
  • This is great! By now everybody probably noticed it, but just in case -- references could be also made within the solution, in such case you need to get `ProjectReference` element too. – astrowalker Apr 12 '17 at 13:00
  • Its very important to not change this line ` XNamespace msbuild = "http://schemas.microsoft.com/developer/msbuild/2003";` Because I changed it to `var` by Resharper and afterward I got only problems! – Patrick Oct 26 '20 at 09:40
  • If you make it "var", the type will be inferred as "string" from the right side. It must be `XNamespace`, so that the latter's implicit conversion operator from string kicks in. – Pavel Minaev Oct 26 '20 at 13:16
11

Building on @Pavel Minaev's answer, this is what worked for me (notice the added .Attributes line to read the Include attribute)

XNamespace msbuild = "http://schemas.microsoft.com/developer/msbuild/2003";
    XDocument projDefinition = XDocument.Load(@"D:\SomeProject.csproj");
    IEnumerable<string> references = projDefinition
        .Element(msbuild + "Project")
        .Elements(msbuild + "ItemGroup")
        .Elements(msbuild + "Reference")
        .Attributes("Include")    // This is where the reference is mentioned       
        .Select(refElem => refElem.Value);
    foreach (string reference in references)
    {
        Console.WriteLine(reference);
    }
Sudhanshu Mishra
  • 6,523
  • 2
  • 59
  • 76
4

Based on @PavelMinaev's answer, I also added the "HintPath" Element to the output. I write the string array "references" to a ".txt" file.

XNamespace msbuild = "http://schemas.microsoft.com/developer/msbuild/2003";
            XDocument projDefinition = XDocument.Load(@"C:\DynamicsFieldsSite.csproj");
            var references = projDefinition
                .Element(msbuild + "Project")
                .Elements(msbuild + "ItemGroup")
                .Elements(msbuild + "Reference")
                .Select(refElem => (refElem.Attribute("Include") == null ? "" : refElem.Attribute("Include").Value) + "\n" + (refElem.Element(msbuild + "HintPath") == null ? "" : refElem.Element(msbuild + "HintPath").Value) + "\n");
            File.WriteAllLines(@"C:\References.txt", references);
Amadeus Sanchez
  • 2,375
  • 2
  • 25
  • 31