Dependency injection 如何使用Func<;T>;内置依赖注入
使用Dependency injection 如何使用Func<;T>;内置依赖注入,dependency-injection,asp.net-core,Dependency Injection,Asp.net Core,使用asp.net 5我希望我的控制器被注入Func而不是T 例如: 公共家庭控制器(Func uow) 而不是 公共家庭控制器(Interfaces.IUnitOfWork uow) 内置DI是否有可能,或者我是否被迫移动到外部DI?据我所知,使用ASP.NET Core中的当前默认IoC容器不可能延迟此类依赖项。反正我也没能让它工作 要延迟此类依赖项的初始化,您需要实现一个功能更丰富的现有IoC容器。Func默认情况下不会注册或解析,但没有任何东西阻止您自己注册它 e、 g servic
asp.net 5
我希望我的控制器被注入Func
而不是T
例如:
公共家庭控制器(Func uow)
而不是
公共家庭控制器(Interfaces.IUnitOfWork uow)
内置DI是否有可能,或者我是否被迫移动到外部DI?据我所知,使用ASP.NET Core中的当前默认IoC容器不可能延迟此类依赖项。反正我也没能让它工作 要延迟此类依赖项的初始化,您需要实现一个功能更丰富的现有IoC容器。
Func
默认情况下不会注册或解析,但没有任何东西阻止您自己注册它
e、 g
services.AddSingleton(提供者=>
新建Func(()=>provider.GetService());
请注意,您还需要以通常的方式注册IUnitOfWork本身。您可以向
服务集合注册Func
或委托。我建议使用委托,因为它允许您区分具有相同签名的不同方法
这里有一个例子
public interface IThingINeed {}
public class ThingINeed : IThingINeed { }
public delegate IThingINeed ThingINeedFactory();
public class DelegateRegistrationTests
{
[Test]
public void RegisterDelegateFromDependency()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IThingINeed, ThingINeed>();
serviceCollection.AddTransient<ThingINeedFactory>(
provider => provider.GetService<IThingINeed>);
var serviceProvider = serviceCollection.BuildServiceProvider();
var factoryMethod = serviceProvider.GetService<ThingINeedFactory>();
var output = factoryMethod();
Assert.IsInstanceOf<ThingINeed>(output);
}
}
公共接口需要{}
公共类ThingIdeed:ItingIdeed{}
公共委托i需要ThingINeedFactory();
公共类委派注册测试
{
[测试]
公共无效RegisterDelegateFromDependency()
{
var servicecolection=新servicecolection();
serviceCollection.AddTransient();
serviceCollection.AddTransient(
provider=>provider.GetService);
var serviceProvider=servicecolection.BuildServiceProvider();
var factoryMethod=serviceProvider.GetService();
var输出=factoryMethod();
Assert.IsInstanceOf(输出);
}
}
这看起来几乎像一个服务定位器,因为我们正在解析的函数实际上是IServiceCollection.GetService()
。但这隐藏在构图的根中。注入此委托的类取决于委托,而不是实现
如果要返回的方法属于容器必须解析的类,则可以使用相同的方法
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<IThingINeed, ThingINeed>();
serviceCollection.AddSingleton<ThingINeedFactory>();
serviceCollection.AddSingleton<ThingINeedFactoryMethod>(provider =>
provider.GetService<ThingINeedFactory>().Create);
var serviceProvider = serviceCollection.BuildServiceProvider();
var factoryMethod = serviceProvider.GetService<ThingINeedFactoryMethod>();
var created = factoryMethod("abc");
var greeting = created.SayHello();
Assert.AreEqual("abc", greeting);
}
}
需要的公共接口
{
字符串SayHello();
}
公共类ThingIdeed:我需要
{
私有只读字符串\u;
公共物品需求(字符串问候语)
{
_问候=问候;
}
公共字符串SayHello()=>\u问候语;
}
公营物流工厂
{
公共IThingIdemand创建(字符串输入)=>新的ThingIdemand(输入);
}
公共委托i需要ThingINeedFactoryMethod(字符串输入);
公共类委派注册测试
{
[测试]
公共无效RegisterDelegateFromDependency()
{
var servicecolection=新servicecolection();
serviceCollection.AddSingleton();
serviceCollection.AddSingleton();
serviceCollection.AddSingleton(提供程序=>
provider.GetService().Create);
var serviceProvider=servicecolection.BuildServiceProvider();
var factoryMethod=serviceProvider.GetService();
创建的风险值=工厂法(“abc”);
var greeting=created.SayHello();
主张平等(“abc”,问候语);
}
}
这里有一个扩展方法(可能)让它变得更简单:
public static class ServiceCollectionExtensions
{
public static IServiceCollection RegisterDelegate<TSource, TDelegate>(
this IServiceCollection serviceCollection,
Func<TSource, TDelegate> getDelegateFromSource)
where TDelegate : class
{
return serviceCollection.AddSingleton(provider =>
getDelegateFromSource(provider.GetService<TSource>()));
}
}
serviceCollection
.RegisterDelegate<ThingINeedFactory, ThingINeedFactoryMethod>(
factory => factory.Create);
公共静态类ServiceCollectionExtensions
{
公共静态IServiceCollection RegisterDelegate(
此IServiceCollection服务集合,
Func getDelegateFromSource)
TDelegate:类在哪里
{
返回serviceCollection.AddSingleton(提供程序=>
getDelegateFromSource(provider.GetService());
}
}
服务集合
.RegisterDelegate(
factory=>factory.Create);
虽然.net core的默认依赖项注入中没有内置的Func构建支持,但我们可以构建一个扩展方法来添加所有缺少的Func。我们只需要确保在注册结束时打电话
public static class ServiceCollectionExtensions
{
private static MethodInfo GetServiceMethod;
static ServiceCollectionExtensions()
{
Func<IServiceProvider, object> getServiceMethod = ServiceProviderServiceExtensions.GetService<object>;
GetServiceMethod = getServiceMethod.Method.GetGenericMethodDefinition();
}
/// <summary>
/// Registers all Funcs in constructors to the ServiceCollection - important to call after all registrations
/// </summary>
/// <param name="collection"></param>
/// <returns></returns>
public static IServiceCollection AddFactories(this IServiceCollection collection)
{
// Get a list of all Funcs used in constructors of regigstered types
var funcTypes = new HashSet<Type>(collection.Where(x => x.ImplementationType != null)
.Select(x => x.ImplementationType)
.SelectMany(x => x.GetConstructors(BindingFlags.Public | BindingFlags.Instance))
.SelectMany(x => x.GetParameters())
.Select(x => x.ParameterType)
.Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(Func<>)));
// Get a list of already registered Func<> and remove them from the hashset
var registeredFuncs = collection.Select(x => x.ServiceType)
.Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(Func<>));
funcTypes.ExceptWith(registeredFuncs);
// Each func build the factory for it
foreach (var funcType in funcTypes)
{
var type = funcType.GetGenericArguments().First();
collection.AddTransient(funcType, FuncBuilder(type));
}
return collection;
}
/// <summary>
/// This build expression tree for a func that is equivalent to
/// Func<IServiceProvider, Func<TType>> factory = serviceProvider => new Func<TType>(serviceProvider.GetService<TType>);
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static Func<IServiceProvider, object> FuncBuilder(Type type)
{
var serviceProvider = Expression.Parameter(typeof(IServiceProvider), "serviceProvider");
var method = GetServiceMethod.MakeGenericMethod(type);
var call = Expression.Call(method, serviceProvider);
var returnType = typeof(Func<>).MakeGenericType(type);
var returnFunc = Expression.Lambda(returnType, call);
var func = Expression.Lambda(typeof(Func<,>).MakeGenericType(typeof(IServiceProvider), returnType), returnFunc, serviceProvider);
var factory = func.Compile() as Func<IServiceProvider, object>;
return factory;
}
}
公共静态类ServiceCollectionExtensions
{
私有静态MethodInfo GetServiceMethod;
静态ServiceCollectionExtensions()
{
Func getServiceMethod=ServiceProviderServiceExtensions.GetService;
GetServiceMethod=GetServiceMethod.Method.GetGenericMethodDefinition();
}
///
///将构造函数中的所有函数注册到ServiceCollection-在所有注册后调用很重要
///
///
///
公共静态IServiceCollection AddFactorys(此IServiceCollection集合)
{
//获取regigstered类型的构造函数中使用的所有函数的列表
var funcTypes=newhashset(collection.Where(x=>x.ImplementationType!=null)
.选择(x=>x.ImplementationType)
.SelectMany(x=>x.GetConstructors(BindingFlags.Public | BindingFlags.Instance))
.SelectMany(x=>x.GetParameters())
.选择(x=>x.ParameterType)
其中(x=>x.IsGenericType&&x.GetGenericTypeDefinition()==typeof(Func));
//获取已注册Func的列表,并将其从哈希集中删除
var registeredFuncs=collection.Select(x=>x.ServiceType)
其中(x=>x.IsGenericType&&x.GetGenericTypeDefinition()==typeof(Func));
funcTypes.ExceptWith(registeredFuncs);
//每个func都为其建立工厂
foreach(funcTypes中的var funcType)
{
var type=funcType.GetGenericArguments().First();
AddTransient(funcType,FuncBuilder(type));
}
回收;
}
///
///此func的生成表达式树等效于
///Func factory=serviceProvider=>newfunc(serviceProvider.GetService);
///
///
///
专用静态Func FuncBuilder(类型)
{
变量
public static class ServiceCollectionExtensions
{
private static MethodInfo GetServiceMethod;
static ServiceCollectionExtensions()
{
Func<IServiceProvider, object> getServiceMethod = ServiceProviderServiceExtensions.GetService<object>;
GetServiceMethod = getServiceMethod.Method.GetGenericMethodDefinition();
}
/// <summary>
/// Registers all Funcs in constructors to the ServiceCollection - important to call after all registrations
/// </summary>
/// <param name="collection"></param>
/// <returns></returns>
public static IServiceCollection AddFactories(this IServiceCollection collection)
{
// Get a list of all Funcs used in constructors of regigstered types
var funcTypes = new HashSet<Type>(collection.Where(x => x.ImplementationType != null)
.Select(x => x.ImplementationType)
.SelectMany(x => x.GetConstructors(BindingFlags.Public | BindingFlags.Instance))
.SelectMany(x => x.GetParameters())
.Select(x => x.ParameterType)
.Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(Func<>)));
// Get a list of already registered Func<> and remove them from the hashset
var registeredFuncs = collection.Select(x => x.ServiceType)
.Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(Func<>));
funcTypes.ExceptWith(registeredFuncs);
// Each func build the factory for it
foreach (var funcType in funcTypes)
{
var type = funcType.GetGenericArguments().First();
collection.AddTransient(funcType, FuncBuilder(type));
}
return collection;
}
/// <summary>
/// This build expression tree for a func that is equivalent to
/// Func<IServiceProvider, Func<TType>> factory = serviceProvider => new Func<TType>(serviceProvider.GetService<TType>);
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static Func<IServiceProvider, object> FuncBuilder(Type type)
{
var serviceProvider = Expression.Parameter(typeof(IServiceProvider), "serviceProvider");
var method = GetServiceMethod.MakeGenericMethod(type);
var call = Expression.Call(method, serviceProvider);
var returnType = typeof(Func<>).MakeGenericType(type);
var returnFunc = Expression.Lambda(returnType, call);
var func = Expression.Lambda(typeof(Func<,>).MakeGenericType(typeof(IServiceProvider), returnType), returnFunc, serviceProvider);
var factory = func.Compile() as Func<IServiceProvider, object>;
return factory;
}
}
// Add to your Service Collection.
services.AddTransient(typeof(Lazy<>), typeof(LazyServiceFactory<>));
class LazyServiceFactory<T> : Lazy<T>
{
public LazyServiceFactory(IServiceProvider serviceProvider)
: base(() => serviceProvider.GetRequiredService<T>())
{
}
}
// And some tests...
[TestMethod]
[DataTestMethod]
[DataRow(ServiceLifetime.Transient)]
[DataRow(ServiceLifetime.Scoped)]
[DataRow(ServiceLifetime.Singleton)]
public void Resolve_GivenLazyilyRegisteredService_CanResolve(ServiceLifetime serviceLifetime)
{
// Arrange
IServiceProvider serviceProvider = CreateServiceProvider(serviceLifetime);
using IServiceScope scope = serviceProvider.CreateScope();
// Act
Func<Lazy<ClassHello>> result = () => scope.ServiceProvider.GetRequiredService<Lazy<ClassHello>>();
// Assert
result
.Should()
.NotThrow()
.And
.Subject()
.Value
.Should()
.NotBeNull();
}
static IServiceProvider CreateServiceProvider(ServiceLifetime serviceLifetime)
{
IServiceCollection services = new ServiceCollection();
services.Add(new ServiceDescriptor(typeof(Lazy<>), typeof(LazyServiceFactory<>), serviceLifetime));
services.Add(new ServiceDescriptor(typeof(ClassHello), typeof(ClassHello), serviceLifetime));
return services.BuildServiceProvider(true);
}