Thursday, 29 November 2007

"Access to path is denied" in Team Build

In our builds we often need to copy files around. This sometimes includes overriding files that were retrieved from source control and are therefore read-only because they haven't been checked out.

Surprisingly enough, the Copy target in Team Build doesn't allow you to override the read-only flag. There's a simple workaround for it though: before copying the files, run the attrib command to remove the read-only flag.

Add this line just before executing the Copy target.

<Exec Command="attrib -r *.* /S" WorkingDirectory="$(SolutionRoot)" />

Depending on the number of files you are dealing with you will probably want to use a more accurate working directory, and/or wildcards to speed it up a bit.

Monday, 5 November 2007

Migrating Two Source Safe Projects to the Same Team Project

Just the other day I had some issues migrating two Source Safe projects to the same, existing Team Project. I had created two brand new folders in the destination Team Project to hold each of my VSS projects, checked them in, and started the migration using the following configuration files:

For Project1:

<ConverterSpecificSetting>
<
Source name="VSS">
<
VSSDatabase name="C:\VSSData"></VSSDatabase>
</
Source>
<
ProjectMap>
<
Project Source="$/Project1" Destination="$/MyTeamProject/Proj1"></Project>
</
ProjectMap>
</
ConverterSpecificSetting>

And for Project2:

<ConverterSpecificSetting>
<
Source name="VSS">
<
VSSDatabase name="C:\VSSData"></VSSDatabase>
</
Source>
<
ProjectMap>
<
Project Source="$/Project2" Destination="$/MyTeamProject/Proj2"></Project>
</
ProjectMap>
</
ConverterSpecificSetting>

Project1 was migrated without problems. But when trying to migrate Project2 I got the following error:


TF60099: Given folder mappings do not match with last migrated mappings. Following was the original mapping please use this only for incremental migration. <From>$/Project1</From><To>$/MyTeamProject/Proj1</To>


Which was strange since I was trying to migrate two different projects to two completely separate folders in TFS. The problem was that, at the very start, I had created both folders (Proj1 and Proj2) in TFS and checked them in the same changeset.

To resolve the problem I simply deleted the Proj2 folder from my Team Project, re-created it, and ran the migration again. Worked like a charm.

If you are curious (as I was) to find out why that makes a difference, have a look here.

Thursday, 1 November 2007

How To Schedule a Team Build

As it turns out the features for managing Team Builds available in Team Explorer 2005 are quite limited. Which means, among other things, that it's not possible (quite surprisingly in my opinion) to schedule builds to run at a particular time (this is available in TFS 2008 only)

There is quite a simple workaround though. You can create a batch file which starts up TFSBuild and schedule it via Windows Task Scheduler.

Your batch file should look like this:

TFSBuild start Teamfoundationserver TeamProject BuildType [/machine:buildmachine] [/directory:builddirectory]

An example would be:

"C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\TFSBuild" start http://MyTFS:8080 SomeProject "My Nightly Build Type"

TFSBuild is typically located at C:\Program Files\Microsoft Visual Studio 8\Common7\IDE. See this for a detailed reference of the TFSBuild start command: http://msdn2.microsoft.com/en-us/library/ms181742(VS.80).aspx

Now use Windows Task Scheduler to schedule the build to run at the desired time. Configure the task to run as your domain build account (If you don't have one, chances are you don't have the build server set up properly. See this post for details on setting up a Team Build Server)

Ellerslie DNUG Meeting: PerformancePoint Server

At quite a short notice we've decided to have another Ellerslie .NET User Group meeting. This is just two weeks after our previous meeting but Adam Cogan is going to be in New Zealand from Australia for some presentations on PerformancePoint and he offered to speak at our User Group.

So here are the details:

Microsoft PerformancePoint 2007
Auckland Ellerslie Thursday 8 November 2007
Gather at 5:45, starting at 6:00
Presented by Adam Cogan (Chief Architect at SSW, MVP)

Microsoft Office PerformancePoint Server 2007 is an integrated performance management application designed to help improve operational and financial performance across all departments and all levels of your organization.

With Office PerformancePoint Server 2007, you can monitor progress, analyse what is driving variances, and plan your business from budgeting to creating management reports. You can have metrics, key performance indicators (KPIs), and reports delivered to every desktop through intuitive scorecards, dashboards, and the easy-to-use 2007 Microsoft Office system environment. A key component of the Microsoft Business Intelligence (BI) offering, Office PerformancePoint Server 2007 can help you understand how performance can align with personal and departmental.

http://www.microsoft.com/business/performancepoint/

