Monthly Archives: February 2008

Display WorkItems in a WinForms application

Using the Microsoft.TeamFoundation.WorkItemTracking.Controls assembly it is possibe to display WorkItems. Here is a little demo application that will display all the WorkItems that have been changed by one of the given users in the given range:

screenshot of workitemtracker application

Feel free to download the source: WorkItemTracker.zip

Edit (05/03/2008):

Refactored the code a little and added some features like sortable columns, loading default tfsserver and users from App.Config, …

Find WorkItems that have been changed between two dates

Sometimes i want to know which WorkItems i have closed (or completed) between two dates. According to Amit Ghosh it’s not possible to write such a query so i wrote some code that uses the TFS SDK to get that list:

static void Main(string[] args)
{
 TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer("tfsrtm08");
 WorkItemStore wis = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));

 DateTime begin = new DateTime(2008, 1, 1);
 DateTime end = new DateTime(2008, 2, 28);
 string username = "Darren";

 foreach (WorkItem workItem in FindChangesByUserInRange(wis, username, begin, end))
 {
  Console.WriteLine("[{0:00000}] {1}", workItem.Id, workItem.Title);
 }

 Console.WriteLine("Press any key to continue...");
 Console.ReadKey();
}

static List<workItem> FindChangesByUserInRange(WorkItemStore workItemStore, string username, DateTime begin, DateTime end)
{
 string query = "SELECT System.ID, System.Title FROM workitems WHERE [Changed By] EVER '{0}' AND [State] IN ('Closed', 'Resolved') AND [Changed Date] >= '{1}'";
 query = string.Format(query, username, begin.Date.ToShortDateString());

 List<workItem> result = new List<workItem>();

 foreach (WorkItem workItem in workItemStore.Query(query))
 {
  if (IsChangedByUserInRange(workItem, username, begin, end))
  {
   result.Add(workItem);
  }
 }

 return result;
}

private static bool IsChangedByUserInRange(WorkItem workItem, string username, DateTime begin, DateTime end)
{
 foreach (Revision rev in workItem.Revisions)
 {
  string changedBy = (string)rev.Fields["Changed By"].Value;
  if (changedBy == username)
  {
   DateTime changedDate = (DateTime)rev.Fields["Changed Date"].Value;
   if (begin <= changedDate && changedDate <= end)
   {
    return true;
   }
  }
 }

 return false;
}

Writing Xml without the XmlDeclaration

Consider the following xml file:

<?xml version="1.0" encoding="utf-8" ?>
<!-- some comment -->
<root>
</root>
<!-- another comment -->

If you look at the Well-Formed XML Documents section in the XML specification you see that a well-formed document is defined as:

[1] document ::= prolog element Misc*

Since there is only 1 root element (ever), i assumed that if you Load this file with XmlDocument their would be only one XmlNode in the document ChildNodes. In reality there ChildNodes.Count returns 4.

The simplest way to write this XmlDocument without the declaration would be as following:

XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.OmitXmlDeclaration = true;
xmlWriterSettings.Encoding = Encoding.UTF8;
using (XmlWriter writer = XmlWriter.Create(@"result.xml", xmlWriterSettings))
{
 xmlDoc.WriteTo(writer);
}

Introducing DeferredExecutionHelper

Sometimes i don’t want a costly function to be performed unless it’s really necessary. In Patterns of Enterprise Application Architecture it’s described as Lazy Load. Anyway, in order to achieve that i’ve written a wrapper for RealProxy:

public static class DeferredExecutionHelper
{
 public static IList<tresult> GetListHelper<t, TResult>(Func<t, IList<tresult>> costlyFunction, T t)
 {
  return new Proxy<t, IList<tresult>>(costlyFunction, t).ResultProxy;
 }

 public static TResult GetHelper<t, TResult>(Func<t, TResult> costlyFunction, T t) where TResult : MarshalByRefObject
 {
  return new Proxy<t, TResult>(costlyFunction, t).ResultProxy;
 }
}

