Guidelines for Creating a TFS Adapter

In order to make the TFS Adapters most useful they should all be implemented using a consistent pattern. Your best bet is to use an existing adapter as a template. The guidelines below use the WorkItemAdapter as an example.

Implementing an adapter for a Team Foundation API sealed class is rather straightforward. But you need to make sure that your implementation is complete and consistent. To that end, please review these guidelines.

In order to assure consistency, please follow these guidelines for creating a new TFS Adapter. Suggestions for improvement are always welcome!

Naming Conventions

We've tried to make the naming conventions as simple, intuitive and useful as possible.
  • Namespaces. Use the following namespaces for the adapters and interfaces:
    • Build: CodePlex.TeamFoundation.Adapters.Build
    • Version Control: CodePlex.TeamFoundation.Adapters.VersionControl
    • Work Item Tracking: CodePlex.TeamFoundation.Adapters.WorkItemTracking
    • Note that the CodePlex.TeamFoundation.Adapters project has folders for Build, VersionControl and WorkItemTracking. By creating your interface and adapter in the appropriate folder, the proper namespace will be applied automatically.
  • Interfaces
    • Each interface should have the name of the sealed class it represents, prefixed with the capital letter I.
    • For instance, the interface for the sealed class Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem should be named IWorkItem, and it should be in the CodePlex.TeamFoundation.Adapters.WorkItemTracking namespace.
  • Adapters
    • Each adapter should have the name of the sealed class it represents, with the word Adapter appended to it.
    • For instance, the adapter for the sealed class Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem should be named WorkItemAdapter, and it should be in the CodePlex.TeamFoundation.Adapters.WorkItemTracking namespace.

Creating a public interface for a sealed class

  • In the CodePlex.TeamFoundation.Adapters project, create a new interface in the appropriate folder, using the naming convention described above.
  • Make sure that your interface is marked "public" so that it can be accessed by external assemblies.
  • Find an instance of the sealed class in your code. Example:
WorkItem myWorkItem = workItemStore.GetWorkItem(workItemID);
  • Right-click on the type declaration (WorkItem in this case) and click on Go to Definition. This displays the public properties and methods of the class, derived from its metadata.
  • Copy and paste the properties, methods and events from the definition to your interface. Remove all the "public" access modifiers from the properties, methods and events, as they are not needed. Also, you will need to remove (or at least comment out) all the static methods, as they cannot be mocked. (TODO: write-up how to deal with static methods).

Generating the adapter class

  • In the CodePlex.TeamFoundation.Adapters project, create a new class in the appropriate folder, using the naming convention described above.
    • Make sure that your class is marked "public" so that it can be accessed by external assemblies.
    • Configure your class to implement the appropriate adapter interface. Example:
public class WorkItemAdapter : IWorkItem
  • Regions within the class
  • In the CodePlex.TeamFoundation.Adapters proejct, create a new class in the appropriate folder, using the naming convention described above.
  • Declare a private instance of the sealed class being adapted. Example:
#region Private Variables
WorkItem tfsWorkItem;
#endregion
  • Adapter Constructors
    • Hide the default constuctor. Example:
private WorkItemAdapter() { // Hide the default constuctor }
  • Add a new public constructor that take an instance of the sealed class being adapted. Example:
public WorkItemAdapter(WorkItem sourceWorkItem)
{
tfsWorkItem = sourceWorkItem;
tfsWorkItem.FieldChanged += this.FieldChanged;
}
  • Interface implementation
    • Right click on the inteface name in the class declaration, and click on Implement Interface. This will generate stubs for the inteface methods and properties.
    • Implement the stub, using an existing adapter as a template.

Updating the other adapters

  • Find all instances of the sealed class in the other adapter classes, and replace them with your new adapter interface.

Adding the adapter to the factory

  • If the sealed class can be generated by the TeamFoundationServer class, then add a new Get method to ITfsFactory and implement that method in the TfsFactory class. Example:
public IWorkItemStore GetWorkItemStore()
{
WorkItemStore store = (WorkItemStore)GetTeamFoundationServer().GetService(typeof(WorkItemStore));
return new WorkItemStoreAdapter(store);
}

Creating a sample unit test

  • Add a method to the CodePlex.TeamFoundation.Utilities project that illustrates the proper use of your adapter.
  • Add a unit test to the CodePlex.TeamFoundation.Utilities.Test project that illustrate how your adapter can be mocked.

Last edited Mar 9, 2009 at 11:40 PM by mdanner, version 13

Comments

No comments yet.