Apr 29

Passing Parameters to a target in MSBuild

On our current project we are using MSBuild to build our application. This is my first time using MSBuild other than just tinkering and I have found it…. challenging to say the least. A lot of my challenges are lack of knowledge but the other half is the language itself.

The most recent challenge I wanted to write about was calling a target multiple times. Our scenario is this: We have to generate a batch file for each environment we are going to install in with environment specific settings. The issue I had was that for each environment we had that we were copying and pasting the steps and changing values for each environments. While this worked, as the number of environments grew the size of the build task grew and got harder to modify as requirements changed.

Ideally what we would have is a task that would generate a batch file based on a set of parameters that we could just call out to so I built this:

   <Target Name=”BuildBatchFile “>
    <Copy SourceFiles=”install.bat”
                 DestinationFiles=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                
ContinueOnError=”false” 
                 SkipUnchangedFiles=”false” />
    <FileUpdate Files=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                           Regex=”{ENV}”
                           ReplacementText=”$(ENV)” />
    <FileUpdate Files=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                           Regex=”{VDIR}”
                           ReplacementText=”$(VDIR)” />
    <FileUpdate Files=”MyApp.Setup\Release\install.$(BATCHENV).bat”
                           Regex=”{INSTALLDIR}”
                           ReplacementText=”$(INSTALLDIR)” />
  </Target>

So this copies my template install.bat to install.[ENVIRONMENT[.bat and then does all the string replacements on it.

The issue is how to invoke this task with different sets of data. My first thought was this:

<CallTarget Targets=”BuildConfigFile” />

Unfortunately, there is no way to pass parameters to a target. The only way to do that is to call MSBuild and set the parameters passed to MSBuild (this does feel wrong but I am not sure of a better way to do it so far)

<Target Name=”BuildDeploymentPackage”>
    <MSBuild Projects=”$(MSBuildProjectFile)”
                      Targets=”BuildBatchFile “  
                      Properties=”BATCHENV=ALPHA;ENV=ALPHA;VDIR=PASIPrep;INSTALLDIR=C:\inetpub\wwwroot\MyApp;” />
    <MSBuild Projects=”$(MSBuildProjectFile)”
                       Targets=”BuildBatchFile ”
                        Properties=”BATCHENV=SYST;ENV=SYST;VDIR=MyApp;INSTALLDIR=C:\inetpub\wwwroot\MyApp;” />
    <MSBuild Projects=”$(MSBuildProjectFile)”
                       Targets=”BuildBatchFile “ 
                       Properties=”BATCHENV=TRAINING;ENV=TEST;VDIR=MyApp;INSTALLDIR=C:\inetpub\wwwroot\MyApp.TEST;” />
  </Target>

The above target calls MSBuild to call its own build file and run the BuildBatchFile target with a set of parameters.

Hope this helps (or someone shows me a better way to do it)!

 

 

 

Apr 16

Testing Your Configuration

One common issue of team development is sharing configuration files. If a developer is testing something out and changes a value and then accidentally checks that file in it affects all developers.

There are a few approaches to solving this issue:
1) Be very careful and disciplined.

+Simple
-SImple to forget

2) Have a web.config.template under source control that developers copy to web.config and not include in source control.

+Prevents checkins of web.config files that affect other people
-Developers need to manually update their config files if a new value is added/removed/or the default updated

3) Have a build script task to generate a config file on demand.

+Changes are easily propagated through the script
-If a developer mucks with the build script and checks it in then we have the same problem (but less likely to happen)

4) What we are trying. Unit test the configuration to make sure it is correct.
+web.config is under source control
+changes are caught by a test. If it is meant to be distributed to all developers then the test should be updated as well
-have to write a test for the configuration (not a big minus in my opinion)
-If you have different config settings for the test project than the actual project then this will not work

In order to test a config file though we need to be able to load that config file! In our case we are testing a web.config and nunit is expecting a app.test.dll.config file. The easy way around this was to copy the web.config from our application to the proper folder and name with a pre-build event:

copy $(SolutionDir)\App.Service\web.config $(ProjectDir)\bin\App.Test.dll.config /y

Now my tests use that config file to assert that the settings are proper. The big downside to this approach is that it will overwrite the app.config file that you may already have for your test which may not be desirable.

