HarborObjects

Practical Team Foundation Server - Slides

by Bryan Knox 27. January 2012 01:22

I really had a good time presenting at the "Practical Team Foundation Server - A Quick Start" event. There were lots of good questions and everyone who came to the event in Los Angeles, San Diego and Orange County was great. I thank everyone who attended. I really enjoyed talking to all of you.

Use the link below to download a PDF of a subset of the slides I had prepared from the event.

The PDF includes the slides from the TFS Tour and Setup for Development sections.

Download:

2012-01-25 Practical TFS 2010 sub set.zip (1.16 mb)

Tags:

TFS

Free Event: Practical Team Foundation Server - A Quick Start

by Bryan Knox 30. November 2011 19:37

HarborObjects is providing FREE all-day TFS training in January to developers in Southern California. I’ll be leading the training and assisted by Reza Madani.

The goal of this training is to quickly bring you up to speed with the essentials features of Team Foundation Server 2010 so that you can quickly setup and be productive in your own TFS environment.

We start out by outlining generic development activities that are encountered in any software development process. We'll use those activities as the context in which you'll learn to use TFS and you'll be able to easily map those activities into the process that you use in your own development work.

2012 Free Event Dates:

  • January 11th - Microsoft Office, Los Angeles
  • January 18th - Microsoft Office, San Diego
  • January 25th - Microsoft Office, Irvine

Tags:

TFS

TFS SDK - Setting Work Item Query Permissions

by Bryan Knox 24. August 2011 02:01

In this article I'll demonstrate how to set permissions on work item queries or query folders using the Team Foundation Server 2010 Client SDK.

The source code can be downloaded from the following link:

WitQueryPermissions.zip (35.73 kb)

I often run into situations where I need to set a bunch of permission on specific work item query folders and doing it from the Team Explorer UI too time consuming. I looked into scripting the task using the TFSSecurity.exe command line tool that comes with TFS 2010, but it needs the GUID of each query item, and getting that GUID isn't easy. See this item in the MSDN forums for details.

What I want is to specify the path to the query item, the name of the account, and the permission to be granted for the account on the query item.

The path to the query item looks something like:

"DemoAgile/Team Queries/Hello World"

image

Below I use the TFS SDK and write some code to do what I want.

Here's we needed to do:

  1. Connect to the TFS team project collection.
  2. Get the IdentityDescriptor for the named user or group.
  3. Get the QueryHierarchy (the root of the query folders)
  4. Get the QueryItem for the given work item query path.
  5. Set and save the permissions on the QueryItem.

Project References and Namespaces

Here's a list of the TFS SDK references added to the Visual Studio project.

Microsoft.TeamFoundation.Client
Microsoft.TeamFoundation.Common
Microsoft.TeamFoundation.WorkItemTracking.Client

Here's a list of the TFS SDK namespace used.

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

Connect to the TFS team project collection.

Connecting to a TFS team project collection is easy.

string teamProjectCollectionUrl = "http://Win7Dev-8:8080/TFS/DefaultCollection";
 
var teamProjectCollection = new TfsTeamProjectCollection(new Uri(teamProjectCollectionUrl));
 

Get the IdentityDescriptor for the named user or group.

TFS uses IdentityDescriptor objects to reference security users and groups.

The code below shows how to get the IdentityDescriptor object associated with the identity with the given display name in the given project collection. The display name has the form::

[MyTeamProject]\SomeIdentityName

We use the display name rather than the account name because the same account name may be defined within multiple team projects.

IdentityDescriptor GetIdentityDescriptorForDisplayName(
                TfsTeamProjectCollection teamProjectCollection,
                string identityDisplayName)
{
    IIdentityManagementService identityManagementService =
    teamProjectCollection.GetService<IIdentityManagementService>();

    TeamFoundationIdentity identity = identityManagementService.ReadIdentity(
            IdentitySearchFactor.DisplayName,
            identityDisplayName,
            MembershipQuery.Direct,
            ReadIdentityOptions.None);

    IdentityDescriptor securityGroupDescriptor = identity.Descriptor;

    return securityGroupDescriptor;
}

 

Get the QueryHierarchy (the root of the query folders)

The root of the work item query hierarchy is a QueryHierarchy object that has the same name as the containing team project. We need the QueryHierarchy object so that we can save the changes we make to the permissions.

The QueryHierarchy object is derived from QueryFolder and it typically contains only two items, both are QueryFolder objects. One named "My Queries" and one named "Team Queries".

