Geeks With Blogs


View Tarun Arora's profile on LinkedIn

profile for Tarun Arora at Stack Overflow, Q&A for professional and enthusiast programmers

Tarun Arora - Visual Studio ALM MVP ALM, Agile, Automation, Performance Testing, Software QA, Cloud, ...

Problem Definition

I am about to take ownership of a TFS 2005 repository that has projects for BizTalk, SharePoint, SSIS, SSAS, different flavors of .NET, to complicate things, the customer is using different versions of visual studio to develop and maintain these solutions. To take control of the source control and successfully manage the build infrastructure it is important for me to have a view on what project types, what version of these project types, what version of visual studio, etc are being used.

Not a lot of this information is available in the TFS data warehouse, so it’s not possible to report these details from the warehouse…

Note – Download a working demo solution from here


In this blog post, I’ll walk you through using the TFS API to generate a report by querying the csproj, sln files in the source control repository. Further parsing the csproj and sln files to generate the below report…


  • Name of the project/solution


  • Server Path of the project/solution in the TFS repository


  • Target framework version – In case of sln: VS file version, In case of csproj: the version of .NET


  • Output Type – The project output type such as win exe, library, etc (Not applicable to sln)


  • Project Type – Only applicable to csproj: Parse the Project Type Guid to return the project type such as WPF, MVC, Web App, C#, etc


  • Reference – Only applicable to csproj: Generate a list of project references and strict version where applicable


  • Last Check In Date – When was the proj or sln file last changed


  • Last Changed By – Who was the proj or sln file last changed by




The code solution I have implemented,

  • Download and Install the TFS API, create a new WPF project and add a reference to the following dll’s. More details on how to use the TFS API here


  • Use the TFS API to prompt the user to connect to TFS and select a team project (this can easily be scaled to allow multiple tpc)
private static TfsTeamProjectCollection _tfs;
private static ProjectInfo _selectedTeamProject;
private static VersionControlServer _vcs;
private static Workspace _workspace;

// Connect to TFS Using Team Project Picker
private static void ConnectToTfsUsingTeamProjectPicker()
    // The  user is allowed to select only one project
    var tfsPp = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false);


    // The TFS project collection
    _tfs = tfsPp.SelectedTeamProjectCollection;

    if (tfsPp.SelectedProjects.Any())
        //  The selected Team Project
        _selectedTeamProject = tfsPp.SelectedProjects[0];
  • Use the TFS API to Create a temporary workspace
  • Use the TFS API to perform a wildcard based get operation to ONLY download the sln and csproj files in the temp workspace
