我正在尝试查看是否有一种方法可以让Autofac解析特定类型的所有实现(IEnumerable<TService>
),返回所有可以成功解析的实现,同时默默地忽略那些失败的实现
在我的一个库中,我定义了一个ICommunicationService
接口,我在其他各个地方实现了该接口。我已经创建了一个“测试床”ASP.NET核心Web服务,我可以用它在其依赖项中获取该接口的所有实现,并允许我测试它们。
当我尝试访问浏览器中的选择页面时,Web服务使用以下查询来查找所有候选项:
var query = from service in container.Resolve<IEnumerable<ICommunicationService>>()
let serviceType = service.GetType()
let serviceAssembly = serviceType.GetTypeInfo().Assembly
let assemblyName = serviceAssembly.GetName().Name
let version = serviceAssembly.GetName().Version.ToString()
select new { service, assemblyName, version };
然而,最近我添加了一种新的“可重启”通信服务,该服务不处理任何通信本身,而是委托其他服务。这使得它不适合作为测试候选者。但是,由于它是公共具体类型,Autofac会尝试(并且失败)解决它:
DependencyResolutionException:找不到任何构造函数 类型上的'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' 'MyCompany.Communications.UsbDevice.RestartableUsbCommunicationService' 可以使用可用的服务和参数调用:不能 解析参数'Int32 vendorId'的构造函数'Void .ctor(Int32, Int32,DelegateServiceFactory, LibUsbDotNet.DeviceNotify.IDeviceNotifier,Serilog.ILogger)'。
我假设任何可以解析的服务都是我要测试的服务(一个直接涉及与设备通信的服务),而那些无法解析的服务是这样的类型,只包装其他服务。
答案 0 :(得分:0)
我已经通过编写下面的方法来解决这个问题,该方法迭代每个公开所需服务类型的注册并尝试依次解决它们。将返回已解析的那些,并且将忽略那些失败的那些。
private static IEnumerable<T> TryResolveCollection<T>(IComponentContext context)
{
bool RegistrationProvidesService(IComponentRegistration registration) =>
registration.Services.OfType<IServiceWithType>().Any(it => it.ServiceType.Name == typeof(T).Name);
var registrations = context.ComponentRegistry.Registrations.Where(RegistrationProvidesService);
var resolvedServices = new HashSet<Type>();
foreach (var registration in registrations)
{
T service;
try
{
service = (T)context.ResolveComponent(registration, Enumerable.Empty<Parameter>());
}
catch (DependencyResolutionException)
{
continue;
}
if (resolvedServices.Add(service.GetType()))
{
yield return service;
}
}
}
这可以很容易地转换为IComponentContext
上的扩展方法,但由于我只需要在一个地方,我只是将它定义为私有方法并使用它如下:
var query = from service in TryResolveCollection<ICommunicationService>(container)
let serviceType = service.GetType()
let serviceAssembly = serviceType.GetTypeInfo().Assembly
let assemblyName = serviceAssembly.GetName().Name
let version = serviceAssembly.GetName().Version.ToString()
select new { service, assemblyName, version };
有趣的是,当我运行它时,它仍然设法解析RestartableUsbCommunicationService
,即使我不知道如果我尝试运行它会发生什么(我不知道它是哪个底层通信服务包装)。