The following code shows how to access the QueryHierarchy for a named team project within a team project collection.

    QueryHierarchy GetQueryHierarchy(
TfsTeamProjectCollection teamProjectCollection, 
string teamProjectName)
    {
        WorkItemStore workItemStore = teamProjectCollection.GetService<WorkItemStore>();

        Project witProject = workItemStore.Projects[teamProjectName];

        return witProject.QueryHierarchy;
    }

Get the QueryItem for the given work item query path.

TFS does not provide a built-in way to get a QueryFolder object specified by a given query folder path string such as:

"MyTeamProject\Team Queries\Iteration 1"

The following code show how to get the QueryFolder object specified by a given query folder path string.

static QueryItem GetQueryItemAtPath(QueryHierarchy queryHierarchy, string queryItemPath)
{
    string[] itemArray = queryItemPath.Split('/');

    // We skip the root folder from the itemArray
    // so that only sub items remain.
    string[] relItemArray = itemArray.Skip(1).ToArray();

    // The QueryHierarchy object is the root QueryFolder.
    QueryItem queryItem = GetQueryItemRecursive(queryHierarchy, relItemArray);

    return queryItem;
}

QueryItem GetQueryItemRecursive(QueryItem queryItem, string[] relItemArray)
{
    QueryItem itemFound = null;

    if (relItemArray.Length == 0)
    {
        itemFound = queryItem;
    }
    else
    {
        // We assume the queryItem is a folder
        // and look inside it.

        QueryFolder queryFolder = (QueryFolder)queryItem;

        QueryItem subItem = queryFolder[relItemArray[0]];

        // Recurse.
        itemFound = GetQueryItemRecursive(subItem, relItemArray.Skip(1).ToArray());
    }
    return itemFound;
}

Set and save the permissions on the QueryItem.

Permissions are assigned to QueryItem objects via the item's access control list (ACL) accessible via the item's AccessControlList property.

AccessControlList acl = queryItem.AccessControlList;

You change permissions for a QueryItem by changing the properties of individual AccessControlEntry objects in the work item's ACL.

When the AccessControlList.SetPermissions(..) method is called a new AccessControlEntry object will be added to the ACL if there is not one for the given descriptor.

If you set both allow and deny to QueryItemPermissions.None then the AccessControlEntry will be automatically removed from the copy of the ACL on the server after it is saved.

To save the changed to the TFS server you need to invoke the Save() method on the containing QueryHierarchy object.

    if (queryItem.IsDirty)
    {
        queryHierarchy.Save();
    }

You can determine whether or not a QueryItem has changes that need to be save by inspecting its IsDirty property.

The IsDirty property is not propagated up to the root of the hierarchy so the QueryHierarchy object's IsDirty property will not be changed when IsDirty changes on a child item.

Here's the code that sets and saves the permissions.

    void ChangeQueryItemPermissions(QueryHierarchy queryHierarchy,
                        QueryItem queryItem, 
                        IdentityDescriptor identityDescriptor,
                        QueryItemPermissions allowPermissions, 
                        QueryItemPermissions denyPermissions)
    {
        AccessControlList acl = queryItem.AccessControlList;

        acl.SetPermissions(identityDescriptor, 
                    (int)allowPermissions, 
                    (int)denyPermissions, 
                    merge: false);

        if (queryItem.IsDirty)
        {
            queryHierarchy.Save();
        }
    }

Putting it all together

Here's code for the Main of a sample command line that puts all the pieces together.

static void Main(string[] args)
{
    string teamProjectCollectionUrl = "http://MyTfsServer:8080/TFS/DefaultCollection";
            
    string teamProjectName = "MyTeamProject";

    string identityDisplayName = @"[MyTeamProject]\Test Group";

    string queryItemPath = "MyTeamProject/Team Queries/Hello World";

    QueryItemPermissions allowPermissions = QueryItemPermissions.Read
                                            | QueryItemPermissions.Contribute;

    QueryItemPermissions denyPermissions = QueryItemPermissions.None;


    var teamProjectCollection = new TfsTeamProjectCollection(
                                        new Uri(teamProjectCollectionUrl));

    IdentityDescriptor identityDescriptor = GetIdentityDescriptorForDisplayName(
                                               teamProjectCollection,
                                               identityDisplayName);

    QueryHierarchy queryHierarchy = GetQueryHierarchy(teamProjectCollection,
                                    teamProjectName);

    QueryItem queryItem = GetQueryItemAtPath(queryHierarchy, queryItemPath);

    ChangeQueryItemPermissions(queryHierarchy,
                    queryItem,
                    identityDescriptor,
                    allowPermissions,
                    denyPermissions);
}

The source code can be downloaded from the following link:

WitQueryPermissions.zip (35.73 kb)

Tags:

TFS

Team Foundation Server 2010 Concepts slides from OC .NET UG

