Thursday, April 05, 2012
If you've downloaded the new VS 11 Beta and done any merging, then you've probably seen the new diff and merge tools built into VS 11. They are awesome, and by far a vast improvement over the ones included in VS 2010. There is one problem with the merge tool though, and in my opinion it is huge.
Basically the problem with the new VS 11 Beta merge tool is that when you are resolving conflicts after performing a merge, you cannot tell what changes were made in each file where the code is conflicting. Was the conflicting code added, deleted, or modified in the source and target branches? I don't know (without explicitly opening up the history of both the source and target files), and the merge tool doesn't tell me. In my opinion this is a huge fail on the part of the designers/developers of the merge tool, as it actually forces me to either spend an extra minute for every conflict to view the source and target file history, or to go back to use the merge tool in VS 2010 to properly assess which changes I should take.
I submitted this as a bug to Microsoft, but they say that this is intentional by design. WHAT?! So they purposely crippled their tool in order to make it pretty and keep the look consistent with the new diff tool? That's like purposely putting a little hole in the bottom of your cup for design reasons to make it look cool. Sure, the cup looks cool, but I'm not going to use it if it leaks all over the place and doesn't do the job that it is intended for. Bah! but I digress.
Because this bug is apparently a feature, they asked me to open up a "feature request" to have the problem fixed. Please go vote up both my
bug submission and the
feature request so that this tool will actually be useful by the time the final VS 11 product is released.
Friday, March 30, 2012
Hey everyone, I just discovered this great post yesterday that shows how to have msbuild build projects in parallel 
Basically all you need to do is pass the switches “/m:[NumOfCPUsToUse] /p:BuildInParallel=true” into MSBuild.
Example to use 4 cores/processes (If you just pass in “/m” it will use all CPU cores):
MSBuild /m:4 /p:BuildInParallel=true "C:\dev\Client.sln"
Obviously this trick will only be useful on PCs with multi-core CPUs (which we should all have by now) and solutions with multiple projects; So there’s no point using it for solutions that only contain one project. Also, testing shows that using multiple processes does not speed up Team Foundation Database deployments either in case you’re curious 
Also, I found that if I didn’t explicitly use “/p:BuildInParallel=true” I would get many build errors (even though the MSDN documentation says that it is true by default).
The poster boasts compile time improvements up to 59%, but the performance boost you see will vary depending on the solution and its project dependencies. I tested with building a solution at my office, and here are my results (runs are in seconds):
| # of Processes | 1st Run | 2nd Run | 3rd Run | Avg | Performance |
| 1 | 192 | 195 | 200 | 195.67 | 100% |
| 2 | 155 | 156 | 156 | 155.67 | 79.56% |
| 4 | 146 | 149 | 146 | 147.00 | 75.13% |
| 8 | 136 | 136 | 138 | 136.67 | 69.85% |
So I updated all of our build scripts to build using 2 cores (~20% speed boost), since that gives us the biggest bang for our buck on our solution without bogging down a machine, and developers may sometimes compile more than 1 solution at a time. I’ve put the any-PC-safe batch script code at the bottom of this post.
The poster also has a follow-up post showing how to add a button and keyboard shortcut to the Visual Studio IDE to have VS build in parallel as well (so you don’t have to use a build script); if you do this make sure you use the .Net 4.0 MSBuild, not the 3.5 one that he shows in the screenshot. While this did work for me, I found it left an MSBuild.exe process always hanging around afterwards for some reason, so watch out (batch file doesn’t have this problem though). Also, you do get build output, but it may not be the same that you’re used to, and it doesn’t say “Build succeeded” in the status bar when completed, so I chose to not make this my default Visual Studio build option, but you may still want to.
Happy building!
-------------------------------------------------------------------------------------
:: Calculate how many Processes to use to do the build.
SET NumberOfProcessesToUseForBuild=1
SET BuildInParallel=false
if %NUMBER_OF_PROCESSORS% GTR 2 (
SET NumberOfProcessesToUseForBuild=2
SET BuildInParallel=true
)
MSBuild /maxcpucount:%NumberOfProcessesToUseForBuild% /p:BuildInParallel=%BuildInParallel% "C:\dev\Client.sln"
Sunday, February 05, 2012
Arrggghhhh TFS and builds! Such a love-hate
relationship! So we have our TFS builds setup to both compile our C#
projects as well as compile and deploy our Team Foundation (TF) Database (DB) projects.
One day I started getting the following file path too long error message on our build server:
$/RQ4TeamProject/Prototypes/BuildProcessTests/RQ4.Database.sln - 1 error(s), 69
warning(s), View Log File
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\TeamData\Microsoft.Data.Schema.TSqlTasks.targets
(80): The "SqlSetupDeployTask" task failed unexpectedly.
Microsoft.Data.Schema.Build.BuildFailedException: The specified path, file
name, or both are too long. The fully qualified file name must be less than 260
characters, and the directory name must be less than 248 characters. --->
System.IO.PathTooLongException: The specified path, file name, or both are too
long. The fully qualified file name must be less than 260 characters, and the
directory name must be less than 248 characters. at
System.IO.PathHelper.Append(Char value) at
System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32
maxPathLength) at System.IO.FileStream.Init(String path, FileMode
mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share,
Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String
msgPath, Boolean bFromProxy, Boolean useLongPath) at
System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare
share, Int32 bufferSize, FileOptions options, String msgPath, Boolean
bFromProxy) at System.IO.FileStream..ctor(String path,
FileMode mode, FileAccess access, FileShare share, Int32 bufferSize,
FileOptions options) at System.IO.StreamReader..ctor(String
path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32
bufferSize) at System.IO.StreamReader..ctor(String path,
Boolean detectEncodingFromByteOrderMarks) at
Microsoft.Data.Schema.Sql.Build.SqlPrePostDeploymentModifier.GenerateMergedSqlCmdFiles(DeploymentContributorConfigurationSetup
setup, DeploymentContributorConfigurationFile configFile) at
Microsoft.Data.Schema.Sql.Build.SqlPrePostDeploymentModifier.OnEstablishDeploymentConfiguration(DeploymentContributorConfigurationSetup
setup) at
Microsoft.Data.Schema.Build.DeploymentContributor.EstablishDeploymentConfiguration(DeploymentContributorConfigurationSetup
setup) --- End of inner exception stack trace
--- at Microsoft.Data.Schema.Build.DeploymentContributor.EstablishDeploymentConfiguration(DeploymentContributorConfigurationSetup
setup) at
Microsoft.Data.Schema.Build.DeploymentProjectBuilder.VerifyConfiguration()
at Microsoft.Data.Schema.Tasks.DBSetupDeployTask.BuildDeploymentProject(ErrorManager
errors, ExtensionManager em) at
Microsoft.Data.Schema.Tasks.DBSetupDeployTask.Execute() at
Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
at Microsoft.Build.BackEnd.TaskBuilder.ExecuteInstantiatedTask(ITaskExecutionHost
taskExecutionHost, TaskLoggingContext taskLoggingContext, TaskHost taskHost,
ItemBucket bucket, TaskExecutionMode howToExecuteTask, Boolean& taskResult)
Naturally I said, "Ok, our TF DB project isn't compiling because a path is
too long. Somebody must have checked in a stored procedure with a really long
name". After viewing the history of the branch I was trying to build
however, I didn't see anything that stuck out. So for fun I thought I
would shorten the Build Definition name's length and build again. Viola,
like most path issues with TFS this fixed the issue (this is because the build
definition name is often used in the path that TFS moves/builds files
to). However, we have many queries setup that match the specific Build
Definition name (since it's used in the "Integrated in Build" work
item value), so shortening it wasn't a long term solution. As an added
frustration bonus, I discovered our build definition name was only 1 character too
long!
The first thing I did was make a Path Length Checker program
so I could see how long the file paths (files and directories) really were on the build server. Oddly enough, the longest paths were 40
characters short of the maximum limit described by the error message.
So I took a look at our database folder structure and saw that it really was
wasting a lot of characters. This is what the path to one of our stored
procedure folders looks like: "..\Database\Schema
Objects\Schemas\dbo\Programmability\Stored Procedures\Procs1". I
figured that I would just rename some of these folders in Visual Studio and
that should be good........OMG never try this while connected to TFS! I
got a popup warning for every single file under the directory I was renaming
(thousands of them), with something along the lines of "Cannot access file
X, or it is locked.....blah blah. Please press OK". So after holding
down the enter key for a over an hour to get past all these prompts it finally
finished. When I reviewed the changes to check in, I saw that many
duplicate folders had been created, and there were miscellaneous files all over
the place; some got moved, some never; what a mess. So I went ahead and reverted my
changes.
So I thought, "Ok, let's try this again, but first going offline so as not
to connect to TFS". So I disabled my internet connection and opened
the database solution (this is the only way that I know of to work
"offline" in TFS :( ). I then tried to change the high
level folder "Schema Objects" to just "Schema". Nope,
Visual Studio complained that the folder was locked and couldn't be changed.
I thought to myself, "TFS makes all non-checked out files read-only, and I'm offline so it can't check them out.
That must be the problem". So I opened up explorer and made all of
the files and folders writable and tried again. Nope, no deal; same error message.
So I thought, "Alright, let's try doing a low level directory
instead". It seems that VS would only let me rename a directory that
didn't contain other directories. So I renamed the "Procs1"
folder to just "1". I no longer got the warning prompt for every
file, but it was still pretty slow and I could watch VS process every file in
the Solution Explorer window. After about 10 minutes it finally
finished. So I checked in my changes and tried building again.
Nope, same error message as before about the path being too long.
So I said screw this. I opened up the TFS Source Control Explorer and
renamed the folder from there. It worked just fine. I then had to
open up the Database.dbproj file in a text editor and do a find and replace to
replace "\Schema Objects\" with "\Schema\". This
worked for refactoring the folder structure quickly, but I was still getting
the "path too long" error message on the build server. Arrrrgg!
So I went back to the build, set the verbosity to
“diagnostic” and launched another build (which failed again with the path too long error). Looking through the error message I noticed
that it did complete building the DB schema, and went on to failing on building
the Pre/Post deployment scripts. Looking
back to my original error message and reading it more carefully I noticed this
line, “Microsoft.Data.Schema.Sql.Build.SqlPrePostDeploymentModifier.GenerateMergedSqlCmdFiles”. So now I was pretty sure the problem was in
the pre and post deployment scripts.
Now, we have a very custom process for our database scripts,
and part of this process involves using SQLCMD mode to include other script files
into our pre and post deployment files when they are generated; it basically
makes it look like the referenced script’s contents were in the pre/post
deployment script the entire time. This is necessary for us so that developers don't have to look through pre and post deployment scripts that are tens of thousands of lines long. It
turns out that while none of these referenced script files themselves had a
path that was over the limit, somehow during the generation of the pre/post
deployment scripts it was making the path even longer. I looked through our referenced scripts and saw a few
particularly long ones. So I refactored
them to shorten the file names, and presto the build worked! Hooray!
I’m guessing that the reason the build wouldn’t give me an
actual filename when it encountered the error is because SQLCMD mode was
dynamically referencing those scripts at build time, so to the build it just looked like the pre and post deployment scripts were each thousands of lines long, when in fact they are only maybe 50 lines long, but they "include" other files, and those file references must be used at build time.
So the morals of this story are:
1. If VS is blowing chunks when you try to rename a folder
(especially when connected to TFS), don't do it through VS. Instead
modify the folder structure outside of VS and then manually edit the
.csproj/.dbproj/.vbproj files to mirror the changes.
2. Whenever you are stumped on a build error, go back and
THOROUGHLY read the ENTIRE error message.
3. Be careful when using compile-time language features to
reference/include external files.
Wednesday, September 07, 2011
I watched an awesome Channel 9 Visual Studio Tips And Tricks video, so I thought I'd share. Some great VS gems in there. Even a few Windows 7 ones, like using Alt+D to jump to the address bar in Windows Explorer, and typing "cmd" in the Windows Explorer address bar to open a command prompt at the current directory.
Also, if you're interested in what the next Visual Studio release has in store, check out this Channel 9 video.
Friday, September 02, 2011
James Michael Hare has a lot of awesome C# and .Net related posts, so this is just a little shout out to him (and my own little way of bookmarking his blogs since GWG doesn't provide a way to "favorite" or "follow" him). Of particular awesomeness is his C#/.NET Little Wonders and Pitfalls series, and the C#/.NET Fundamentals: Choosing the Right Collection Class. Keep the great posts coming James!
Wednesday, August 17, 2011
I recently discovered this post which shows how you can programmatically update queries in TFS, which is great for when you make a WIT (Work Item Template) change that will affect tons of queries.
That post then led me to this one which is great as well. In fact, Tarun Arora has tons of great posts relating to TFS. Rock on!
Monday, July 11, 2011
There are a few great features in the TFS Power Tools that I wasn't aware of, such as TreeDiff which let's you compare folders (or even entire branches) to see the differences between them, and Undo Unchanged which undoes files that are checked out, but don't have any chnages made to them, so that they don't appear in the Pending Changes window. This blog explains some of the features, and this one shows how to add the console-app-only features as External Tools in Visual Studio to easily run them from Visual Studio. Very cool!
Wednesday, June 29, 2011
Just found a few websites that show some Visual Studio tips that I haven't seen before, so I thought I'd share:
1 - Tips and Tricks for the Visual Studio .NET IDE
2 - Essential Visual Studio Tips & Tricks that Every Developer Should Know
3 - Channel 9's Visual Studio Toolbox - weekly series dedicated to showing all the cool stuff that Visual Studio can do and how to be more productive with it.
Wednesday, June 01, 2011
I came across this great article which talks about simply unloading projects from a solution to make the solution load and build faster in Visual Studio. This is great, as some of the solution files I work in contain over 300 projects and it can sometimes take a while to load. Also, because the information about which projects to load is stored in the .suo file (not the .sln file itself), this can be configured per developer so they only have to load the projects that they work in (the .suo files should never be stored in source control).
Now, unloading 300 projects one at a time would take forever, but luckily there the Visual Studio 2010 extentension PowerCommands allows us to quickly Load or Unload all of the projects in the solution (or a solution folder) with a couple clicks. So I typically just unload all of the projects in the solution, and then enable the ones I am working with.

The one caveat with this is that because Visual Studio only builds the projects that are loaded, if you get your team's latest code from source control and then try to build the solution from within visual studio, the build may fail since it will only build the projects you have loaded, and these may depend on changes made to the other projects that you don't have loaded. So you can easily reload all of the projects in the solution, build, and then unload all the ones you don't want again, or what I prefer to do is simply build the solution from MSBuild, as this ignores the .suo file and builds all projects referenced in the .sln file. I often build my solution files from MSBuild anyways since it has the added benefit of not locking up my visual studio UI while building :).
Happy Coding!
One of the greatest benefits of building your solution flies in MSBuild (vs in Visual Studio directly) is that it doesn't lock up the Visual Studio UI, which can be a huge pain if you have a large solution that takes several minutes (or longer) to build. Building your solution in MSBuild leaves you free to inspect code in Visual Studio while your solution is building. The only problem is that to do this you have to open a command prompt and type the command + path every time to build.
If you want to be able to right-click on a solution file and build it in MSBuild from the Windows Explorer context menu, check out MSBuildShellExtension (it's free). Being able to build right from Windows Explorer (without having to even open Visual Studio) is cool and may be enough to passify you, but I wanted to be able to build my solution file at anytime from anywhere on my PC with a keyboard shortcut.
Below I outline how I've setup my system to build my solution files in MSBuild with a quick keystroke. Setup only takes a few minutes and requires AutoHotkey to be installed (it's free and awesome).
Step 1 - Install AutoHotkey.
Step 2 – Create a shortcut to the Visual Studio Command Prompt (2010), move it directly to the C: drive, and make sure it is called “Visual Studio Command Prompt (2010)” (it is referenced at this location with this name by the AutoHotkey script in the following steps, but can be changed if needed).


Step 3 – Create your AutoHotkey script……luckily, you don’t have to create it from scratch; you can use mine as your template and just adjust it to your liking
. So copy and paste the script in the textbox below into a new text file, and then save it with the extension ".ahk", which is the AutoHotkey script extension (so you can just call it "AutoHotkeyScript.ahk" for example). You will need to modify the code directory paths and solution file names in the script to match yours to build your solutions, but I've commented the script fairly thoroughly so it's easy to see what it's doing.
In my office we have both a Client solution and a Server solution, so I have the script setup to build the client solution with WindowsKey+C and the server solution with WindowsKey+S. We also work in multiple branches, so I have global variables near the top of the script that I can set to true to quickly switch between Development, QA, and Release branches. I also have WindowsKey+U configured to open the code directory and WindowsKey+Q to open the database directory. Obviously you can change the keyboard mappings to your liking; these are just the ones that I prefer. As a side note here, just be aware that these will override the default windows key shortcuts; so in my case WindowsKey+U no longer opens up the Windows Ease of Access Center window.
Step 4 – Have your AutoHotkey script automatically start when you login to Windows, so that you don’t have to manually launch it all the time.
Method 1:
This method is the easiest, but I discovered it after Method 2 (below). Simply open up the Windows Start Menu, navigate to the Startup folder within All Programs, right-click on it and choose Open All Users. Then simply paste a shortcut to your AutoHotkey script in this folder. That's it; the script will now launch whenever any user logs into Windows. If you only want the script to run when you log into Windows (no other users), then just choose Open instead of Open All Users when right-clicking on the Startup folder.


Method 2:
Open the Windows Task Scheduler and create a new Basic Task. Give it a name and description (something like “launch AutoHotkey script at login”), and then specify to have it run “When I log on”. Then specify that you want it to “Start a program”, and then point it towards the AutoHotkey script you created in Step 3. Before you finish the wizard, check off “Open the Properties dialog for this task when I click Finish”. When that Properties dialog opens up, go to the Conditions tab and make sure none of the checkboxes under the Power category are checked off; this will ensure the script still launches if you are on a laptop and not plugged into AC power.



And that's it. Now you can build your solution file in MSBuild with a quick keystroke from anywhere on your computer. I have chosen to use the Windows Key for my shortcut keys, but you don't have to; you can use whatever keyboard shortcut you want. And feel free to modify the script I provided to do whatever else you want; AutoHotkey is very powerful and can be used for so many things, so be sure to checkout their website for more examples of scripts and what it can do. For example lots of people use it to automatically spell-correct as they type, or to automatically expand abbreviations (so I could type DS and hit tab, and have it expand to Daniel Schroeder, or type MyAddress and have it put my address in).
Happy Coding!