Occasionally the question of whether to use the TeamFoundationServerFactory.GetServer() method or the TeamFoundationServer constructor comes up, and someone recently asked this question on an internal list.  The answer depends on the needs of the application that you are writing.  In this post, I'll discuss the main differences between the two.

If you have an application where different parts of the code will need to access the same TeamFoundationServer object (say you need to hook up event handlers to the same VersionControlServer object that the rest of the code is using) but only have the name/URL of the server, then the TeamFoundationServerFactory is the correct choice. The TeamFoundationServerFactory caches the TeamFoundationServer objects it creates and always returns a cached TeamFoundationServer object if one matching the request exists. Those cached objects are indexed only by server URL, which is why there is no way to specify the credentials in the GetServer() method. Every time you request the TeamFoundationServer object for http://yourserver:8080, for example, via TeamFoundationServerFactory.GetServer(), you will get the same exact instance, and thus no chance to connect to the same server with different credentials.

The Team Explorer needs this type of behavior and is why TeamFoundationServerFactory exists. The different parts of the code shouldn't pop up additional login dialogs and yet the code wouldn't know how to retrieve the existing TFS object from a cache whose key included the credentials without first asking the user what credentials to use (there are also complications in dealing with CredentialCache objects; you can read more about CredentialCache objects in the post, Authentication in web services with HttpWebRequest).

However, if you want to connect to the same Team Foundation Server with different credentials, you must use the constructor. For example, you connect to server A as users X and Y.

TeamFoundationServer tfsX = 
new TeamFoundationServer("http://serverA:8080",
new NetworkCredential(userX, passwordX, domain)); TeamFoundationServer tfsY =
new TeamFoundationServer("http://serverA:8080",
new NetworkCredential(userY, passwordY, domain));

The command line, tf.exe, is an example of an application that can do that via command files containing commands with /login options specifying different users.  For example, you could execute the following by saving the commands in a file called cmd.tfc and running tf @cmd.tfc.  These two commands execute within the context of one running instance of tf.exe, which means tf.exe must use the constructor.

edit foo.cs /login:userX,passwordX
perm $/blah/foo.cs /deny:read /login:userY,passwordY

If you don't have either of these requirements and just need a TeamFoundationServer object to do something, you could choose either.  You'll find examples of both in this collection of code that uses the API.  Personally, I tend to use the constructor for utility apps and examples, but there's no profound reason behind it.

If you need to prompt the user for credentials to connect to the server, see the post, How to get the login dialog when using the Team Foundation Server API.  The example uses the constructor, but you can also pass the credential provider to the TeamFoundationServerFactory.GetServer() method.

tags: , ,