Using asp.net 5
I\'d like my controller to be injected with a Func
instead of T
For example:
You can register a Func
or a delegate with a ServiceCollection
. I recommend a delegate because it allows you to distinguish between different methods with identical signatures.
Here's an example.
public interface IThingINeed {}
public class ThingINeed : IThingINeed { }
public delegate IThingINeed ThingINeedFactory();
public class DelegateRegistrationTests
{
[Test]
public void RegisterDelegateFromDependency()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient();
serviceCollection.AddTransient(
provider => provider.GetService);
var serviceProvider = serviceCollection.BuildServiceProvider();
var factoryMethod = serviceProvider.GetService();
var output = factoryMethod();
Assert.IsInstanceOf(output);
}
}
This almost looks like a service locator because the function we're resolving is actually IServiceCollection.GetService
. But that's hidden in the composition root. A class that injects this delegate depends on the delegate, not on the implementation.
You can use the same approach if the method you want to return belongs to a class that the container must resolve.
public interface IThingINeed
{
string SayHello();
}
public class ThingINeed : IThingINeed
{
private readonly string _greeting;
public ThingINeed(string greeting)
{
_greeting = greeting;
}
public string SayHello() => _greeting;
}
public class ThingINeedFactory
{
public IThingINeed Create(string input) => new ThingINeed(input);
}
public delegate IThingINeed ThingINeedFactoryMethod(string input);
public class DelegateRegistrationTests
{
[Test]
public void RegisterDelegateFromDependency()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton();
serviceCollection.AddSingleton();
serviceCollection.AddSingleton(provider =>
provider.GetService().Create);
var serviceProvider = serviceCollection.BuildServiceProvider();
var factoryMethod = serviceProvider.GetService();
var created = factoryMethod("abc");
var greeting = created.SayHello();
Assert.AreEqual("abc", greeting);
}
}
Here's an extension method to (maybe) make it a little bit easier:
public static class ServiceCollectionExtensions
{
public static IServiceCollection RegisterDelegate(
this IServiceCollection serviceCollection,
Func getDelegateFromSource)
where TDelegate : class
{
return serviceCollection.AddSingleton(provider =>
getDelegateFromSource(provider.GetService()));
}
}
serviceCollection
.RegisterDelegate(
factory => factory.Create);