Just A Programmer We're just programmers

8Nov/120

Visual Studio 2010 and VisualStudio.com TFS Hosting

Yesterday, Stan, the founder of this blog, gave me a link to a project host on the Team Foundation Service (visual studio.com). I tried to connect to it with Visual Studio 2010. it simply refused to work.

Visual Studio Add TFS Server Error

After much annoyance, he asked me to try adding the TFS server to Visual Studio 2012 and it worked (Why didn’t I think of that?). Eventually I figured out that I needed to install the Visual Studio 2010 SP1 Team Foundation Server 2012 Compatibility GDR (KB2662296). Then I was able to add the solution to Visual Studio 2010. It seems there are several updates for Visual Studio 2010 SP1, some specifically dealing with Windows 8 compatibility. Unfortunately Windows update does not prompt me to install them. I will search for and install these tonight to prevent future issues.

27Oct/119

Continuous Integration with TFS2010, MSDeploy & VSDBCMD

After I created an account at Cytanium, I quickly discovered the glory of One-Click Publish. After setting up my source control in TFS. All I could think of, was getting TFS to do the same thing for me, but even I knew that wouldn’t be enough. I wanted TFS to deploy my database changes as well. Well, there is that Schema Compare utility in Visual Studio, I know it can figure out and deploy changes to a database. I figured if Visual Studio can do all of these things, I should be able to as well… shouldn’t I?

Custom Build Process Templates

Very soon after you start to ask these kinds of questions, you find yourself looking at TFS Build Process Templates. The templates are designed in Windows Workflow and thanks to a few good blogs out there this is a rather approachable topic. Most of my starting information came from this blog sequence: Ewald Hofman’s – Customize Team Build 2010.

Before you start, save yourself the pain, take Ewald’s advice and add the Team Foundation Build Activities to your Toolbox. This will shave 15 seconds off the time to open every template.

Exposing Arguments and Providing Metadata

More lessons from Ewald on adding arguments and adding more complex arguments. We will use them and see how the values are supplied a bit later on.

  • Continuous Integration Database Deployment
    • ciVSDBCMDConnectionString: “Database Connection String”
    • ciVSDBCMDManifestFile: “Database Manifest File”
    • ciVSDBCMDTargetDatabase: “Target Database”
  • Continuous Integration Website Deployment
    • ciMSDeployWebProject: “Web Project”
    • ciMSDeployUsername: “MSDeploy Credentials: Username”
    • ciMSDeployPassword: “MSDeploy Credentials: Password”
    • ciMSDeployWebService: “MSDeploy Web Service Url”
    • ciMSDeployWebApplication: “Web Application Name”

Customizing the Template

Under your Team Project, go to the folder BuildProcessTemplates, and branch DefaultTemplate.xaml to ContinuousIntegrationTemplate.xaml.

Open it up and and take a look around. It will help if you take a top down approach, Collapse All, using the controls in the top right. Locate the AgentScope Activity named “Run On Agent” and expand it. Now look for the open space after the “Try Compile, Test, and Associate Work Item” Sequence Activity; this is where we will start adding our custom functionality.

In this space add a If Activity and name it: “If Build and Test Succeeded”. In its condition we are going to add the following VB statement:

BuildDetail.CompilationStatus = BuildPhaseStatus.Succeeded And
    (BuildDetail.TestStatus = BuildPhaseStatus.Succeeded Or
        BuildDetail.TestStatus = BuildPhaseStatus.Unknown)

In the Then clause we drop a sequence named: “Deploy Database and Website”. Inside that sequence, go ahead and create a “Deploy Database” Sequence and a “Deploy Website” Sequence. In the else clause we can create a WriteBuildWarning with the message: “Deployment Skipped”. It should all look like this in the end…

Deploy Database

A large part of my introduction to VSDBCMD (not to mention a large part of this idea) came from this Visual Studio Walkthrough on the topic. If you are willing to work through the various issues with using Database Deployment, it is worth it.

I happen to have Visual Studio installed on my TFS Server, if you dont, copy this application from your Visual Studio install to all your TFS Build Agents.

C:Program Files (x86)Microsoft Visual Studio 10.0VSTSDBDeploy

We are going to use an InvokeProcess Activity to call VSDMCMD.exe with the following code for arguments property. The manifest file will contain the Database name and Connection String that was configured in the project, but chances are you are going to want to override this per environment.

String.Format("/a:Deploy /dd+ /dsp:Sql" _
     & " /manifest:""{0}{1}""" _
     & " /p:TargetDatabase=""{2}"" /cs:""{3}""", _
     BuildDetail.DropLocation, ciVSDBCMDManifestFile, _
     ciVSDBCMDTargetDatabase, ciVSDBCMDConnectionString)

