Team Foundation Version Control client API example for TFS 2010 and newer


Over six years ago, I posted a sample on how to use the version control API.  The API changed in TFS 2010, but I hadn’t updated the sample.  Here is a version that works with 2010 and newer and is a little less aggressive on clean up in the finally block.

This is a really simple example that uses the version control API.  It shows how to create a workspace, pend changes, check in those changes, and hook up some important event listeners.  This sample doesn’t do anything useful, but it should get you going.

You have to supply a Team Project as an argument.

The only real difference in this version is that it uses the TeamFoundationServer constructor (in beta 3, you were forced to use the factory class).

You’ll need to add references to the following TFS assemblies to compile this example.

Microsoft.TeamFoundation.VersionControl.Client.dll
Microsoft.TeamFoundation.Client.dll

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Text;
  6. using Microsoft.TeamFoundation.Client;
  7. using Microsoft.TeamFoundation.VersionControl.Client;
  8.  
  9. namespace BasicSccExample
  10. {
  11.     class Example
  12.     {
  13.         static void Main(string[] args)
  14.         {
  15.             // Verify that we have the arguments we require.
  16.             if (args.Length < 2)
  17.             {
  18.                 String appName = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);
  19.                 Console.Error.WriteLine(“Usage: {0} collectionURL teamProjectPath”, appName);
  20.                 Console.Error.WriteLine(“Example: {0} http://tfsserver:8080/tfs/DefaultCollection $/MyProject”, appName);
  21.                 Environment.Exit(1);
  22.             }
  23.  
  24.             // Get a reference to our Team Foundation Server.
  25.             TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri(args[0]));
  26.  
  27.             // Get a reference to Version Control.
  28.             VersionControlServer versionControl = tpc.GetService<VersionControlServer>();
  29.  
  30.             // Listen for the Source Control events.
  31.             versionControl.NonFatalError += Example.OnNonFatalError;
  32.             versionControl.Getting += Example.OnGetting;
  33.             versionControl.BeforeCheckinPendingChange += Example.OnBeforeCheckinPendingChange;
  34.             versionControl.NewPendingChange += Example.OnNewPendingChange;
  35.  
  36.             // Create a workspace.
  37.             Workspace workspace = versionControl.CreateWorkspace(“BasicSccExample”, versionControl.AuthorizedUser);
  38.  
  39.             String topDir = null;
  40.  
  41.             try
  42.             {
  43.                 String localDir = @”c:\temp\BasicSccExample”;
  44.                 Console.WriteLine(“\r\n— Create a mapping: {0} -> {1}”, args[1], localDir);
  45.                 workspace.Map(args[1], localDir);
  46.  
  47.                 Console.WriteLine(“\r\n— Get the files from the repository.\r\n”);
  48.                 workspace.Get();
  49.  
  50.                 Console.WriteLine(“\r\n— Create a file.”);
  51.                 topDir = Path.Combine(workspace.Folders[0].LocalItem, “sub”);
  52.                 Directory.CreateDirectory(topDir);
  53.                 String fileName = Path.Combine(topDir, “basic.cs”);
  54.                 using (StreamWriter sw = new StreamWriter(fileName))
  55.                 {
  56.                     sw.WriteLine(“revision 1 of basic.cs”);
  57.                 }
  58.  
  59.                 Console.WriteLine(“\r\n— Now add everything.\r\n”);
  60.                 workspace.PendAdd(topDir, true);
  61.  
  62.                 Console.WriteLine(“\r\n— Show our pending changes.\r\n”);
  63.                 PendingChange[] pendingChanges = workspace.GetPendingChanges();
  64.                 Console.WriteLine(”  Your current pending changes:”);
  65.                 foreach (PendingChange pendingChange in pendingChanges)
  66.                 {
  67.                     Console.WriteLine(”    path: “ + pendingChange.LocalItem +
  68.                                       “, change: “ + PendingChange.GetLocalizedStringForChangeType(pendingChange.ChangeType));
  69.                 }
  70.  
  71.                 Console.WriteLine(“\r\n— Checkin the items we added.\r\n”);
  72.                 int changesetNumber = workspace.CheckIn(pendingChanges, “Sample changes”);
  73.                 Console.WriteLine(”  Checked in changeset “ + changesetNumber);
  74.  
  75.                 Console.WriteLine(“\r\n— Checkout and modify the file.\r\n”);
  76.                 workspace.PendEdit(fileName);
  77.                 using (StreamWriter sw = new StreamWriter(fileName))
  78.                 {
  79.                     sw.WriteLine(“revision 2 of basic.cs”);
  80.                 }
  81.  
  82.                 Console.WriteLine(“\r\n— Get the pending change and check in the new revision.\r\n”);
  83.                 pendingChanges = workspace.GetPendingChanges();
  84.                 changesetNumber = workspace.CheckIn(pendingChanges, “Modified basic.cs”);
  85.                 Console.WriteLine(”  Checked in changeset “ + changesetNumber);
  86.             }
  87.             finally
  88.             {
  89.                 if (topDir != null)
  90.                 {
  91.                     Console.WriteLine(“\r\n— Delete all of the items under the test project.\r\n”);
  92.                     workspace.PendDelete(topDir, RecursionType.Full);
  93.                     PendingChange[] pendingChanges = workspace.GetPendingChanges();
  94.                     if (pendingChanges.Length > 0)
  95.                     {
  96.                         workspace.CheckIn(pendingChanges, “Clean up!”);
  97.                     }
  98.  
  99.                     Console.WriteLine(“\r\n— Delete the workspace.”);
  100.                     workspace.Delete();
  101.                 }
  102.             }
  103.         }
  104.  
  105.         internal static void OnNonFatalError(Object sender, ExceptionEventArgs e)
  106.         {
  107.             if (e.Exception != null)
  108.             {
  109.                 Console.Error.WriteLine(”  Non-fatal exception: “ + e.Exception.Message);
  110.             }
  111.             else
  112.             {
  113.                 Console.Error.WriteLine(”  Non-fatal failure: “ + e.Failure.Message);
  114.             }
  115.         }
  116.  
  117.         internal static void OnGetting(Object sender, GettingEventArgs e)
  118.         {
  119.             Console.WriteLine(”  Getting: “ + e.TargetLocalItem + “, status: “ + e.Status);
  120.         }
  121.  
  122.         internal static void OnBeforeCheckinPendingChange(Object sender, ProcessingChangeEventArgs e)
  123.         {
  124.             Console.WriteLine(”  Checking in “ + e.PendingChange.LocalItem);
  125.         }
  126.  
  127.         internal static void OnNewPendingChange(Object sender, PendingChangeEventArgs e)
  128.         {
  129.             Console.WriteLine(”  Pending “ + PendingChange.GetLocalizedStringForChangeType(e.PendingChange.ChangeType) +
  130.                               ” on “ + e.PendingChange.LocalItem);
  131.         }
  132.     }
  133. }