Click Here to Register

Catering: Pizza & Drinks
Door Charge: Free!
Parking: Free, just park in Olympic Software’s car park

Venue
Olympic Software
10 Cawley St
Ellerslie
Auckland

Map of venue

Tuesday, 16 October 2007

Ellerslie DNUG Meeting: Policy Injection Application Block

The second meeting of our Ellerslie .NET User Group has been confirmed for Wednesday, 24 October 2007. Check it out:

 

Policy Injection Application Block
Ellerslie, Auckland 24/10/2007
Gather at 5:45, starting at 6:00
Presented by Mateus Velloso (Principal Software Architect at Gen-i, MVP)

Ready to pimp your objects?

The Policy Injection Application Block simplifies the separation of business logic from cross cutting concerns (such as logging, validation, exception handling, and authorisation) by letting you define policies and the objects/methods they apply to in a declarative way.

 

Catering: Pizza & Drinks
Door Charge: Free
Parking: Free, just park in Olympic Software’s car park.

Click Here to Register

Venue
Olympic Software
10 Cawley St
Ellerslie
Auckland

Map of venue

Monday, 8 October 2007

Moving TFS Databases

Just the other day we had to move our Team Foundation Server databases to a different disk because they had been installed on the wrong (smaller) disk by mistake.

The process is quite straightforward but I do recommend that you have a backup of all TFS databases before moving them.

  1. Stop the following services (by going to Start/Control Panel/Administrative Tools/Services):
    • SharePoint Timer Service
    • SQL Server Reporting Services
    • TFSServerScheduler
  2. Shut down IIS. This is the easiest and quickest way but If you have non TFS related websites running on the same server it may not be an option. In that case you will need to stop the following application pools:
    • ReportServer
    • TFS AppPool
    • TFSWSS
    • TFSWSSADMIN
    • If you use Team Plain or VSTS Web Access, the application pool it uses (usually TswaPool1)
  3. Open SQL Server Management Studio and locate the following databases. You can move any (or all) of them. Do steps 4 - 7 for each database you want to move:
    • ReportServer
    • ReportServerTempDB
    • STS_Config_TFS
    • STS_Content_TFS
    • TfsActivityLogging
    • TfsBuild
    • TfsIntegration
    • TfsVersionControl
    • TFSWarehouse
    • TfsWorkItemTracking
    • TfsWorkItemTrackingAttachments 
  4. Make a backup of the database. You shouldn't need this
  5. Detach the database (right-click the database, then choose Tasks and Detach)
  6. Copy the the data and log files (.mdf and .ldf) to the new location. E.g. for the ReportServer database you will be moving the ReportServer.mdf and the ReportServer.ldf database files. These files are usually located in C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data.
  7. Attach the database files from the new location. You do this from SQL Server Management Studio by right-clicking the Database node and selecting Attach. Select the .mdf file in the new location and click OK. (change the location of the log file if needed)
  8. Start IIS (or the application pools listed in step 2 if you haven't shut down IIS)
  9. Start the services you stopped in step 1.

At this point TFS should already be up and running. Before giving the all clear to the rest of the team you might want to go to Team Explorer and Source Control Explorer to make sure everything looks ok.

A couple of other (more detailed) posts about moving TFS databases can be found here and here.

Wednesday, 26 September 2007

Set the Maximum Attachment Size for Work Items

For a while now we have been using work items in TFS but resigned to the fact that 4MB was the maximum attachment size. This is fine for most cases but if you want to attach stuff like database backups or large documents it could be an annoying limitation.

It turns out that the maximum attachment size for work items is configurable and quite easy to change in a couple of steps as described in MSDN:

  1. Remote desktop or log into your TFS Server (you can only invoke the web service locally)

  2. In Internet Explorer, open the following URL: http://localhost:8080/WorkItemTracking/v1.0/ConfigurationSettingsService.asmx?op=SetMaxAttachmentSize

  3. In the maxSize box, enter the maximum attachment size in bytes, and then click Invoke. The maximum attachment size is 2 gigabytes.

Note that if you use Team Plain or some other web based work item tracking application you will have to increase the maximum request size in your Web.config otherwise it won't accept files larger than the default 4MB, even after increasing the limit in TFS. Just add the following to the system.web section (this sets the limit to 10MB):

<httpRuntime maxRequestLength="10240"/>

Thanks to Dinuka for finding out about this one!

Sunday, 23 September 2007

Running a User Group

Darryl posted a series of entries about starting up and running a User Group. Well worth the read, especially if like me you are starting a group, or thinking about it.

By the way, we're always looking for suggestions of topics for our brand new .NET User Group in Ellerslie, Auckland. If there's anything you would like to see, let me know!

Friday, 21 September 2007

Extension Methods in C# 2.0, part 2

In my previous post I had a sample of a class which extends List and implements IEnumerable to provide similar functionality to extension methods.

The problem with that of course is that as the extension methods (Where(), Select(), etc.) are called, you wear the cost of creating a new instance of List each time.

To avoid that you can always make you class not extend List while still implementing IEnuberable. This solution will probably perform better, but it is not thread safe. To get around problems with concurrency you will have to call ToList() before start iterating through the enumeration.

public class ExtendedList<T> : IEnumerable<T>
{
private IEnumerable<T> _inner;
public ExtendedList(IEnumerable<T> sequence)
{
_inner = sequence;
}
public ExtendedList<T> Where(Predicate<T> filter)
{
// the only problem here is that we have to create a new List each time
return new ExtendedList<T>(SequenceOperators.Where(_inner, filter));
}
public ExtendedList<R> Select<R>(Func<T, R> mapping)
{
// the only problem here is that we have to create a new List each time
return new ExtendedList<R>(SequenceOperators.Select(_inner, mapping));
}
public List<T> ToList()
{
return new List<T>(_inner);
}

#region IEnumerable<T> Members
public new IEnumerator<T> GetEnumerator()
{
return this.GetEnumerator();
}
#endregion

#region
IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}

public delegate R Func<T, R>(T t);
public static class SequenceOperators
{
public static IEnumerable<R> Select<T, R>(IEnumerable<T> sequence, Func<T, R> mapping)
{
foreach (T t in sequence)
yield return mapping(t);
}
public static IEnumerable<T> Where<T>(IEnumerable<T> sequence, Predicate<T> filter)
{
foreach (T t in sequence)
if (filter(t))
yield return t;
}
}

Thursday, 20 September 2007

Extension Methods in C# 2.0

If you're dying to use extension methods in your project but can't migrate to C# 3 just yet, here's a workaround you can use that mimics extension methods using C# 2.0 generics.

I have to say this is largely due to Alex James, as I was struggling to get it going before he dropped by to help me and came up with the whole thing himself! So thanks for this Alex.

It allows us to do stuff like this:

// Initialise a list of strings containing numbers
ExtendedList<string> myList = new ExtendedList<string>(new string[5] { "-1", "0", "1", "2", "3" });

// Create a list containing all numbers in the
// previous lists that are greater than zero
ExtendedList<int> posNumbers = myList.Select<int>(Convert.ToInt32).Where(delegate(int i) { return i > 0; });


The code is basically an extension of the List class which define methods that work using Predicates and other delegates. So you keep all the functionality of List and still get your "extended" methods.

public class ExtendedList<T> : List<T>, IEnumerable<T>
{
public ExtendedList() { }
public ExtendedList(IEnumerable<T> sequence) : base(sequence) { }

public ExtendedList<T> Where(Predicate<T> filter)
{
// the only problem here is that we have to create a new List each time
return new ExtendedList<T>(SequenceOperators.Where(this, filter));
}
public ExtendedList<R> Select<R>(Func<T, R> mapping)
{
// the only problem here is that we have to create a new List each time
return new ExtendedList<R>(SequenceOperators.Select(this, mapping));
}

#region IEnumerable<T> Members
public new IEnumerator<T> GetEnumerator()
{
return this.GetEnumerator();
}
#endregion

#region
IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}

public delegate R Func<T, R>(T t);
public static class SequenceOperators
{
public static IEnumerable<R> Select<T, R>(IEnumerable<T> sequence, Func<T, R> mapping)
{
foreach (T t in sequence)
yield return mapping(t);
}
public static IEnumerable<T> Where<T>(IEnumerable<T> sequence, Predicate<T> filter)
{
foreach (T t in sequence)
if (filter(t))
yield return t;
}
}

Friday, 14 September 2007

Copy Source As HTML

If, like me or Jacqui, you are hosting your blog with Blogger or some other free hosting service, you must have had problems with getting source code samples to show properly in your posts.

You may have known about this for ages but i didn't: it turns out there's this simple plug in to Visual Studio called CopySourceAsHtml. It will let you copy any sample code from Visual Studio editor with a right-click. Download it here, and see MSDN for a quick description of how it works -- not that you'll need it.

My blogging has just been made sooooo much easier :)

