Posts Tagged Visual Studio
On merging project files
Merging Visual Studio Project files: there’s not much nice to say about that. It’s just a pain, and I’ve ssen it become the number one or two reason of errors when merging between code branches.
Even when a project consists of a single team, it is not unusual that one developer adds a bunch of files while another one adds some more, or deletes and moves things around in the project. The source control system and its diff/merge tooling easily copes with the added and deleted code files, and it reliably notices and auto-resolves changes within code. However, to integrate into Visual Studio and the build process, code files also need to be referenced correctly in the *.csproj (or *.vbproj) project files. Here, developers often find strange conflicts, and the diff/merge tools are often not much of a help.
Project files consist or XML that is read by Visual Studio and Msbuild. Their root element is a Project. Project has child elements that indicate properties of the project like its build configuration (and some more), but most important in this context are the ItemGroup elements that contains the content the project:
- Compile elements that define files compiled into the assembly
- Content elements that define files not compiled, but otherwise included in the project: MVC views, script files, images contained in a Silverlight XAP…
- Reference elements that define the projects binary or project dependencies.
Here’s a simplified project file for an ASP.NET MVC project file:
<Project>
<!-- Project properties and extensions omitted for brevity -->
<ItemGroup>
<Reference Include="System.Web.Mvc />
<Reference Include="System.Web.WebPages" />
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\SquirrelController.cs" />
<Compile Include="DataAccess\SquirrelRepository.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
<Content Include="Global.asax" />
<Content Include="Content\Site.css" />
<Content Include="Web.config" />
<Content Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
</Content>
<Content Include="Web.Release.config">
<DependentUpon>Web.config</DependentUpon>
</Content>
<Content Include="Scripts\jquery-1.4.1.js" />
<Content Include="Scripts\jquery-1.4.1.min.js" />
</ItemGroup>
</Project>
Now why is there such a problem? First, most diff/merge tools just do not understand XML. These tools are designed to identify blocks of code. They know things about code: that outside strings, different kinds of whitespace can be considered as equivalent; that changes within a comment are less significant than elsewhere; where casing is significant or not. What most tools do not understand is that all of the following statements are equivalent:
<Squirrel name="Alex" fur="red"/>
<Squirrel fur="red" name="Alex" />
<Squirrel
fur="red"
name="Alex" />
<Squirrel fur="red" name="Alex"></Squirrel>
Secondly, the order of ItemGroup elements in the project, and of elements within them, does not matter – in programming languages, the sequence of statements is essential. Now that for project files the sequence is not significant, Visual Studio feels free to arrange items as it feels fit – and the diff/merge tool report hard to resolve conflicts even if two versions of a project file are absolutely equivalent.
Avoiding the pain
One feasible way of avoiding merging between versions of project files is to apply pessimistic locking. Only one developer can have a writable copy of the project, and there are no more conflicting version (at least within the same code branch). The downside is that developers may have to wait for their colleagues to finish their revision. The most frequent thing that a developer does with a project file is probably adding content. To get the shortest possible pessimistic lock on the project file, it should be committed as soon as the files are added – the added files should not contain any code at that point in time that could break the build until it is complete.
However, this approach does not remedy merges between code branches, and does not work with source control systems that just do not allow any pessimistic locking. And this includes each distributed source control system like Git or Mercurial.
Tooling
As we’ve seen, the root of the problem is not that project files are resistant to merging by their nature; it’s just the standard tooling that do not fit. However, there are specific tools that can help. The best candidate I’ve seen so far is a commercial yet relatively cheap (19€) tool called ProjectMerge (http://www.projectmerge.com). ProjectMerge understands XML: it recognizes equivalent XML elements and attributes despite or a possibly different serialization into text. But what is really sweet is that ProjectMerge can be told if the order of elements matters, and by which attributes equivalent elements are determined. In the case of Visual Studio project files, this attribute is the Include attribute of Compile, Content, None, and Reference elements. In effect, ProjectMerge will be able to understand these instructions are equivalent:
<Compile Include="1.cs" /> <Compile Include="2.cs" /> <Compile Include="3.cs" /> <!-- and --> <Compile Include="3.cs" /> <Compile Include="2.cs" /> <Compile Include="1.cs" />
The necessary settings to understand a specific project file format are stored in a distributable file format. Here’s my (probably not very complete) shot at C# projects – download here (from my Dropbox) and store under %PROGRAMDATA%\Oso\ProjectMerge\Formats.
I haven’t used the tool in practice yet, but I think we’re going to try it in a >10 person team over the next week, and see how it performs.
Link whole directories into Visual Studio Projects
You can include a file into a Visual Studio project in two ways: copy it into the project directory, or link it. Copying the file into the project directory is Visual Studio’s default option: it’s what happens when you drag a file from Explorer into VS’s project explorer, or when you use the dialog Project -> Add existing item. This is fine unless you wish to share files between multiple projects. An example where I needed to share a whole lot of files between different projects is NUnit for Silverlight: the same code is used by three projects for different versions of Silverlight and the Silverlight unit testing framework.
To link a file into Visual Studio, you can use the Project -> Add existing item dialog: the “Add” button has a dropdown menu, and the second option is “Add as link”. This will leave the file where it is and add a relative link to the Visual Studio project file. In the project file (which is BTW a MSBuild file), this looks like that:
<Compile Include="..\..\..\src\VersionInfo.cs">
<Link>VersionInfo.cs</Link>
</Compile>
If you add multiple files, Visual Studio will create one item like this for each file. To add all files in a directory, mark all files in the the Project -> Add existing item dialog, and link them. This is fine as long as you don’t delete any files or add new ones – Visual Studio will not pick up these changes. New files in the directory won’t be in the project, and deleting/renaming files will cause the build to fail.
A solution is to modify the project file manually. The Include directive supports wildcards. So to link all C# code files in a directory, you can do this:
<Compile Include="..\..\..\src\NUnit.Silverlight.Framework\*.cs" />
Nice, but in the case of NUnit for Silverlight, there were C# code files in subdirectories. Using the Compile directive as above, the files are included, but all appear in the root folder of the project – and if a file with the same name exists in the parent directory and the subdirectory, it won’t work. However, there is support for metadata keywords in MSBuild. For example, the %(Filename) keyword is a placeholder for each match in a wildcard. See this article for reference: MSBuild: By Example—Introducing Well-Known Metadata. Now we can include subdirectories:
<Compile Include="..\..\..\src\NUnit.Silverlight.Framework\*.cs" />
<Compile Include="..\..\..\src\NUnit.Silverlight.Framework\Attributes\*.cs">
<Link>Attributes\%(FileName)</Link>
</Compile>
<Compile Include="..\..\..\src\NUnit.Silverlight.Framework\Constraints\*.cs">
<Link>Constraints\%(FileName)</Link>
</Compile>
<Compile Include="..\..\..\src\NUnit.Silverlight.Framework\Exceptions\*.cs">
<Link>Exceptions\%(FileName)</Link>
</Compile>
As you see, I need to link three subdirectories. Using a * placeholder in the directory name and the %(RecursiveDir) keyword should enable adding these with a single statement like this:
<Compile Include="..\..\..\src\NUnit.Silverlight.Framework\*\*.cs">
<Link>%(RecursiveDir)%(FileName)</Link>
</Compile>
… but that does not work. Never mind, including subdirectories one by one is enough for me right now.
Format all files in project
Yesterday I discovered an awesomely useful Visual Studio macro: it applies that code formatting rules to all files in the whole solutions. Code formatting includes indentation, spacing, tabs vs. spaces: all the things that people tend to get irate about. By default, these formatting rules are applied only when you write new code. To apply them to an existing page, there’s the command Edit --> Format Document with the keyboard chord Ctrl-K, Ctrl-D. Now this macro goes and opens all files and applies this command – a very good idea to do before a major commit.
Sub FormatProject()
For Each Proj As Project In DTE.Solution.Projects
For Each Item As ProjectItem In Proj.ProjectItems
Dim window As EnvDTE.Window
Try
window = Item.Open()
window.Activate()
DTE.ExecuteCommand("Edit.FormatDocument", "")
Catch ex As Exception
End Try
Next
Next
End Sub
Found as a comment by saraford to this MSDN post from 2005.
Yesterday’s Good and Bad in Silverlight
Bad:
Installed the Silverlight 4 plug-in on my work notebook, which I develop a Silverlight 3 app with Visual Studio 2008 on. Result: the debugger would not start any more. The rest of the afternoon looked like that: Called IT if I could finally get my new laptop that they had lying around for a week so I don’t have to figure out what the heck went wrong when I’ve got a fresh install to do anyway, they said maybe, uninstalled Silverlight 4, rebooted (20mins – Vista), re-installed Silverlight 3 developer tools, rebooted, IT calls and says I can have the laptop, debugger works again, 3 hours lost. Well, after all it isn’t that bad; I’ve got the new laptop now. Which is really seriously fast, and has a good keyboard, and Win7 – we’re going to be friends.
Good:
Good news for guys like me who still have Silverlight 3 projects cooking is that Jeff Wilcox has ported the unit testing framework from the March 2010 Silverlight toolkit to Silverlight 3 - the latest release of the toolkit is only available for Silverlight 4. The obvious improvement is the new UI that lest you pick which tests to run when it starts – which I find extremely useful. I noticed that the buttons to copy the selected test don’t work, but that’s probably easy to fix.
My own humble unofficial port of NUnit to Silverlight does not work yet, but that will also be easy to fix – I think I’m going to have it out by the end of the weekend. But for now, I’ve got an appointment with the sun.
Visual Studio 2010 Express – No tests, please.
So Visual Studio 2010 has been released today. I recognize that .NET 4 is a great step forward, and Silverlight 4 just sounds sweet. But for people who are not provided with licenses by their employer, there’s quite a drawback.
The Standard edition has gone away. The previously cheapest edition of Visual Studio is no longer offered. With Visual Studio 2010, the lowest possible license is the Professional Edition which comes for $550 with a basic MSDN subscription for one year and $1,200 for a license with one year of a full MSDN subscription. Now if you’re an enthusiast or self-employed on the lower end of the food chain, this might be hefty price tag – and a significant increase compared to Visual Studio 2008 Standard (approx $280).
So at a first glance, moving away from the full versions of Visual Studio to the Express versions might sound tempting. You can have multiple Express Editions on the same machine (e.g. C# for Windows Services and Web Edition for ASP.NET and Silverlight), and the license does not prohibit commercial use.
However, there is one drawback that sounds like a massive deal breaker to me. Running Unit tests with Visual Studio 2010 is not (easily) possible.
Firstly, the integrated MSTest feature does not seem to be included. It’s not in the menu, and the ASP.NET MVC2 template comes without the test project it normally includes. Well, I could live with that, as I am a confession NUnit aficionado.
But: in Express Edition, you cannot attach the debugger to NUnit. The usual workflow is: start NUnit, attach the debugger to the NUnit process, debug your test. In Express Edition, the ability to attach the debugger to an exisiting process has been removed. And as plug-ins don’t work due to licensing restrictions in Express Edition, it’s not possible to retrofit the ability to run tests. (Visual NUnit for example won’t install.)
Steve Dunns has published a workaround for NUnit; it works by turning the unit test project into a command line application and bootstrap NUnit. That’s a nice trick and not the opposite of elegant, but far from ideal.
I’m not one who says everything should be free. Microsoft do not claim to offer a free full-blown development environment; that’s OK. But from all things that you can leave out: why does it have to be the all abilities to run unit tests? That seems like a strange signal towards the importance of quality.
Free NUnit integration for Visual Studio
It’s been around for half a year now, but I totally missed that there is a free&open tool out there that lets you run NUnit tests from within Visual Studio. The thing is called Visual NUnit (documentation and download available from that link). It does exactly what it promises to do – run NUnit tests from within Visual Studio, and debug without attaching the debugger to NUnit first, and that’s it – and performs very solidly; I’ve tested it with VS2008 with a 2000+ test suite, and with the RC of VS2010 (but not with that many tests).
No hard feelings, but I always thought that the price tag for TestDriven.Net was a little over the top; maybe worth paying, but not worth the fight of getting the budget for.
Thanks Tommi Laukkanen for putting this together! (And BTW, there another Tommi Laukkanen who’s made the mobile Twitter app Twim that I use on the e71. But they’re not the same).