I have the following extension method, which exists (naturally) in a static class.
public static class MyExtensions
{
[Dependency]
private static IMyDataContext _myDataContext { get; set; }
public static void MyExtensionMethod(this MyType myType)
{
// do stuff
_myDataContext.DoAwesomeThing();
}
}
the _myDataContext
object is null.
Normally I'd use the UnityContainer
to register the type, but as this is a static class, I can't.
What do I need to instantiate _myDataContext
so that it's not null when I need it?
As you have already mentioned, Unity can't be used to resolve the class due to it being static. There are a few options for this. My personal favorite is using the Abstract Factory pattern. I tend to tweak the pattern just a tad to work well with DI.
The factory typically kind of looks like this:
/// <summary>
/// Creates an IMyDataContext instance
/// </summary>
public static class MyDataContextFactory
{
/// <summary>
/// The factory used to create an instance
/// </summary>
static Func<IMyDataContext> factory;
/// <summary>
/// Initializes the specified creation factory.
/// </summary>
/// <param name="creationFactory">The creation factory.</param>
public static void SetFactory(Func<IMyDataContext> creationFactory)
{
factory = creationFactory;
}
/// <summary>
/// Creates a new IMyDataContext instance.
/// </summary>
/// <returns>Returns an instance of an IMyDataContext </returns>
public static IMyDataContext CreateContext()
{
if (factory == null) throw new InvalidOperationException("You can not create a context without first building the factory.");
return factory();
}
}
In your bootstrap process (where ever you setup your service registrations), you can initialize the factory to resolve your dependency.
MyDataContextFactory.SetFactory(() => this.Container.Resolve<IMyDataContext>());
Now in your extension method, you fetch a context.
public static class MyExtensions
{
public static void MyExtensionMethod(this MyType myType)
{
MyDataContextFactory.CreateContext().DoAwesomeThing();
}
}
Your Unity registration of the context, can handle the various different configurations of the service if there are conditions to resolving it. If there is the possibility that the context can be set by something other than Unity, that owner can just pass in a new delegate that the extension method will use.
I tend to avoid passing the containers themselves in to my factories, as that starts creeping tight-coupling of the containers to my app. If I'm going to pass anything in to the factory, i'd rather it be a factory delegate used to resolve via DI, than to pass the DI container in itself.