Validation Autofac注册验证
我正在为大型应用程序构建核心服务,我们从castle windsor切换到autofac。在使用assemly扫描和模块的自动注册方法中,一切正常,但我们有一个最新有趣的案例:一个接口有两个实现,autofac当然会以随机顺序注册它们,从业务角度来看,解决了错误的实现。当然,手动注册可以完成这项工作,但最好在IContainer级别上进行一些验证,至少将每个已注册服务的信息作为输出提供,如果它有多个实现,则应该将它们标记为默认值-这将在使用resolve请求容器时得到解决。其目的是当存在多个可用的但保持自动注册时,强制开发人员注册特定的具体实现。Validation Autofac注册验证,validation,dependency-injection,inversion-of-control,autofac,Validation,Dependency Injection,Inversion Of Control,Autofac,我正在为大型应用程序构建核心服务,我们从castle windsor切换到autofac。在使用assemly扫描和模块的自动注册方法中,一切正常,但我们有一个最新有趣的案例:一个接口有两个实现,autofac当然会以随机顺序注册它们,从业务角度来看,解决了错误的实现。当然,手动注册可以完成这项工作,但最好在IContainer级别上进行一些验证,至少将每个已注册服务的信息作为输出提供,如果它有多个实现,则应该将它们标记为默认值-这将在使用resolve请求容器时得到解决。其目的是当存在多个可用
你找到解决这个问题的方法了吗?
公共静态类AutofacExtensions
public static class AutofacExtensions
{
/// <summary>
/// Checks if one implementation was chosen by developer for every interface
/// </summary>
/// <param name="container"></param>
public static void ValidateRegistrations(this IContainer container)
{
if (container == null)
{
throw new ArgumentNullException(nameof(container));
}
var registrations = GetRegistrations(container);
Validate(registrations);
}
static void Validate(IDictionary<Type, IList<Type>> registrations)
{
foreach (var registration in registrations.OrderBy(x => x.Key.FullName))
{
var unique = registration.Value.Distinct().Count();
if (unique > 1)
{
var all = registration.Value.Count;
if (all <= unique)
{
var currentImplementations = registration.Value.Distinct().Select(x => x.FullName);
var aggregatedImplementations = string.Join(", ", currentImplementations);
throw new InvalidOperationException($"IoC/DI: for type '{registration.Key.FullName}' was not chose default implementation! Registered available implementations: {aggregatedImplementations}");
}
}
}
}
static IDictionary<Type, IList<Type>> GetRegistrations(IContainer container)
{
var registrations = new Dictionary<Type, IList<Type>>();
foreach (var registration in container.ComponentRegistry.Registrations)
{
foreach (var service in registration.Services.OfType<IServiceWithType>().Where(x => x.ServiceType.Namespace != null && x.ServiceType.Namespace.ToLowerInvariant().StartsWith("flb.")))
{
IList<Type> implementations;
if (!registrations.TryGetValue(service.ServiceType, out implementations))
{
implementations = new List<Type>();
registrations[service.ServiceType] = implementations;
}
implementations.Add(registration.Activator.LimitType);
}
}
return registrations;
}
}
{
///
///检查开发人员是否为每个接口选择了一个实现
///
///
公共静态无效验证注册(此IContainer容器)
{
if(容器==null)
{
抛出新ArgumentNullException(nameof(container));
}
var注册=GetRegistrations(容器);
验证(注册);
}
静态无效验证(IDictionary注册)
{
foreach(registrations.OrderBy(x=>x.Key.FullName)中的var注册)
{
var unique=registration.Value.Distinct().Count();
如果(唯一性>1)
{
var all=registration.Value.Count;
如果(全部x.全名);
var aggregateImplements=string.Join(“,”,currentImplements);
抛出新的InvalidOperationException($“IoC/DI:对于类型“{registration.Key.FullName}”,未选择默认实现!已注册的可用实现:{AggregateImplements}”);
}
}
}
}
静态IDictionary GetRegistrations(IContainer容器)
{
var注册=新字典();
foreach(容器中的var注册.ComponentRegistry.Registrations)
{
foreach(registration.Services.OfType()中的var服务,其中(x=>x.ServiceType.Namespace!=null&&x.ServiceType.Namespace.ToLowerInvariant().StartsWith(“flb”))
{
IList实现;
if(!registrations.TryGetValue(service.ServiceType,out实现))
{
实现=新列表();
注册[service.ServiceType]=实现;
}
Add(registration.Activator.LimitType);
}
}
申报注册;
}
}
今天,我向负责维护代码的github开发人员询问了同样的问题,但回答是“它不会包含在基本api中,因为它会对许多核心类产生影响”:(这里有一个提示,至少有两种方法可以构建简单的解决方案:一种是使用反射和访问私有结构和字段,另一种是使用官方api。做你必须做的事情,只要你理解你得到的信息可能不准确,原因如中所述。谢谢Travis,我已经准备好了som对IContainer的一个简单的扩展方法,它可以简单地计算注册数,对于简单的注册,它看起来很有效。我会让我的代码运行一段时间,看看它是否可以管理更复杂的注册。