Be sure to properly name the InvokeProcess Activity, as well as provide WriteBuildMessage and WriteBuildError Actvities for the standard and error output.

Deploy Website

Deploying databases was actually a lot easier than I expected, which is fortunate, because deploying websites was a lot more challenging.

Lets add a few variables to the Deploy Website Sequence:

  • Name: websitePublishDirectoryPath
  • Variable type: String
  • Default:
    String.Format("{0}Website Deployment", BinariesDirectory)
  • Name: msDeployManifestFilePath
  • Variable type: String
  • Default:
    String.Format("{0}{1}.manifest", websitePublishDirectoryPath, ciMSDeployWebProject)

As we will continue by defining a Sequence named “Prepare Deployment”. This sequence is responsible for preparing a folder to publish. So we have to create the directory copy the output to it and perform any Web.config transformations. First lets declare a variable in this scope:

  • Name: platformConfiguration
  • Variable type: Microsoft.TeamFoundation.Build.Workflow.Activities.PlatformConfiguration
  • Default:
    BuildSettings.PlatformConfigurations.First
  • Name: websiteSourceDirectory
  • Variable type: String
  • Default:
    String.Format("{0}_PublishedWebsites{1}", BinariesDirectory, ciMSDeployWebProject)
  • Name: websiteDestinationDirectory
  • Variable type: Microsoft.TeamFoundation.Build.Workflow.Activities.PlatformConfiguration
  • Default:
    String.Format("{0}{1}", websitePublishDirectoryPath, ciMSDeployWebProject)

One CreateDirectory Activity to create the folder named in variable `websitePublishDirectory`, one CopyDirectory Activity to copy `websiteSourceDirectory` to `websiteDestinationDirectory` and an additonal Sequence named “Find and Transform Web.config Files”

Click for the full workflow

Yet Another Web.config Transform

There seems to be a lot of places to find good information on the Web.config
transformation topic. So I’m not reinventing anything here. Generally I looked for web.config files and any matching transformation files. An MSBuild Activity is used to perform the transformation. Finally delete all transform files, and continue. It’s important, but rather boring… and this blog post is long enough already.

Web Deploy 2.0

Hopefully you can have someone else configure Web Deploy 2.0 for you, but since you are reading this, I doubt that is the case. On learn.iis.net, I found the best set of tutorials to install, configure, (and most importantly) debug. If you are having problems with the setup, don’t hesitate to enable tracing of failed requests. Once you are able to deploy with Visual Studio you are ready to continue… right? I mean, the MSDeploy command doesn’t seem too intimidating. After a day and change, I was ready to scream uncle. Until I found this StackOverflow Question, I was unable to figure out the arguments of the command that Visual Studio used to initiate the deployment.

First we have to generate a msdeploy manifest file. An InvokeMethod Activity to call `System.IO.File.WriteAllText` with the following expression

String.Format("<?xml version=""1.0"" encoding=""utf-8""?>" _
    & "<sitemanifest>" _
        & "<contentPath path=""{0}{1}"" />" _
        & "<setAcl path=""{0}{1}"" setAclResourceType=""Directory"" />" _
        & "<setAcl path=""{0}{1}"" setAclUser=""anonymousAuthenticationUser"" " _
            & "setAclResourceType=""Directory"" />" _
    &"</sitemanifest>", _
    websitePublishDirectoryPath, ciMSDeployWebProject)

Finally we can execute MSDeploy with an InvokeProcess Activity and the following arguments.