Alternatives:
1) Parse the XML of the config file you want to test and verify
2) Load and unload and external config file in a test (I started with this and could not get it to work)

Mar 25

Staying Secure

I have started to realize that there are a few things I do that most average users do not to stay secure.

  1. I use a password manager (Roboform) that integrates with my browser. This tool makes me remember one master password and then allows me to fill in login forms on websites with only needing to know one master password. This has let me use unique passwords on all the sites I login to. I see looking through my list of sites that I have 45 accounts on various sites and there is no way that I could remember 45 unique passwords.
  2. I use encrypted pop/smtp/imap so as not to divulge my password. Most of the world still seems to use unauthenticated POP3 for some reason
  3. I use the NoScript add on for Firefox that allows me to control if scripts run on a page or not
  4. I use the ForceTLS add on for Firefox so that if I visit a http site that it will redirect me to an https site (unfortunately you have to setup this list on your own)
  5. I never upgrade an OS. I always reinstall. Call me paranoid but it is hard for anything bad to survive a wipe and reinstall
  6. I run the Secunia Personal Software Inspector that checks for security issues in third party apps and allows me to easily download updates
  7.  I run Microsoft Security Essentials. A free, lightweight, and (from what I have read) accurate virus scanner. It reminds me of how all antivirus software starts out so lets hope MS does not bloat it up.
Jan 20

Trust. It is a Two Way Street

One of the most common flaws I am seeing in applications is the lack of mutual authentication. Most systems authenticate that the user connecting to their system is a valid user. What is lacking is that the client verifies that it is connecting to who it thinks it is connecting to.

One of the big examples of this is WiFi. If I have a wireless router named “myrouter” and set my laptop to use that router things work great. If I go down the street and someone else has a router named “myrouter”, my laptop automatically tries to connect to it. This is because the WiFi implementation does not verify that I am connecting to who I think I am connecting to.

This happens a lot on the service level of applications. The client app resolves a DNS name like www.myservice.com to it’s IP address and then sends over some form of authentication. Now what happens if I somehow manage to change the DNS record for www.myservice.com to point to my IP address which contains a service with the same name and same methods exposed to it? The client will connect and divulge its authentication data to this fake service. I can now use the authentication data that you gave me authenticate against the real system and do whatever nefarious things I desire.

The solution for this is for clients to verify that the service it is talking to is actually the service you want to be talking to. This is best accomplished by using some form of shared secret. This takes on many forms but a few methods:

  1. Ask the server to answer a shifting question. i.e. ask the server to hash a certain string. If the hash the server returns matches what you expect then the server might be the one you want (or an attacker managed to replicate the algorithm)
  2. Use windows authentication. For WCF the mutual authentication is implied in this case.
  3. Use certificate authentication. This is the best way to do this task but can be a pain to implement.
Jan 19

Team City Build Versioning

One of the great things about continuous integration is that we can increment our assemblies version number with each build. For our project we also apply a label to our source code repository every time we build a deployment package. This allows us to get the version of source code from the exact point in time that the msi was built.

One of the issues we ran into was that we have three build configurations:
1. “CI” This gets run on every checkin of code
2. “Deploy – ALPHA” This is run manually to deploy to our alpha test environment
3. “Deploy – ALPHA & BETA” This is also run manually and this deploys the same version to both the alpha and beta test environments

The issue we ran into is that each configuration has its own build number that is incrementing so if we ran “Deploy – ALPHA” 10 times we would have v 1.10.0.0 in ALPHA. If we then ran “Deploy – ALPHA & BETA” for the first time suddenly ALPHA now has v1.1.0.0! Obviously this is not very intuitive. In the end we added in the version number from our source code repository into our build numbers for both deploy configurations. Now we get build numbers like this: 1.46347373.0.0

The way we did this was by using the vcs variable in team city: 1.{build.vcs.number.TheNameOfVCSRoot}.0.{0}. The last digit is still an incrementing counter in case you re-run the build that something still increments even though the version in source control has not changed.

Jan 18

Remote MSI Execution

One of the things we have started doing as part of our process is having a build script that creates our deployment package in an automated fashion. We then tied that into our build server so that from one click anyone could create the package. The issue is that we have several test environments and copying the setup.msi file to multiple servers and installing it is a time consuming pain. To streamline our deployment we created a vbscript (yes, it was painful) to remotely uninstall previous versions and then install the new version of the msi. Here is the script currently:

strComputer = “mytestserver”

Wscript.Echo “Getting WMI Object”
Set objWMIService = GetObject(“winmgmts:” & “{impersonationLevel=impersonate}!\\” & strComputer & “\root\cimv2″)

Wscript.Echo “Finding Previous versions”
Set colSoftware = objWMIService.ExecQuery (“Select * from Win32_Product Where Name = ‘My First Setup Project’”)
For Each objSoftware in colSoftware
    Wscript.Echo “Uninstalling a previous version”
    objSoftware.Uninstall()
Next

Wscript.Echo “Getting Software Object”
Set objSoftware = objWMIService.Get(“Win32_Product”)

Wscript.Echo “Installing”
errReturn = objSoftware.Install(“c:\builds\MyFirstSetupProject.msi”, “TARGETENV=DEVL”,True)

Wscript.Echo “Install status: ” & errReturn

In order for this to work the msi must be copied to the remote machine to work. I tried connecting to a central network share but it did not seem to work for me. The script needs a bit of work but now we can deploy to the environments we want updated in a couple of minutes instead of the 15-20 minutes it took us before.

Jan 17

Return To Blogging

I am finally finding some time and desire to write again. Life has been busy with my both my company and my family expanding. It feels like things are starting to get back to normal again so I should be writing more frequently.

Some of the things I have been working with that I hope to write about:

  • nHibernate / fluent nHibernate / Linq to nHibernate
  • WPF
  • Click once
  • Silverlight
  • A fluent .NET build langauage called fluent-build
  • Being a lead on a project
  • Multithreading
  • Caching of large amounts of data
  • Threat modeling
  • Other security items
Aug 10

Excluding Items From MSTest Code Coverage

One thing I really like about MSTest is that you can turn code coverage on so you can see where unit tests are lacking (or non-existent).

One thing I don’t like is that in VB there is a class generated for settings in the “My” namespace. While it is handy for coding in some cases it irks me that it gets included in my code coverage result.

The only way to exclude it (that I have found anyways), is to add the DebuggerNonUserCode attribute to the MySettings class in the project. Not very intuitive I know but maybe we can get a IgnoreFromTestCoverage result attribute someday. (NOTE: I did try to create my own custom attribute but DebuggerNonUserCode is not inheritable).

This class can be found by selecting the project in solution explorer, selecting “show all files”, then finding the Settings.settings file in the “My Project” folder. Alternatively you should be able to create a partial class if you want to avoid it being lost if the code is regenerated.

Aug 6

Edmonton Code Camp: Call For Speakers

Edmonton Code Camp is happening again this year and we are looking for speakers! Topics are wide open. That means ANY language, ANY technique, or ANY technology.

When: September 19,2009
Where: Grant MacEwan Downtown Campus, Edmonton, Alberta

Please submit talks to dave@solidhouse.com by August 15, 2009

Aug 6

Book Review: Brownfield Application Development

I was asked to review the soon to be published Brownfield Application Development by Kyle Baley and Donald Belcham. For those who have not heard the term, a brownfield application is one that already has some code developed but is usually not complete. A lot of developers are brought into projects like this and therefore have had no say on the techniques and tools to start developing the application. This book covers how to make an existing application better, more testable, and easier to work with in a simple and accurate fashion.

The book is split into two sections, the first one: The Ecosystem covers important topics like version control, testing, continuous integration, and defect tracking. The chapters were well written with no bias towards a particular technology (although the pros and cons are discussed of some systems). Baley and Belcham accurately describe how to setup an ecosystem that allows you to develop and maintain a code base well into the future.

The second section: The Code, hits home with how to bring good quality code practices into the code base. I found over and over again that the authors hit on all the problems I have seen working on brownfield and legacy code bases and great recommendations on how to overcome them.

One of the key things the authors hit on is how to minimize dependencies in your code base. Tightly coupled code is both hard to change and test which makes minimizing the dependencies very important. The best part of this book is that they have a separate chapter for reducing dependencies internally and on external systems. I find this to be the most important topics that this book covers.

I wish I would have had this book ten years ago and not had to learn these lessons the hard way. The book so accurately describes the pain points of software development and how to eliminate or mitigate those issues. The authors have obviously gone through the same learning curve that I have and have perfectly summarized their years of experience in an easy to consume format.