Monday, 10 September 2007

Ellerslie .NET User Group

In addition to the CBD .NET User Group, we are starting another user group in Ellerslie. It will be hosted at Olympic Software starting this Tuesday 11 September.

Here are the details:

A lap around Visual Studio 2008 & A lap around C# 3.0
Auckland 11/09/2007
Gather at 5:45, starting at 6:00

A lap around Visual Studio 2008
Presented by Darryl Burling
Explore all the new Visual Studio 2008 features, from language enhancements; improved designers; Web and smart-client development tools; to Visual Studio Team System, a suite of software lifecycle management tools poised to transform how you deliver software for Windows Vista, the 2007 Microsoft Office system, and the Web.

A lap around C# 3.0
Presented by Alex James
Explore quickly the new features of C# 3.0, including things like LINQ, Lambda Expressions, Anonymous Types etc.

Catering: Pizza & Drinks
Door Charge: Free
Parking: Free, just park in Olympic Software’s car park.

Venue
Olympic Software
10 Cawley St
Ellerslie Auckland

Map of venue

Friday, 7 September 2007

Building Multiple Team Projects with Team Build

Manish Agarwal has posted a very good tip on how to use Team Build to work with multiple Team Projects. You see, Team Build 1.0 workspace mappings don't support getting the latest version of multiple Team Projects. As a workaround, Manish suggests (see his post for details on each of these steps):

  1. Skipping the automatic workspace initialisation
  2. Defining the Team Projects for which you want to get the latest in an Item Group
  3. Manually initialising the workspace for each of the Team Projects by overriding the "BeforeGet" target