String.Format("-source:manifest='{0}'" _
              & " -dest:auto,ComputerName='{1}?site={2}',UserName='{3}',Password='{4}',IncludeAcls='False',AuthType='Basic'" _
              & " -verb:sync -disableLink:AppPoolExtension -disableLink:ContentExtension -disableLink:CertificateExtension" _
              & " -setParam:kind='ProviderPath',scope='contentPath',match='^{5}\{6}$',value='{2}'" _
              & " -setParam:kind='ProviderPath',scope='setAcl',match='^{5}\{6}$',value='{2}' -allowUntrusted", _
              msDeployManifestFilePath, ciMSDeployWebService, ciMSDeployWebApplicationName, _
              ciMSDeployUsername, ciMSDeployPassword, _
              websitePublishDirectoryPath.Replace("", "\").Replace(" ", " ").Replace(".", "."), _
              ciMSDeployWebProject.Replace(" ", " ").Replace(".", "."))
Configure and Queue the Build

We can finally see the light at the end of the tunnel here. Since we provided the metadata for our arguments, we get a rather impressive display of customization.

Queue up your build and hopefully you wont have to do too much debugging to get this to work for yourself.

Conclusion

After seeing this work, it was all worth it. Of course, this is all very custom, I have my xaml attached here as an example, but you will have to be prepared to work with it to make it work for you. Drop me a line, I’ll help you out if I can.

ContinuousIntegrationTemplate.zip

24Sep/111

YUI’s CompressorTask with MSBuild and Visual Studio

While trying to integrate YUI Compressor as a build task in my current project…

http://yuicompressor.codeplex.com/documentation

Post Build Event:

$(MSBuildBinPath)msbuild.exe "$(SolutionDir)MinificationSettings.xml" /property:SourceLocation=$(ProjectDir) /p:JavaScriptOutputFile=$(ProjectDir)ContentMinScriptsExample.min.js /p:CssOutputFile=$(ProjectDir)ContentMinCSSSite.min.css

I got the error:

MSBUILD : error MSB1008: Only one project can be specified.

C:WindowsMicrosoft.NETFrameworkv4.0.30319msbuild.exe "c:usersspadedocumentsvisual studio 2010ProjectsExampleYUICompressorTaskMinificationSettings.xml"
    /p:SourceLocation=c:usersspadedocumentsvisual studio 2010ProjectsExampleYUICompressorTaskMVCExample
    /p:JavaScriptOutputFile=c:usersspadedocumentsvisual studio 2010ProjectsExampleYUICompressorTaskMVCExampleContentMinScriptsExample.min.js
    /p:CssOutputFile=c:usersspadedocumentsvisual studio 2010ProjectsExampleYUICompressorTaskMVCExampleContentMinCSSSite.min.css

It seems that the spaces in the folder path are preventing me from enjoying YUI Compressor. Quite the same problem this person is having: MSDN Forums: Unable to correctly pass parameters to MS build. Although I suspect he gave up a bit too early.

I tried adding quotes around the value of the parameters, you would think this is going to work, it doesn’t.

Looking for a way to replace the spaces, I came across MS Build Property Functions.

With Build Property Functions, it becomes possible to run the simple replace command in all the spots where I need to, my first guess was to replace space with ‘%20′. That had mixed results, so I was left with choosing an arbitrary token for replacement.

Post Build Event:

$(MSBuildBinPath)msbuild.exe "$(SolutionDir)MinificationSettings.xml"
    /p:SourceLocation=$(ProjectDir.Replace(" ", "[[REPLACESPACE]])
    /p:JavaScriptOutputFile=$(ProjectDir.Replace(" ", "[[REPLACESPACE]])ContentMinScriptsExample.min.js
    /p:CssOutputFile=$(ProjectDir.Replace(" ", "[[REPLACESPACE]])ContentMinCSSSite.min.css

MinificationSettings.Xml:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/MsBuild/2003">
  <UsingTask
      TaskName="CompressorTask"
      AssemblyFile="packagesYUICompressor.NET-MsBuild-Task.1.6.0.2libNET35Yahoo.Yui.Compressor.MsBuildTask.dll" />

  <PropertyGroup>
    <CssOutputFile Condition=" '$(CssOutputFile)'=='' ">SylesSheetFinal.css</CssOutputFile>
    <JavaScriptOutputFile Condition=" '$(JavaScriptOutputFile)'=='' ">JavaScriptFinal.js</JavaScriptOutputFile>
  </PropertyGroup>

  <PropertyGroup>
    <CssOutputFileFix>$(CssOutputFile.Replace('[[REPLACESPACE]]', ' '))</CssOutputFileFix>
    <JavaScriptOutputFileFix>$(JavaScriptOutputFile.Replace('[[REPLACESPACE]]', ' '))</JavaScriptOutputFileFix>
  </PropertyGroup>

  <Target Name="MyTaskTarget">
    <ItemGroup>
      
      <JavaScriptFiles Include="$(SourceLocation.Replace('[[REPLACESPACE]]', ' '))ContentScriptsExample.js"/>
	  <CssFiles Include="$(SourceLocation.Replace('[[REPLACESPACE]]', ' '))ContentCSSSite.css"/>

    </ItemGroup>
    <CompressorTask
        CssFiles="@(CssFiles)"
        DeleteCssFiles="false"
        CssOutputFile="$(CssOutputFileFix)"
        CssCompressionType="YuiStockCompression"
        JavaScriptFiles="@(JavaScriptFiles)"
        ObfuscateJavaScript="True"
        PreserveAllSemicolons="False"
        DisableOptimizations="Nope"
        EncodingType="Default"
        DeleteJavaScriptFiles="false"
        LineBreakPosition="-1"
        JavaScriptOutputFile="$(JavaScriptOutputFileFix)"
        LoggingType="ALittleBit"
        ThreadCulture="en-au"
        IsEvalIgnored="false"
            />
  </Target>
</Project>

Source Code

30Jan/110

Visual Studio, Line Numbers and Ankhsvn

Although I am a git and DVCS true believer, I still deal with SVN. In Visual Studio this usually means I use AnkhSVN. For anyone paying for the VisualSVN client, I really think you should evaluate this tool. Its Visual Studio Integration is superb and I’ve had no usability problems in recent versions.

One thing about it annoyed me was caused by it integrating too well with Visual Studio. That problem was it is the display of line numbers on the editor screen. I setup Visual Studio to display line numbers in editor windows, and this has the side effect of displaying line numbers in the log message editor of the commit screen. I find this annoying. I don’t need line numbers for my commit log files and they take up precious screen real estate.

Commit to Subversion With Line Numbers

Luckily I found a solution. Apparently, in the current version of AnkhSVN, the commit editor has its own section in the Visual Studio Text editor options. So turning off the line numbers on the commit screen, but not the other editor screens can be done from the Tools | Options menu.

Options|TextEditor|General

Options|TextEditor|General

Options|TextEditor|Log Messages (AnkhSVN)

Options|TextEditor|Log Messages (AnkhSVN)

After that, the line numbers disappear in the commit dialog.

Commit to Subversion Sans Line Numbers

Its the little things like this that make a software experience truly great.

28Jan/100

Using the registry to resolve Visual Studio reference paths.

Update 2012-12-24: Updated to reflect the MSBuild 4.0 syntax as I describe here.
Note: To skip the long journey of what lead me to figuring this out, click here to go to the howto.

Recently I was asked to look at a fiddler plugin Stan, the founder of this blog, was developing. He gave me a SVN path and asked me to build it and test it.

So I checked out the source code and hit F5. I got a bunch of compiler errors relating to the fact that I didn’t have fiddler installed. I rectified that matter and still got errors. The problem was that the hintpath of fiddler.exe was wrong. On my machine, Fiddler is installed in ‘C:Program FilesFiddler2′, while on Stan’s machine it is installed to ‘C:Program Files (x86)Fiddler2′. I consulted the mighty google, which led me to a StackOverflow question. The question pointed out that you can have multiple hintpaths to an assembly. However, I wanted a better solution. What if someone installed Fiddler to a custom location?

I got the idea of using the registry. Fiddler has an installer. Surely the installer records its install location to the registry. It does in ‘HKEY_LOCAL_MACHINESOFTWAREMicrosoftFiddler2′ (Apparently fiddler is written by a Microsoft Employee). So the question is how to get MSBuild, the tool that visual studio uses to parse project files, to read a value from the registry.

The answer was found in a post on the MSBuild team blog. However, for Visual Studio 2010 and later, I recommend the syntax described here. The new syntax takes into account RegistryView and the Wow6432Node. The old syntax happens to work just fine in Visual Studio because Fiddler is compiled to 32 bits explicitly and Visual Studio is a 32 bit app. However, if you were to compile the app on the command line on a 64 bit system, the reference would not be resolved.

How To

Unfortunately, Visual Studio does not allow you to edit hintpaths to referenced assemblies. So you’re going to have to edit your vcproj or vbproj file in notepad or some other text editor.  Here are the steps:

  1. Open the project file in your text editor.
  2. Look for the <Reference/> element for fiddler.exe. It should look similar to this:
    <Reference Include=”Fiddler, Version=2.2.7.5, Culture=neutral, processorArchitecture=MSIL”>
      <SpecificVersion>False</SpecificVersion>
      <HintPath>C:\Program Files\Fiddler.exe</HintPath>
      <Private>False</Private>
      </Reference>
  3. Change the hintpath as follows (Visual Studio 2010 and later):
    <Reference Include="Fiddler, Version=2.2.7.5, Culture=neutral, processorArchitecture=MSIL">
    <SpecificVersion>False</SpecificVersion>
      <HintPath>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fiddler2@InstallPath)Fiddler.exe</HintPath>
      <Private>False</Private>
    </Reference>
  4. On Visual Studio 2008, you must use the old syntax:
    <Reference Include="Fiddler, Version=2.2.7.5, Culture=neutral, processorArchitecture=MSIL">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fiddler2', 'InstallPath', null, RegistryView.Registry32))Fiddler.exe</HintPath>
    <Private>False</Private>
    </Reference>
  5. Save the file
  6. Visual studio will detect the file change and ask you to reload the file. If you are using SharpDevelop as you’re IDE, you will have to close and reopen the solution.

Thats all there is to it. Happy coding!