用于 Web 的 SimpleInjector RegisterAll Api

SimpleInjector RegisterAll for Web Api

我似乎找不到一种方法来为 Web API 集成注册程序集中的所有类型或相关类型(基于基础 class 或接口)。例如我有以下内容:

public interface IBaseService { }
public interface IServiceA : IBaseService { }
public interface IServiceB : IBaseService { }
public interface IServiceX { }

public class ServiceA : IServiceA {}
public class ServiceB : IServiceB {}
public class ServiceX : IServiceX {}

// register the types
container.RegisterWebApiRequest<IServiceA, ServiceA >();
// I have to repeat this for all types I have
container.RegisterWebApiRequest<IServiceB, ServiceB >(); 
//
container.RegisterWebApiRequest<IServiceX, ServiceX >();

是否有可用于 Web API 请求的等效 RegisterAll?如果不直接支持,有没有办法破解它并实现我需要的?

我不确定 Simple Injector 是否直接支持它,但使用 .NET 反射相当容易。

支持代码

请注意此代码是通用的 - 它适用于任何 DI 容器,而不仅仅是简单注入器。

internal class CommonConventions
{
    public static void RegisterDefaultConventions(
        Action<Type, Type> registerMethod, 
        Assembly[] interfaceAssemblies, 
        Assembly[] implementationAssemblies, 
        Type[] excludeTypes,
        string excludeRegEx)
    {
        List<Type> interfaces = new List<Type>();

        foreach (var assembly in interfaceAssemblies)
            interfaces.AddRange(GetInterfaces(assembly));

        foreach (var interfaceType in interfaces)
        {
            if (!IsExcludedType(interfaceType, excludeTypes, excludeRegEx))
            {
                List<Type> implementations = new List<Type>();

                foreach (var assembly in implementationAssemblies)
                    implementations.AddRange(GetImplementationsOfInterface(assembly, interfaceType).Where(implementation => !IsExcludedType(implementation, excludeTypes, excludeRegEx)).ToArray());

                // Use the default name ITypeName = TypeName
                Type implementationType = implementations.Where(implementation => IsDefaultType(interfaceType, implementation)).FirstOrDefault();

                if (implementationType != null)
                {
                    System.Diagnostics.Debug.WriteLine("Auto registration of {1} : {0}", interfaceType.Name, implementationType.Name);
                    registerMethod(interfaceType, implementationType);
                }
            }
        }
    }

    private static bool IsExcludedType(Type type, Type[] excludeTypes, string excludeRegEx)
    {
        return IsExcludedType(type, excludeTypes) || IsExcludedType(type, excludeRegEx);
    }

    private static bool IsExcludedType(Type type, Type[] excludeTypes)
    {
        return excludeTypes.Contains(type);
    }

    private static bool IsExcludedType(Type type, string excludeRegEx)
    {
        if (string.IsNullOrEmpty(excludeRegEx)) return false;
        return Regex.Match(type.Name, excludeRegEx, RegexOptions.Compiled).Success;
    }

    private static bool IsDefaultType(Type interfaceType, Type implementationType)
    {
        return interfaceType.Name.Equals("I" + implementationType.Name);
    }

    private static IEnumerable<Type> GetInterfaces(Assembly assembly)
    {
        return assembly.GetTypes().Where(t => t.IsInterface);
    }

    private static IEnumerable<Type> GetImplementationsOfInterface(Assembly assembly, Type interfaceType)
    {
        return assembly.GetTypes().Where(t =>
            !t.IsInterface &&
            !t.IsAbstract &&
            interfaceType.IsAssignableFrom(t) &&
            t.GetConstructors(BindingFlags.Public | BindingFlags.Instance)
                .Any(type => type.GetParameters().Select(p => p.ParameterType).All(p => (p.IsInterface || p.IsClass) && p != typeof(string))));
    }
}

用法

var currentAssembly = typeof(SomeLocalType).Assembly;
var interfaceAssemblies = new Assembly[] { 
    currentAssembly 
    /*, Additional Assemblies */ 
    };
var implementationAssemblies = new Assembly[] { 
    currentAssembly 
    /*, Additional Assemblies */ 
    };
var excludeTypes = new Type[]
{
    // Use this array to add types you wish to explicitly exclude from convention-based  
    // auto-registration. By default all types that either match I[TypeName] = [TypeName] 
    // will be automatically wired up.
    //
    // If you want to override a type that follows the convention, you should add the name 
    // of either the implementation name or the interface that it inherits to this list and 
    // add your manual registration code below. This will prevent duplicate registrations 
    // of the types from occurring. 

    // Example:
    // typeof(SiteMap),
    // typeof(SiteMapNodeVisibilityProviderStrategy)
};

var scopedLifestyle = new WebApiRequestLifestyle();
CommonConventions.RegisterDefaultConventions(
    // This registers with a SimpleInjector container
    (interfaceType, implementationType) => 
        container.Register(interfaceType, implementationType, scopedLifestyle),
    interfaceAssemblies,
    implementationAssemblies,
    excludeTypes,
    string.Empty);

请参阅 MvcSiteMapProvider 项目 here and here 上的完整工作示例。

使用 Simple Injector v3,您可以使用以下代码:

container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();

var implementationTypes = container.GetTypesToRegister(typeof(IBaseService),
    AppDomain.CurrentDomain.GetAssemblies());

foreach (Type implementationType in implementationTypes)
{
    Type serviceType = implementationType.GetInterfaces()
        .Where(i => i != typeof(IBaseService));
        .Single();

    container.Register(serviceType, implementationType, Lifestyle.Scoped);
}