Container.Register(Type,Assembly [])不注册通用实现

时间:2015-11-25 09:45:34

标签: c# dependency-injection simple-injector

我有以下界面:

public interface IQuery<TResult>
{
}

public interface IQueryHandler<in TQuery, out TResult> where TQuery : IQuery<TResult>
{
    TResult Handle(TQuery query);
}

我的一个实施查询是:

public class ApplyPermissionSetForUserAndPermissionTypeQuery<TQueryable, TEntity> : IQuery<TQueryable>
    where TQueryable : IQueryable<TEntity>
{
}

和它的处理程序:

public class ApplyPermissionSetForUserAndPermissionTypeHandler<TQueryable, TEntity> : IQueryHandler<ApplyPermissionSetForUserAndPermissionTypeQuery<TQueryable, TEntity>, TQueryable>
    where TQueryable : IQueryable<TEntity>
{
}

在构建我的容器时,我打电话:

container.Register(typeof(IQueryHandler<,>), container.Settings.QueryHandlerAssemblies);

哪个寄存器中的所有类型都已注册,并且已经适用于我的所有其他句柄。问题之一在于查询和处理程序本身包含泛型类型。

我目前在容器上注册了ResolveUnregisteredType事件,执行以下操作:

private void container_ResolveUnregisteredType(object sender, SimpleInjector.UnregisteredTypeEventArgs e)
{
    var serviceType = e.UnregisteredServiceType;

    if (serviceType.IsGenericType &&
        serviceType.GetGenericTypeDefinition() == typeof(IQueryHandler<,>))
    {
        var queryArg = serviceType.GetGenericArguments()[0];
        var resultArg = serviceType.GetGenericArguments()[1];

        if (queryArg.IsGenericType &&
            queryArg.GetGenericTypeDefinition() == typeof(ApplyPermissionSetForUserAndPermissionTypeQuery<,>))
        {
            var itemTypeArgument = queryArg.GetGenericArguments()[0];
            var entityTypeArgument = queryArg.GetGenericArguments()[1];
            if (itemTypeArgument != resultArg)
                return;

            Type typeToRegister;

            try
            {
                 typeToRegister = typeof(ApplyPermissionSetForUserAndPermissionTypeHandler<,>).MakeGenericType(itemTypeArgument, entityTypeArgument);
            }
            catch (ArgumentException)
            {
                // Thrown by MakeGenericType when the type constraints 
                // do not match. In this case, we don't have to register
                // anything and can bail out.
                return;
            }

            //Register a delegate which will return 
            e.Register(delegate () { return GetInstance(typeToRegister); });
            }
        }
    }

这使它工作,所以我知道可以注册类型。这让我相信我错过了一些明显的东西,例如:该类型没有被&#34; container.Register(typeof(IQueryHandler&lt;,&gt;),container.Settings.QueryHandlerAssemblies)&#34;注册。方法

是否有可能使简单的注入器自动注册这种类型,并且我可以只注册程序集,因为我不会一直知道显式类型。例如。程序集列表可以是变量的,并且包含未知查询,因此我无法调用:

container.Register(typeof(IQueryHandler<,>), typeof(IQueryHandler<ApplyPermissionSetForUserAndPermissionTypeQuery<,>,>))

或者我是否必须自己枚举程序集以查找IQueryHandler&lt;,&gt;采用泛型类型并注册它们的类型,或者只是将我的事件处理程序更改为它的自我?

1 个答案:

答案 0 :(得分:3)

Container.Register(Type, Assembly[])方法不会自动注册通用注册,因为您经常希望以不同方式处理通用实现。例如,装饰器通常是通用的,需要以不同的方式处理。

由于您通常只有几个通用实现,因此可以按如下方式明确注册它们:

container.Register(typeof(IQueryHandler<,>), settings.QueryHandlerAssemblies);

container.Register(typeof(IQueryHandler<,>),
    typeof(ApplyPermissionSetForUserAndPermissionTypeHandler<,>));

如果您有许多通用实现并且定期添加新的通用实现,您还可以通过首先调用Container.GetTypesToRegister方法来包含泛型类型定义:

var queryHandlerTypes = container.GetTypesToRegister(typeof(IQueryHandler<,>), 
    settings.QueryHandlerAssemblies,
    new TypesToRegisterOptions { IncludeGenericTypeDefinitions = true });

container.Register(typeof(IQueryHandler<,>), 
    queryHandlerTypes.Where(t => !t.IsGenericTypeDefinition));

foreach (Type type in queryHandlerTypes.Where(t => t.IsGenericTypeDefinition))
{
    container.Register(typeof(IQueryHandler<,>), type);
}

请注意,这可能会在注册时直接失败,因为Simple Injector可能会检测到提供的开放泛型类型与先前进行的非泛型注册重叠。即使它在注册时没有失败,Simple Injector也可能在运行时(或在调用container.Verify()期间)检测到重叠。这就是为什么这个Register重载不接受开放泛型类型的批量注册的主要原因。如果您需要回退行为,请将注册更改为:

foreach (Type type in queryHandlerTypes.Where(t => t.IsGenericTypeDefinition))
{
    container.RegisterConditional(typeof(IQueryHandler<,>), type, c => !c.Handled);
}