<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>taylaf's TFS Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/taylaf/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/taylaf/feed.xml</link>
    <description>Taylor Lafrinere&amp;#039;s take on all things Team Foundation Server</description>
    <lastBuildDate>Tue, 16 Apr 2019 05:31:20 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Enable Visualization and Changeset Tracking for Branches Through the UI and Programmatically</title>
      <link>https://docs.microsoft.com/archive/blogs/taylaf/enable-visualization-and-changeset-tracking-for-branches-through-the-ui-and-programmatically</link>
      <pubDate>Mon, 26 Apr 2010 14:45:56 GMT</pubDate>
      <dc:creator><![CDATA[Taylor Lafrinere (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/taylaf/2010/04/26/enable-visualization-and-changeset-tracking-for-branches-through-the-ui-and-programmatically/</guid>
      <description><![CDATA[You have just upgraded to TFS 2010 and you are salivating to take advantage of the awesome new...]]></description>
      <content:encoded><![CDATA[<p>You have just upgraded to TFS 2010 and you are salivating to take advantage of the awesome new branch visualization tools that you have seen over at <a href="https://channel9.msdn.com/posts/VisualStudio/Branching-and-Merging-Visualization-with-Team-Foundation-Server-2010/">channel 9</a> or many other places and you are wondering what exactly you need to do to take advantage of these features.&#160; Of course, there is some setup you need to do but hopefully this blog post can help walk you through it.&#160; If you would like a little more background before you dive in then check out <a href="http://blogs.msdn.com/mitrik/archive/2009/06/11/branch-hierarchy-visualization.aspx">this introductory post by Matt Mitrik</a>.</p>  <p><strong>First of all, how do I know if visualization and changeset tracking is already enabled for a given branch?</strong></p>  <p>Great question!&#160; If you have just upgraded your existing TFS 2008 server then you likely don’t have any these features enabled for any of your branches yet because we don’t try to detect them on upgrade.&#160; To make this example a little more concrete, let’s assume you have two branches where you are developing prototypes under the path $/MyProduct/features/Feature1/prototypes.&#160; We can determine if these branches have visualizations enabled by navigating to that folder in Source Control Explorer:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic1_2.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic1_2.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic1" border="0" alt="pic1" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic1_thumb.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic1_thumb.jpg" width="785" height="336" /></a> </p>  <p>In Source Control Explorer and a few other places the branch visualization status of a folder is represented by its icon.&#160; Even though the Jupiter and Saturn folders above were both created by the branch command, only Saturn has visualizations enabled and this is can be determined by looking at their respective icons.&#160; </p>  <p><strong>Cool, so how do I enable visualizations for the Jupiter branch?</strong></p>  <p>Start by right-clicking on the Jupiter folder, selecting Branching and Merging and then clicking on Convert to Branch….&#160; This will bring up the following dialog:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic2_2.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic2_2.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic2" border="0" alt="pic2" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic2_thumb.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic2_thumb.jpg" width="510" height="352" /></a> </p>  <p>At this point you can enter a description for the work that is being done in this branch before converting it.&#160; You should also notice the check box at the bottom of the dialog that reads “Recursively perform this conversion on all folders previously branched from this folder”.&#160; As you might have guessed, this option will recursively convert all of the folders that are child branches of this folder when the conversion is done.&#160; If for some reason, you want to cherry-pick which branches you enable visualizations on then unchecking this box is a good idea.&#160; Now, if we click convert, we will see that the icon for the Jupiter folder now indicates that it has visualizations enabled:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic3_2.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic3_2.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic3" border="0" alt="pic3" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic3_thumb.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic3_thumb.jpg" width="787" height="353" /></a> </p>  <p><strong>But when I tried to do that, I got an error reading “TF203028: You cannot create a branch at $/<em>x</em> because a branch already exists at <em>$/x/y</em>”.</strong></p>  <p>Obviously, in a branch hierarchy, branches can have child branches and parent branches.&#160; However, what a branch cannot have is a folder beneath it in the source control repository that is also a branch.&#160; Thus, in our example, if Jupiter would have had a child folder that had already been converted to a branch we would have received this error.&#160; In TFS 2010, when you perform a branch from the UI, the option to “convert source and target folders to branches” is enabled by default if neither of these folder have a parent folder that is a branch.&#160; Thus, if you haven’t enabled visualizations for your existing branches then it is possible to accidentally create these spurious branches.&#160; If we still want to convert Jupiter to be a branch we will need to convert the offending child folder which is marked as a branch back to a normal folder.&#160; This can be done by selecting the offending child folder then clicking File &gt; Source Control &gt; Branching and Merging &gt; Convert To Folder.&#160; You will receive a prompt to confirm the action you are performing and after confirming it then you should be able to convert the desired parent folder to a branch.</p>  <p>Once you have done that to all of your branches then you can visualize your branch hierarchies by right-clicking on a node and selecting Branching and Merging &gt; View Hierarchy.&#160; By changing the “Show:” drop down menu to have the value “All hierarchies” I was able to generate this diagram:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic4_2.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic4_2.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic4" border="0" alt="pic4" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic4_thumb.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic4_thumb.jpg" width="717" height="396" /></a>&#160;</p>  <p>Unfortunately, its at this point that I notice that the Feature3 branch has the incorrect parent.&#160; While it was originally branched from the Product1 branch we subsequently did a baseless merge with the Product2 branch because we changed our minds about where Feature3 was actually going to live.&#160; Fortunately, there is a way to fix this!&#160; By selecting the Feature3 branch in this view and then clicking File &gt; Source Control &gt; Branching and Merging &gt; Reparent… you will be presented by a dialog that allows you to choose the branches correct parent.&#160; Note, this dialog will only show branches that this branch has a merge relationship with.&#160; Upon completing the reparenting, my diagram now correctly shows Feature3 with the correct parent (that being Product2):</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic5_2.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic5_2.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="pic5" border="0" alt="pic5" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic5_thumb.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/EnableVisualizationandChangesetTrackingf_C6D2/pic5_thumb.jpg" width="713" height="409" /></a> </p>  <h4>Doing All of This Programmatically</h4>  <p>Now let’s say that you do want to cherry-pick the branches that you want to convert and you have too many branches to convert by hand.&#160; Fortunately, we can combat this problem with a command line tool that uses some of the APIs new in TFS 2010.&#160; I will walk you through those APIs here.</p>  <p><em>In order to use the code from the examples in this post you will need the following include statements:</em></p>  <pre class="code"><span style="color: blue">using </span>System;
<span style="color: blue">using </span>System.Collections.Generic;
<span style="color: blue">using </span>System.Linq;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Client;
<span style="color: blue">using </span>Microsoft.TeamFoundation.VersionControl.Client;</pre>
<a href="http://11011.net/software/vspaste"></a>

<p>First, let’s talk about the input to this command-line tool because we will need to know the list of branches that you want convert.&#160; For my example I am going to use an xml document formatted in the following way:</p>

<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">BranchSpecs</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">BranchSpec </span><span style="color: red">path</span><span style="color: blue">=</span>&quot;<span style="color: blue">$/MyProduct/Main</span>&quot; 
                <span style="color: red">owner</span><span style="color: blue">=</span>&quot;<span style="color: blue">taylaf</span>&quot; <span style="color: red">description</span><span style="color: blue">=</span>&quot;<span style="color: blue">The main branch</span>&quot; <span style="color: blue">/&gt;
    &lt;</span><span style="color: #a31515">BranchSpec </span><span style="color: red">path</span><span style="color: blue">=</span>&quot;<span style="color: blue">$/MyProduct/Product1</span>&quot; 
                <span style="color: red">owner</span><span style="color: blue">=</span>&quot;<span style="color: blue">taylaf</span>&quot; <span style="color: red">description</span><span style="color: blue">=</span>&quot;<span style="color: blue">The product1 branch</span>&quot; <span style="color: blue">/&gt;
    &lt;</span><span style="color: #a31515">BranchSpec </span><span style="color: red">path</span><span style="color: blue">=</span>&quot;<span style="color: blue">$/MyProduct/Product2</span>&quot; 
                <span style="color: red">owner</span><span style="color: blue">=</span>&quot;<span style="color: blue">taylaf</span>&quot; <span style="color: red">description</span><span style="color: blue">=</span>&quot;<span style="color: blue">The product2 branch</span>&quot; <span style="color: blue">/&gt;
    &lt;</span><span style="color: #a31515">BranchSpec </span><span style="color: red">path</span><span style="color: blue">=</span>&quot;<span style="color: blue">$/MyProduct/features/Feature1</span>&quot; 
                <span style="color: red">owner</span><span style="color: blue">=</span>&quot;<span style="color: blue">taylaf</span>&quot; <span style="color: red">description</span><span style="color: blue">=</span>&quot;<span style="color: blue">The feature1 branch</span>&quot; <span style="color: blue">/&gt;
    &lt;</span><span style="color: #a31515">BranchSpec </span><span style="color: red">path</span><span style="color: blue">=</span>&quot;<span style="color: blue">$/MyProduct/features/Feature2</span>&quot; 
                <span style="color: red">owner</span><span style="color: blue">=</span>&quot;<span style="color: blue">taylaf</span>&quot; <span style="color: red">description</span><span style="color: blue">=</span>&quot;<span style="color: blue">The feature2 branch</span>&quot; <span style="color: blue">/&gt;
    &lt;</span><span style="color: #a31515">BranchSpec </span><span style="color: red">path</span><span style="color: blue">=</span>&quot;<span style="color: blue">$/MyProduct/features/Feature3</span>&quot; <span style="color: red">overrideParentPath</span><span style="color: blue">=</span>&quot;<span style="color: blue">$/MyProduct/Product2</span>&quot; 
                <span style="color: red">owner</span><span style="color: blue">=</span>&quot;<span style="color: blue">taylaf</span>&quot; <span style="color: red">description</span><span style="color: blue">=</span>&quot;<span style="color: blue">The feature3 branch</span>&quot; <span style="color: blue">/&gt;
    &lt;</span><span style="color: #a31515">BranchSpec </span><span style="color: red">path</span><span style="color: blue">=</span>&quot;<span style="color: blue">$/MyProduct/features/prototypes/Jupiter</span>&quot; 
                <span style="color: red">owner</span><span style="color: blue">=</span>&quot;<span style="color: blue">taylaf</span>&quot; <span style="color: red">description</span><span style="color: blue">=</span>&quot;<span style="color: blue">The jupiter branch</span>&quot; <span style="color: blue">/&gt;
    &lt;</span><span style="color: #a31515">BranchSpec </span><span style="color: red">path</span><span style="color: blue">=</span>&quot;<span style="color: blue">$/MyProduct/features/prototypes/Saturn</span>&quot; 
                <span style="color: red">owner</span><span style="color: blue">=</span>&quot;<span style="color: blue">taylaf</span>&quot; <span style="color: red">description</span><span style="color: blue">=</span>&quot;<span style="color: blue">The saturn branch</span>&quot; <span style="color: blue">/&gt;
&lt;/</span><span style="color: #a31515">BranchSpecs</span><span style="color: blue">&gt;
</span></pre>
<a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><font color="#0000ff" face="Courier New"></font>

<p>You will notice that the $/MyProduct/features/Feature3 is the only branch that has the overrideParentPath attribute set.&#160; This is due to the fact that we want to override what the parent branch is set to when we create the branch objects.&#160; You should know the story as to why we want to do this override if you have read the whole blog post thus far.&#160; If not, you may want to read the section in between the two branch hierarchy screen shots above.&#160; Using some xml parsing magic (which I will leave up to the user to figure out :)) I am going to populate an instance of the following class for each of the BranchSpec entries:</p>

<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">BranchSpec
</span>{
    <span style="color: blue">public </span><span style="color: #2b91af">String </span>Path { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
    <span style="color: blue">public </span><span style="color: #2b91af">String </span>OverrideParentPath { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
    <span style="color: blue">public </span><span style="color: #2b91af">String </span>Owner { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
    <span style="color: blue">public </span><span style="color: #2b91af">String </span>Description { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
}</pre>
<a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a>

<p>Using this class I will produce the list of BranchSpecs that show up in the rest of the example.&#160; Feel free to use whichever input method works best for you.</p>

<p>Now that we have the data we need to do the processing, let’s start with the basics.&#160; We will need a connection to the server that we are going to be converting the branches on as well as a link to the version control client OM entry point:</p>

<pre class="code"><span style="color: #2b91af">TfsTeamProjectCollection </span>tpc = <span style="color: blue">new </span><span style="color: #2b91af">TfsTeamProjectCollection</span>(<span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #a31515">&quot;http://server:8080/tfs/MyTPC&quot;</span>));
<span style="color: #2b91af">VersionControlServer </span>sourceControl = tpc.GetService&lt;<span style="color: #2b91af">VersionControlServer</span>&gt;();</pre>
<a href="http://11011.net/software/vspaste"></a>

<p>Before we write the loop that will actually create the branch objects, let’s write some of the meatier parts that will actually be responsible for the branch object creation.&#160; One of the tasks we are going are going to want to perform is to determine the parent branch of the branch we want to convert so that we can set that piece of the metadata on the branch object.&#160; To do this we will write a function to determine the branch parent that uses the GetBranchHistory API.&#160; Here is the code with some explanation in the comments on how to do this:</p>

<pre class="code"><span style="color: blue">private </span><span style="color: #2b91af">String </span>DetermineParentBranchPath(
    <span style="color: #2b91af">VersionControlServer </span>sourceControl, 
    <span style="color: #2b91af">BranchSpec </span>branchSpec)
{
    <span style="color: green">// Create an ItemSpec for the branch path that we want to determine
    // the parent for.  Make sure to set the RecursionType parameter to
    // None because we only want branch history for the root item.
    </span><span style="color: #2b91af">ItemSpec </span>itemSpec = <span style="color: blue">new </span><span style="color: #2b91af">ItemSpec</span>(branchSpec.Path, <span style="color: #2b91af">RecursionType</span>.None);

    <span style="color: green">// Call GetBranchHistory() on the ItemSpec that we constructed.  We
    // will set the VersionSpec to latest because we know the branch exists
    // at latest.
    </span><span style="color: #2b91af">BranchHistoryTreeItem</span>[][] results = sourceControl.GetBranchHistory(
        <span style="color: blue">new </span><span style="color: #2b91af">ItemSpec</span>[] { itemSpec }, <span style="color: #2b91af">VersionSpec</span>.Latest);

    <span style="color: green">// The results returned from the GetBranchHistory() call are a bit complicated.
    // First of all, we know that the results specific to our query are in the 
    // first entry of the 2D array.  This is because the contract with the method
    // is that it will return an array of BranchHistoryTreeItem for each path that
    // is queried and the entries in the array will be sorted in the order of the
    // input paths.  Let's grab the first element so we can operate on it.
    </span><span style="color: #2b91af">BranchHistoryTreeItem</span>[] thisBranchResults = results[0];

    <span style="color: green">// Now that we have our results we need to process them in order to find the
    // branch that we originally queried on.  In order to do that we will want
    // to look at each BranchHistoryTreeItem and each of its children.  Let's 
    // start by iterating over the results.
    </span><span style="color: blue">foreach </span>(<span style="color: #2b91af">BranchHistoryTreeItem </span>treeItem <span style="color: blue">in </span>thisBranchResults)
    {
        <span style="color: green">// Now, let's invoke a recursive function on the treeItem to iterate
        // over all of its children to determine if we have found the requested
        // item.
        </span><span style="color: #2b91af">BranchRelative </span>requestedItem = FindRequestedItem(treeItem);

        <span style="color: green">// If we found the requested item see if it has an item it was branched from.
        </span><span style="color: blue">if </span>(requestedItem != <span style="color: blue">null</span>)
        {
            <span style="color: blue">return </span>(requestedItem.BranchFromItem == <span style="color: blue">null</span>) ? <span style="color: blue">null </span>: requestedItem.BranchFromItem.ServerItem;
        }
    }

    <span style="color: blue">return null</span>;
}</pre>

<pre class="code"><span style="color: blue">private </span><span style="color: #2b91af">BranchRelative </span>FindRequestedItem(
    <span style="color: #2b91af">BranchHistoryTreeItem </span>treeItem)
{
    <span style="color: green">// If the current item is the requested item then return the
    // BranchRelative for the item.
    </span><span style="color: blue">if </span>(treeItem.Relative.IsRequestedItem)
    {
        <span style="color: blue">return </span>treeItem.Relative;
    }

    <span style="color: green">// Otherwise, iterate over all of the children for this 
    // branch item and call this method on the children.
    </span><span style="color: blue">foreach </span>(<span style="color: #2b91af">BranchHistoryTreeItem </span>child <span style="color: blue">in </span>treeItem.Children)
    {
        <span style="color: #2b91af">BranchRelative </span>requestedItem = FindRequestedItem(child);
        <span style="color: blue">if </span>(requestedItem != <span style="color: blue">null</span>)
        {
            <span style="color: blue">return </span>requestedItem;
        }
    }

    <span style="color: blue">return null</span>;
}</pre>

<p>With the above two methods we can programmatically determine the parent of the current branch.&#160; Of course, it is possible that the branch is a root branch and it does not have a parent.&#160; In that case, null will be returned by DetermineParentBranchPath().&#160; Now, onto making sure the branch exists as a branch object.&#160; In terms of the object-model a branch that has visualizations enabled is referred to as a BranchObject.&#160; For the method that makes sure the branch object exists we will make sure to check to see if it exists first and will update it with the appropriate information if it does exist.&#160; The reason for this will be explained later.&#160; Again, here is the code to do this with explanations in the comments:</p>

<pre class="code"><span style="color: blue">private void </span>EnsureBranchObjectExists(
    <span style="color: #2b91af">VersionControlServer </span>sourceControl,
    <span style="color: #2b91af">String </span>path,
    <span style="color: #2b91af">String </span>parentPath,
    <span style="color: #2b91af">String </span>owner,
    <span style="color: #2b91af">String </span>description)
{
    <span style="color: green">// Create an ItemIdentifier for the path that we will be querying branch objects on.
    </span><span style="color: #2b91af">ItemIdentifier </span>branchItemIdentifier = <span style="color: blue">new </span><span style="color: #2b91af">ItemIdentifier</span>(path);

    <span style="color: green">// Call QueryBranchObjects to determine if a branch object already exists for the
    // given path.  Again, be sure to pass None for the recursion type because we only want to
    // look for the branch object on the item itself.
    </span><span style="color: #2b91af">BranchObject</span>[] branchObjects = sourceControl.QueryBranchObjects(branchItemIdentifier, <span style="color: #2b91af">RecursionType</span>.None);

    <span style="color: #2b91af">BranchObject </span>branchObject = branchObjects.FirstOrDefault();
    <span style="color: blue">if </span>(branchObject != <span style="color: blue">null</span>)
    {
        <span style="color: green">// The branch object exists.  Let's make sure it has the correct properties.
        </span>SetBranchProperties(branchObject.Properties, parentPath, owner, description);

        <span style="color: green">// Now make sure the properties are persisted to the server
        </span>sourceControl.UpdateBranchObject(branchObject.Properties);
    }
    <span style="color: blue">else
    </span>{
        <span style="color: green">// We need to create the branch object.
        </span><span style="color: #2b91af">BranchProperties </span>properties = <span style="color: blue">new </span><span style="color: #2b91af">BranchProperties</span>(branchItemIdentifier);

        <span style="color: green">// Update its properties to the passed in values.
        </span>SetBranchProperties(properties, parentPath, owner, description);

        <span style="color: green">// Save the newly created branch object to the server
        </span>sourceControl.CreateBranchObject(properties);
    }
}

<span style="color: blue">private void </span>SetBranchProperties(
    <span style="color: #2b91af">BranchProperties </span>branchProperties,
    <span style="color: #2b91af">String </span>parentPath, 
    <span style="color: #2b91af">String </span>owner, 
    <span style="color: #2b91af">String </span>description)
{
    <span style="color: green">// We don't want to overwrite the properties if the incoming values are null
    // so make sure to check the values of them before setting.
    </span><span style="color: blue">if </span>(parentPath != <span style="color: blue">null</span>)
    {
        branchProperties.ParentBranch = <span style="color: blue">new </span><span style="color: #2b91af">ItemIdentifier</span>(parentPath);
    }
    <span style="color: blue">if </span>(owner != <span style="color: blue">null</span>)
    {
        branchProperties.Owner = owner;
    }
    <span style="color: blue">if </span>(description != <span style="color: blue">null</span>)
    {
        branchProperties.Description = description;
    }
}</pre>

<p>At this point we should be able to write a fairly simple outer loop that controls the calls to these methods.&#160; This loop is going to consist of determining the proper parent branch, making sure the parent branch exists as a branch object and finally making sure the current branch exists as a branch object.&#160; The reason we need to make sure the parent branch exists as a branch object is because a branch object cannot have a parent that is not also a branch object.&#160; Here we go:</p>

<pre class="code"><span style="color: blue">foreach </span>(<span style="color: #2b91af">BranchSpec </span>branchSpec <span style="color: blue">in </span>branchSpecs)
{
    <span style="color: #2b91af">String </span>parentPath = branchSpec.OverrideParentPath;
    <span style="color: blue">if </span>(<span style="color: #2b91af">String</span>.IsNullOrEmpty(parentPath))
    {
        parentPath = DetermineParentBranchPath(sourceControl, branchSpec);
    }

    <span style="color: blue">if </span>(!<span style="color: #2b91af">String</span>.IsNullOrEmpty(parentPath))
    {
        EnsureBranchObjectExists(sourceControl, parentPath, <span style="color: blue">null</span>, <span style="color: blue">null</span>, <span style="color: blue">null</span>); 
    }
    EnsureBranchObjectExists(sourceControl, branchSpec.Path, parentPath, branchSpec.Owner, branchSpec.Description);
}</pre>

<p>Note, that by passing nulls for the metadata for the parent branch object we will never overwrite valid metadata for that branch object because of the way we have written our SetBranchProperties method.&#160; </p>

<p>And that should be all that it takes!&#160; Once you run the code you should have all of your branches converted to branch objects within TFS.&#160; Have fun with all of the cool visualizations!</p>]]></content:encoded>
    </item>
    <item>
      <title>Using TFS Impersonation with the Version Control Client APIs</title>
      <link>https://docs.microsoft.com/archive/blogs/taylaf/using-tfs-impersonation-with-the-version-control-client-apis</link>
      <pubDate>Mon, 29 Mar 2010 15:14:00 GMT</pubDate>
      <dc:creator><![CDATA[Taylor Lafrinere (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/taylaf/2010/03/29/using-tfs-impersonation-with-the-version-control-client-apis/</guid>
      <description><![CDATA[Recently I have a received a few emails asking questions about how to use the version control client...]]></description>
      <content:encoded><![CDATA[<p>Recently I have a received a few emails asking questions about how to use the version control client APIs to create workspaces and check in files with the most recent one also asking if it could be used with TFS Impersonation to record the check ins as if they had been done by a different user.&nbsp; Since I am in the process of transferring over to the Version Control Server team I thought this would be a great place for me to dig in and use the APIs to put together a code example to answer these questions.</p>
<p>First of all, if you are new to the TFS 2010 OM you may want to start with this <a href="http://blogs.msdn.com/taylaf/archive/2010/02/23/introducing-the-tfsconnection-tfsconfigurationserver-and-tfsteamprojectcollection-classes.aspx">post which introduces the TfsConnection, TfsConfigurationServer and TfsTeamProjectCollection objects</a>.&nbsp; Secondly, if you have not used TFS Impersonation before you will surely find it useful to read up on its introductory post <a href="http://blogs.msdn.com/taylaf/archive/2009/12/04/introducing-tfs-impersonation.aspx">here</a>.</p>
<p><em>In order to use the code from the examples in this post you will need the following include statements:</em></p>
<pre class="code"><span style="color: blue;">using </span>System;
<span style="color: blue;">using </span>System.IO;
<span style="color: blue;">using </span>Microsoft.TeamFoundation.Client;
<span style="color: blue;">using </span>Microsoft.TeamFoundation.Framework.Client;
<span style="color: blue;">using </span>Microsoft.TeamFoundation.Framework.Common;
<span style="color: blue;">using </span>Microsoft.TeamFoundation.VersionControl.Client;</pre>
<p>Let&rsquo;s start by defining a scenario that we want to solve with this example.&nbsp; Since we want to use TFS Impersonation along with the version control client OM a scenario that seems to work well would be one in which a service or a job checks in edits to a file on behalf of a user that triggers some event.&nbsp; In order to have some data for our example to process, let&rsquo;s define some variables up front.&nbsp; This, of course, would need to come from some type of configuration file or user input if this example were to be turned into production code.</p>
<pre class="code"><span style="color: green;">// Holds the uri that points to the team project collection we will communicate with. <br /></span><span style="color: #2b91af;">Uri </span>uriToTeamProjectCollection;

<span style="color: green;">// The account name of the user we will be performing this check in on behalf of. <br /></span><span style="color: #2b91af;">String </span>userAccountName;

<span style="color: green;">// The server path of the file in TFS that we will be modifying. <br /></span><span style="color: #2b91af;">String </span>serverPathForFile;

<span style="color: green;">// The place on the local file system where we want to download the file from TFS <br /></span><span style="color: #2b91af;">String </span>localWorkspacePathForFile;

<span style="color: green;">// Let's assume for this example that the file actually already exists on disk in the form that <br />// we want to send it to the server as. That is, we want to copy the contents of this file<br /> // to send to the server. This is just our way of making changes to the file. <br /></span><span style="color: #2b91af;">String </span>localCopyOfFile;</pre>
<p>Since I wrote the majority of the TFS Impersonation code and haven&rsquo;t touched the version control client OM before, let&rsquo;s start with the easy stuff first :).&nbsp; As you know from reading the TFS Impersonation post above we will actually have to make two connections to our collection in order to perform this scenario.&nbsp; We will use the first connection to determine the IdentityDescriptor for the user we will be impersonating since that is the piece of information needed to perform impersonation:</p>
<pre class="code"><span style="color: #2b91af;">TfsTeamProjectCollection </span>baseUserTpcConnection = <br />  <span style="color: blue;">new </span><span style="color: #2b91af;">TfsTeamProjectCollection</span>(uriToTeamProjectCollection);
<span style="color: #2b91af;">IIdentityManagementService </span>ims =<br />  baseUserTpcConnection.GetService&lt;<span style="color: #2b91af;">IIdentityManagementService</span>&gt;();

<span style="color: green;">// Read out the identity of the user we want to impersonate <br /></span><span style="color: #2b91af;">TeamFoundationIdentity </span>identity = ims.ReadIdentity(<span style="color: #2b91af;">IdentitySearchFactor</span>.AccountName, <br />    userAccountName, <span style="color: #2b91af;">MembershipQuery</span>.None, <span style="color: #2b91af;">ReadIdentityOptions</span>.None);</pre>
<p>Now that we have the identity of the user that we want to impersonate the next step is to actually create the impersonated connection to the collection.&nbsp; But wait! This is a great time to remember that in order for impersonation to work, the user that the process is running as must have the &ldquo;Make requests on behalf of others&rdquo; permission for this collection.&nbsp; If the user does not have this permission then you are going to see an Access Denied error message.&nbsp; So, now that that is taken care of, let&rsquo;s actually create the impersonated connection to the collection.</p>
<pre class="code"><span style="color: #2b91af;">TfsTeamProjectCollection </span>impersonatedTpcConnection = <br />    <span style="color: blue;">new </span><span style="color: #2b91af;">TfsTeamProjectCollection</span>(uriToTeamProjectCollection, identity.Descriptor);</pre>
<p>Great! So now we have our impersonated connection.&nbsp; The next step is to check in the changes to a file using this impersonated connection.&nbsp; In order to this, we must start by creating a workspace and setting up working folder mappings so that we can download the existing file on the server.&nbsp; Note, that for any of you out there wondering, the following code would work in a non-impersonation scenario as well.</p>
<pre class="code"><span style="color: #2b91af;">VersionControlServer </span>sourceControl =<br />   impersonatedTpcConnection.GetService&lt;<span style="color: #2b91af;">VersionControlServer</span>&gt;();

<span style="color: green;">// Create the workspace <br /></span><span style="color: #2b91af;">Workspace </span>workspace =<br />   sourceControl.CreateWorkspace(<span style="color: #2b91af;">String</span>.Format(<span style="color: #a31515;">"MyTempWorkspace-{0}"</span>, <br />   <span style="color: #2b91af;">DateTime</span>.Now));

<span style="color: green;">// Map the file that we want to change <br /></span>workspace.CreateMapping(<span style="color: blue;">new </span><span style="color: #2b91af;">WorkingFolder</span>(serverPathForFile, <br />    localWorkspacePathForFile));</pre>
<p>In the above code, we get the VersionControlServer object because it is the source for performing all version control operations.&nbsp; Next, I create a workspace with a name that has a the current time included in it.&nbsp; The reason that I use a time stamp within the name is because the name of a workspace for a given computer must be unique and although we will try to clean up this workspace later, we do not want a crash of the program to cause us to fail when trying to create the next workspace due to a naming conflict.&nbsp; Finally, we map the server path for the file to a local path.&nbsp; If you are going to change multiple files you do not need to create multiple mappings but can instead pick a root folder that both of the files live in.</p>
<p>The next thing we need to do is actually download the file that exists on the TFS server.&nbsp; In our case, this is a simple as just calling the following method:</p>
<pre class="code"><span style="color: green;">// Download the file <br /></span>workspace.Get();</pre>
<p>Now that we have the file downloaded locally we could add an optimization that terminates execution if the file that we want to upload is the same as the existing file.&nbsp; For brevity, I will avoid that optimization and leave that to you if you feel that you need it.&nbsp; Thus, the next step is to pend the edit that we want to make and then copy in the contents of the file to the file that is mapped in the workspace:</p>
<pre class="code"><span style="color: green;">// Pend the edit on the file to remove the read-only bit <br /></span>workspace.PendEdit(serverPathForFile);

<span style="color: green;">// Copy our file to the mapped location <br /></span><span style="color: #2b91af;">File</span>.Copy(localCopyOfFile, localWorkspacePathForFile, <span style="color: blue;">true</span>);</pre>
<p>Note that in the PendEdit call, I could have passed either the server path or the local path.</p>
<p>Finally, all we have left to do is check in the changes that we have pended and clean up our workspace.&nbsp; This can be done via the following two calls:</p>
<pre class="code"><span style="color: green;">// CheckIn the file <br /></span>workspace.CheckIn(<span style="color: blue;">new </span><span style="color: #2b91af;">WorkspaceCheckInParameters</span>(<br />    workspace.GetPendingChangesEnumerable(), <br />    <span style="color: #a31515;">"Comment detailing what happened."</span>));

<span style="color: green;">// Clean up the workspace <br /></span>workspace.Delete();</pre>
<p>&nbsp;</p>
<p>And voila!&nbsp; The changes to the file are now on the server and they will be recorded as if the impersonated user had performed the operation.&nbsp; Also, it is good to know that if you didn&rsquo;t implement the optimization of checking if the files and they happen to be the same then no check in will actually happen.</p>
<p>Hopefully that gives you a better understanding of both how TFS Impersonation works and how the version control client OM works.&nbsp; Please send me any questions you have either via the contact link above or the comment section below.</p>
<p>Happy Coding!</p>]]></content:encoded>
    </item>
    <item>
      <title>Introducing the TfsConnection, TfsConfigurationServer and TfsTeamProjectCollection Classes</title>
      <link>https://docs.microsoft.com/archive/blogs/taylaf/introducing-the-tfsconnection-tfsconfigurationserver-and-tfsteamprojectcollection-classes</link>
      <pubDate>Tue, 23 Feb 2010 08:41:35 GMT</pubDate>
      <dc:creator><![CDATA[Taylor Lafrinere (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/taylaf/2010/02/23/introducing-the-tfsconnection-tfsconfigurationserver-and-tfsteamprojectcollection-classes/</guid>
      <description><![CDATA[If you are familiar with the TFS 2008 client object model then I am sure you have interacted with...]]></description>
      <content:encoded><![CDATA[<p>If you are familiar with the TFS 2008 client object model then I am sure you have interacted with the TeamFoundationServer object that lived in the Microsoft.TeamFoundation.Client namespace.&#160; It is the starting point for all communication with a 2005 or 2008 Team Foundation Server.&#160; Due to the architectural changes that have been made for TFS 2010 we found that having a single class called TeamFoundationServer did not provide the correct starting point for communicating with a 2010 Team Foundation Server.&#160; Because of this, the TeamFoundationServer class has been deprecated and it has been replaced by the TfsConfigurationServer and the TfsTeamProjectCollection classes.</p>  <p>In order to understand why we made this choice you should first understand how the Team Foundation Server architecture has changed for TFS 2010.&#160; Your best bet is to read <a href="http://blogs.msdn.com/bharry/archive/2009/04/19/team-foundation-server-2010-key-concepts.aspx">Brian Harry’s blog post</a> on that topic and to focus on the section about Team Project Collections.&#160; If you have used the TFS 2010 Beta 1 or Beta 2 APIs then it will be useful to read <a href="http://blogs.msdn.com/granth/archive/2009/12/07/tfs2010-object-model-api-changes-after-beta-2.aspx">Grant Holliday’s blog post</a> on the API renaming that we did.</p>  <p><em>Disclaimer: These classes were introduced in the RC version of TFS 2010<em>.&#160; If you are using one of the Beta versions of TFS 2010 you will not see these classes.</em></em></p>  <p><em>In order to use the code from the examples in this post you will need the following include statements:</em></p>  <pre class="code"><span style="color: blue">using </span>System;
<span style="color: blue">using </span>System.Collections.Generic;
<span style="color: blue">using </span>System.Collections.ObjectModel;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Client;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Framework.Client;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Framework.Common;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Common;</pre>
<a href="http://11011.net/software/vspaste"></a>

<p><font size="4"><strong>The TfsConnection Class</strong></font></p>

<p>The TfsConnection class is the abstract base class for the TfsConfigurationServer and TfsTeamProjectCollection objects.&#160; Before we talk about when you should use each derived class let’s discuss the shared functionality that exists in their base class.&#160; Just like the TeamFoundationServer class in the TFS 2008 OM, the TfsConnection object aims to provide you various information about your connection with TFS as well as ways to initiate and control that connection.&#160; If it isn’t explicitly mentioned here, the functions and properties that existed on the TeamFoundationServer object will likely exist in the same way on the TfsConnection object.</p>

<p><strong>Identity Management</strong></p>

<p>By integrating with the new IIdentityManagementService, the TfsConnection object is able to give you a much richer experience around dealing with the identities that are involved in the connection with TFS.&#160; On the old TeamFoundationServer object you probably remember the three properties that reported the user you were connected as, they were:</p>

<pre class="code"><span style="color: blue">public string </span>AuthenticatedUserDisplayName { <span style="color: blue">get</span>; }<span style="color: green">
</span><span style="color: blue">public </span><span style="color: #2b91af">Identity </span>AuthenticatedUserIdentity { <span style="color: blue">get</span>; }<br /><span style="color: blue">p</span><span style="color: blue">ublic string </span>AuthenticatedUserName { <span style="color: blue">get</span>; }</pre>

<p>Off of the new TfsConnection object you will find that this information along with other information is now available from this property:</p>

<pre class="code"><span style="color: blue">public </span><span style="color: #2b91af">TeamFoundationIdentity </span>AuthorizedIdentity { <span style="color: blue">get</span>; }</pre>

<p></p>

<p>You may also notice that the prefix of the property has changed from “Authenticated” to “Authorized”.&#160; This has to do with the new <a href="http://blogs.msdn.com/taylaf/archive/2009/12/04/introducing-tfs-impersonation.aspx">TFS Impersonation</a> feature that is usable with all TfsConnection objects.&#160; Check out the blog post in the link for more information.&#160; Once you have done that then hopefully you will find the new constructor overloads and this function more useful:</p>

<pre class="code"><span style="color: blue">public void </span>GetAuthenticatedIdentity(<span style="color: blue">out </span><span style="color: #2b91af">TeamFoundationIdentity </span>identity);</pre>

<p><strong>Authentication</strong></p>

<p>With the TeamFoundationServer object, getting the above user information always resulted in two server calls: one to actually authenticate with the server and the second to look information about the user you were connecting as.&#160; In some cases, a third call was then made to read down location information so that other services (such as version control) could be used.&#160; Fortunately, with the TfsConnection object, all of that information is now retrievable in a single call to the server via this method:</p>

<pre class="code"><span style="color: blue">public void </span>Connect(<span style="color: #2b91af">ConnectOptions </span>connectOptions);</pre>
<a href="http://11011.net/software/vspaste"></a>

<p><strong>Catalog Integration</strong></p>

<p>If you are new to TFS 2010 then the catalog service is likely new to you as well.&#160; Check out this <a href="http://blogs.msdn.com/taylaf/archive/2010/01/26/retrieve-the-list-of-team-project-collections-from-tfs-2010-client-apis.aspx">blog post</a> to learn some more about the catalog service.&#160; The TfsConnection object integrates with the catalog service to easily make its CatalogNode object available to the consumer via this property:</p>

<pre class="code"><span style="color: blue">public abstract </span><span style="color: #2b91af">CatalogNode </span>CatalogNode { <span style="color: blue">get</span>; }</pre>

<p>This property will have different meaning based on whether the derived class is a TfsConfigurationServer or a TfsTeamProjectCollection object.&#160; In the case where it is a TfsConfigurationServer object, the catalog node returned will be the one that represents the TFS instance.&#160; In the case where it is a TfsTeamProjectCollection object, the catalog node returned will be the one that represents the given team project collection.</p>

<p><strong><font size="4">The TfsConfigurationServer Class</font></strong></p>

<p>As you read in Brian’s blog post, in TFS 2010 we have introduced a new level of granularity between a TFS instance and the team projects that it contains.&#160; That new level of granularity is called a team project collection and it is used to encapsulate a collection of team projects within a TFS instance.&#160; The container for the set of team project collections is known as the configuration server.&#160; In order to communicate with the configuration server you would construct a TfsConfigurationServer object using either its factory:</p>

<pre class="code"><span style="color: #2b91af">TfsConfigurationServer </span>configurationServer = 
    <span style="color: #2b91af">TfsConfigurationServerFactory</span>.GetConfigurationServer(<span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #a31515">&quot;http://server:8080/tfs&quot;</span>));</pre>
<a href="http://11011.net/software/vspaste"></a>

<p>or one of its constructors:</p>

<pre class="code"><span style="color: #2b91af">TfsConfigurationServer </span>configurationServer = <span style="color: blue">new </span><span style="color: #2b91af">TfsConfigurationServer</span>(<span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #a31515">&quot;http://server:8080/tfs&quot;</span>));</pre>

<p></p>

<p>Of course, using the constructor will always create a new instance of the class while the factory will always give out the same instance of the class.&#160; With this object you can now perform many actions against the configuration server.&#160; Here is a (not necessarily exhaustive) list of services that you can get via the GetService&lt;T&gt;() call along with the tasks that they enable:</p>

<ul>
  <li><strong>Microsoft.TeamFoundation.Framework.Client.ITeamFoundationRegistry: </strong>Exposes APIs for viewing and managing the contents of the TFS registry at the configuration server level. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client</strong>.<strong>IIdentityManagementService</strong>: Exposes APIs for viewing and managing identities that exist in TFS and their group membership details at the configuration server level. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client.ITeamFoundationJobService: </strong>Exposes APIs for viewing and managing job definitions, job schedules and job run history at the configuration server level. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client.IPropertyService: </strong>Exposes APIs for reading from and writing to the generic property store at the configuration server level. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client.IEventService: </strong>Exposes APIs for viewing and managing event subscriptions at the configuration server level. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client.ISecurityService: </strong>Exposes APIs for viewing and managing security namespaces and the security data that each of those namespaces contain at the configuration server level. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client</strong>.<strong>ILocationService: </strong>Exposes APIs for viewing and managing the services defined at the configuration service level along with their configured locations. </li>

  <li><strong>Microsoft.TeamFoundation.Client.TswaClientHyperlinkService: </strong>Exposes APIs for constructing URLs that communicate with TSWA.</li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client.ITeamProjectCollectionService: </strong>Exposes APIs that allow you to perform management and servicing tasks on the set of team project collections. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client</strong>.<strong>IAdministrationService: </strong>Exposes APIs for querying and canceling the active requests on the server. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client</strong>.<strong>ICatalogService: </strong>Exposes APIs for viewing and managing the contents of the catalog. </li>

  <li><strong>Microsoft.TeamFoundation.Lab.Client.LabFrameworkService</strong>: Exposes APIs that allow you to perform verification of Lab Management objects during configuration. </li>
</ul>

<p>One other thing you may want to do from your configuration server object is communicate with each of the team project collections that are members of this configuration server.&#160; As we will discuss in the next section, all communication with a team project collection starts with the TfsTeamProjectCollection class.&#160; In order to get the TfsTeamProjectCollection instance for a given team project collection you can call the following helper method from the TfsConfigurationServer class:</p>

<pre class="code"><span style="color: blue">public </span><span style="color: #2b91af">TfsTeamProjectCollection </span>GetTeamProjectCollection(<span style="color: #2b91af">Guid </span>collectionId);</pre>

<p>One way you could possibly use this method is to enumerate the team project collections that you can see using the catalog to get each of their IDs and then use this function to construct the proxy for talking to that team project collection.&#160; Here is an example of how that would be done. (Note, if you want a better understand of how the catalog is being used here, check out <a href="http://blogs.msdn.com/taylaf/archive/2010/01/26/retrieve-the-list-of-team-project-collections-from-tfs-2010-client-apis.aspx">my blog post on enumerating the team project collections using the catalog</a>).</p>

<pre class="code"><span style="color: #2b91af">Uri </span>configurationServerUri = <span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #a31515">&quot;http://server:8080/tfs&quot;</span>);
<span style="color: #2b91af">TfsConfigurationServer </span>configurationServer =
        <span style="color: #2b91af">TfsConfigurationServerFactory</span>.GetConfigurationServer(configurationServerUri);

<span style="color: #2b91af">CatalogNode </span>configurationServerNode = configurationServer.CatalogNode;

<span style="color: green">// Query the children of the configuration server node for all of the team project collection nodes
</span><span style="color: #2b91af">ReadOnlyCollection</span>&lt;<span style="color: #2b91af">CatalogNode</span>&gt; tpcNodes = configurationServerNode.QueryChildren(
        <span style="color: blue">new </span><span style="color: #2b91af">Guid</span>[] { <span style="color: #2b91af">CatalogResourceTypes</span>.ProjectCollection }, 
        <span style="color: blue">false</span>,                                                 
        <span style="color: #2b91af">CatalogQueryOptions</span>.None);

<span style="color: blue">foreach </span>(<span style="color: #2b91af">CatalogNode </span>tpcNode <span style="color: blue">in </span>tpcNodes)
{
    <span style="color: #2b91af">Guid </span>tpcId = <span style="color: blue">new </span><span style="color: #2b91af">Guid</span>(tpcNode.Resource.Properties[<span style="color: #a31515">&quot;InstanceId&quot;</span>]);
    <span style="color: #2b91af">TfsTeamProjectCollection </span>tpc = configurationServer.GetTeamProjectCollection(tpcId);

    <span style="color: green">// Do your tpc work here.
</span>}</pre>
<a href="http://11011.net/software/vspaste"></a>

<p>So, now that you know how to get a TfsTeamProjectCollection class, let’s discuss that further.</p>

<p><strong><font size="4">The TfsTeamProjectCollection Class</font></strong></p>

<p>From reading the topic above, you already know that you can get an instance of a TfsTeamProjectCollection class from its related TfsConfigurationServer object.&#160; Of course, you can also create an object using the factory method:</p>

<pre class="code"><span style="color: #2b91af">TfsTeamProjectCollection </span>tpc = 
    <span style="color: #2b91af">TfsTeamProjectCollectionFactory</span>.GetTeamProjectCollection(<span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #a31515">&quot;http://server:8080/tfs/Collection&quot;</span>));</pre>

<p>or from one of its constructors:</p>

<pre class="code"><span style="color: #2b91af">TfsTeamProjectCollection </span>tpc = <span style="color: blue">new </span><span style="color: #2b91af">TfsTeamProjectCollection</span>(<span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #a31515">&quot;http://server:8080/tfs/Collection&quot;</span>));</pre>
<a href="http://11011.net/software/vspaste"></a>

<p>Out of the three classes presented in this blog post, this class is the most like the old TeamFoundationServer object because of the services you can get from it.&#160; Just like the old TeamFoundationServer object, this class provides the capability for talking to the version control, work item tracking and build services as well as all of the other services that you used in the TFS 2005 and 2008 to work with your team projects.&#160; Because of this, you can use the TfsTeamProjectCollection class to talk to TFS 2010 team project collections as well as 2008 and 2005 instances of Team Foundation Server.</p>

<p>Speaking of the services that you can get from the TfsTeamProjectCollection.GetService&lt;&gt;() method, let’s take a look at another (not necessarily exhaustive) list of services that TFS ships with:</p>

<ul>
  <li><strong>Microsoft.TeamFoundation.Framework.Client.ITeamFoundationRegistry: </strong>Exposes APIs for viewing and managing the contents of the TFS registry for this team project collection. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client</strong>.<strong>IIdentityManagementService</strong>: Exposes APIs for viewing and managing identities that exist in TFS and their group membership details for this team project collection. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client.ITeamFoundationJobService: </strong>Exposes APIs for viewing and managing job definitions, job schedules and job run history for this team project collection. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client.IPropertyService: </strong>Exposes APIs for reading from and writing to the generic property store within this team project collection. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client.IEventService: </strong>Exposes APIs for viewing and managing event subscriptions for this team project collection. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client.ISecurityService: </strong>Exposes APIs for viewing and managing security namespaces and the security data that each of those namespaces contain for this team project collection. </li>

  <li><strong>Microsoft.TeamFoundation.Framework.Client</strong>.<strong>ILocationService: </strong>Exposes APIs for viewing and managing the services defined for this team project collection along with their configured locations. </li>

  <li><strong>Microsoft.TeamFoundation.Client.TswaClientHyperlinkService: </strong>Exposes APIs for constructing URLs that communicate with TSWA.</li>

  <li><strong>Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer: </strong>Exposes APIs for performing all version control related operations. </li>

  <li><strong>Microsoft.TeamFoundation.Build.Client.IBuildServer: </strong>Exposes APIs for viewing and managing build controllers, build agents, build definitions, build results and the build queue. </li>

  <li><strong>Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore: </strong>Exposes APIs for performing all work item tracking related operations. </li>

  <li><strong>Microsoft.TeamFoundation.TestManagement.Client.ITestManagementService: </strong>Exposes APIs for viewing and managing test controllers, test runs and test results. </li>

  <li><strong>Microsoft.TeamFoundation.Lab.Client.LabFrameworkService</strong>: Exposes APIs that allow you to perform verification of Lab Management objects during configuration. </li>

  <li><strong>Microsoft.TeamFoundation.Lab.Client.LabAdminService: </strong>Exposes APIs for viewing and managing the top-level lab management objects. </li>

  <li><strong>Microsoft.TeamFoundation.Lab.Client.LabService: </strong>Exposes APIs for viewing and managing other lab management objects. </li>

  <li><strong>Microsoft.TeamFoundation.Lab.WorkflowIntegration.Client.IWorkflowIntegrationService: </strong>Exposes APIs for viewing and managing workflow integration for lab environments that are created by the Team Foundation Lab Service. </li>

  <li><strong>Microsoft.TeamFoundation.Lab.TestIntegration.Client.ITestIntegrationService: </strong>Exposes APIs for viewing and managing the testing capability with lab environments that are created by the Team Foundation Lab Service. </li>

  <li><strong>Microsoft.TeamFoundation.ILinking: </strong>Exposes APIs for the retrieving the details about linking artifacts and their URLs. </li>

  <li><strong>Microsoft.TeamFoundation.Server.ICommonStructureService3: </strong>Exposes APIs for viewing and managing areas, iterations, and team projects. </li>

  <li><strong>Microsoft.TeamFoundation.Server.IServerStatus: </strong>Exposes APIs for getting the status of the server. </li>

  <li><strong>Microsoft.TeamFoundation.Server.IProcessTemplates: </strong>Exposes APIs for viewing and managing the process templates for this team project collection. </li>
</ul>

<p>There are also some services that can still be retrieved using GetService&lt;T&gt;() because of backwards compatibility reasons but have replaced by newer services.&#160; Here are a list of those with the service(s) they have been replaced by.</p>

<ul>
  <li><strong>Microsoft.TeamFoundation.Server.IRegistration:</strong> This has been replaced by the ILocationService and ITeamFoundationRegistry services from above. </li>

  <li><strong>Microsoft.TeamFoundation.Server.ICommonStructureService: </strong>This has been replaced by the ICommonStructureService3 service from above. </li>

  <li><strong>Microsoft.TeamFoundation.Server.IGroupSecurityService</strong>: This has been replaced by the IIdentityManagementService from above. </li>

  <li><strong>Microsoft.TeamFoundation.Server.IGroupSecurityService2</strong>: This has been replaced by the IIdentityManagementService from above. </li>

  <li><strong>Microsoft.TeamFoundation.Server.IAuthorizationService</strong>: This has been replaced by the ISecurityService from above. </li>
</ul>

<p>Also, just as the TfsConfigurationServer class has a helper method for retrieving TfsTeamProjectCollection objects, the TfsTeamProjectCollection class has a property for retrieving the TfsConfigurationServer object that it is a member of:</p>

<pre class="code"><span style="color: blue">public </span><span style="color: #2b91af">TfsConfigurationServer </span>ConfigurationServer { <span style="color: blue">get</span>; }</pre>

<p><strong>I notice that some services can be retrieved from both TfsConfigurationServer and TfsTeamProjectCollection instances.&#160; Why is this and how are they different?</strong></p>

<p>Great observation.&#160; The services that are available from both of these objects are known as “framework” services.&#160; From the list above you can see that the ITeamFoundationRegistry, IIdentityManagementService, ITeamFoundationJobService, IPropertyService, IEventService, ISecurityService and ILocationService are all framework services.&#160; Whether you get these services from a TfsConfigurationServer or TfsTeamProjectCollection object, they will still provide the same functionality but the scope that you are affecting with those methods will be different.</p>

<p>Let’s look at the ISecurityService to demonstrate this.&#160; One of the functions this service provides is the ability to list all of the security namespaces that exist for that host.&#160; If you list the security namespaces for a security service that was retrieved from a TfsTeamProjectCollection object then you will see a security namespace for version control because we apply security to version controlled items within a team project collection.&#160; However, you would not see this security namespace exist for a security service retrieved from a TfsConfigurationServer object because version control does not exist within the configuration server.&#160; The opposite is true for the team project collection management security namespace.&#160; This namespace will only exist for a security service retrieved from a TfsConfigurationServer object because it offers functionality for managing team project collections.</p>

<p>The same is true for all of the other framework services.&#160; If you set a registry entry using the ITeamFoundationRegistry service from a TfsTeamProjectCollection object, it will not have any affect on the ITeamFoundationRegistry service from the TfsConfigurationServer object.&#160; The same is also true for TfsTeamProjectCollection objects that talk to two different team project collections.&#160; Setting a security or registry entry against on team project collection will not affect the security or registry setting in a different team project collection object.</p>

<p>Hopefully this gives you a good jumping off point for utilizing these new classes.&#160; Feel free to hit up the comment section below or the contact link above if you have any questions.</p>]]></content:encoded>
    </item>
    <item>
      <title>Team Foundation Server: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.</title>
      <link>https://docs.microsoft.com/archive/blogs/taylaf/team-foundation-server-unable-to-read-data-from-the-transport-connection-an-existing-connection-was-forcibly-closed-by-the-remote-host</link>
      <pubDate>Wed, 10 Feb 2010 14:52:40 GMT</pubDate>
      <dc:creator><![CDATA[Taylor Lafrinere (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/taylaf/2010/02/10/team-foundation-server-unable-to-read-data-from-the-transport-connection-an-existing-connection-was-forcibly-closed-by-the-remote-host/</guid>
      <description><![CDATA[Updated 4/21/2010: The Windows patch to solve this problem has been released.&#160; It can be found...]]></description>
      <content:encoded><![CDATA[<p><strong>Updated 4/21/2010: The Windows patch to solve this problem has been released.&#160; It can be found <a href="http://support.microsoft.com/kb/981898">here</a>.</strong></p>  <p>Recently, while dogfooding our internal <a href="http://blogs.msdn.com/granth/archive/2009/08/27/vsts-pioneer-tfs2010-dogfood-server.aspx">pioneer</a> server, a few members of our team started to notice this error message when downloading files from TFS:</p>  <p>C:\dev\code\somefile.txt: <b>Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.</b></p>  <p>Luckily, we were able to reproduce the issue on a consistent enough basis to investigate the issue.&#160; After a few fun days of client-side TFS logging, sever-side TFS logging, TFS activity logging, fiddler tracing, netmon tracing, procmon tracing and finally http.sys tracing we were able to determine that we were being affected by an http.sys bug that was introduced in Windows Server 2008 R2.</p>  <p><strong>Are you experiencing the same issue that we were?</strong></p>  <p>Let’s find out.&#160; First of all, this bug is new to Windows Server 2008 <strong>R2</strong>.&#160; If you are running any version of Windows Server 2003, Windows Server 2008 R1 RTM or Windows Server 2008 R1 SP1 then you are most likely not hitting the same bug that we were.&#160; The issue tended to occur more often if the file that was being downloaded was relatively large (&gt; 2MB) and rate of occurrence seemed to grow with the size of the file.&#160; Finally, we were only able to reproduce the issue over slower networks (3 to 4 kb/sec file transfer rate).&#160; </p>  <p><strong>Great news! The bug has been fixed!</strong></p>  <p>This bug has been fixed by the Windows team and they have released a QFE for it.&#160; You can find the QFE <a href="http://support.microsoft.com/kb/981898">here</a>.&#160; You will need to install in on all of your ATs.</p>  <p>The following lists the initial workarounds that we were able to come up with before this bug was fixed.&#160; I am going to leave them up here for reference but the real solution should be to install the QFE mentioned above.</p>  <p>--</p>  <p>   <p><strong></strong></p> If you are still hitting the issue after setting up the proxy or you are unable to set up a proxy then you are not out of luck just yet.&#160; First, a little more information about why this issue is happening.&#160; <a href="http://learn.iis.net/page.aspx/101/introduction-to-iis-7-architecture/">Http.sys</a> is the http protocol stack that IIS uses to perform http communication with clients.&#160; It has a timer called MinBytesPerSecond that is responsible for killing a connection if its transfer rate drops below some kb/sec threshold.&#160; By default, that threshold is set to 240 kb/sec.&#160; It turns out that there is a bug with this timer and it is causing connections to be prematurely killed.&#160; We have found that lowering this threshold reduces the number of connections that are killed by the server.&#160; </p>  <p>In order to lower the threshold follow these directions:</p>  <ol>   <li>Open the IIS Manager </li>    <li>In the Connections pane, make sure the name of your AT is selected. </li>    <li>In the middle pane (titled “&lt;MachineName&gt; Home”), make sure you are in the “Features View” (bottom) and scroll down to the Management section. </li>    <li>Double-click the “Configuration Editor” icon. </li>    <li>The middle pane should now have the title “Configuration Editor”.&#160; In the Section pull down near the top, expand the system.applicationHost and select “webLimits”. </li>    <li>You should now see a bunch of property value pairs, one of which is named “minBytesPerSecond”.&#160; Its value is most like 240.&#160; You will want to lower this value for the workaround.&#160; </li> </ol>  <p>In general, the lower the threshold is, the lower the chances are that you hit the issue above.&#160; However, you may not want to lower the setting too much because then connections that should be killed by this timer will not be appropriately cleaned up.&#160; Play around with values to see what works best for you.</p>  <p>If you have any other questions, be sure to let us know.</p>]]></content:encoded>
    </item>
    <item>
      <title>Retrieve the List of Team Project Collections from TFS 2010 Client APIs</title>
      <link>https://docs.microsoft.com/archive/blogs/taylaf/retrieve-the-list-of-team-project-collections-from-tfs-2010-client-apis</link>
      <pubDate>Tue, 26 Jan 2010 15:19:02 GMT</pubDate>
      <dc:creator><![CDATA[Taylor Lafrinere (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/taylaf/2010/01/26/retrieve-the-list-of-team-project-collections-from-tfs-2010-client-apis/</guid>
      <description><![CDATA[If you have started playing with one of the TFS 2010 betas then you have probably noticed the new...]]></description>
      <content:encoded><![CDATA[<p>If you have started playing with one of the TFS 2010 betas then you have probably noticed the new snazzy connect dialog:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/RetrievetheListofTeamProjectCollectionsf_8999/ss4_2.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/RetrievetheListofTeamProjectCollectionsf_8999/ss4_2.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ss4" border="0" alt="ss4" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/RetrievetheListofTeamProjectCollectionsf_8999/ss4_thumb.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/RetrievetheListofTeamProjectCollectionsf_8999/ss4_thumb.jpg" width="523" height="443" /></a> </p>  <p>For those of you new to TFS 2010, the pane on the left above shows the list of “Team Project Collections” that exist on the TFS Instance that you have connected to.&#160; If you want a deeper explanation of what a team project collection is then check out <a href="http://blogs.msdn.com/bharry/archive/2009/04/19/team-foundation-server-2010-key-concepts.aspx">Brian Harry’s post</a> on the subject.&#160; Recently, a few people have asked what the proper way is to retrieve that list of team project collections using the TFS 2010 client APIs so I figured it was worth a blog post since this seems to be a fairly popular question.</p>  <p><em>Disclaimer: The code presented in this blog post assumes you are using the RTM version of TFS.&#160; Some of these APIs were refactored between TFS 2010 Beta 2 and TFS 2010 RTM.&#160; <em>Please see the section at the end of the post to see how the new API names map to those in the Beta 1 and Beta 2 versions of TFS 2010.</em></em></p>  <p><em>If you are new to the TFS 2010 OM you may want to start with this <a href="http://blogs.msdn.com/taylaf/archive/2010/02/23/introducing-the-tfsconnection-tfsconfigurationserver-and-tfsteamprojectcollection-classes.aspx">post which introduces the TfsConnection, TfsConfigurationServer and TfsTeamProjectCollection objects</a>.</em></p>  <p><em>In order to use the code from the examples in this post you will need the following include statements:</em></p>  <pre class="code"><span style="color: blue">using </span>System;
<span style="color: blue">using </span>System.Collections.Generic;
<span style="color: blue">using </span>System.Collections.ObjectModel;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Client;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Framework.Client;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Framework.Common;</pre>
<a href="http://11011.net/software/vspaste"></a>

<p><strong>First, let’s talk about how not to get this list of team project collections.</strong></p>

<p>So, if you are at home (or at work) digging through the new TFS 2010 APIs trying to find out where to get the list of team project collections you may come across the new TeamProjectCollectionService, seen that it has a GetCollections method and think “Great! I have found what I am looking for”.&#160; Unfortunately, this is not the case.&#160; The TeamProjectCollectionService can be thought of more as a management related service than a user related service.&#160; It offers methods to create, delete and edit team project collections.&#160; While it also does offer the previously mentioned method to get the list of team project collections, the data returned by that function call has too much information for the normal user to see.&#160; For example, it contains the connection string to the database that stores the data for each team project collection and exposing this information to a normal user is not acceptable.</p>

<p>While we are on the topic though, if you are writing a management tool, here is how you would use the TeamProjectCollectionService to get a list of team project collections along with some of their configuration details:</p>

<pre class="code"><span style="color: #2b91af">Uri </span>configurationServerUri = <span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #a31515">&quot;http://your-server:8080/tfs&quot;</span>);
<span style="color: #2b91af">TfsConfigurationServer </span>configurationServer = 
        <span style="color: #2b91af">TfsConfigurationServerFactory</span>.GetConfigurationServer(configurationServerUri);

<span style="color: #2b91af">ITeamProjectCollectionService </span>tpcService = configurationServer.GetService&lt;<span style="color: #2b91af">ITeamProjectCollectionService</span>&gt;();

<span style="color: blue">foreach </span>(<span style="color: #2b91af">TeamProjectCollection </span>tpc <span style="color: blue">in </span>tpcService.GetCollections())
{
    <span style="color: green">// Do your work for each TeamProjectCollection object here.
</span>}</pre>
<a href="http://11011.net/software/vspaste"></a><font face="Courier New"></font>

<p>The GetCollections() method called here is guarded by the “Edit server-level information” permission which by default is only granted to server administrators.&#160; That means, if a regular user were to call this method then that user would see the message:</p>

<p>“Access Denied: DOMAIN\NormalUser needs the following permission(s) to perform this action: Edit instance-level information”</p>

<p><strong>So, what is the proper way to get the list of team project collections for a normal user then?</strong></p>

<p>The answer to that question relies on a new technology introduced in TFS 2010 called the catalog service.&#160; The goal of the new catalog service is to provide a publishing and discovery service for any resources used in a TFS deployment.&#160; For example, team project collections, team projects, SharePoint resources and Reporting Service resources among many other things are represented in the catalog.&#160; In order to represent such diverse objects and the relationships between them in a single store the catalog has many different concepts, some of which are fairly complicated.&#160; I am planning an in-depth look at the catalog for a future post so for the purpose of this discussion we will try to stay on the surface.</p>

<p>Each entity that is represented in the catalog exists as a CatalogResource.&#160; Each CatalogResource has a type (team project collection, team project, etc.) and some properties that better define the object that it represents.&#160; The catalog stores how each CatalogResource relates to other CatalogResources in a hierarchical fashion.&#160; Currently the catalog has two well-defined trees for representing relationships: the Infrastructure tree and the Organizational tree.&#160; The Infrastructure tree is used to represent the hardware in your TFS deployment and can answer queries like “show me all of the machines that I have TFS Web Applications installed on”.&#160; The Organizational tree is used to represent the relationships between the TFS resources such as the team project collections and team projects in your deployment.&#160; </p>

<p>In order to be represented in one of the catalog trees mentioned above a CatalogResource must be associated with a CatalogNode.&#160; A CatalogNode represents a place in the catalog tree and thus conveys how each resource relates to each other.&#160; For example, there is a CatalogResource for the TFS configuration server associated with a CatalogNode under the root of the Organizational tree.&#160; As children of the configuration server node, there is a CatalogNode associated with each of the CatalogResources that represent team project collections.&#160; Continuing, there is a CatalogNode associated with each of the CatalogResources that represent a team project under the given team project collection node that that team project belongs to.&#160; Hopefully with that background information, the following example on retrieving the list of team project collections from the catalog will make sense:</p>

<pre class="code"><span style="color: #2b91af">Uri </span>configurationServerUri = <span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #a31515">&quot;http://your-server:8080/tfs&quot;</span>);
<span style="color: #2b91af">TfsConfigurationServer </span>configurationServer =
        <span style="color: #2b91af">TfsConfigurationServerFactory</span>.GetConfigurationServer(configurationServerUri);

<span style="color: #2b91af">CatalogNode </span>configurationServerNode = configurationServer.CatalogNode;

<span style="color: green">// Query the children of the configuration server node for all of the team project collection nodes
</span><span style="color: #2b91af">ReadOnlyCollection</span>&lt;<span style="color: #2b91af">CatalogNode</span>&gt; tpcNodes = configurationServerNode.QueryChildren(
        <span style="color: blue">new </span><span style="color: #2b91af">Guid</span>[] { <span style="color: #2b91af">CatalogResourceTypes</span>.ProjectCollection }, 
        <span style="color: blue">false</span>,                                                 
        <span style="color: #2b91af">CatalogQueryOptions</span>.None);

<span style="color: blue">foreach </span>(<span style="color: #2b91af">CatalogNode </span>tpcNode <span style="color: blue">in </span>tpcNodes)
{
    <span style="color: green">// Use tpcNode.Resource to get the details for each team project collection.
</span>}</pre>

<p>Let’s go into this example with a little more detail now.&#160; The CatalogNode for any TfsConnection object is stored as a property called “CatalogNode”.&#160; From this we can call the QueryChildren method to find out information about what children it has.&#160; In the first argument to this call we specify that we only want to see children that are of type “ProjectCollection”.&#160; In the second argument, we specify the value “false” for recurse since we know that a team project collection node will only exist as a child of our node.&#160; If it were possible that a team project collection node could exist as a grandchild (or deeper) of our node then we would need to pass true here.&#160; Finally, we pass CatalogQueryOptions.None as the last parameter because we don’t need any details about the parent nodes or dependencies filled out.&#160; Don’t worry about dependencies for now, those will be covered in a later post.&#160; So, with that query, you now have a list of all of the catalog nodes that represent team project collections that you are allowed to see.</p>

<p><strong>Great, so what exactly can I learn or do with these CatalogResource objects that represent the team project collections?</strong></p>

<p>Good question.&#160; For starters, accessing the following properties will give you relevant information about the team project collection:</p>

<pre class="code"><span style="color: green">// Get the team project collection name.
</span><span style="color: #2b91af">String </span>displayName = tpcNode.Resource.DisplayName;

<span style="color: green">// Get the team project collection description.
</span><span style="color: #2b91af">String </span>description = tpcNode.Resource.Description;

<span style="color: green">// Get other dynamic properties that describe this collection
</span><span style="color: blue">foreach </span>(<span style="color: #2b91af">KeyValuePair</span>&lt;<span style="color: #2b91af">String</span>, <span style="color: #2b91af">String</span>&gt; property <span style="color: blue">in </span>tpcNode.Resource.Properties)
{
    <span style="color: #2b91af">String </span>propertyKey = property.Key;
    <span style="color: #2b91af">String </span>propertyValue = property.Value;
}</pre>

<p>Also, using the information in the ServiceReferences property you can get the url that is used to actually connect to the team project collection:</p>

<pre class="code"><span style="color: green">// Get the ServiceDefinition for the team project collection from the resource.
</span><span style="color: #2b91af">ServiceDefinition </span>tpcServiceDefinition = tpcNode.Resource.ServiceReferences[<span style="color: #a31515">&quot;Location&quot;</span>];

<span style="color: #2b91af">ILocationService </span>configLocationService = configurationServer.GetService&lt;<span style="color: #2b91af">ILocationService</span>&gt;();
<span style="color: #2b91af">Uri </span>tpcUri = <span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(configLocationService.LocationForCurrentConnection(tpcServiceDefinition));

<span style="color: green">// Actually connect to the team project collection
</span><span style="color: #2b91af">TfsTeamProjectCollection </span>tpc = <span style="color: #2b91af">TfsTeamProjectCollectionFactory</span>.GetTeamProjectCollection(tpcUri);

<span style="color: green">// Perform operations against the team project collection object here
</span></pre>

<p>Hopefully that should be enough of an example to get you started with working with the catalog to determine the list of team project collections.</p>

<p><strong>Cool, anything else I should know about using the catalog service?</strong></p>

<p>I will dive deeper into the catalog service at a later point but here is a good tip: the catalog service is not backward compatible and will not work against a TFS 2005 or TFS 2008 server.&#160; In order to determine if you are talking to a TFS 2010 server from your client application, check out this <a href="http://blogs.msdn.com/taylaf/archive/2010/01/05/determining-the-tfs-server-version-using-client-apis.aspx">post</a>.&#160; If there is anything specific that you would like to know about the catalog service, feel free to mention it in the comments or shoot me an email and I will make sure to address it.</p>

<p><em>If you are using TFS 2010 Beta 1 or Beta 2 then everything you just read is still true but some of the APIs have different names.&#160; Here are the mappings that you will need to make this work in one of the betas:</em></p>

<p>TfsTeamProjectCollection is equivalent to TeamFoundationServer.&#160; TfsConfigurationServer is equivalent to TeamFoundationApplicationInstance.&#160; TfsConnection is equivalent to TeamFoundationServerBase.&#160; For more information on this see <a href="http://blogs.msdn.com/granth/archive/2009/12/07/tfs2010-object-model-api-changes-after-beta-2.aspx">Grant Holliday's blog post</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Determine the Currently Executing Statement in a Long Running SQL Stored Procedure</title>
      <link>https://docs.microsoft.com/archive/blogs/taylaf/determine-the-currently-executing-statement-in-a-long-running-sql-stored-procedure</link>
      <pubDate>Mon, 25 Jan 2010 14:08:15 GMT</pubDate>
      <dc:creator><![CDATA[Taylor Lafrinere (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/taylaf/2010/01/25/determine-the-currently-executing-statement-in-a-long-running-sql-stored-procedure/</guid>
      <description><![CDATA[Along with sharing information about TFS, another purpose for this blog will be to share general...]]></description>
      <content:encoded><![CDATA[<p>Along with sharing information about TFS, another purpose for this blog will be to share general tips and tricks that I come across while coding.&#160; I have really been trying to improve my SQL Server coding and debugging skills lately so expect SQL Server to be a common theme in these types of posts.&#160; Anyway, on to the content!</p>  <p>The issue that inspired this post happened a few days ago.&#160; A fellow developer had reported that one of my stored procedures seemed to “hang” while performing an operation so I needed to dig in to hopefully determine what the issue was.&#160; Since I wasn’t able to repro the issue with a simple case my next plan was to try to capture the exact command that caused the issue to reproduce using SQL Server Profiler and then replay that command in Sql Server Management Studio repeatedly with a bunch of different traces turned on.</p>  <p>While I was in the process of capturing the command using the profiling tool I noticed that the operation appeared to be in this “hanging” state that my colleague had reported.&#160; Since I had assumed that the hang was due to a bad SQL query plan or some other intermittent problem I was ecstatic that I was able to get it to reproduce.&#160; Then the panic set in.&#160; I realized that I didn’t have any statement level traces set up and was immediately worried that I wouldn’t gain any knowledge from this instance of a seemingly hard-to-reproduce issue.</p>  <p>So, with time on this repro running low, I did what every developer on my team with a SQL emergency would do, and that was to call my co-worker <a href="http://blogs.msdn.com/chandrur/">Chandru</a> to help.&#160; Luckily, Chandru was able to save the day and determine what statement was causing the delay within the stored procedure before we lost the repro.&#160; So, for both your benefit and mine here is a recap of what I learned about how he was able to figure this out:</p>  <p><strong>On to the contrived example!</strong></p>  <p>In order to reproduce this issue at home, let’s use this example stored procedure:</p>  <pre class="code"><span style="color: blue">CREATE PROCEDURE </span>prc_LongRunningProcedure
<span style="color: blue">AS

</span><span style="color: green">-- Declare some table
</span><span style="color: blue">DECLARE </span>@table <span style="color: blue">TABLE </span><span style="color: gray">(
    </span>Value1  <span style="color: blue">INT</span><span style="color: gray">,
    </span>Value2  <span style="color: blue">INT
</span><span style="color: gray">)

</span><span style="color: blue">INSERT  </span>@table <span style="color: gray">(</span>Value1<span style="color: gray">, </span>Value2<span style="color: gray">)
</span><span style="color: blue">VALUES  </span><span style="color: gray">(
        </span>1<span style="color: gray">,
        </span>2
        <span style="color: gray">)
        
</span><span style="color: blue">WAITFOR DELAY </span><span style="color: red">'05:00'

</span><span style="color: blue">SELECT  </span><span style="color: gray">*
</span><span style="color: blue">FROM    </span>@table

<span style="color: blue">RETURN </span>0
<span style="color: blue">GO</span></pre>

<p>After a quick inspection you will notice that the above procedure declares a temporary table, inserts some values, <strong>waits for 5 hours</strong>, and then returns the values from the table.&#160; While this example is incredibly contrived it will serve our purposes well.&#160; In an SSMS query window copy in the statement above and run it to create the stored procedure in a test database.&#160; Next, in another query window, run the following statement:</p>

<pre class="code"><span style="color: blue">EXEC </span>dbo<span style="color: gray">.</span>prc_LongRunningProcedure</pre>

<p>So now we have achieved the same issue that I was experiencing: a long running stored procedure that was stuck on an unknown statement.&#160; Okay, maybe you can guess what statement we are stuck on here but you know what I mean.</p>

<p><strong>So, what next?</strong></p>

<p>Luckily, SQL provides a number of different tables and functions that help track things that are of interest to someone trying to debug various issues.&#160; One of the most commonly useful tables is sys.dm_exec_requests which will report some details about the currently operating requests.&#160; Access those details using the following query:</p>

<pre class="code"><span style="color: blue">SELECT  </span><span style="color: gray">*
</span><span style="color: blue">FROM    </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">dm_exec_requests </span>requests
<span style="color: blue">WHERE   </span>requests<span style="color: gray">.</span>session_id <span style="color: gray">&gt; </span>50
<span style="color: blue">ORDER BY </span>total_elapsed_time <span style="color: blue">DESC</span></pre>

<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a>Note that we make sure to only select requests with a session_id above 50 because these represent “user” requests.&#160; Any request with a session_id at or below 50 represents a “system” request and those won’t be useful to us here.&#160; Running this statement in a new query editor window in SSMS yielded the following results for me.&#160; Note, you may see more or less results with different ids when you run this against your server.</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss1_2.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss1_2.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ss1" border="0" alt="ss1" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss1_thumb.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss1_thumb.jpg" width="872" height="84" /></a></p>

<p>Scrolling to the right it is fairly obvious for me which request is the long running one: the top row has a much higher total_elapsed_time value than the other entries.&#160; However, in a real world scenario, you may not be able to tell what stored procedure is running.&#160; In order to associate the currently running request with the stored procedure that is running we will have to call upon sys.dm_exec_sql_text:</p>

<pre class="code"><span style="color: blue">SELECT  </span>requests<span style="color: gray">.</span>session_id<span style="color: gray">, 
        </span>requests<span style="color: gray">.</span><span style="color: blue">status</span><span style="color: gray">, 
        </span>requests<span style="color: gray">.</span>command<span style="color: gray">, 
        </span>requests<span style="color: gray">.</span>statement_start_offset<span style="color: gray">,
        </span>requests<span style="color: gray">.</span>statement_end_offset<span style="color: gray">,
        </span>requests<span style="color: gray">.</span>total_elapsed_time<span style="color: gray">,
        </span>details<span style="color: gray">.</span><span style="color: blue">text
FROM    </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">dm_exec_requests </span>requests
<span style="color: gray">CROSS APPLY </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">dm_exec_sql_text </span><span style="color: gray">(</span>requests<span style="color: gray">.</span>plan_handle<span style="color: gray">) </span>details
<span style="color: blue">WHERE   </span>requests<span style="color: gray">.</span>session_id <span style="color: gray">&gt; </span>50
<span style="color: blue">ORDER BY </span>total_elapsed_time <span style="color: blue">DESC</span></pre>

<p><a href="http://11011.net/software/vspaste"></a>This statement uses the plan handle from the requests table to call the table-valued function sys.dm_exec_sql_text to determine the text of the procedure that is being run.&#160; When I run the above query, I see this:</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss2_2.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss2_2.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ss2" border="0" alt="ss2" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss2_thumb.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss2_thumb.jpg" width="864" height="69" /></a> </p>

<p>In case we weren’t sure what row was ours before we can tell now because the details.text column shows the text from our example stored procedure.&#160; Let’s talk about some other details in this output.&#160; The status column will tell you the current status of the request.&#160; Since we used the WAITFOR command to cause our program to freeze we see that the status is “suspended”.&#160; If this were an actual stored procedure you may see “running” here if a statement is currently executing or “suspended” if you are waiting on something (like a lock resource).&#160; For information on other values, check out this <a href="http://msdn.microsoft.com/en-us/library/ms177648(SQL.90).aspx">doc page</a>.</p>

<p>Another useful piece of information is the command column.&#160; It will tell you what type of command is currently running.&#160; Again, in our case, the WAITFOR command pollutes this field but in a real world scenario this would tell you something such as “DELETE” or “INSERT” which can help you determine your problem area.&#160; At this point, if you still don’t know what statement the delay is caused by we can dig a little deeper with the information provided by sys.dm_exec_requests and sys.dm_exec_sql_text:</p>

<pre class="code"><span style="color: blue">SELECT  </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span>detail<span style="color: gray">.</span><span style="color: blue">text</span><span style="color: gray">, 
                  </span>requests<span style="color: gray">.</span>statement_start_offset <span style="color: gray">/ </span>2<span style="color: gray">, 
                  (</span>requests<span style="color: gray">.</span>statement_end_offset <span style="color: gray">- </span>requests<span style="color: gray">.</span>statement_start_offset<span style="color: gray">) / </span>2<span style="color: gray">)
</span><span style="color: blue">FROM    </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">dm_exec_requests </span>requests
<span style="color: gray">CROSS APPLY </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">dm_exec_sql_text </span><span style="color: gray">(</span>requests<span style="color: gray">.</span>plan_handle<span style="color: gray">) </span>detail
<span style="color: blue">WHERE   </span>requests<span style="color: gray">.</span>session_id <span style="color: gray">= </span>67</pre>

<p><a href="http://11011.net/software/vspaste"></a>Here, we do the same CROSS APPLY as before but we are more selective and only look at the row that interests us (it has session_id 67).&#160; Also, instead of looking at the entire sql text, we use the statement offsets provided by sys.dm_exec_requests to find the exact statement that is currently executing:</p>

<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss3_2.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss3_2.jpg"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ss3" border="0" alt="ss3" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss3_thumb.jpg" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/DeterminetheCurrentlyExecutingStatementi_E060/ss3_thumb.jpg" width="865" height="69" /></a> </p>

<p>So, at this point, we know both the stored procedure and the statement that was executing when the delay was noticed.&#160; Now, as far as figuring out what the delay is caused by, that one is on you :).</p>]]></content:encoded>
    </item>
    <item>
      <title>Determining the TFS Server Version Using Client APIs</title>
      <link>https://docs.microsoft.com/archive/blogs/taylaf/determining-the-tfs-server-version-using-client-apis</link>
      <pubDate>Tue, 05 Jan 2010 14:38:06 GMT</pubDate>
      <dc:creator><![CDATA[Taylor Lafrinere (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/taylaf/2010/01/05/determining-the-tfs-server-version-using-client-apis/</guid>
      <description><![CDATA[In today’s software world supporting backward and forward compatibility between different versions...]]></description>
      <content:encoded><![CDATA[<p>In today’s software world supporting backward and forward compatibility between different versions of clients and servers for a given product is usually both a headache and a hard-requirement from the customer.&#160; When writing a client application that supports talking to different versions of a server one of the key problems to solve is figuring out what version of the server the client is talking to so that the client knows what functionality the server offers.&#160; This post will hopefully help the author of a client application that talks to a Team Foundation Server determine what version the server is, and most importantly what services this version of the server offers.</p>  <p><em>Disclaimer: The code presented in this blog post assumes you are using the RTM version of TFS.&#160; Some of these APIs were refactored between TFS 2010 Beta 2 and TFS 2010 RTM.&#160; <em>Please see the section at the end of the post to see how the new API names map to those in the Beta 1 and Beta 2 versions of TFS 2010.</em></em></p>  <p><em>If you are new to the TFS 2010 OM you may want to start with this <a href="http://blogs.msdn.com/taylaf/archive/2010/02/23/introducing-the-tfsconnection-tfsconfigurationserver-and-tfsteamprojectcollection-classes.aspx">post which introduces the TfsConnection, TfsConfigurationServer and TfsTeamProjectCollection objects</a>.</em></p>  <p><em>In order to use the code from the examples in this post you will need the following include statements:</em></p>  <pre class="code"><span style="color: blue">using </span>System;
<span style="color: blue">using </span>System.Collections.Generic;
<span style="color: blue">using </span>Microsoft.TeamFoundation;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Client;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Framework.Client;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Server;</pre>
<a href="http://11011.net/software/vspaste"></a>

<pre class="code"><h1><font face="Verdana">What Services Does this Instance of TFS Offer?</font></h1></pre>

<p>Included in the release of Microsoft Team Foundation Server 2010 there are a number of new services that exist that provide a great deal of new functionality.&#160; Unfortunately, for a client application developer, in order to take advantage of some of these new features the client must first determine if the given TFS server supports these new features.</p>

<p>It seems that one way to accomplish this would be to maintain a list of what features are shipped in each version of TFS, determine which version of TFS is being talked to and then make assumptions about what services can be called.&#160; Firstly, this method seems a bit clunky and has a lot of overhead.&#160; Where are you going to find a list of all of the services that each version of TFS offers?&#160; How are you going to represent these in your codebase?&#160; And most importantly, how will your support forward compatibility with future TFS versions if you don’t know what services they will or will not offer?</p>

<p>Also, what about server-side third party add-ins for TFS?&#160; How will you be able to tell if any of these exist if all you are doing is looking at some type of version stamp for the given server?&#160; </p>

<p>The answer is that you won’t be able to do any of these things effectively by following this approach.&#160; Instead of memorizing what services are available in each version of TFS it seems that what we really should be doing is asking this instance of TFS what services it offers.</p>

<p><strong>So how do I ask a given instance of TFS what services it offers?</strong></p>

<p>Fortunately, there is a TFS service for that!&#160; Well, that is not its sole purpose of the service but the Team Foundation Server Location Service has the ability to tell the client what services are available from a given instance of TFS.&#160; This is a new service that has been introduced in TFS 2010. </p>

<p><strong>Wait, if it is a new service in TFS 2010 then how do I know if I can use it without checking to see if I am talking to a TFS 2010 server first?</strong></p>

<p>Great question, I am glad to see you have been paying attention.&#160; Fortunately, a few of the new services that we have introduced in TFS 2010 have backward compatibility built-in to parts of them and the location service is one of these services.&#160; That means, whether you are talking to the 2005, 2008 or 2010 version of TFS you will be able to use certain functions from the location service.</p>

<p>Let’s start by seeing a code example of how you can retrieve the location service to start using it:</p>

<pre class="code"><span style="color: #2b91af">TfsTeamProjectCollection </span>teamProjectCollection = 
        <span style="color: blue">new </span><span style="color: #2b91af">TfsTeamProjectCollection</span>(<span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #a31515">&quot;http://your-server:8080/tfs/Collection0&quot;</span>));

<span style="color: #2b91af">ILocationService </span>locationService = teamProjectCollection.GetService&lt;<span style="color: #2b91af">ILocationService</span>&gt;();</pre>

<p>Note, the location service is also available off of a TfsConfigurationServer object and can be used the same way we will use it in the following examples.&#160; </p>

<p>Before we dig in on how you can use this object to determine if a given service is present we first need to get some background on what exactly the location service does.&#160; I am planning a larger post at some point to provide an in-depth look at the functionality of the location service so I will keep this short.&#160; For the purpose of this discussion, you can think of the location service as a means for the registration and discoverability of the services offered within a TFS instance.&#160; In the location service, a service is defined by an object called a ServiceDefinition.&#160; </p>

<p>The ServiceDefinition object contains many properties that convey the different attributes of a given service but for right now we will only worry about the ServiceType and Identifier properties.&#160; Much like a .NET interface a service defines a collection of methods that serve as a contract between the user of the service and the implementer of the service.&#160; This collection of methods is given a name, just as a .NET interface is given a name, and that name is what populates the ServiceType field.&#160; Now, just as a .NET interface can have many different classes that implement it, the same is true for our ServiceType.&#160; This means that multiple ServiceDefinitions can have the same ServiceType.&#160; However, each different implementation of a given ServiceType will have its own unique Identifier (in the form of a GUID).</p>

<p>With that knowledge, hopefully the next sections will make sense.&#160; </p>

<p>When coding it is generally useful to know if a specific service exists.&#160; Let’s say that you want to take advantage of the new Team Foundation Server Security Service that has been introduced in TFS 2010 but you also want to fail gracefully if you are talking to a version of the server that doesn’t offer the new security service.&#160; Moreover, let’s also assume that you want to work with the specific security service that TFS ships with.&#160; In order to accomplish this your code could look like this:</p>
<a href="http://11011.net/software/vspaste"></a>

<pre class="code"><span style="color: blue">if </span>(<span style="color: blue">null </span>!= locationService.LocationForCurrentConnection(<span style="color: #2b91af">ServiceInterfaces</span>.SecurityService, 
                                                         <span style="color: #2b91af">FrameworkServiceIdentifiers</span>.CollectionSecurity)) 
{ 
    DoSecurityServiceWork(); 
}
<span style="color: blue">else
</span>{
    ShowMessageThatSecurityServiceIsNotAvailableForThisServer();
}</pre>
<a href="http://11011.net/software/vspaste"></a>

<p>This code is asking the location service if there is a known location for a service that fulfills the security service contract and has the well-known identifier that represents the TFS implementation of the security service.&#160; If the location service returns an object that means the service is registered and if it returns null then it means that this service does not exist on the current server.&#160; Each of the TFS Services has a well known ServiceType and a well-known Identifier that uniquely define and identify it.</p>

<p><strong>Cool, so how expensive is it to ask the location service if a service is defined?&#160; Does it make a server call each time?</strong></p>

<p>The first time a call is made to the location service for a given host it will query that host for all of the services defined on it.&#160; All of those services are then cached on the client and each subsequent call uses that cache to determine if the service is present or not.&#160; Furthermore, this cache is persisted to disk so the next time this client application starts up it will not have to query the services again.&#160; That means that unless we are talking about the first call to this location service then each call to look up a service is very inexpensive.</p>

<p><strong>But what if I really, really just need to know what version of the server I am talking to?</strong></p>

<p>Unfortunately there is not some uniform method that you can call that will simply tell you “You are communicating with version X of TFS”.&#160; In order to determine what version of the server you are talking to we are going to use the principals about querying for services above along with some knowledge about what services were available in each release.</p>

<p>As mentioned above, the security service is new in TFS 2010.&#160; We also know that version 2 of the group security service was introduced in TFS 2008.&#160; With that information, we can use the following algorithm to determine which version of the server we are talking to:</p>

<pre class="code"><span style="color: blue">if </span>(<span style="color: blue">null </span>!= locationService.LocationForCurrentConnection(<span style="color: #2b91af">ServiceInterfaces</span>.SecurityService, 
                                                         <span style="color: #2b91af">FrameworkServiceIdentifiers</span>.CollectionSecurity))
{
    <span style="color: green">//We are talking to TFS 2010
</span>}
<span style="color: blue">else if </span>(<span style="color: blue">null </span>!= locationService.LocationForCurrentConnection(<span style="color: #a31515">&quot;GroupSecurity2&quot;</span>, 
                                                              <span style="color: #2b91af">IntegrationServiceIdentifiers</span>.GroupSecurity2))
{
    <span style="color: green">//We are talking to TFS 2008
</span>}
<span style="color: blue">else
</span>{
    <span style="color: green">//We are talking to TFS 2005
</span>}</pre>
<a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a>

<p><strong>Since we are talking about compatibility here what if I want to update my 2008 clients to be aware of what server version they are talking to.&#160; I am guessing I cannot use the location service, correct?</strong></p>

<p>Correct, the location service isn’t available in the TFS 2008 Client OM.&#160; However, you can still accomplish this feat using the Team Foundation Server Registration Service – though the solution will be a bit more terse.&#160; The registration service is basically a collection of objects called RegistrationEntry.&#160; In TFS 2010 we added a new RegistrationEntry for the value “Framework”.&#160; We will use this along with our other knowledge about version 2 of the group security service to build the following algorithm:</p>

<pre class="code"><span style="color: #2b91af">TeamFoundationServer </span>server = <span style="color: blue">new </span><span style="color: #2b91af">TeamFoundationServer</span>(<span style="color: #a31515">&quot;http://your-server:8080/&quot;</span>);
<span style="color: #2b91af">IRegistration </span>registrationService = (<span style="color: #2b91af">IRegistration</span>)server.GetService(<span style="color: blue">typeof</span>(<span style="color: #2b91af">IRegistration</span>));

<span style="color: #2b91af">RegistrationEntry</span>[] frameworkEntries = registrationService.GetRegistrationEntries(<span style="color: #a31515">&quot;Framework&quot;</span>);
<span style="color: blue">if </span>(frameworkEntries.Length &gt; 0)
{
    <span style="color: green">//We are talking to TFS 2010
</span>}
<span style="color: blue">else
</span>{
    <span style="color: #2b91af">RegistrationEntry</span>[] vstfsEntries = registrationService.GetRegistrationEntries(<span style="color: #a31515">&quot;vstfs&quot;</span>);
    <span style="color: blue">if </span>(vstfsEntries.Length != 1)
    {
        <span style="color: green">//We must be talking to an unknown version of TFS
    </span>}
    <span style="color: blue">else
    </span>{
        <span style="color: #2b91af">Boolean </span>groupSecurity2Found = <span style="color: blue">false</span>;
        <span style="color: blue">foreach </span>(<span style="color: #2b91af">ServiceInterface </span>serviceInterface <span style="color: blue">in </span>vstfsEntries[0].ServiceInterfaces)
        {
            <span style="color: blue">if </span>(serviceInterface.Name.Equals(<span style="color: #a31515">&quot;GroupSecurity2&quot;</span>, <span style="color: #2b91af">StringComparison</span>.OrdinalIgnoreCase))
            {
                groupSecurity2Found = <span style="color: blue">true</span>;
            }
        }

        <span style="color: blue">if </span>(groupSecurity2Found)
        {
            <span style="color: green">//We are talking to TFS 2008
        </span>}
        <span style="color: blue">else
        </span>{
            <span style="color: green">//We are talking to TFS 2005
        </span>}
    }
}</pre>
<a href="http://11011.net/software/vspaste"></a>

<p>Hopefully that should be enough to get you started with using the location service to determine what services are available from the TFS Instance you are talking to.&#160; Feel free to ask questions in the comments or contact me via the contact tab.</p>

<p><em>If you are using TFS 2010 Beta 1 or Beta 2 then everything you just read is still true but some of the APIs have different names.&#160; Here are the mappings that you will need to make this work in one of the betas:</em></p>

<p>TfsTeamProjectCollection is equivalent to TeamFoundationServer.&#160; For more information on this see <a href="http://blogs.msdn.com/granth/archive/2009/12/07/tfs2010-object-model-api-changes-after-beta-2.aspx">Grant Holliday's blog post</a>.</p>

<p>Also, in TFS 2010 Beta 2 the function LocationForCurrentConnection was named FindServiceLocation.</p>]]></content:encoded>
    </item>
    <item>
      <title>Introducing TFS Impersonation</title>
      <link>https://docs.microsoft.com/archive/blogs/taylaf/introducing-tfs-impersonation</link>
      <pubDate>Fri, 04 Dec 2009 11:08:18 GMT</pubDate>
      <dc:creator><![CDATA[Taylor Lafrinere (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/taylaf/2009/12/04/introducing-tfs-impersonation/</guid>
      <description><![CDATA[One of the many things I will be covering in this blog will be the Team Foundation Server APIs and...]]></description>
      <content:encoded><![CDATA[<p>One of the many things I will be covering in this blog will be the Team Foundation Server APIs and the functionality they offer.&#160; The first example of this will be the new TFS Impersonation API that is new in TFS 2010.</p>  <p><em>Disclaimer: The code presented in this blog post assumes you are using the RTM version of TFS.&#160; These APIs were refactored between TFS 2010 Beta 2 and TFS 2010 RTM.&#160; Please see the section at the end of the post to see how the new API names map to those in the Beta 1 and Beta 2 versions of TFS 2010.</em></p>  <p><em>If you are new to the TFS 2010 OM you may want to start with this <a href="http://blogs.msdn.com/taylaf/archive/2010/02/23/introducing-the-tfsconnection-tfsconfigurationserver-and-tfsteamprojectcollection-classes.aspx">post which introduces the TfsConnection, TfsConfigurationServer and TfsTeamProjectCollection objects</a>.</em></p>  <p><em></em></p>  <h1>What is TFS Impersonation?</h1>  <p>TFS Impersonation is a feature that was introduced in TFS 2010 in order to allow a process running as User A to make web service calls to TFS in such a way that TFS thinks the actions are being performed by User B.</p>  <p>This is often useful when writing a tool or service that wants to perform actions in Team Foundation Server and have the server apply permissions and record the action as if a given user had performed it.&#160; For the purposes of this blog post we will assume that this action is the queuing of a build on behalf of another user (perhaps in response to a notification that a CheckIn by this user has just occurred). </p>  <p><strong>Isn’t this already possible through the use of Windows Impersonation?</strong></p>  <p>Well, yes, that is true.&#160; I assume you mean by doing something like this:</p>  <pre class="code"><span style="color: blue">private void </span>QueueBuildForUserUsingWindowsImpersonation(
    <span style="color: #2b91af">Uri </span>teamProjectCollectionUri,
    <span style="color: #2b91af">String </span>teamProjectName,
    <span style="color: #2b91af">String </span>buildDefinitionName,
    <span style="color: #2b91af">String </span>principal, 
    <span style="color: #2b91af">String </span>authority, 
    <span style="color: #2b91af">String </span>password)
{
    <span style="color: #2b91af">IntPtr </span>impersonatedUserToken;
    LogonUser(principal, authority, password, <span style="color: #2b91af">LogonTypes</span>.Interactive, 
            <span style="color: #2b91af">LogonProviders</span>.Default, <span style="color: blue">out </span>impersonatedUserToken);

    <span style="color: #2b91af">WindowsIdentity </span>identity = <span style="color: blue">new </span><span style="color: #2b91af">WindowsIdentity</span>(impersonatedUserToken);
    <span style="color: blue">using </span>(<span style="color: #2b91af">WindowsImpersonationContext </span>impersonationContext = identity.Impersonate())
    {
        <span style="color: green">// Create the proxy object so that we can communicate with the Team Project Collection
        </span><span style="color: #2b91af">TfsTeamProjectCollection </span>teamProjectCollection = 
                <span style="color: blue">new </span><span style="color: #2b91af">TfsTeamProjectCollection</span>(teamProjectCollectionUri);

        <span style="color: #2b91af">IBuildServer </span>buildServer = teamProjectCollection.GetService&lt;<span style="color: #2b91af">IBuildServer</span>&gt;();
        
        <span style="color: green">// Find the build definition for the build to queue.
        </span><span style="color: #2b91af">IBuildDefinition </span>buildDefinition = GetBuildDefinition(buildServer, teamProjectName, 
                buildDefinitionName);

        <span style="color: blue">if </span>(buildDefinition == <span style="color: blue">null</span>)
        {
            WriteToLog(<span style="color: #a31515">&quot;Couldn't find build definition&quot;</span>);
            <span style="color: blue">return</span>;
        }
        <span style="color: blue">else
        </span>{
            WriteToLog(<span style="color: #a31515">&quot;Found build definition, queuing now...&quot;</span>);
        }

        <span style="color: green">// Queue the build as our impersonated user.
        </span>buildServer.QueueBuild(buildDefinition.CreateBuildRequest());

        WriteToLog(<span style="color: #a31515">&quot;Build successfully queued&quot;</span>);
    }
}</pre>
<a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a>

<p></p>

<p>Yes, the code above will in fact queue a build as the user who’s information is passed into the function (principal, authority and password) but this has some caveats.&#160; </p>

<ul>
  <li>First and foremost, you must have the user’s username and password in order to call LogonUser.&#160; This data is usually only available through user input and in the case where your tool is automatically queuing builds after CheckIns, it is likely that you will not have this information or will have to do something unsafe to get access to it. </li>

  <li>This only works for windows identities on windows clients.&#160; With <a href="http://blogs.msdn.com/bharry/archive/2009/11/09/microsoft-has-acquired-the-teamprise-client-suite.aspx">Microsoft’s acquisition of the Teamprise Client Suite</a> it is important that the TFS Client Object Model offers its own method of impersonation instead of relying on the operating system to support it and it is worthwhile to have one standard solution that applies across all operating systems. </li>

  <li>It means that you use the LogonUser unmanaged method which requires dll importing the advapi32.dll.&#160; LogonUser can be slow, is easy to misuse and requires that you handle a series of error conditions (all of which are not done here). </li>

  <li>Finally, this also means that your current thread is running as the user that you have impersonated.&#160; If the thread does logging (as above) or other actions that cause disk resources to be created, deleted or modified then the user that is being impersonated will need the appropriate permissions to these resources or methods of delaying these actions until the impersonation has ended will need to be implemented. </li>
</ul>

<p><strong>Well, what about supplying a different set of credentials to the TfsTeamProjectCollection object that you are creating?&#160; Doesn’t that get around some of these problems and still accomplish the main goal?</strong></p>

<p>Well, yes, supplying different credentials to the TfsTeamProjectCollection object will get you around a few of the above caveats.&#160; Let’s look at an example of this:</p>

<pre class="code"><span style="color: blue">private void </span>QueueBuildForUserUsingDifferentCredentials(
    <span style="color: #2b91af">Uri </span>teamProjectCollectionUri,
    <span style="color: #2b91af">String </span>teamProjectName,
    <span style="color: #2b91af">String </span>buildDefinitionName,
    <span style="color: #2b91af">String </span>principal,
    <span style="color: #2b91af">String </span>authority,
    <span style="color: #2b91af">String </span>password)
{
    <span style="color: green">// Create the proxy object so that we can communicate with the Team Project Collection
    </span><span style="color: #2b91af">TfsTeamProjectCollection </span>teamProjectCollection =
            <span style="color: blue">new </span><span style="color: #2b91af">TfsTeamProjectCollection</span>(teamProjectCollectionUri, 
                <span style="color: blue">new </span><span style="color: #2b91af">NetworkCredential</span>(principal, password, authority));

    <span style="color: #2b91af">IBuildServer </span>buildServer = teamProjectCollection.GetService&lt;<span style="color: #2b91af">IBuildServer</span>&gt;();

    <span style="color: green">// Find the build definition for the build to queue.
    </span><span style="color: #2b91af">IBuildDefinition </span>buildDefinition = GetBuildDefinition(buildServer, teamProjectName,
            buildDefinitionName);

    <span style="color: blue">if </span>(buildDefinition == <span style="color: blue">null</span>)
    {
        WriteToLog(<span style="color: #a31515">&quot;Couldn't find build definition&quot;</span>);
        <span style="color: blue">return</span>;
    }
    <span style="color: blue">else
    </span>{<br />        WriteToLog(<span style="color: #a31515">&quot;Found build definition, queuing now...&quot;</span>);
    }

    <span style="color: green">// Queue the build as our impersonated user.
    </span>buildServer.QueueBuild(buildDefinition.CreateBuildRequest());

    WriteToLog(<span style="color: #a31515">&quot;Build successfully queued&quot;</span>);
}</pre>

<p>In this example we are able to stop using the clunky Windows Impersonation which saves us the use of unmanaged code and DllImports and also prevents the problems with logging mentioned above.&#160; Also, since this is a wholly TFS solution, this solution can be used by Teamprise users as well.&#160; </p>

<p>However, this solution still runs into the main problem that we had above which is that in order to create the NetworkCredential object for the other user that user’s password is needed.&#160; </p>

<p><strong>Ahh, gotcha.&#160; So I am guessing this is where TFS Impersonation comes in?</strong></p>

<p>Yes, this is where TFS Impersonation comes in.&#160; The main advantages that TFS Impersonation has over the two solutions above is that it does not require that the user’s password is supplied.</p>

<p>Before we dive into the example, let’s look at the APIs that are related to TFS Impersonation.&#160; Off of any object that derives from the TfsConnection object (currently only TfsTeamProjectCollection and TfsConfigurationServer) there are new constructors that take the IdentityDescriptor of the identity to impersonate:</p>

<pre class="code"><span style="color: blue">public </span>TfsTeamProjectCollection(
<span style="color: #2b91af"><font color="#333333">    </font>Uri </span>uri,
    <span style="color: #2b91af">IdentityDescriptor </span>identityToImpersonate)</pre>

<p>This method (and the other overloads that take the identityToImpersonate parameter) constructs an instance of the TfsTeamProjectCollection object that will make all web requests as the impersonated user.&#160; Also, for the example below you will also need to include the following two namespaces that are new in TFS 2010:</p>

<pre class="code"><span style="color: blue">using </span>Microsoft.TeamFoundation.Framework.Client;
<span style="color: blue">using </span>Microsoft.TeamFoundation.Framework.Common;</pre>
<a href="http://11011.net/software/vspaste"></a>

<p>Let’s see how our example looks using TFS Impersonation:</p>
<a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a>

<pre class="code"><span style="color: blue">private void </span>QueueBuildForUserUsingTFSImpersonation(
    <span style="color: #2b91af">TfsTeamProjectCollection </span>currentUserCollection,
    <span style="color: #2b91af">String </span>teamProjectName,
    <span style="color: #2b91af">String </span>buildDefinitionName,
    <span style="color: #2b91af">String </span>username)
{
    <span style="color: green">// Get the TFS Identity Management Service
    </span><span style="color: #2b91af">IIdentityManagementService </span>identityManagementService =
            currentUserCollection.GetService&lt;<span style="color: #2b91af">IIdentityManagementService</span>&gt;();

    <span style="color: green">// Look up the user that we want to impersonate
    </span><span style="color: #2b91af">TeamFoundationIdentity </span>identity = identityManagementService.ReadIdentity(
            <span style="color: #2b91af">IdentitySearchFactor</span>.AccountName, username, <span style="color: #2b91af">MembershipQuery</span>.None, <span style="color: #2b91af">ReadIdentityOptions</span>.None);

    <span style="color: #2b91af">TfsTeamProjectCollection </span>impersonatedCollection = 
            <span style="color: blue">new </span><span style="color: #2b91af">TfsTeamProjectCollection</span>(currentUserCollection.Uri, identity.Descriptor);
    <span style="color: #2b91af">IBuildServer </span>impersonatedBuildServer = impersonatedCollection.GetService&lt;<span style="color: #2b91af">IBuildServer</span>&gt;();

    <span style="color: green">// Find the build definition for the build to queue.
    </span><span style="color: #2b91af">IBuildDefinition </span>buildDefinition = GetBuildDefinition(impersonatedBuildServer, teamProjectName,
            buildDefinitionName);

    <span style="color: blue">if </span>(buildDefinition == <span style="color: blue">null</span>)
    {
        WriteToLog(<span style="color: #a31515">&quot;Couldn't find build definition&quot;</span>);
        <span style="color: blue">return</span>;
    }
    <span style="color: blue">else
    </span>{
        WriteToLog(<span style="color: #a31515">&quot;Found build definition, queuing now...&quot;</span>);
    }

    <span style="color: green">// Queue the build as our impersonated user.
    </span>impersonatedBuildServer.QueueBuild(buildDefinition.CreateBuildRequest());

    WriteToLog(<span style="color: #a31515">&quot;Build successfully queued&quot;</span>);
}</pre>
<a href="http://11011.net/software/vspaste"></a>

<p>As you can see in the example, the need for the user’s password is now gone.&#160; </p>

<p>The only thing new to this example is how we discovered the user’s IdentityDescriptor by calling into the Identity Management Service.&#160; This means that in order to use TFS Impersonation either the user’s account name or IdentityDescriptor is needed.&#160; Some of the objects that are new to TFS 2010 will have the TeamFoundationIdentity or IdentityDescriptor objects available as properties so this extra call may not always be needed.&#160; If not, the account name should be discoverable and the IdentityDescriptor can be resolved as it was above.</p>

<p><strong>Wait, doesn’t it seem dangerous that one user can perform actions in Team Foundation Server on behalf of another user without that user’s password?</strong></p>

<p>Yes!&#160; Luckily, not everyone is able to do this.&#160; Since TFS Impersonation actually takes place in the server (see the next section for more of an explanation on this) there is a permission in the server that controls who is and who is not allowed to perform impersonation.&#160; This permission is titled “Make requests on behalf of others” and it can be managed for a Team Project Collection in the TPC security dialog within Team Explorer and it can be managed for the Configuration Server from within the Administer Security dialog off of the Application Tier node in the TfsMgmt console.</p>

<p>This permission is encapsulated within each Team Project Collection and within the Configuration Server.&#160; This means that if User A has this permission on TPC1 he will not be allowed to impersonate users when talking to TPC2 or the Configuration Server.&#160; Similarly, if User B has this permission on the Configuration Server she will not be able impersonate users when talking to any of the Team Project Collections.</p>

<p>Administrators should be very careful when granting this permission.&#160; For the most part, it should only be granted to well-protected service accounts or tool accounts that can be trusted to take actions on behalf of other users.&#160; Because of this, it is one of the few TFS permissions that is not automatically granted to the Configuration Server level or Team Project Collection level Administrators groups.&#160; </p>

<p><em>Note, the following issue has been fixed in TFS 2010 RTM.&#160; I will leave the description up for now since the betas are still heavily being used.</em></p>

<p>Unfortunately, the concept of not granting a permission to the Administrators group does not mesh well with the current TFS security dialog.&#160; This is because that dialog makes the assumption that the Administrators group already has all of the permissions that it needs and actually does not allow you to change these permissions.&#160; </p>

<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/IntroducingTFSImpersonation_EAB2/image_4.png" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/IntroducingTFSImpersonation_EAB2/image_4.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/taylaf/WindowsLiveWriter/IntroducingTFSImpersonation_EAB2/image_thumb_1.png" original-url="http://blogs.msdn.com/blogfiles/taylaf/WindowsLiveWriter/IntroducingTFSImpersonation_EAB2/image_thumb_1.png" width="545" height="515" /></a> </p>

<p>In the above screenshot, the dialog is lying to you.&#160; By default, the Administrators group does not have the “Make requests on behalf of others” permission.&#160; Making things worse is that since the dialog prevents any permissions from being changed for the Administrators group the user is unable to actually give the Administrators group this permission using the UI.&#160; </p>

<p>However, the ability to not set this permission may have a good consequence.&#160; As discussed above, administrators should be very careful when granting this permission.&#160; If it were given to the administrators group then this would mean that any administrator would be able to make a request on behalf of another user.&#160; Now, granted, since they are an administrator they still have the power to grant this permission to them self but at least that takes an explicit action.</p>

<p>If it is decided that this permission needs to be given to the Administrators group then this is possible via the following command from the command-line:</p>

<pre class="csharpcode">tfssecurity.exe /collection:http://taylaf-dev:8080/tfs/Collection0 /a+ Server FrameworkGlobalSecurity Impersonate adm: ALLOW</pre>
<style type="text/css">




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>

<p><strong>Cool, is there anything else I should know about TFS Impersonation?</strong></p>

<p>Of course!&#160; We should definitely talk about the difference between an authenticated identity and the authorized identity and how they relate to TFS Impersonation.&#160; In any web service call, the authenticated identity is the identity that authenticates with the web server (IIS in this case) and the authorized identity is the identity that the web application applies its internal permission restrictions to and is who it records as “performing” the given action.</p>

<p>In the normal case where impersonation is not being used, the authenticated identity and the authorized identity will always be the same.&#160; For the first two examples in this post (Windows Impersonation and Using Different TFS Credentials) the authenticated and authorized identities for the web service calls will also be the same.&#160; This is because in both of those cases, the web service call is being made by the user being “impersonated”.&#160; Since this is true, both the authenticated and authorized identities refer to this “impersonated” user.&#160; </p>

<p>As you might have guessed, these two identities will be different when TFS Impersonation is used.&#160; When using TFS Impersonation the <em>web service</em> call is still made by the user running the process.&#160; This means that the authenticated identity is the user running the process.&#160; It isn’t until the web request enters the TFS web application and the “Make requests on behalf of others” permission is verified that the request becomes associated with the user being impersonated.&#160; Thus, in this case the authorized identity is the identity that is being impersonated.</p>

<p>These ideas are exposed on the TfsConnection base class using the following properties:</p>

<pre class="code"><span style="color: blue">public </span><span style="color: #2b91af">TeamFoundationIdentity </span>AuthorizedIdentity { <span style="color: blue">get</span>; }</pre>
<a href="http://11011.net/software/vspaste"></a>

<pre class="code"><span style="color: blue">public void </span>GetAuthenticatedIdentity(<span style="color: blue">out </span><span style="color: #2b91af">TeamFoundationIdentity </span>identity);</pre>
<a href="http://11011.net/software/vspaste"></a>

<p>When there is an active ITeamFoundationImpersonationContext the AuthorizedIdentity property refers to the user being impersonated and the identity returned by GetAuthenticatedIdentity is the user doing the impersonation.</p>

<p>You may be wondering why we chose to implement the authenticated identity accessor as a method with an out parameter instead of a property like we did with AuthorizedIdentity.&#160; The answer is that when a consumer of this API wants to know “who the active user is” in order to display some details about that user they should almost always show information for the user the who the requests are being made on behalf of (the authorized identity).&#160; Because of this and because of how easy it is to confuse the authorized and authenticated identities <em>we actually wanted to make it hard to get the authenticated identity</em>.&#160; Hopefully, this will prevent programmers from accidentally using the authenticated identity when they should be using the authorized identity and will force them to think about their scenario if they do think they should be using the authenticated identity.</p>

<p><strong>Updated!</strong> Want to see another example using TFS Impersonation? <a href="http://blogs.msdn.com/taylaf/archive/2010/03/29/using-tfs-impersonation-with-the-version-control-client-apis.aspx">Check out this example</a>.</p>

<p>Hopefully that should be enough to get you started with TFS Impersonation.&#160; I am sure there will be more posts about it as people ask more questions about it.&#160; Speaking of, if you have questions feel free to ask in the comments or via the contact form.</p>

<p><em>If you are using TFS 2010 Beta 1 or Beta 2 then everything you just read is still true but some of the APIs have different names.&#160; Here are the mappings that you will need to make this work in one of the betas:</em></p>

<p>TfsTeamProjectCollection is equivalent to TeamFoundationServer.&#160; For more information on this see <a href="http://blogs.msdn.com/granth/archive/2009/12/07/tfs2010-object-model-api-changes-after-beta-2.aspx">Grant Holliday's blog post</a>.</p>

<p>In the Beta 2 version of this API you will not find the new constructors that are needed to perform the impersonation.&#160; Instead, you will find a method off of the TeamFoundationServer object called ApplyThreadImpersonationContext().&#160; This should be called immediately after constructing the TfsTeamProjectCollection object in order to do impersonation.</p>]]></content:encoded>
    </item>
    <item>
      <title>Ping</title>
      <link>https://docs.microsoft.com/archive/blogs/taylaf/ping</link>
      <pubDate>Thu, 03 Dec 2009 12:53:19 GMT</pubDate>
      <dc:creator><![CDATA[Taylor Lafrinere (MSFT)]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/taylaf/2009/12/03/ping/</guid>
      <description><![CDATA[Hello!&#160; If you couldn’t tell from the title of the blog (or if I have undoubtedly changed it)...]]></description>
      <content:encoded><![CDATA[<p>Hello!&#160; If you couldn’t tell from the title of the blog (or if I have undoubtedly changed it) my name is Taylor Lafrinere.&#160; I joined the Team Foundation Server group on July 16, 2007 and have been working as a part of the Enterprise TFS Management and Version Control Platform teams ever since.&#160; The goal of this blog will be to let you know about new features in TFS, how to take advantage of them and most importantly how to troubleshoot any problems you are running into while using them.&#160; I also plan to venture outside of strictly TFS content at some points to share any general coding tips and tricks that I come across.</p>  <p>Before coming to North Carolina to work for Microsoft I spent the previous 18 years in Michigan.&#160; I grew up in Cheboygan (yes, I am holding my hand up right now pointing to where Cheboygan is) and then went to college at the University of Michigan in Ann Arbor.&#160; I will bleed Maize and Blue forever and yes, it is absolutely crushing me that our football team is missing a bowl game for the second year in a row.</p>  <p>Anyway, welcome to the blog and I hope you find something useful or entertaining to read.</p>]]></content:encoded>
    </item>
  </channel>
</rss>