This works fine when your Team Projects are mapped to separate root folders. But as it happens the setup I am working with is slightly different than the one described by Manish. Both Team Projects map to the same folder, and I have a single solution which includes both projects:

$/TP1/Framework maps to $(SolutionRoot)\TP2\WebApplication1
$/TP2/WebApplication1/Portal maps to $(SolutionRoot)\TP2\WebApplication1\Portal

This happens because my framework is a web application itself, and it's used by other projects in a similar way. Now, I know this is probably not the smartest project setup I could have but I had to make it work nonetheless and not worry about having to do a big re-factor of any kind.

I tried to do the following:


<ItemGroup>

    <Map Include="$/TP1/Framework">

        <LocalPath>$(SolutionRoot)\WebApplication1</LocalPath>

    </Map>

    <Map Include="$/TP2/WebApplication1/Portal">

        <LocalPath>$(SolutionRoot)\WebApplication1\Portal</LocalPath>

    </Map>

</ItemGroup>


But my problem was that both Team Projects were being mapped to the same folder. This caused the creation of workspaces within the "BeforeGet" target to delete all contents of my folder before getting the latest version of each project which meant that after getting latest I only had the source code for TP2!

A very simple workaround was:

Slightly modify the mapping so that each Team Project was mapped to a different folder:


<ItemGroup>

    <Map Include="$/TP1/Framework">

        <LocalPath>$(SolutionRoot)\WebApplication1</LocalPath>

    </Map>

    <Map Include="$/TP2/WebApplication1/Portal">

        <LocalPath>$(SolutionRoot)\WebApplication1_TEMP</LocalPath>

    </Map>

</ItemGroup>


Override the "AfterGet" target to do a simple recursive copy from the temporary folder into the proper location:

<!-- Creates a list with all files in the temporary folder -->

<ItemGroup>

    <TempFolderContents Include="$(SolutionRoot)\WebApplication1_TEMP\**\*.*" />

</ItemGroup>

 

<!-- Recursively copies all files into $(SolutionRoot)\WebApplication1\Portal -->

<Target Name="AfterGet">

    <Copy SourceFiles="@TempFolderContents"

          DestinationFolder="$(SolutionRoot)\WebApplication\Portal\%(RecursiveDir)" />

</Target>

Thursday, 6 September 2007

Blog is live!

What a mission. Finally got this baby going.

Since I didn't want this blog to go live without a proper domain name I had to dig up the andremeurer.com domain I've had for ages but hadn't really put to good use for a while. That meant playing around with CNAMEs and MX Records which sound very daunting but are actually a piece of cake to get going.

However ditching the dodgy Brazilian ISP (which shall remain nameless) I had been using meant my e-mail addresses were now homeless. That's when I bumped into Darryl Burling's post on how to host my email using Windows Live. A few simple steps and I had my email up and running on Windows Live. Still to give the Outlook Connector a try but it looks promising.

Hosting my blog with Windows Spaces wasn't really an option (you'll find out why if you ever try to) so I stuck with blogspot. So far so good!