Welcome to EMC Consulting Blogs Sign in | Join | Help

James Dawson's Blog (2005 - 2011)

I have now left EMC Consulting, if you wish to continue to receive new content then please subscribe to my new blog here: http://www.readsource.co.uk

  • T4: Pain Relief for .NET Configuration Management – Pt.1

    Anyone who has done anything moderately complex with .NET will have undoubtedly felt the pain associated with having to deal with your application requiring different configuration settings when deployed into to different environments – and if you’re working with WCF then even more so! (Clearly this is a general pain felt across all flavours of development and whilst for purposes of this post I’m focussing on the .NET world, the core approach could be applied more broadly)

    Here at EMC Consulting this challenge has typically fallen to us Platform Architects to overcome, and over years we’ve evolved some in-house tooling that could integrate with our build and deployment processes whilst at the same time trying to minimise any additional overhead on the day-to-day development process.  The various evolutions all followed this basic premise:

    • Configuration settings that need to be environment-specific are replaced with tokens
    • Maintain a set of mappings that assign the required values for each token, for a given environment
    • During deployment, use a simple search & replacement operation to patch any tokenised configuration files with the required values

    The need for developers to have valid configuration files to support local their local build & debugging activities, meant that earlier iterations involved maintaining a template copy of each configuration file that contained environment sensitive settings.  Whilst this gave us a good story for not impacting the day-to-day developer activities, it did bring the additional overhead of having to keep the two files in-sync.  Inevitably, this would not always happen (particularly when the configuration change was not of an environment-specific nature) and thus the template version would become out of date and ultimately result in a deployment failure later on.

    It was this aspect that led me to think about alternative approaches that could reduce this overhead. Several years ago I remember seeing a cool approach for doing this that formed part of the Enterprise Library (EntLib) – whilst still relying on a separate configuration file it used a mechanism that permitted target configuration files to be transformed based on criteria in this separate configuration file (which only had to contain the elements that needed to change, rather than a complete copy of the target configuration file).

    Specifically, this approach expected you to define a transform for each environment where you would apply the required settings, but I figured you could equally create a single transform and use the tokens mentioned above instead and then run the search & replace operation against the transformed configuration file.  The main downside of this tool, in my view, was that it seemed to only work for custom configuration settings implemented via EntLib so could not be used to manage standard web.config settings, for example.

    I would hazard a guess that the above EntLib functionality was the basis/inspiration for the similar functionality we now see in the MSDeploy ‘configuration transform’ feature.  However, in terms of the out-of-the-box experience this feature is limited to web.config files, although there are various posts out there that show how to use it more broadly (http://www.olegsych.com/2010/12/config-file-transformation/).  Again, this approach could be combined with the use of tokens to avoid maintaining multiple transform files.

     

    With that background out of the way let’s get to the title point of this post – using T4 templates to address the issues outlined above.

    If you’d like some more information of T4, then here are a few links to get you started:

    The essence of this approach is just an extension of the one above, and it looks like this:

    • Convert all configuration files that need to be environment-specific to be T4 templates
    • Implement T4 logic that can inject into these configuration files, either:
      1. actual values (to support local build & debugging activities)
      2. tokens (for deployment packages)
    • Utilise the T4 support built into Visual Studio to regenerate the config file using the #1 scenario above, whenever the file is modified
    • Have the build process execute the T4 logic using the #2 scenario to create the tokenised configuration files
    • Maintain a set of mappings that assign the required values for each token, for a given environment
    • During deployment, use a simple search & replacement operation to patch any tokenised configuration files with the required values

    This allows a single copy of that configuration file to be maintained (albeit in a modified form) and also has the added benefit of placing the environment-specific nature of the configuration file in clear view of anyone working on that file, hopefully making it more likely that they will think about the broader configuration concerns rather than just whatever it takes to get it working for them.

    In closing, at the risk of being hit with the ‘Not Invented Here’ stick, whilst the latest tools from Microsoft (config file transformations) are a welcome addition to the stock toolbox, they are limited to being used with XML files (and MSBuild seemingly) – which whilst representing the majority of scenarios does leave some edge cases unsupported.  As with most things in our industry there are many ways to solve this problem, and each has their own pros and cons and I present this as just another option.

    In my next post I’ll run through a sample implementation of the above.

    In the meantime, if you have any comments on this approach or can suggest other alternatives that have worked for you then please drop me a comment.

    Cheers, James.
    (@James_Dawson)

  • DevOps to Solve all the Software Delivery World’s Ills?

    As part of my self-imposed DevOps induction I’ve been casually following the #devops feed on Twitter, and a tweet from @emmanuel_belo got me thinking – seemingly enough to spur me into firing-up Live Writer!

    image

    Whilst the underlying point is rather self-evidently correct, I view it as a bit of a straw-man argument.  There are a multitude of difficulties associated with delivering quality software of which giving the user or customer actually what they want is just facet (albeit an important one).  As such there are plenty of strategies out there that aim to address this, but few of those really tackle the issue of the Development/Operations divide in any detailed way – for those that do, that part of the message tends to be lost amongst the rest of the goodness that they proffer us.

    It’s all to easy to say that DevOps doesn’t solve the whole problem, represents nothing new, or is nothing more than common sense and therefore deem it to be of limited value.

    Working in the consulting business as I do, does mean that I tend to miss out on the long-tail part of the application lifecycle – keeping it running in production, on-going releases etc.  However, the flip-side of that coin is that I get to see a lot of variety in terms of the technology, business models, delivery practises, team dynamics, to name but a few.

    The reality is that even in organisations that have done a good job at adopting these ‘other’ strategies for improving their software delivery capability, you still see this divide between their Development and Operations teams – no matter how agile or how refined their engineering practises are such a divide can still be hugely divisive.

    It is on this premise that I see the value in the notion of DevOps; it allow us to bring focus to a particular set of problems and in doing so (whilst not primarily concerned with the end-user or customer) should help ensure that customer requirements, particularly non-functional ones, are far more likely to be met – which seems like a ‘good thing’™ to me.

    To view DevOps as aiming to solve all our software delivery ills is to fall into the silver bullet trap, and frankly, miss the point.

    Cheers, James.
    (@James_Dawson)

  • On Discovering DevOps

    A few weeks ago James sent me an e-mail saying that he’d been coming across this thing called ‘DevOps’ a lot lately and it seemed like it might be the closest thing yet to our Platform Architect role, outside of EMC Consulting.

    The Platform Architect team is a small, and mostly merry, band of technical consultants who typically started out their careers on the Infrastructure side of IT and have evolved to straddle the fence that divides the Infrastructure and Development worlds - if you read Grace’s blogs, then you’ll already have a fair idea of the types of things we get up to.

    So getting back to my introduction to the DevOps world, I was intrigued by it not least because I often struggle to define what we as PA’s do when talking to Clients without getting bogged-down in details; such is the breadth of what we have to cover.  Hence why coming across a term with a defined understanding in the outside world was of such interest to me, both in terms of talking to Clients as well as how we find and recruit new PA’s.

    Hunting around for some further reading, one of the first articles I came across, was a guest post by Stephen Nelson-Smith on the rather coolly-named jedi.be blog (Just Enough Developed Infrastructure – nice!) which resonated with me hugely.  As consultants, clearly we’re not sysadmins in the purest sense, but we are invariably the sysadmins for those projects that we’re involved with and as such the same pain points and desire to make things better still ring true.  However, one of the benefits of operating within the team at EMC Consulting is that the typical barriers between disciplines that Stephen mentions are far less prevalent, as is the siloisation, mainly due to working in small to medium-sized project teams.  That said, we will often collaborate with the Client’s various teams and it is here that we regularly see exactly the tensions between them that Stephen highlights, and in that respect our role is very much a bridging one too.

    One thing that seems notably absent from what I’ve read about DevOps (to-date) is any mention of Application Lifecycle Management (ALM) – this forms a fairly large part of the PA role here and I’m keen to learn whether ALM is indeed considered outside of DevOps, or whether I just haven’t been looking in the right places.  On the surface, much of what is talked about seems relevant to different parts of ALM but no-one seems to be making any explicit references to it.  I’d be really interested to hear from anyone who can shed some light on this, one way or the other.

    Configuration Management seems, understandably, to be a key topic in the DevOps world so in my next post I want to discuss an approach for tackling application configuration management that I’ve been working on lately.  I use a lowercase C & M on purpose, as it is very much a lightweight approach that aims to remove as much friction as possible from the task of making application configuration files environment-agnostic (e.g. not hard-coding server names, credentials, paths etc.) whilst at the same time ensuring that the need for this activity is still very much front-and-centre in the development team’s mind.

    Cheers,

    James.

    (@James_Dawson) 

  • Installing TFS 2008 onto SQL Server 2008 SP1 (you can't!)

    This post definitely falls into the 'note-to-self' category - myself and a blog-less colleague wasted a good few hours this morning trying to get Team Foundation Server (TFS) installed onto a new virtual machine.

    If you're in the habit of using slipstreaming to integrate service packs into products' base installers (to save time), which you can do with both TFS 2008 and SQL Server 2008, then be aware that TFS 2008 SP1 will not let you install to a server running SQL Server 2008 SP1 - it needs to be the RTM version.  Attempting to do so (as we did) will result in the TFS pre-install checks failing saying that a suitable version of SQL Server is not available.

    Initially I was convinced that I had previously done an installation with this combination, however, after a couple hours that self-belief was in tatters!  Fortunately, we were able to cleanly uninstall the SQL Server service pack via 'Add/Remove Programs', somewhat surprisingly, with no undue side effects on other databases that had already been deployed. (It's always nice when something works the way it's supposed to!)

    If you want more information on how to create slipstreamed versions of Team Foundation Server 2008 or SQL Server 2008, then you should take look at the following links:

    UPDATE: I knew putting "can't" into the title would ensure I got proved wrong!  Thanks to @StuartPreston for pointing me in the direction of a hotfix that resolves this issue: http://support.microsoft.com/kb/969985

     

  • TFS vs. SVN vs. Git …

    So, there’s been a bit of storm blowing through the part of the InterWeb that I inhabit recently – see http://blog.benday.com/archive/2009/07/27/23233.aspx for the low-down.

    I’ve seen these types of discussions countless times, both online and in the real world – the thing that wears me down the most is the seemingly constant assertion that ‘SVN/Git/Mercurial = TFS’, as if source control is the only consideration.

    Let me lay down a couple points of order before I get flamed to oblivion:

    1. I’ve generalised this assertion, somewhat
    2. I’ve spent time using both SVN and Git and like them both
    3. I have no desire to sound like a Microsoft shill!

    Fundamentally, SVN and TFS are implementations of a centralised version control system (VCS) that are designed using polar-opposite philosophies – TFS is server-centric whilst SVN is client-centric.  The reality is that both of these approaches have advantages and disadvantages in terms of usability and performance.

    Regarding the centralised versus distributed debate, I actually like a lot of things about Git et. al. and I would guess that as the various tooling/integration stories develop we will see more corporate and enterprise adoption.

    Getting to my point though, most of the customers I talk to rarely arrive at the TFS ‘answer’ on the basis of a VCS selection process (those that have, usually get a suggestion from me to look at other open source alternatives), they get there because they are looking for something to satisfy their Application Lifecycle Management (ALM) needs – I consider TFS to be pretty cost-effective in the ALM space.  Granted, there is a sizable chunk of TFS adopters who migrate from Visual SourceSafe (and are pre-disposed to use Microsoft tools) but as a like-for-like swap Microsoft have, in general terms, made that migration relatively painless.

    However, increasingly we’re seeing customers who have arrived at the TFS ‘answer’ because they use Scrum to manage their development projects and have chosen Scrum for Team System (a TFS process template we make available for free) as their preferred project management tool - and from their perspective TFS comes with the added bonus of not having to worry about selecting and integrating a separate VCS and automated build system.

     

  • TFS, Build Servers and Un-Trusted Domains

    I’ve been meaning to write this up for a while now, and a recent Twitter exchange with @thiago_bagua prompted me to finally get around to it.  This post will describe a way of getting a TFS 2008 build server up and running in an Active Directory domain that has no trust relationship with its associated TFS server.

    CAVEAT: Whilst the approach I going to describe below worked for me, your mileage may vary and I doubt that it is an officially supported configuration.

     

    Assumptions:

    • You have a working instance of TFS
    • You have already installed the TFS Build Agent (aka Team Build) on your build server

     

    The diagram below illustrates the basic scenario, with the TFS Application-Tier (AT) and TFS Build Agent residing in separate domains with no trust relationships.

    image

     

    With the above configuration there are basically two problems we need to overcome:

    • The Build Agent that runs as a Windows service called ‘Visual Studio Team Foundation Build’, will need to authenticate with the TFS AT in order to consume the various web services (e.g. source control, work item tracking, publishing build results etc.)
    • The TFS AT will need to authenticate with the Build Agent service in order to be allowed to start a build

     

    Build Agent to TFS Authentication

    Solving the first problem involves storing a saved password in the profile of the Build Agent’s service account, in this scenario ‘DOMAINB\TFSBuild’, and ensuring that the server will use that credential automatically.

    1) Log onto the Build Agent server as the ‘DOMAINB\TFSBuild’ user (or equivalent)
    2) Open the ‘User Accounts’ Control Panel applet (also called ‘Stored User Names and Passwords’ on Windows Server 2003)
    3)

    Select ‘Manage your network passwords’

     image

    4) Add an entry for the server running the TFS Application Tier (you may want to add two, one for the server’s NetBIOS name and another for the server’s FQDN).
    image

    The username you enter here needs to be an account in the ‘DOMAINA’ domain that is a member of the ‘Build Services’ application group in the Team Project(s) the Build Agent will be servicing.
     image

    Here you can see both the NetBIOS and FQDN entries for the TFS server have been added.
    image
    5) Review the Internet Explorer security settings of the ‘Local Intranet Zone’ and ensure that the ‘Automatic logon only in Intranet zone’ is selected.
     image
    image
    6) By default the FQDN of the TFS Application Tier is unlikely to be treated as being in the Intranet Zone, so we need to add it explicitly.
    image
    image
    7) You should now be able to test these changes by opening Team Explorer and verifying that you are able to transparently connect to the TFS server (i.e. you aren’t prompted to enter credentials).

     

    TFS-to-Build Agent Authentication

    Having completed the above, we now just need to solve the second problem.  My approach was to create a local account on the Build Agent with the same username and password as the account used as the identity of the ‘Microsoft Team Foundation Server Application Pool’ on the TFS Application Tier.  This has the effect of allowing the TFS Application Tier to authenticate to the build server using it credentials.

    As an alternative to this, you could setup a saved password, this time on the TFS server, in the profile of the ‘DOMAINA\TFSService’ account for the build agent server that use a domain account in ‘DOMAINB’ or local account on the build server.

     

    At this point you should be able to register the new build agent in your Team Project and queue a build to it.

     

    Troubleshooting

    If you have hit problems whilst trying the queue the build, then this indicates that the TFS Application Tier had a problem connecting to the build agent.  This is typically caused by TFS not being able to authenticate to the build agent or some kind of firewalling preventing the network connection, usually via TCP port 9191.

    If the build starts but quickly fails, then this generally points to either or both of the following:

    1. The Build Agent service account cannot authenticate to the TFS Application Tier (i.e. a problem with its saved username/password).
    2. The saved username/password has not been added to the ‘Build Services’ application group in the relevant Team Project.

     

    Anyway, if you find yourself in this sort of edge case scenario then hopefully the steps detailed here will be helpful.  I'm now wondering whether a similar approach could be used to workaround the issue of not being able to add users, from a Trusting domain, to TFS application groups when there isn't a 2-way trust in place...?

     

  • Using Linked Files with Web Application Projects

    A customer recently contacted me saying that they had upgraded to Visual Studio 2008 and had also taken the opportunity to switch from a Web Site Project to a Web Application Project.  A while back I'd helped them to centralise some of their configuration so that they only had a single copy of all the configuration sections that were referenced by multiple projects (e.g. the web site, various unit test projects etc.).

    This involved creating separate configuration files for each section and referencing them from the main web/app config using the 'configSource' attribute, for example:

      <!-- Reference the shared config file -->

      <connectionStrings configSource="dbConfig.config" />

     

    The above referenced configuration file would something like this:

      <connectionStrings>

        <add name="DB1"

             connectionString="Data Source=.;Initial Catalog=DB1;Integrated Security=SSPI"

             providerName="System.Data.SqlClient" />

      </connectionStrings>

     

    Due to the 'configSource' attribute not supporting relative paths, it was necessary to setup pre-Build events to copy the referenced files into the project folder - especially for the Web Site project where a valid web.config is required by the ASPNET compiler.

    After the switch to the Web Application project model the client was wondering whether they needed to change how they were handling these shared configuration files.  My initial response was to suggest that they discontinue the pre-build scripts and instead use the 'linked files' feature that was available with web application projects (much like they have been for other types of projects a long time).

    For those of you unfamiliar with this useful feature, here's how you add a linked file via the 'Add Existing Item' option:

    image image

    Such files appear in Solution Explorer as normal project items, albeit with a shortcut icon.

    image

    However, after trying it, they reported that those files were missing from the web site which was causing all manner of problems.

    It turns out that when you build the project linked files are not copied into the project folder, which is obviously a problem as it means that the file is not available to the web site at runtime.  Your first thought might be to enable the 'Copy Local' option for the linked files, however, all this does is to copy the linked files to the 'bin' folder... not exactly the result we're after.

    Before carrying on, it's worth looking at how the linked items are stored in the actual web application project file, as it will later help us understand why this issue occurs.

      <ItemGroup>

        <Content Include="..\..\dbConfig.config">

          <Link>dbConfig.config</Link>

        </Content>

      </ItemGroup>

     

    From this you can see the main path for the item (the 'Include' attribute) is a relative path to the shared configuration file, whilst the 'Link' attribute tells Visual Studio where the item exists within the project - in this case, the file was added to the root of the project.

    To investigate further I took a look at the 'Microsoft.WebApplication.targets' file that contains the Web Application project build process and typically lives in the 'C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\WebApplications' folder.  There I found a target called '_CopyWebApplication' which only gets executed when the output directory has been overridden (e.g. what TeamBuild does to redirect all build outputs into a single directory):

      <Target Name="_CopyWebApplication" Condition="'$(OutDir)' != '$(OutputPath)'" >

     

    At the end of this Target there is the following call to the MSBuild Copy task:

      <!-- Copy content files recursively to _PublishedWebsites\app\ folder -->

      <Copy SourceFiles="@(Content)" DestinationFolder="$(WebProjectOutputDir)\%(Content.RelativeDir)" />

     

    So when the above Copy task executes it's going to use the relative path to the linked item as part of the destination path, rather than the path within the project (i.e. the 'Link' attribute) - so this explains why the files aren't getting copied:

    1. When building in Visual Studio, nothing special happens to copy the content files (linked or otherwise)
    2. When redirecting the output path, normal Content files are copied fine (their 'Include' attribute does not contain a relative path), but the linked content files will get copied to a folder with the same relative path to the actual output folder, as the linked item has to the project file (e.g. 'MyOutDir\..\..\dbConfig.config' instead of 'MyOutDir\dbConfig.config')

    Anyway, let's cut to the chase... here is my suggested workaround:

    1. Fix the 'Copy' task to not include linked files
    2. Create another target to handle the copying of linked files using the correct destination path

    To achieve the first, we'll need to override the built-in '_CopyWebApplication' target by pasting it into our web application's project file and tweaking the 'Copy' task mentioned above:

      <!--

      ============================================================

      _CopyWebApplication

      MODIFIED: Ignores linked files as part of normal deployment logic.

     

      This target will copy the build outputs along with the

      content files into a _PublishedWebsites folder.

     

      This Task is only necessary when $(OutDir) has been redirected

      to a folder other than ~\bin such as is the case with Team Build.

      ============================================================

      -->

      <Target Name="_CopyWebApplication" Condition="'$(OutDir)' != '$(OutputPath)'">

        <!-- Log tasks -->

        <Message Text="Copying Web Application Project Files for $(MSBuildProjectName)" />

        <!-- Create the _PublishedWebsites\app\bin folder -->

        <MakeDir Directories="$(WebProjectOutputDir)\bin" />

        <!-- Copy build outputs to _PublishedWebsites\app\bin folder -->

        <Copy SourceFiles="@(IntermediateAssembly)"

              DestinationFolder="$(WebProjectOutputDir)\bin"

              SkipUnchangedFiles="true" />

        <Copy SourceFiles="@(AddModules)"

              DestinationFolder="$(WebProjectOutputDir)\bin"

              SkipUnchangedFiles="true" />

        <Copy SourceFiles="$(IntermediateOutputPath)$(_SGenDllName)"

              DestinationFolder="$(WebProjectOutputDir)\%(Content.SubFolder)%(Content.RecursiveDir)"

              SkipUnchangedFiles="true"

              Condition="'$(_SGenDllCreated)'=='true'" />

        <Copy SourceFiles="$(IntermediateOutputPath)$(TargetName).pdb"

              DestinationFolder="$(WebProjectOutputDir)\bin"

              SkipUnchangedFiles="true"

              Condition="'$(_DebugSymbolsProduced)'=='true'" />

        <Copy SourceFiles="@(DocFileItem)"

              DestinationFolder="$(WebProjectOutputDir)\bin"

              SkipUnchangedFiles="true"

              Condition="'$(_DocumentationFileProduced)'=='true'" />

        <Copy SourceFiles="@(IntermediateSatelliteAssembliesWithTargetPath)"

              DestinationFiles="@(IntermediateSatelliteAssembliesWithTargetPath->'$(WebProjectOutputDir)\bin\%(Culture)\$(TargetName).resources.dll')"

              SkipUnchangedFiles="true" />

        <Copy SourceFiles="@(ReferenceComWrappersToCopyLocal); @(ResolvedIsolatedComModules); @(_DeploymentLooseManifestFile); @(NativeReferenceFile)"

              DestinationFolder="$(WebProjectOutputDir)\bin"

              SkipUnchangedFiles="true" />

        <!-- copy any referenced assemblies to _PublishedWebsites\app\bin folder -->

        <Copy SourceFiles="@(ReferenceCopyLocalPaths)"

              DestinationFolder="$(WebProjectOutputDir)\bin"

              SkipUnchangedFiles="true" />

        <!-- MODIFICATION HERE: Copy local content files (i.e. non-linked files) recursively to _PublishedWebsites\app\ folder -->

        <Copy Condition=" '%(Content.Link)' == '' "

              SourceFiles="%(Content.Identity)"

              DestinationFolder="$(WebProjectOutputDir)\%(Content.RelativeDir)" />

      </Target>

     

    For the second, we need to add a new target to our project file and override the default dependencies to have it executed:

      <!--

      ============================================================

      CopyLinkedContentFiles

     

      A new target to copy any linked content files into the

      web application output folder.

     

      NOTE: This is necessary even when '$(OutDir)' has not been redirected.

      ============================================================

      -->

      <Target Name="CopyLinkedContentFiles">

        <!-- Remove any old copies of the files -->

        <Delete Condition=" '%(Content.Link)' != '' AND Exists('$(WebProjectOutputDir)\%(Content.Link)') "

                Files="$(WebProjectOutputDir)\%(Content.Link)" />

        <!-- Copy linked content files recursively to the project folder -->

        <Copy Condition=" '%(Content.Link)' != '' "

              SourceFiles="%(Content.Identity)"

              DestinationFiles="$(WebProjectOutputDir)\%(Content.Link)" />

      </Target>

      <!-- Override the default target dependencies to -->

      <!-- include the new _CopyLinkedContentFiles target. -->

      <PropertyGroup>

        <PrepareForRunDependsOn>

          $(PrepareForRunDependsOn);

          _CopyWebApplication;

          CopyLinkedContentFiles;

          _BuiltWebOutputGroupOutput

        </PrepareForRunDependsOn>

      </PropertyGroup>

     

    With these changes, whenever you build the web project any linked content files will be copied into the web application's folder structure  - whether you override the default output directory or not.

    If anyone is interested I've attached a sample solution that demonstrates the above workaround (as well as an unmodified project file so you can see the issue).

    Part of me wonders whether this is a bug at all, or whether it is in fact just an unexpected feature that was never supposed to be supported... I've raised a bug on Connect, so I guess I'll find out in due course.

  • TeamBuild Plug-in for CruiseControl.NET now on CodePlex

    Back in May this year I blogged about a CruiseControl.NET plug-in that I had written to allow CCNet to trigger a TFS Build - I had a few comments at the time, but recently I've had a flurry of comments & emails (well, a comparative flurry for my blog anyway!), many with the recurring theme of requesting the source.  Having been on a project full time for most of this year, I've found very little time to revisit this - other than a couple of minor private fixes for people who emailed me.  I've recently begun to roll-off this long term project so have finally found some time for this.

    I've setup a new CodePlex project (called CcNetTeamBuildTask) to host the source code and have published a release of the plug-in.  The following is a list of the main changes  compared to the version I posted back in May.

    • Compiled against the latest version of CruiseControl.NET - v1.3.0.2918
    • Fixed a bug that manifested itself when dealing with Team Project names that contained spaces
    • Fixed a bug with publishing the MSTest code coverage results, that occurred when specifying your build server using an FQDN (if you specify your build server by IP address, then this functionality will probably still not work for you)
    • Removed the task's queuing logic as CCNet now provides this out-of-the-box
    • New configuration property 'pathToTfExe' to support scenarios where Visual Studio is not installed in the default location
    • New configuration property 'useXmlLogger' to more easily switch between text or XML based MSBuild logging
      • Currently, the XML log file can only be automatically published by the task if you customise your TeamBuild to copy the 'msbuild-results.xml' file to the Drops Location
      • The text log file (BuildLog.txt) will always be automatically published to the CCNet Dashboard if this option is false
    • A general tidy-up of the code

    With the release of TFS 2008, I'm unsure whether this plug-in will be as valuable given the new features that Microsoft has added to TFS - but feel free to drop me a line if you have any ideas or would like to join the project.

    Cheers, James.

  • Configuring DCOM Security

    This post started out as a comment on one of Jamie's recent posts, however, I realised that the explanation would be easier to follow with screenshots... so here we go.

    To paraphrase, Jamie's issue was that whilst trying to use an SSIS package he was getting a DCOM access denied error (full details here) - this had worked in previous environments, but not once it got to Production.  The eventual solution that got everything working was to make the account running the package a local administrator (as it was in other environments) and reboot the server.

    Whilst this obviously got things working, what I'd like to illustrate here is a more secure way of overcoming this type of issue - as a platform guy, developer code running with full admin rights makes me twitchy! Smile

    DCOM security is managed using the 'Component Services' MMC snap-in, a shortcut to which is 'Start -> Run -> DCOMCNFG'


     

    The next step is locate the component that needs to have its security tweaked.  Jamie's post shows how to use the CLSID from the error message to locate the registration information for the component in the Registry.


     

    The value of the ''AppID' key is the surefire way of locating the component in DCOMCNFG, however, this is only visible from the component's property page - so ideally you want to find
    the component by name.  However, the names in DCOMCNFG do not necessarily exactly match those in the registry (typically it's a substring).


     

    Armed with the AppID and some ideas about the component name, return to DCOMCNFG and start hunting:


     

    Once you've found a candiate, open its properties and verify the AppID

     

     

    If you've found it, select the 'Security' tab, select 'Customize' and 'Edit..' under 'Launch and Activation Permissions', and grant the required user the rights requested in the original error message.


     

    Now you should be good to go. (complete with that warm and fuzzy feeling that you get from knowing that you haven't unduly compromised server security)
     

  • TeamBuild Plug-in for CruiseControl.NET

    I've been meaning to write this post for a couple of months now as a follow-up to a session that Colin and I gave at the Microsoft Architect Insight Conference back in March, but just haven't found the time... at least, that's my excuse - anyway cutting to the chase!

    Since the release of Team Foundation Server (TFS) there have been several Continuous Integration add-ons produced by various folks:

    We've used most of the above, but despite however well they worked have found myself wanting some feature or other that was available in CCNet (actually it more about being badgered by developers about the missing features!).  Whilst some of the above could have been extended to support these features, I couldn't help but feel that this would have been reinventing the wheel - hence the idea to extend CCNet.

    By the time I started this Vertigo had already released the VSTS plug-in for CCNet (which is a CCNet source control plug-in), so it was just a matter of producing a CCNet task plug-in that was able to trigger a Team Build.  The guts of calling the Team Build web service I based on the original CI Sample, but I was also keen to provide a mechanism for customising the behaviour of a Team Build in a more dynamic way than just creating another build type and changing the MSBuild properties.

    Team Build provides a mechanism for passing custom MSBuild properties into it via a source controlled file called TFSBuild.rsp.  This file consists of 1 or more lines each containing a valid MSBuild commandline switch (e.g. /p:PropName=value, would set the property 'PropName' to be 'value').  With that in mind, I developed the plug-in to allow these switches to be specified in the CCNet server configuration file (on a per CCNet project basis) and have it update the '.rsp' (in source control) before calling the build web service.

    I'll hold off diving into any more detail at this point, but if there is interest out there then I can do a follow-up.

    Attached to this post should be the plug-in assembly which you need to copy into your CCNet 'server' directory (along with the VSTS plug-in referred to above), and below is a configuration excerpt that shows how to configure the 'teambuild' task in CCNet.

    <project name="TeamBuild_CI">

      ...

      <tasks>

        <teambuild>

          <tfsServerUri>http://MyTfsServer:8080</tfsServerUri>

          <teamBuildServer>MyBuildServer</teamBuildServer>

          <teamProject>MyTeamProject</teamProject>

          <teamBuildType>MyTeamBuildType</teamBuildType>

          <workspace>MyBuildServer_MyTeamProject_MyTeamBuildType</workspace>

          <dropsLocation>MyDropsArea\MyTeamProject</dropsLocation>

          <msBuildParameters>

            <MsBuildParameter>/v:d</MsBuildParameter>

            <MsBuildParameter>/logger:ThoughtWorks.CruiseControl.MsBuild.XmlLogger,ThoughtWorks.CruiseControl.MsBuild.dll;msbuild-output.xml</MsBuildParameter>

            <MsBuildParameter>/p:SkipInitializeWorkspace=true</MsBuildParameter>

            <MsBuildParameter>/p:SkipGet=true</MsBuildParameter>

            <MsBuildParameter>/p:SkipClean=true</MsBuildParameter>

            <MsBuildParameter>/p:SkipDropBuild=true</MsBuildParameter>

          </msBuildParameters>

          <useMsTest>true</useMsTest>

          <useMsTestCodeCoverage>true</useMsTestCodeCoverage>

        </teambuild>

      </tasks>

      <publishers>

        <merge>

          <files>

            <file>C:\MyTeamBuildWorkspacePath\MyTeamProject\MyTeamBuildType\BuildType\msbuild-output.xml</file>

          </files>

        </merge>

        <xmllogger>

          <logDir>.\Web\Logs</logDir>

        </xmllogger>

      </publishers>

      ...

    </project>

    Let me know if you find it useful, interesting or a waste of your time! (actually, maybe save your bandwidth in the case of the latter).

     

Powered by Community Server (Personal Edition), by Telligent Systems