Here are a couple of unittests that demonstrate how the wrapper can be used for MarshalByRefObjects:

[TestMethod]
public void GetHelperTestDeferredExecution()
{
 string expectedParameter = "x";
 Order expectedResult = new Order(1, new List<amount>(new Amount[] { new Amount(1) }));

 // DeferredExecutionHelper.GetHelper<t, TResult> where TResult : MarshalByRefObject
 Order actualResult = DeferredExecutionHelper.GetHelper<string, Order>(delegate(string actualParameter)
 {
  Assert.AreEqual(expectedParameter, actualParameter);
  Assert.Fail("Should not perform this method.");
  return expectedResult;
 }, expectedParameter);
}

[TestMethod]
public void GetHelperTestDeferredExecutionResult()
{
 string expectedParameter = "x";
 Order expectedResult = new Order(1, new List<amount>(new Amount[] { new Amount(1) }));

 Order actualResult = DeferredExecutionHelper.GetHelper<string, Order>(delegate(string actualParameter)
 {
  Assert.AreEqual(expectedParameter, actualParameter);
  return expectedResult;
 }, expectedParameter);

 Assert.AreEqual(expectedResult.Id, actualResult.Id);
 Assert.AreEqual(expectedResult.Amounts, actualResult.Amounts);
}

I’ve also added a helper method that allows you to defer execution of methods that return an IList of T. Here are some tests that demonstrate it’s usage:

[TestMethod]
public void GetListHelperTestDeferredExecution()
{
 double expectedParameter = 1;
 IList<int> expectedResult = new List<int>(new int[] { 1, 2, 3 });

 IList<int> actualResult = DeferredExecutionHelper.GetListHelper<double, int>(delegate(double actualParameter)
 {
  Assert.AreEqual(expectedParameter, actualParameter);
  Assert.Fail("Should not perform this method.");
  return expectedResult;
 }, expectedParameter);
}

[TestMethod]
public void GetListHelperTestDeferredExecutionResult()
{
 double expectedParameter = 1;
 IList<int> expectedResult = new List<int>(new int[] { 1, 2, 3 });

 IList<int> actualResult = DeferredExecutionHelper.GetListHelper<double, int>(delegate(double actualParameter)
 {
  Assert.AreEqual(expectedParameter, actualParameter);
  return expectedResult;
 }, expectedParameter);

 Assert.AreEqual(expectedResult.Count, actualResult.Count);
 for (int i = 0; i < expectedResult.Count; ++i)
 {
  Assert.AreEqual(expectedResult[i], actualResult[i]);
 }
}

Feel free to download DeferredExecution.zip

Generating Artifacts By Using Text Templates

Since i remember myself thinking “I should look up that .tt templating thing” already a couple of times and always forgot to actually do so, i’m posting it here: Generating Artifacts By Using Text Templates. The tools comes with the Visual Studio SDK.

How the name of an embedded resource is generated in a C# project

A while ago i was wondering how the name of an embedded resource is generated in a C# project. Earlier today i was looking in Microsoft.CSharp.targets and found the answer:

The CreateManifestResourceNames target create the manifest resource names from the .RESX files.

[IN]
@(ResxWithNoCulture) - The names the non-culture .RESX files.
@(ResxWithCulture) - The names the culture .RESX files.
@(NonResxWithNoCulture) - The names of the non-culture non-RESX files (like bitmaps, etc).
@(NonResxWithCulture) - The names of the culture non-RESX files (like bitmaps, etc).

[OUT]
@(ManifestResourceWithNoCultureName) - The corresponding manifest resource name (.RESOURCE)
@(ManifestResourceWithCultureName) - The corresponding manifest resource name (.RESOURCE)
@(ManifestNonResxWithNoCulture) - The corresponding manifest resource name.
@(ManifestNonResxWithCulture) - The corresponding manifest resource name.

