1

I have a classic bootstrapping problem. I am trying to inject the TFS client libraries for version control into my application, but I need to load different versions of the client library in different situations: the TFS 2013 client libraries cannot connect to TFS 2005 or TFS 2008 servers, so I need to load an earlier version of the client libraries when connecting to these older versions of TFS. I have found that I can reliably determine the version of TFS that I am connecting to by requesting the BuildServerVersion property from the IBuildServer service.

Normally I would solve this problem using an Abstract Factory pattern and use an IoC container to load the appropriate factory implementation; however, normally the decision would be entirely the responsibility of the application. In my situation, the decision is based on the response from the TFS server, and, crucially, I have to load a version of the TFS client library to request that information from the TFS server in the first place.

What approaches can I consider to address this problem?

alastairs
  • 6,697
  • 8
  • 50
  • 64
  • 2
    Can the call to get the BuildServerVersion be made without needing the TFS libraries? If yes, create a small wrapper around that one call – Ian Johnson Jan 29 '14 at 15:31
  • Yes, but: "Microsoft does not provide support for talking directly to the web services. These interfaces may change drastically in the future" (quote from [this answer from an MS employee](http://stackoverflow.com/a/9134693/5296)). – alastairs Jan 29 '14 at 15:47
  • I think that this whole situation that you're in is one big *interfaces change drastically in the future* situation. That's why you have to use different clients against different servers... – Mark Seemann Jan 29 '14 at 16:08
  • Can the different versions of the client libraries exist in the same AppDomain side by side? – Mark Seemann Jan 29 '14 at 16:09
  • @MarkSeemann Yes, I think so: the client libraries have different major versions. It's possible [this assembly binding redirect technique](http://stackoverflow.com/questions/6132652/use-different-versions-of-referenced-dll) might help with this too. – alastairs Jan 29 '14 at 16:23
  • If the server version your application connects to is fixed during the application lifetime, and you can call `IBuildServer.BuildServerVersion` during startup, you can determine the server version before configuring you configure the container and wire the container based on that knowlegde. This removes the need to have a factory, adapter, or anything else. – Steven Mar 02 '14 at 12:37

2 Answers2

3

Since it sounds like it's possible to have multiple versions of the client libraries loaded at the same time, the easiest solution is probably to take a hint from the Interface Segregation Principle. Define a Role Interface with the sole purpose of figuring out the BuildServerVersion.

It might be something like

public interface IBuildServerVersionQuery
{
    Version GetBuildServerVersion();
}

You can then write an Adapter around one of the client libraries and use it to get the BuildServerVersion.

Then, when you have the BuildServerVersion, you can use it to implement an Abstract Factory that returns the real client library.

You can also use one of these selection mechanisms, such as Metadata, Role Interfaces, or (my preferred) Partial Type Name, to select the appropriate client library.

Unless the GetBuildServerVersion() method returns the version corresponding to the client library that implements IBuildServerVersionQuery interface itself, this means that you'll have a (now) redundant client library loaded into the AppDomain, but is that really a problem?

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
1

Can you load a version of the TFS libs in an AppDomain? Then you can make the call, unload the AppDomiain, which will unload the libs, and reload the correct version.

JohnStov
  • 11
  • 1