Comments (47)

  1. Ikram says:

    This was MOST helpful!! Now we can directly save files processed via SSIS to TFS for version control!

    Thank a BUNCH!

  2. buckh says:

    Glad it helped!

  3. Hrusi says:

    I'm getting this exception while running the sample code:

    Could not load file or assembly 'file:///C:TfsAppbinMicrosoft.WITDataStore.dll' or one of its dependencies. The module was expected to contain an assembly manifest.

    Exception Details: System.BadImageFormatException: Could not load file or assembly 'file:///C:TfsAppbinMicrosoft.WITDataStore.dll' or one of its dependencies. The module was expected to contain an assembly manifest.

    Any ideas?

  4. buckh says:

    Hrusi, my guess it would be due to how the code is being built. It's been a while since I've messed with it, but check AnyCPU vs. x86.

  5. Veena says:

    Hi, I am getting no pendingchanges in my console app. I had same issue with web app, I tried the same code on web form application where it worked. I thought it has to do with IIS permissions evenhugh i am passing different credential object to create TfsTeamProjectCollectio..

  6. buckh says:

    Veena, I'd recommend running it under a debugger and stepping through the code to see what's going wrong.

  7. vikram says:

    i have a file which is created by taking a backup of tables,this file i need to checkin to tfs 2010.

    so how this can be done.

  8. buckh says:

    Vikram, if it's a file on disk, then you can pend an add on it and check it in. The sample code shows both pending an add and checking in.

  9. Daniel says:

    Hi Buck, I really need your help, whenever a do a checkout on a file and the try to write changes to it using StreamWriter I get "The process cannot access the file because it is being used by another process"

  10. Daniel says:

    Nevermind! I found the issue :P. Before calling the writer I had an open stream of the file

  11. Hi, I tried the same code but when i call  workspace.CheckIn(pendingChanges, "Sample changes"); I am getting "No files checked in error" Could you please tell me what could be the issue is?

  12. buckh says:

    Vidhya, make sure your pending changes array has your pending changes listed in it and make sure a file has changed.

  13. Buck, I have the two pending changes and also the basic.cs has been added with the line. I am not sure what could be the issue now?

  14. Mayank Goswami says:

    I am exactly doing what is reffered in above sample code. But not getting any Pending changes to checkin.

    Looking for a help, it is an asp.net wep app. When running the applicaiton with Development server, every thing works fine. But as soon as we deploy it on IIS, pending changes can not be fteched.

    Request for an immediate help, if anyone encounter this problem and resolved.

    Thanks in advance.

  15. Allan R says:

    Whenever I get to workspace.CheckIn, I receive the following error:

    err.Message = "TF204000: The Team Foundation Server for this workspace does not support one or more of the checkin options you have selected."

    Any help would be greatly appreciated.

  16. buckh says:

    Allan, are the server and client different versions (e.g., one is 2010 and the other 2012)? Are you explicitly specifying any checkin options?

  17. Tahir says:

    Im getting an error when installing my tfs api on client machine .Microsoft.widatastore.dll missing without visual studio installed rather than the latter on dev machine.Is this due to not having visual studio installed because im accessing tfs server through api what could be the issue.Any ideas anyone?

  18. buckh says:

    Tahir, you need one of the following installed:

    That will provide the required DLLs.

  19. Tman558 says:

    Thanks

  20. Tman558 says:

    Hi EveryOne,

    I have a tfs api. A user logs in and i want his valid projects that he has permissions too.So i can put it in a combo box to choose from and area and iterations etc. Does anyone know of a way.

  21. buckh says:

    If you want to make requests to TFS as another user, you would need to use impersonation. In the future when we have OAuth support, that would be a better way to go.

    blogs.msdn.com/…/introducing-tfs-impersonation.aspx

  22. Tman558 says:

    Thanks

  23. Rajesh Sharma says:

    Hi Buck, Its a very helpful code, but I am facing an issue. I have mapped the workspace with local folder.

    I am trying to get latest using workspace, it works fine. but when I deployed it to IIS on  development server. Some time it takes ages to download and does not throw and error. I has fine downloaded in partial document format. Can you tell him why this kind of behaviour.

    Any input appreciated. Below is simple sample code used.

    GetRequest request = new GetRequest(new ItemSpec(path, RecursionType.Full), VersionSpec.Latest);

    status = Workspace.Get(request, GetOptions.Overwrite);

  24. Rajesh Sharma says:

    Folder size which I download are any where from 10 MB to 30 MB. There are some partial downloaded file, which my give you some clue

  25. buckh says:

    Rajesh, when running under IIS, make sure that the user under which it runs has sufficient privileges and there is enough disk space. Also, make sure that user has a Windows profile and access to the temp directory (all files downloaded first go to the temp folder and then are copied to the ultimate destination). It's those sorts of things that tend to cause problems under IIS.

  26. Rajesh Sharma says:

    I have a windows profile and also access to temp dir. I am able to download most of the time. Bu some times while downloading "when the code calls  Workspace.Get() It keeps on  loading. and does not even throw an error. Is there a way I  can find what could be the issue.

  27. buckh says:

    Rajesh, your best bet would be to attach a debugger and have it break on exceptions to see where the problem is (assuming that the problem involves an exception). If not, then after it hangs for a while, break on it and see what it's waiting on.

  28. Jaideep Singh says:

    Hello Buck,

    Is it possible to capture a Check-In that happens in TFS and trigger off an action based on that.

    Lets say I build a Windows Service or a Console App that monitors a particular Project in TFS and on Check-In on any of the files inserts a record in a SQL DB table with the name of the file, class and method that was modified?

  29. buckh says:

    Jaideep, if you are looking to do this on the server, I'd suggest a server-side plugin where you could do it in .NET. This book has details: smile.amazon.com/…/ref=la_B004AR91MM_1_1.

    If you are looking to do this on Visual Studio Online, check out Service Hooks: http://www.visualstudio.com/…/get-started-service-hooks-creating-and-managing-vsi.

    Regardless, please don't do anything in SQL. It would put your server in an unsupported state.

  30. Josh Jay says:

    Hi Buck,

    Thanks for posting this code!  I'm working on automating the checking in of code on a server and am having trouble capturing the pending changes.  I was able to create a local workspace, map folders, and do a get latest in code.  However, when a change is made to a file on the local folder, it is not getting picked up with "workspace.GetPendingChanges()".  I even tried "workspace.PendEdit(workspacePath, RecursionType.Full)" before calling GetPendingChanges() to no avail.  This code seems to work fine on my development machine.

    One difference between the dev and prod machines are I have VS 2012 installed on my dev machine, but just copied the Microsoft.TeamFoundation.*.dll's (.Client; .Common; .VersionControl.Client; TeamFoundation) to the server.  Do I need team explorer or something else installed on the server or is there a way to force the pending changes to get picked up?

    Thanks!

  31. buckh says:

    Josh, that last detail about copying the dlls, that's definitely a problem (and likely the root cause of it not working on the server). You can install Team Explorer on the server or you can install the TFS Object Model, which is even smaller. You can use 2013 or 2012, based on what you need. Here's the link to the 2013 version: visualstudiogallery.msdn.microsoft.com/3278bfa7-64a7-4a75-b0da-ec4ccb8d21b6

  32. Josh Jay says:

    Thanks Buck!  That seemed to do the trick.

  33. buckh says:

    Josh, glad to hear it!

  34. Rajesh Sharma says:

    Hi Buck,

    I am getting an error while check-in code using api code. But I am getting this error. Did not found any once facing the issue. There is no documentation on why this error thrown by TFS Version control client.

    TF14054: The Encoding -2 is not valid. The client should never send this value

  35. buckh says:

    Rajesh, if I recall correctly that means that the client OM didn't set the encoding. I can't say I remember any case like that. Are you using the code in this blog post or something else?

    Here's a blog post on encoding detection that we do: blogs.msdn.com/…/463281.aspx.

  36. Rajesh Sharma says:

    I am using the code mentioned in the above code given by you. "workspace.PendAdd(topDir, true);". This method throws the error "TF14054: The Encoding -2 is not valid. The client should never send this value".

    Although the above code works fine on local. It fails when I upload the project on development server.Development server is Windows server 2012 and local has windows 7. Is there any dependency on OS or  Is there any dll the required might not present.  I have below dll on project bin folder

    1. Microsoft.TeamFoundation.Client.dll
    2. Microsoft.TeamFoundation.Common.dll

    3. Microsoft.TeamFoundation.VersionControl.Client.dll

    4 Microsoft.TeamFoundation.VersionControl.Common.dll

    1. Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll

    Please help me out with this issue. Kind of killing me.:)

  37. Rajesh Sharma says:

    Adding to above question, what can be done if TFS  did not detect the encoding properly. Can we set it manually. But again the question is if I need to set it manually I need to find the encoding :)

  38. Rajesh Sharma says:

    Hi Buck,

    I solved the problem, I installed the OM on server and it worked. I went through couple of question you answered and fixed it.

    Thanks a lot for your efforts for helping people use TFS and TFS API. Is there any good book for TFS API. Wanted to do some mastering on that.

  39. buckh says:

    Rajesh, I'm glad you got it fixed. The professional TFS book by Holliday and others is good and talks about writing apps with the client OM.

  40. Anders K says:

    thanks for the example, it is always easier to see things actually used than from the documentation.

  41. kiquenet says:

    Very useful. Interesting.

    IMHO, for minimize learning curve, better a good unit test Method that Console Application.

    What's is best patterns and practices for unit testing using TeamFoundationClient (TFS API)?.

    I use VS 2012 and TFS 2008.

    I think in unit test like this:

    Include file in Source Control

    Check Out

    Check In

    Create Branch

    Merge

    Delete Branch

    [TestClass]

    public class TfsTests

    {

       [TestMethod]

       public void TestMethod1()

       {

           var serverUrl = "tsfserver";

           var tfs = new TeamFoundationServer(serverUrl);

           var vcServer = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));

           // Code here

       }

    }

    IMHO, the more complete unit test like this:

    Create Team Project

    Create WorkSpace

    Mapping local folder for Workspace

    Include files in Source Control (in those Workspace and TeamProject)

    Check Out file

    Check In file

    Create Branch

    View History

    Merge

    View History

    Delete Branch

    Delete Mappings

    Delete WorkSpace

    Delete Team Project

    Any suggestions about it ? Maybe share source code about all in github, and share it for all Community.

  42. buckh says:

    It's a good suggestion. We always need more examples of how to use the API.

  43. abdel says:

    Hi buck,

    what is the arguments in a Main??

  44. Michael Day says:

    Thanks, Buck! We use a SharedAsemblyInfo.cs versioning scheme(blogs.msdn.com/…/shared-assembly-info-in-visual-studio-projects.aspx), and with a little tweaking, I was able to use this to successfully update our file versions prior to building.

  45. buckh says:

    Michael, glad to hear it. Your comment also reminded me to add an update do this post about our new NuGet packages for the client object model.

  46. Milos says:

    Hi,

    Whenever I get to workspace.CheckIn, I receive the following error:

    err.Message = "TF204000: The Team Foundation Server for this workspace does not support one or more of the checkin options you have selected."

    Any help would be greatly appreciated.

    I am not using any checkin options or setting them whatsoever. The problem is that my version of Microsoft.TeamFoundation.Client is from VS2012 but if I use VS2010 dll this problem is solved. Is there a way to avoid loading multiple dll since I am using different versions of TFS server? Btw when checking in from VS2012 to the server it works without any problems.

  47. Milos says:

    I was able to resolve previous problem with:

    WorkspaceCheckInParameters workspaceCheckInParameter = new WorkspaceCheckInParameters(changes, comment);

    Workspace.CheckIn(workspaceCheckInParameter);