views:

222

answers:

3

We have an app which optionally integrates with TFS, however as the integration is optional I obviously dont want to have all machine need the TFS assemblies as a requirement.

What should I do?

  1. Is it ok for me to reference the TFS libraries in my main assemblies and just make sure that I only reference TFS related objects when I'm using TFS integration.
  2. Alternatively the safer option would be to reference the TFS libraries in some separate "TFSWrapper" assembly:
    • Is it then ok for me to reference that assembly directly (again as long as I'm careful about whatI call)
    • Should I instead be exposing a set of interfaces for my TFSWrapper assembly to implement, and then instantiate those objects using reflection when require.

1 seems risky to me, on the flip side 2b. seems over-the-top - I would essentially be building a plug-in system.

Surely there must be a simpler way?

A: 

A "plug-in" concept may be the way to go, and it may also allow you to (later) extend your application to work with other products than TFS if needed. Option 2a will be just as "risky" (failing when the linked files are missing) as option 1.

You can make an assembly with the required interfaces for your specific purpose, and reference this assembly from both your app and the "TFS plug-in". The latter then provides implementations of your interfaces and uses TFS to perform the operations. The app can dynamically load an assembly and create instances of the plug-in types needed (via Activator etc.) and cast those instances to your interfaces.

In fact, if you make those types inherit from MarshalByRef, you could even load them into another AppDomain and thus make a clean separation of your plugins, and also make them unloadable.

Lucero
+1  A: 

The safest way (i.e. the easiest way to not make a mistake in your application) might be as follows.

Make an interface which abstracts your use of TFS, for example:

interface ITfs
{
  bool checkout(string filename);
}

Write a class which implements this interface using TFS:

class Tfs : ITfs
{
  public bool checkout(string filename)
  {
    ... code here which uses the TFS assembly ...
  }
}

Write another class which implements this interface without using TFS:

class NoTfs : ITfs
{
  public bool checkout(string filename)
  {
    //TFS not installed so checking out is impossible
    return false;
  }
}

Have a singleton somewhere:

static class TfsFactory
{
  public static ITfs instance;

  static TfsFactory()
  {
    ... code here to set the instance
    either to an instance of the Tfs class
    or to an instance of the NoTfs class ...
  }
}

Now there's only one place which needs to be careful (i.e. the TfsFactory constructor); the rest of your code can invoke the ITfs methods of your TfsFactory.instance without knowing whether TFS is installed.

ChrisW
But your saying that its ok if the implementation of the Tfs class lives inside the same assembly?
Kragen
Using the traditional Windows API, if you link to a DLL which doesn't exist on the end-user machine then your executable won't load at all: and so, instead, you need to use explicit LoadLibrary. I'm not certain that I've tested this, but I don't believe that's true anymore of dotNet references to assemblies which don't exist on the end-user machine ... and so it's safe to have those references in your assembly (there'll be a run-time exception only when/if you try to call the non-existent assembly).
ChrisW
+1  A: 

You might look at Managed Extensibility Framework (MEF).

TrueWill
That does look pretty interesting, although possibly a little over the top for what I'm doing at the moment!I'll probably take a look later though.
Kragen