How to use Func in built-in dependency injection

前端 未结 6 684
梦毁少年i
梦毁少年i 2021-02-14 11:17

Using asp.net 5 I\'d like my controller to be injected with a Funcinstead of T

For example:



        
6条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-02-14 11:53

    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);
    

提交回复
热议问题