private void CreateWorkspace()
    _vcs = _tfs.GetService<VersionControlServer>();
    var name = string.Format("{0}_{1}", "TempWs", Guid.NewGuid());
    var c = new CreateWorkspaceParameters(name)
        Computer = Environment.MachineName,
        Folders = new[] { new WorkingFolder(string.Format(@"$/{0}", 
                    string.Format("{0}_{1}", Path.GetTempPath(), name)) },
        Location = WorkspaceLocation.Local,
        OwnerDisplayName = Environment.UserName,
        WorkspaceName = name

    _workspace = _vcs.CreateWorkspace(c);

    tbSearchPattern.Text = string.Format("$/{0}/*.csproj | $/{0}/*.sln", _selectedTeamProject.Name);

    var req1 = new GetRequest(string.Format("$/{0}/*.csproj", _selectedTeamProject.Name), RecursionType.Full,

    var req2 = new GetRequest(string.Format("$/{0}/*.sln", _selectedTeamProject.Name), RecursionType.Full,

    _workspace.Get(req1, GetOptions.GetAll);
    _workspace.Get(req2, GetOptions.GetAll);
  • Loop through the workspace and fetch all csproj and sln files
var workingFolder = _workspace.Folders.FirstOrDefault();

if (workingFolder == null) return;
var files = Directory.GetFiles(workingFolder.LocalItem, "*.csproj", SearchOption.AllDirectories);
  • Parse the csproj file to read the target version, output type, projectTypeGuid, Reference properties
var ppList = new List<ProjectProperty>();
foreach (var file in files)
    var pp = new ProjectProperty
            Name = Path.GetFileName(file),
            ServerPath = _workspace.GetServerItemForLocalItem(file)

    var history = _vcs.QueryHistory(pp.ServerPath, RecursionType.OneLevel).FirstOrDefault();

    if (history != null)
        pp.LastCheckIn = history.CreationDate.ToString("r");
        pp.LastChangedBy = history.OwnerDisplayName;

    var doc = XDocument.Load(file);
    var ns = doc.Root.Name.Namespace;

    foreach (var propGroup in doc.Descendants(ns + "PropertyGroup"))
        var targetFrameworkVersion = propGroup.Descendants(ns + "TargetFrameworkVersion").FirstOrDefault();
        if (targetFrameworkVersion == null) continue;
        var frameworkVersion = targetFrameworkVersion.Value;
        pp.TargetFrameworkVersion = frameworkVersion;

        var outputType = propGroup.Descendants(ns + "OutputType").FirstOrDefault();
        if (outputType == null) continue;
        var oType = outputType.Value;
        pp.OutputType = oType;

        var projectTypeGuids = propGroup.Descendants(ns + "ProjectTypeGuids").FirstOrDefault();
        if (projectTypeGuids == null) continue;
        var prjTypeGuids = projectTypeGuids.Value;

        var pType = (from fmw in prjTypeGuids.Split(';')
                        let value =
                            ProjectTypeDictionary.ProjectType.Where(c => c.Key.ToLower() == fmw.ToLower())
                        select value.Any() ? value.FirstOrDefault().Value : fmw).Aggregate(string.Empty,
                                                                                        (current, o) =>
                                                                                            ? o
                                                                                            : string.Format(
                                                                                                "{0}, {1}",
                                                                                                current, o));
        pp.ProjectType = pType;

    var inc = string.Empty;
    foreach (var reference in doc.Descendants(ns + "Reference"))
        var include = reference.Attribute("Include");
        if (include != null)
            inc = string.IsNullOrEmpty(inc)
                        ? include.Value
                        : string.Format("{0} {1} {2}", inc, Environment.NewLine, include.Value);

        var requiredTargetFramework = reference.Descendants("RequiredTargetFramework").FirstOrDefault();
        if (requiredTargetFramework != null)
            inc = string.Format("{0} {1}", inc, requiredTargetFramework.Value);

    pp.Reference = inc;

  • Convert the projectTypeGuid to Project Name
{"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", "C#"},
{"{F2A71F9B-5D33-465A-A702-920D77279786}", "F#"},
{"{E6FDF86B-F3D1-11D4-8576-0002A516ECE8}", "J#"},
{"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}", "VB.NET"},
{"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "C++"},    
{"{349C5851-65DF-11DA-9384-00065B846F21}", "Web Application"}, 
{"{E24C65DC-7377-472B-9ABA-BC803B73C61A}", "Web Site"},
{"{F135691A-BF7E-435D-8960-F99683D2D49C}", "Distributed System"},
{"{3D9AD99F-2412-4246-B90B-4EAA41C64699}", "Windows Communication Foundation (WCF)"},
{"{60dc8134-eba5-43b8-bcc9-bb4bc16c2548}", "Windows Presentation Foundation (WPF)"},
{"{C252FEB5-A946-4202-B1D4-9916A0590387}", "Visual Database Tools"},
{"{A9ACE9BB-CECE-4E62-9AA4-C7E7C5BD2124}", "Database"},
{"{4F174C21-8C12-11D0-8340-0000F80270F8}","Database (other project types)"},
{"{20D4826A-C6FA-45DB-90F4-C717570B9F32}","Legacy (2003) Smart Device (C#)"},
{"{CB4CE8C6-1BDB-4DC7-A4D3-65A1999772F8}","Legacy (2003) Smart Device (VB.NET)"},
{"{4D628B5B-2FBC-4AA6-8C16-197242AEB884}","Smart Device (C#)"},
{"{68B1623D-7FB9-47D8-8664-7ECEA3297D4F}","Smart Device (VB.NET)"},
{"{32F31D43-81CC-4C15-9DE6-3FC5453562B6}","Workflow Foundation"},
{"{14822709-B5A1-4724-98CA-57A101D1B079}","Workflow (C#)"},
{"{D59BE175-2ED0-4C54-BE3D-CDAA9F3214C8}","Workflow (VB.NET)"},
{"{06A35CCD-C46D-44D5-987B-CF40FF872267}","Deployment Merge Module"},
{"{3EA9E505-35AC-4774-B492-AD1749C4943A}","Deployment Cab"},
{"{978C614F-708E-4E1A-B201-565925725DBA}","Deployment Setup"},
{"{AB322303-2255-48EF-A496-5904EB18DA55}","Deployment Smart Device Cab"},
{"{A860303F-1F3F-4691-B57E-529FC101A107}","Visual Studio Tools for Applications (VSTA)"},
{"{BAA0C2D2-18E2-41B9-852F-F413020CAA33}","Visual Studio Tools for Office (VSTO)"},
{"{F8810EC1-6754-47FC-A15F-DFABD2E3FA90}","SharePoint Workflow"},
{"{EC05E597-79D4-47f3-ADA0-324C4F7C7484}","SharePoint (VB.NET)"},
{"{593B0543-81F6-4436-BA1E-4747859CAAE2}","SharePoint (C#)"},
{"{6D335F3A-9D43-41b4-9D22-F6F17C4BE596}","XNA (Windows)"},
{"{2DF5C3F4-5A5F-47a9-8E94-23B4456F55E2}","XNA (XBox)"},
{"{D399B71A-8929-442a-A9AC-8BEC78BB2433}","XNA (Zune)"},
{"{F85E285D-A4E0-4152-9332-AB1D724D3325}","Model-View-Controller v2 (MVC2)"},
{"{E53F8FEA-EAE0-44A6-8774-FFD645390401}","Model-View-Controller v3 (MVC3)"},
{"{E3E379DF-F4C6-4180-9B81-6769533ABE47}","Model-View-Controller v4 (MVC4)"},
{"{BC8A1FFA-BEE3-4634-8014-F334798102B3}","Windows Store Apps (Metro Apps)"}
  • Use the TFS API to get the last check in date and last check in owner for the file
var history = _vcs.QueryHistory(pp.ServerPath, RecursionType.OneLevel).FirstOrDefault();

if (history != null)
    pp.LastCheckIn = history.CreationDate.ToString("r");
    pp.LastChangedBy = history.OwnerDisplayName;
  • Present the results on the UI
dgProjectDetails.ItemsSource = dt.DefaultView;
dgProjectDetails.AutoGenerateColumns = true;



Download a working demo solution from here.

If you have any feedback please feel free to leave a comment. Thank you for taking the time out and reading this blog post. If you enjoyed the post, remember to subscribe to Stay tuned!


Posted on Tuesday, January 29, 2013 1:36 AM TFS API , TFS2012 | Back to top

Comments on this post: TFS API - Reporting Visual Studio Solution And Project Versions

comments powered by Disqus

Copyright © Tarun Arora [Microsoft MVP] | Powered by: