Pages

syntax highlight, analytics

18 July 2011

Project reference strictness in Visual Studio 2010

Visual Studio 2008 happily allows you to reference .NET 3.5-dependent projects from a project that targets .NET framework 2.0—because the CLR version is the same for both frameworks. On the contrary, Visual Studio 2010 refuses to build such a solution, perhaps out of a desire to enforce Best Practices For Creating Reliable Builds, and gives missing namespace errors:
The name 'FooTools' does not exist in the current context
and warnings such as:
The primary reference "System.Web.Extensions.Design, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" could not be resolved because it has an indirect dependency on the framework assembly "System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" which could not be resolved in the currently targeted framework. ".NETFramework,Version=v2.0". To resolve this problem, either remove the reference "System.Web.Extensions.Design, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" or retarget your application to a framework version which contains "System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089".
Some legacy projects may be required to stay on 2.0 while still being able to reference a library that uses 3.5 sugar. There's nothing wrong with that: the 2.0 project doesn't care what the sugar looks like, because the IL code compiled from the 3.5 project executes on the v2.0.50727 runtime—same as the 2.0 project.

Luckily, you can force VS 2010 to allow forward-version referencing (up to 3.5) by editing each project file. Just add a specificversion element to each ProjectReference as needed:
<projectreference include="..\Foo\Common\Common.csproj">
    <project>{3A15B7A1-4FDA-21B0-877F-6F5D21B3C47F}</project>
    <name>Common</name>
    <specificversion>true</specificversion>
</projectreference>

However, in a large solution with many projects referencing each other, this could have a cascading effect, and editing the project files would be very cumbersome. So I wrote the PowerShell script below. Drop it in the top level of your solution, and the script searches recursively for .csproj files and updates the ProjectReference elements matching the partial GUIDs (which you must specify by editing the relevant line of the script).

Note: Close Visual Studio before running this script, since it modifies project files.
update_csproj.ps1:
dir -recurse -filter *.csproj | foreach { 
    $xml = New-Object XML

    $xml.Load($_.FullName)

    # we want the ItemGroup that contains the references
    $itemgroup = $xml.Project.ItemGroup | where { $_.ProjectReference }
    # Partial project GUIDs to search for... (edit as needed for your projects)
    $projrefs = $itemgroup.ProjectReference `
        | where { !$_.SpecificVersion `
            -and ( $_.Project -like "*CF2185B1*" `
                -or $_.Project -like "*FOO185B2*" `
                -or $_.Project -like "*BAR185B3*" `
                -or $_.Project -like "*BAZ185B4*") `
        }
    
    if ($projrefs) {
        Write-Host $_.FullName
        
        foreach($ref in $projrefs) {
            if($ref) {
                # <specificversion>true</specificversion>
                $el = $xml.CreateElement("SpecificVersion", $xml.Project.xmlns)   
                $el.InnerText = "true" 
                $ref.AppendChild($el) | out-null
                Write-Host "    updated: " $ref.Name
            }
        }

        $xml.Save($_.FullName) 
    }
}

Write-Host "Press any key to continue ..."
$host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

The script output will look like this:

2 comments:

  1. No need for a script. Specific Version is an editable field in the VS 2010 properties window for the reference.

    ReplyDelete
  2. Hmmm. You're right--no need to edit the .csproj XML by hand, at least. For a solution with 10+ projects, each with multiple references, the script could still be handy.

    ReplyDelete

Previous Posts


Creative Commons License   This work is licensed under a Creative Commons Attribution 3.0 Unported License.