Printer Friendly Version      Send     
Click to Rate and Give Feedback
Related Articles
This article presents an overview of the motivation behind new techniques that decompose problems into independent pieces for optimal use of parallel programming.

By David Callahan (October 2008)
We take a look at planned support for parallel programming for both managed and native code in the next version of Visual Studio.

By Stephen Toub and Hazim Shafi (October 2008)
Here we describe some of the more common challenges to concurrent programming and present advice for coping with them in your software.

By Joe Duffy (October 2008)
Here is an ASP.NET AJAX data-driven Web application that takes the best features from server- and client-side programming to deliver an efficient, user-friendly experience.

By Bertrand Le Roy (October 2008)
More ...
Articles by this Author
Use the Team Foundation Server EventService to create and manage event subscriptions or create a Web service to receive and process events.

By Brian A. Randell (May 2008)
Team Foundation Server provides APIs that let you create check-in notes (categorized string data) and custom check-in policy implementations. These features combine to give project administrators better control over the group development process.

By Brian A. Randell (November 2007)
Add support for work items to the Team Foundation Server version control add-in.

By Brian A. Randell (September 2007)
In this column, Brian Randell explains how to build a simple Work Item explorer and demonstrates the core operations needed to add work item support when building your own add-in.

By Brian A. Randell (April 2007)
Here Brian Randell presents everything you need to know to get started with Visual Studio 2005 Team Edition for Database Professionals.

By Brian A. Randell (February 2007)
In this new column, Brian Randell begins his long look at how to extend and enhance Visual Studio Team System.

By Brian A. Randell (January 2007)
The Express Editions of Visual Basic and SQL Server 2005 have lots of the features of the full-sized versions, but with a lot less of the overhead. Professional developer features such as full IntelliSense support, local debugger, Add Web Reference, and the improved Visual Data Tools will all be available in the Express products, so you don't have to leave your favorite features behind. In this article the author introduces you to these express editions and builds a sample app to get you started.

By Brian A. Randell (September 2004)
Microsoft is introducing a new suite of tools (code-named "Whitehorse") that will make it easier for you to design and implement systems that conform to a service-oriented architecture. Two of these tools -- the SOA Design Suite and the Class Designer -- support the graphical design of systems and components with support for code generation and support for bi-directional synchronization which lets you ensure that your diagram always represents your system design. This article introduces these tools and shows you how they'll improve your design and development efforts.

By Brian A. Randell and Rockford Lhotka (July 2004)
More ...
Popular Articles
One-time passwords offer solutions to dictionary attacks, phishing, interception, and lots of other security breaches. Here's how it all works.

By Dan Griffin (May 2008)
The goal of the ADO.NET Data Services Framework is to create a simple REST-based framework for exposing and consuming data-centric services easily.

By Elisa Flasko and Mike Flasko (August 2008)
See how to build a document-level Visual Studio Tools for Office customization and integrate it with a content type in SharePoint.

By Steve Fox (May 2008)
In this excerpt from his upcoming book, Laurence Moroney explains the basics of Silverlight animation and the animation tools available in Expression Blend.

By Lawrence Moroney (August 2008)
More ...
Read the Blog
Long-running processes are common in distributed computing. Some business processes are made up of multiple execution sequences which may last many days or even weeks. In the October 2008 issue of MSDN Magazine, Juval Lowy discusses several techniques ...
Read more!
Correctly engineered concurrent code must live by an extra set of rules. Reads and writes from memory and access to shared resources need to be regulated so that conflicts do not arise. Additionally, threads often need to coordinate to get the job done. In the October 2008 issue of MSDN Magazine, Joe ...
Read more!
Well designed code keeps things that have to change together as close together in the code as possible and allows unrelated things in the code to change independently, while minimizing duplication in the code. In the October 2008 issue of MSDN Magazine, Jeremy Miller shows you some design ...
Read more!
The process for ink capture and analysis on the Tablet PC is straightforward in managed code. To the uninitiated developer, however, creating unmanaged Tablet PC applications can be rather daunting. In the October 2008 issue of MSDN Magazine, Gus Class a quick introduction to the Tablet PC ...
Read more!
Multicore systems are becoming increasingly prevalent, but the majority of software today will not automatically take advantage of this additional processing ability. And multithreaded programming, for anything but the most trivial of systems, is incredibly difficult and error prone today. In the October 2008 issue of MSDN ...
Read more!
Concurrent programming is notoriously difficult, even for experts. You have all of the correctness and security challenges of sequential programs plus all of the difficulties of parallelism and concurrent access to shared resources. In the October 2008 issue of MSDN Magazine, David Callahan describes ...
Read more!
More ...
Team System
Check-in Notes and Policies
Brian A. Randell

