c# - 用于 Web Api 的 SimpleInjector RegisterAll

标签 c# dependency-injection simple-injector

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

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 容器,而不仅仅是 Simple Injector。

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 项目的完整工作示例 herehere .

关于c# - 用于 Web Api 的 SimpleInjector RegisterAll,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31979192/

相关文章:

c# - 静态变量的初始化顺序不明确

c# - 如何从 Windows 服务中 FileSystemWatcher 监视的共享文件夹中删除的文件中获取用户名

c# - 如何检查方法是否具有 CaSTLe 拦截器的属性?

javascript - Nest JS 无法解析服务中的依赖关系

c# - FluentValidation DI 将值传递给子验证器

c# - FluentValidation 验证器和简单注入(inject)器,其中验证器作为数组注入(inject)

c# - 面向对象编程 : Separation of Data and Behavior

c# - 使用 SimpleInjector 动态选择具有名称的具体对象

c# - 简单注入(inject)器:跨相同图的服务注入(inject)相同的UnitOfWork实例

C# CS0029 无法将类型 'char' 隐式转换为 'string'