2015-08-13 38 views
1

我似乎无法找到一种方法来注册用于Web API集成的程序集或相关类型(基于基类或接口)中的所有类型。例如,我有以下几点:SimpleInjector RegisterAll for 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?如果没有直接支持,是否有办法破解它并实现我所需要的?

+1

你为什么要使用'RegisterAll'? 'RegisterAll'用于注册同一个抽象项目的集合。我没有看到你有相同抽象的多个实现。你想要达到什么目标? – Steven

+0

对不起,如果我让你感到困惑。是的,你是对的我没有同一个抽象的多个实现。问题是“我必须为每个TService执行RegisterWebApiRequest”吗?TImplementation? –

回答

2

我不确定它是否直接支持Simple Injector,但使用.NET Reflection会很容易。

支持代码

注意此代码是通用的 - 它会与任何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项目herehere完整的工作示例。

1

用简单的喷油器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); 
} 
+1

酷!我刚刚看到你最近在nuget上发布了它。我会给它一个镜头。谢谢! –

+0

我试过了,得到这个错误:'为了能够使用Lifestyle.Scoped属性,请通过设置Container.Options.DefaultScopedLifestyle属性为您的类型提供所需的范围生活方式,以确保容器配置了默认的有限生活方式'然后我做了这个'container.Options.DefaultScopedLifestyle = ScopedLifestyle.Scoped;'并给了我这个错误:'DefaultScopedLifestyle不能设置为Lifestyle.Scoped的值。我错过了什么? –

+0

DefaultScopedLifestyle = new WebApiRequestLifestyle(), – Steven