by Bryan Knox 10. August 2011 18:27
Use the link below to download my slides (as PDF) from my "Team Foundation Server 2010 Concepts" presentation at the OC .NET User Group on 8/9/2011.

HO TFS 2010 Concepts.pdf (1.92 mb)

Tags:

TFS

C# 4.0 concepts

by RezaMadani 28. July 2011 20:45

Attached please find the slide deck for my C# 4.0 new concepts and features presentation.

CSharpConcepts.pdf (140.59 kb)

Tags:

TFS

Team Foundation Server 2010 Overview slides

by Bryan Knox 28. July 2011 18:48
Use the link below to download a zip file containing my July 27, 2011 presentation, "Team Foundation Server 2010 Overview".

Tags:

TFS

Windows Phone 7 Unleashed Event Code & Slide Decks

by RezaMadani 4. June 2011 23:50

Attached please find the slide decks for all three sessions along with the accompanying completed code.

 HOL_Finished_Code.zip (1.69 mb)

 WP7Unleashed_Session1.pdf (2.66 mb)

 WP7Unleashed_Session2.pdf (1.17 mb)

 WP7Unleashed_Session3.pdf (2.09 mb)

Tags: ,

Windows Phone 7

Windows Phone 7 Unleashed Event Hand Outs

by RezaMadani 3. June 2011 23:23

For those of you attending my WP7 all day event, the required course material is attached here.

assets, images and Word docs:

 WP7_Hands_On_Lab_Documents.zip (4.13 mb)

PDF version of docs:

 WP7_Hands_On_Lab_Documents_pdf.zip (2.19 mb)

Demo sample code presented:

 WP7_Sample_Code.zip (3.85 mb)

Tags: ,

Windows Phone 7

Label permissions and label scope in TFS 2010

by Bryan Knox 11. May 2011 20:01

There are some key things you need to know and do when Label permissions in TFS 2010 version control are limited to particular folders. The key thing you need to know is that you can control the scope of labels in TFS when they are created. The key thing you need to do is to create labels within a scope that is allowed by the permissions that have been granted.

Many TFS users only apply labels using the Apply Label menu item in Visual Studio Source. Well, by default the scope of any labels created is the team project, so the user must have Label permission allowed at the team project level. But, if a user is only granted Label permission on a folder within the team project an error like the following will be displayed when they attempt to place a label on that folder or any its subfolders.

TF14098: Access Denied: User %USER% needs Label permission(s) for $/TeamProject1

This error occurs because by default the scope of the label is created with team project scope which requires Label permission at the team project level. To avoid this error the user needs to create the label within a scope that compatible with where the Label permission is Allowed.

Unfortunately the Visual Studio 2010 Source Control Explorer UI doesn't expose any options to set the scope of a label when it is created, but the tf.exe command line tool does.

For an example we'll set Label and Read permissions to Allow for the user on the Product1 folder at the following path and not on the team project or any other folder.

$\TeamProject1\Customer1\Product1

Here's the command line equivalent of what the Source Control Explorer UI does when a new label is created on the "$\TeamProject1\Customer1\ Product1" folder:

tf label /server:http://ServerName:8080/tfs LabelName $\TeamProject1\Customer1\ Product1\Main /recursive

If the user runs that command it will result in the error mentioned earlier.

Here's a command line that will limit the scope of the label to the "$\TeamProject1\Customer1\ Product1" folder:

tf label /server:http://ServerName:8080/tfs LabelName@$\TeamProject1\Customer1\Product1 $\TeamProject1\Customer1\Product1 /recursive

Notice the LabelName@Scope argument. In this example we set the scope of the label to be the same as folder that is being labeled. This is compatible with the user's permissions so it works.

Information about the scope of labels in TFS is hard to find and that's too bad because label scope is necessary to understand in order to use TFS in many scenarios. Using label scope effectively provides power and flexibility. With the default scope at the team project level all label names must be unique within the team project. Good use of label scope allows you to use the same label names in different scopes.

Hopefully future versions of the Source Control Explorer UI will allow us to control label scope with Apply Label. Until then we can create scoped labels from the command line. The tf.exe documentation has the good information about labels in TFS.

 

Tags:

TFS

WPF animation techniques and SQL Server 2008 features

by RezaMadani 5. May 2011 04:34

I have two presentations coming at Cal State Fullerton Code Camp on January 25th.
One is an overview of animation techniques in WPF and Silverlight. This is one of my better presentations. It provides a good overview of animation capabilities of WPF. Find out more details here.
The other is an overview of the new cool capabilities of SQL server 2008 one can benefit from immediately. This is intended for developers and DBAs. Find out more details here.

Tags: , ,