如何使用标准MVC核心依赖注入解决未注册类型
本文关键字:解决 注册 类型 注入 依赖 何使用 标准 MVC 核心 | 更新日期: 2023-09-27 17:54:42
是否有办法让IServiceProvider.GetService<T>
返回一个实例,即使T
没有显式地与容器注册?
如果我知道T
有依赖关系,我希望它们基于它们的注册被注入,而不必注册T
本身。
我相信Ninject会智能地找出最合适的构造函数,或者在没有找到合适的构造函数时回退到无参数构造函数。如果可能的话,我想使用标准MVC Core DI框架复制这种行为。
要保持最新:有一种方法可以实现您正在寻找的东西。
.NET Core的标准依赖注入器
在我的示例中,我为showcase创建了一个新的IServiceCollection实例:var services = new ServiceCollection();
var serviceProvider = services.BuildServiceProvider();
var unregisteredClassInstance =
ActivatorUtilities.CreateInstance<UnregisteredClass>(serviceProvider);
这给了你一个UnregisteredClass类型的实例,它之前没有注册过,但是它接受了之前在ServiceCollection上注册过的构造函数参数。
第三方依赖注入器
SimpleInjector可以通过container.GetInstance<UnregisteredClass>();
.
虽然默认情况下没有提供解析未注册的具体类型的方法,但您可以添加一个扩展函数来提供此功能。需要注意的是,这可能被滥用为服务定位器,这是一种反模式。根据你的使用情况,你可以利用这一点,而不用把它变成一个服务定位器。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceProviderExtensions
{
public static TService AsSelf<TService>(this IServiceProvider serviceProvider)
{
return (TService)AsSelf(serviceProvider, typeof(TService));
}
public static object AsSelf(this IServiceProvider serviceProvider, Type serviceType)
{
var constructors = serviceType.GetConstructors(BindingFlags.Public | BindingFlags.Instance)
.Select(o => o.GetParameters())
.ToArray()
.OrderByDescending(o => o.Length)
.ToArray();
if (!constructors.Any())
{
return null;
}
object[] arguments = ResolveParameters(serviceProvider, constructors);
if (arguments == null)
{
return null;
}
return Activator.CreateInstance(serviceType, arguments);
}
private static object[] ResolveParameters(IServiceProvider resolver, ParameterInfo[][] constructors)
{
foreach (ParameterInfo[] constructor in constructors)
{
bool hasNull = false;
object[] values = new object[constructor.Length];
for (int i = 0; i < constructor.Length; i++)
{
var value = resolver.GetService(constructor[i].ParameterType);
values[i] = value;
if (value == null)
{
hasNull = true;
break;
}
}
if (!hasNull)
{
// found a constructor we can create.
return values;
}
}
return null;
}
}
}
public static T? BuildNoneRegisteredType<T>(this IServiceProvider serviceProvider)
{
var constructor = typeof(T).GetConstructors().First();
var parameters = constructor.GetParameters();
if (parameters is null || parameters.Length < 1)
return Activator.CreateInstance<T>();
var parametersToPas = new object?[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
var a = serviceProvider.GetService(parameters[i].ParameterType);
parametersToPas[i] = a;
}
var obj = Activator.CreateInstance(typeof(T), parametersToPas);
return obj is null ? default : (T)obj;
}
当我有多个数据库并且我不想在解析它们时使用键时,我使用这个。如果我需要mongoDb类型的新数据库,我将这样做:
var myMongoDb = webApp.ServiceProvider.BuildNoneRegisteredType<MongoDb>()