For C# applications the transformation is like:

Resources1.resx => RootNamespace.Resources1 => Build into main assembly
SubFolder\Resources1.resx => RootNamespace.SubFolder.Resources1 => Build into main assembly
Resources1.fr.resx => RootNamespace.Resources1.fr => Build into satellite assembly
Resources1.notaculture.resx => RootNamespace.Resources1.notaculture => Build into main assembly

For other project systems, this transformation may be different.

With Attrice Corporation Microsoft Build Sidekick v2 you can easily visualize the flow throughout the targets via Tools -> View Targets Diagram.

Updating Assembly References with TFS

A while ago i posted some code that allows you to update the Assembly references. Here is some code that uses the Team Foundation Server SDK that checks the csproj files out and updates their references. Afterwards it’s possible to check the modified csproj files in with a reference to a WorkItem (or to undo the checkout in case no modifications were made).

static void Main()
{
 string tfsServerName = "tfsrtm08";
 string projectsPath = @"D:\Projects";

 Console.WriteLine( "Connecting to TFS [" + tfsServerName + "]..." );
 TeamFoundationServer teamFoundationServer = TeamFoundationServerFactory.GetServer( tfsServerName );

 Console.WriteLine( Environment.NewLine + "Modified ProjectFiles:" );
 List<workspace> workSpacesWithUpdatedProjectFiles = UpdateReferencesInProjectFiles( teamFoundationServer, projectsPath );

 Console.WriteLine( Environment.NewLine + "Modified Workspaces: " );
 foreach( Workspace workSpace in workSpacesWithUpdatedProjectFiles )
 {
  Console.WriteLine( workSpace.Name );
 }

 //int workItemId = -1;
 //CheckInPendingChanges( teamFoundationServer, workItemId, workSpacesWithUpdatedProjectFiles );

 Console.Write( "{0}Press any key to continue...", Environment.NewLine );
 Console.ReadKey();
}

private static List<workspace> UpdateReferencesInProjectFiles( TeamFoundationServer teamFoundationServer, string projectsPath )
{
 VersionControlServer versionControlServer = (VersionControlServer) teamFoundationServer.GetService( typeof( VersionControlServer ) );

 List<workspace> workSpacesWithUpdatedProjectFiles = new List<workspace>();
 foreach( string projectFileName in ProjectFile.Find( projectsPath ) )
 {
  Workspace workSpace = versionControlServer.GetWorkspace( Path.GetFullPath( projectFileName ) );
  workSpace.PendEdit( projectFileName );

  if( UpdateReferencesInProjectFile( projectFileName ) )
  {
   Console.WriteLine( projectFileName );
   if( !workSpacesWithUpdatedProjectFiles.Contains( workSpace ) )
   {
    workSpacesWithUpdatedProjectFiles.Add( workSpace );
   }
  }
  else
  {
   workSpace.Undo( projectFileName );
  }
 }
 return workSpacesWithUpdatedProjectFiles;
}

private static void CheckInPendingChanges( TeamFoundationServer teamFoundationServer, int workItemId, List<workspace> workSpacesWithUpdatedProjectFiles )
{
 WorkItemStore workItemStore = (WorkItemStore) teamFoundationServer.GetService( typeof( WorkItemStore ) );

 WorkItem workItem = workItemStore.GetWorkItem( workItemId );
 WorkItemCheckinInfo[] workItemChanges = new WorkItemCheckinInfo[] { new WorkItemCheckinInfo( workItem, WorkItemCheckinAction.Associate ) };
 foreach( Workspace workSpace in workSpacesWithUpdatedProjectFiles )
 {
  PendingChange[] pendingChanges = workSpace.GetPendingChanges();
  workSpace.CheckIn( pendingChanges, string.Empty, null, workItemChanges, null );
 }
}

Feel free to download the code: ReferenceManager.zip.