Code download available at: TeamSystem2008_Launch.exe (150 KB)
Browse the Code Online
Back in the January 2007 installment of this column, I started a discussion on using the Team Foundation Server (TFS) version control APIs from a Microsoft® Word 2003 add-in. Here I am, more than a year later, with the fifth and final part dedicated to the version control APIs and the Word add-in. (I really didn't think it would take this many installments.)
You may recall from earlier columns that the add-in currently supports check-in, check-out, undo pending changes, and the ability to associate work items with a check-in. In my most recent column, I examined check-in notes and check-in policies. This month, I will show you how to add check-in notes and check-in policy support to the Word add-in. In addition, you'll learn about how to deal with check-in conflicts. And if you haven't read the rest of this series (listed in the "First Four Parts of This Series" sidebar), be sure to check them out.

Check-In Notes
Check-in notes are free-form text fields that you can associate with a check-in. You can mark check-in notes as mandatory and control the order in which they appear in the Visual Studio® check-in dialog. In order to mimic this behavior in the Word add-in, you should get the list of check-in notes for the active team project, sort the list, and display a label and textbox for each check-in note.
The VersionControlServer object exposes the GetCheckinNoteDefinitions method, which accepts an array of team project names and returns an array of CheckinNoteFieldDefinition objects. Each CheckinNoteFieldDefinition instance exposes properties for check-in note name, display order, whether it's required, and a server item string. GetCheckinNoteDefinitions returns the list of items in what appears to be a seemingly random order. In my tests, I found that notes are returned sorted by check-in note name and grouped by team project name no matter what order the team project references are passed into the method. Thus, assuming there are two team projects defined, one called MSF-Agile and one called MSF-CMMI with the default set of notes, the results would appear as shown in Figure 1. And if you created a new check-in note called Build Master and added it to the MSF-CMMI team project, it would appear first in the list.
The tfsVCUtil class, created for the Word add-in, has two new shared methods that you can use to retrieve check-in notes: GetAllCheckInNotesByTeamProjectName and GetAllCheckInNotesByItemLocalPath. Using either of these methods, you can get the unmodified list of CheckinNoteFieldDefinitions, if any, for the team project.
Supporting check-in notes on the check-in dialog requires that you add an extra toggle button under the existing work items button, an extra panel to act as a container, and a label and textbox for each check-in note. (The code download provides a simple implementation.) However, adding support for check-in notes to the check-in dialog is just one piece of the puzzle. You also need to add code to enforce required notes. Check-in policies and conflict detection require that you make additional changes to how the check-in dialog and supporting code in the tfsVCUtil class work.

Check-In Policies
Just as with check-in notes, the first order of business for supporting check-in policies is figuring out what policies are enabled for the active team project. The second order of business is deciding how to process check-in policies. Because Microsoft designed check-in policies primarily for developers checking in code from Visual Studio, two of the three built-in policies that ship with TFS 2005 don't work correctly when used to a validate a check-in for a single Word document. Thus it's necessary that the add-in only process errors from check-in policies that make sense in the context of a Word document.
It turns out there is only one way to solve this problem. You have the add-in evaluate all enabled policies and ignore the errors generated by those policies that don't make sense. On initial inspection of how check-in policies work, it looks as if a possible alternative is to have the add-in run the evaluation process manually against those policies that should work. But it turns out this is not possible.
By default, check-in policies and check-in notes are not evaluated as part of the check-in process when using custom code. In order to mimic the behavior of Visual Studio, it's up to your application code to ensure that required check-in notes are provided and that there are no policy violations—or, if there are violations, that policy override information is provided.
To make life a bit easier, the Workspace class exposes an EvaluateCheckin method. You use this to check for conditions that might cause a check-in to fail. Here's the method prototype from the MSDN® documentation:
Public Function EvaluateCheckin ( _
    options As CheckinEvaluationOptions, _
    allChanges As PendingChange(), _
    changes As PendingChange(), _
    comment As String, _
    checkinNote As CheckinNote, _
    workItemChanges As WorkItemCheckinInfo() _
) As CheckinEvaluationResult
The method first wants to know what you would like to evaluate. You provide this information by passing the correct enumeration value via the options parameters. You can have the method look for check-in conflicts, required check-in notes, policies violations, or all three.
The method then requires that you pass in an array of PendingChange objects for the second and third parameters. Why two sets? In Visual Studio, for example, you could have ten modified files in the current workspace, but the user can choose to check only three files for check-in. Thus, Visual Studio passes all ten files via the allChanges parameters and the three checked files via the changes parameter. The method provides this information for the enabled policy assemblies. In the case of the Word add-in, you pass the same array for both parameters.
For the fourth parameter, you pass in the comment text, if any, provided by the user doing the check-in. To pass check-in notes, you create an instance of the type CheckInNote, which accepts an array of CheckinNoteFieldValue instances, and pass this as the fifth parameter. Finally, you pass an array of WorkItemCheckinInfo instances for the last parameter. You can pass nothing for any of the last three parameters.
Once you've called EvaluateCheckin, you receive a CheckinEvaluationResult instance. This object exposes the results via three array properties: Conflicts, NoteFailures, and PolicyFailures. If there are no values for a particular result set, EvaluateCheckin returns a zero-length array. It is up to you to enumerate each array and process the results. Note that even if EvaluateCheckin returns failures for check-in notes or policies, this does not block a check-in. You must implement logic in your code to prevent a check-in when these rules aren't satisfied. However, if conflicts exist, TFS does block the check-in. To take advantage of this method for the Word add-in, expose EvaluateCheckin via the tfsVCUtil class using a shared method called PreValidateCheckIn:
Public Shared Function PreValidateCheckIn( _
  ByVal docPath As String, _
  ByVal options As CheckinEvaluationOptions, _
  ByVal comments As String, ByVal notes As CheckinNote, _
  ByVal workitems() As WorkItemCheckinInfo) _
  As CheckinEvaluationResult

  Dim pc As PendingChange() = _
      m_userWorkspace.GetPendingChanges(docPath)

  Return m_userWorkspace.EvaluateCheckin(options, _
      pc, pc, comments, notes, workitems)
End Function
As you can see from the code listing, PreValidateCheckIn mimics the signature of EvaluateCheckin with the additional parameter for the document to evaluate. Once you call this method from the check-in dialog, you enumerate the arrays for the items you requested to be validated, looking for issues and, if necessary, providing a visual indication to the user of what's wrong.
With regard to policy violations, you have to decide what policies make sense for your application. Naturally, the built-in policies offered by Microsoft, as well as many of those available in the wild, are biased to the check-in experience in Visual Studio. In the case of the Word add-in, only the work-item-required policy makes sense when examining the three built-in policies in the 2005 edition of Visual Studio Team System. Aside from the built-in policies, the Word add-in solution needs to worry only about policy errors raised by relevant assemblies. Using some out-of-band mechanism, such as name/value pairs stored in the add-in's configuration file, the code knows which policies should be respected. Then, at run time, the code examines the policy errors collection and ignores all errors not on the list. One way you can do this is to cast the IPolicyEvaluation reference returned from the PolicyFailure instance's Policy property to an instance of IPolicyDefinition. Then, IPolicyDefinition exposes a Type property that can be used to identify the policy source. Here's a simple example:
Dim cer As CheckinEvaluationResult = {Call to server elided}
Dim i As IPolicyDefinition = Nothing
For Each pf As PolicyFailure In cer.PolicyFailures
  i = DirectCast(pf.Policy, IPolicyDefinition)
  If i.Type = "Work Items" Then
    ' process this policy failure
  End If
Next
There is a downside to this approach. As part of the Visual Studio 2005 Team Foundation Server Power Tools, Microsoft added four additional check-in policies (see msdn2.microsoft.com/vstudio/aa718351). One policy in particular, the custom path policy, uses a bit of indirection via delegation to run another policy, such as the work item policy, when the pending changes being provided match a particular regular expression. Teams use this policy to enforce stricter check-in rules on only part of their code repository while another section can be less restrictive. Thus, if this policy is used, the previously listed code sees the type of the custom path policy, not the actual policy executing—for example, the work items policy.
You might try to do what Visual Studio does, but that doesn't work. While you can discover the list of enabled policies by calling GetCheckinPolicies off of a valid TeamProject instance, there's no (reasonable) way to acquire a valid IPendingCheckin reference that is required as a parameter to IPolicyEvaluation's Initialize method. Thus, to deal with the custom path policy, you need to examine the Description property returned from IPolicyDefinition. The authors of the policy chose to store the Type value from the delegated policy here. Thus, the refactored code looks like this:
Dim cer As CheckinEvaluationResult = '{Call to server elided}
Dim i As IPolicyDefinition = Nothing
Dim processPolicy As Boolean = False
For Each pf As PolicyFailure In cer.PolicyFailures
  i = DirectCast(pf.Policy, IPolicyDefinition)

  processPolicy = (i.Type = "Work Items")
  If Not processPolicy AndAlso _
    i.Type = "Custom Path Policy" Then
    processPolicy = (i.Description = "Work Items")
  End If
  If processPolicy Then
    ' process this policy failure
  End If
This version does a basic job of handling both the standard Work Items policy and a delegated version using the Custom Path Policy. Your own implementation may be more complex and may require a more elaborate solution, but now you are equipped with the tools to solve the problem.
I've shown you how to get the list of check-in notes so you can present a UI. If you look at EvaluateCheckin and the wrapper method PreValidateCheckIn, you'll see that in order to validate check-in notes, you need to create and then pass an instance of CheckinNote. After you execute EvaluateCheckin, either directly or via the wrapper, you need to examine the NoteFailures collection. Each NoteFailure instance exposes a Definition property that represents the CheckinNoteFieldDefinitions for the check-in note. From there, you can easily access the Name property to know which check-in notes to highlight in your UI. The Message property is a generic message stating "A value must be specified for the check-in note." As mentioned earlier, neither policy violations nor missing check-in notes will block a check-in executed from code. It's up to you to ensure that things are, in fact, satisfactory before you call your check-in code.

Check-In Conflicts
Check-in conflicts, on the other hand, do block your check-in. You control the default check-out behavior for artifacts from the version control repository using the File Types dialog (shown in Figure 2), which is accessible via Team | Team Foundation Server Settings | Source Control File Types. Using this dialog, you control which files support file merging and thus simultaneous check out. For example, you can see in Figure 2 that Microsoft Office Files have file merging disabled. As a result, when you perform a check out using the Source Control explorer or the APIs, you get an exclusive check out. To adjust the multiple check-out and file merging settings for a set of file extensions, simply click the Edit button to open the Edit File Types dialog.
Figure 2 Configured File Types for Version Control (Click the image for a larger view)
If file merging is enabled for a particular file extension and a conflict occurs at check-in, Visual Studio, by default, displays the Team Explorer Merge Tool. Microsoft made this a configurable option on a per developer basis. Within Visual Studio, you can go to Tools | Options, and then under the Source Control node, select the Visual Studio Team Foundation Server node. On the options page, you click Configure User Tools and then Add. You now have full control over how a particular file extension or set of extensions are handled (see Figure 3).
Figure 3 Configuring a New Merge Tool for a File Extension (Click the image for a larger view)
Thus, the default behavior is for an exclusive check out when you use the Word add-in to check out a Word document. In theory, this eliminates the need to deal with conflicts in the add-in code. However, there's an issue with this default behavior that catches many new TFS users off guard. By default, if you request a checkout using TFS 2005 via Visual Studio or the APIs, the check out occurs against the current local file in your workspace—even if it's not the most current version of the file stored in TFS. The underlying code does not perform a get latest. So it is possible for you to check out a file via the Word add-in, make changes, and then have the check-in fail when you are done.
You can solve this problem in a number of ways. In fact, Microsoft has listened to customer feedback, and in TFS 2008 you can enable Get Latest on Check out on a per Team Project basis; you can also control this feature at your local installation. Microsoft also updated the PendEdit API to support this feature. However, for the add-in working against TFS 2005, you need to modify the existing check out code to manually perform a get latest before check out. To do this, you need to add a line of code that calls Workspace.Get with the correct parameters before the call to PendEdit. The code in Figure 4 does just that.
The Get command returns an instance of a GetStatus object, which exposes a set of properties that provide statistics related to the number of conflicts, failures, operations, and warnings. You can use this data to determine if the Get command worked as expected.
With the add-in using this version of CheckOutDocument, you shouldn't run into any conflicts. But if you're still concerned about conflicts, just check the Conflicts array returned by EvaluateCheckin. In case there are conflicts, you need to provide an experience that lets the user pick the so-called "winner." If you want the winner to be the person attempting to perform the current check-in, you need to use the QueryConflicts method of the Workspace object. This returns an array of Conflict objects. You then set the Resolution property of the Conflict instance to Resolution.AcceptYours and pass the object to the Workspace.ResolveConflict method. Providing a richer experience than this will require serious thought and additional investment in both time and code.
Now, provided you have all five parts of this series on hand, you should have all the tools and information necessary to code up your own rich custom check-in experiences for your applications. Going forward, you'll need to review the updated APIs provided with Team Foundation Server 2008 and get ready for even more enhancements in the "Rosario" release coming sometime in the future.
A special thanks to Martin Woodward of Teamprise and all the folks on the Visual Studio Team System team who have helped with this and the previous columns in this series.

Send your questions and comments to mmvsts@microsoft.com.


Brian A. Randell is a Senior Consultant with MCW Technologies LLC. He spends his time speaking, teaching, and writing about Microsoft technologies. Brian is the author of Pluralsight's Applied Team System course and is a Microsoft MVP. You can contact Brian via his blog at mcwtech.com/cs/blogs/brianr.

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.
Page view tracker