2012-12-05 96 views
1

在我正在開發的ASP.NET MVC項目中,我有下面這段代碼,它基本上將實例注入我的程序集中的特定方法。Autofac和實例注入

因此,在應用程序根目錄中,我有一個類來註冊像這樣的實例,並最終處理注入。

ApplicationServiceProvider serviceProvider = ApplicationServiceProvider.CreateDefaultProvider(); 
serviceProvider.RegisterInstance(GlobalConfiguration.Configuration); 
serviceProvider.RegisterInstance(GlobalFilters.Filters); 
serviceProvider.RegisterInstance(RouteTable.Routes); 
serviceProvider.RegisterInstance(BundleTable.Bundles); 
serviceProvider.Distribute(); 

現在,當我想從組件訪問這些情況下,我要創建一些處理程序(方法),並具有以下屬性'ApplicationServiceHandler就像在下面的例子中對它進行標記。

[ContractVerification(false)] 
public static class RouteConfiguration 
{ 
    [ApplicationServiceHandler] 
    public static void Register(RouteCollection routes) 
    { 
    } 
} 

這是這是目前工作還算不錯的項目擴展層的一部分。

現在,我是新來的Autofac,我想知道我是否可以使用Autofac爲我完成這項工作,而不是使用我自己的實現(我在下面提供),可能效率較低,處理的案例少已經被Autofac覆蓋。

我注意到Autofac有一個RegisterInstance方法,但我不知道如何告訴它將實例注入用'ApplicationServiceHandler'屬性標記的方法,我不確定它甚至是正確的方法,但基於名稱它似乎是正確的。

非常感謝任何形式的幫助,謝謝。

編輯:下面是我使用的代碼,在我的項目中沒有Autofac的情況下實現這一點。

ApplicationServiceHandlerAttribute.cs

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 
public sealed class ApplicationServiceHandlerAttribute : Attribute 
{ 
} 

ApplicationServiceHandler.cs

public sealed class ApplicationServiceHandler 
{ 
    private readonly MethodInfo _method; 

    private readonly object[] _args; 

    public ApplicationServiceHandler(MethodInfo method, object[] args) 
    { 
     Contract.Requires(method != null); 
     Contract.Requires(args != null); 

     _method = method; 

     _args = args; 
    } 

    public void Invoke() 
    { 
     _method.Invoke(null, _args); 
    } 

    [ContractInvariantMethod] 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")] 
    private void ObjectInvariant() 
    { 
     Contract.Invariant(_method != null); 
     Contract.Invariant(_args != null); 
    } 
} 

ApplicationServiceProvider.cs

public sealed class ApplicationServiceProvider 
{ 
    private readonly IEnumerable<Assembly> _assemblies; 

    private readonly Dictionary<Type, object> _instances; 

    public ApplicationServiceProvider(IEnumerable<Assembly> assemblies) 
    { 
     Contract.Requires(assemblies != null); 

     _assemblies = assemblies; 

     _instances = new Dictionary<Type, object>(); 
    } 

    public static ApplicationServiceProvider CreateDefaultProvider() 
    { 
     Contract.Ensures(Contract.Result<ApplicationServiceProvider>() != null); 

     return new ApplicationServiceProvider(PackageLoader.ReferencedAssemblies); 
    } 

    public void Distribute() 
    { 
     foreach (var handler in GetHandlers()) 
     { 
      Contract.Assume(handler != null); 

      handler.Invoke(); 
     } 
    } 

    public IEnumerable<ApplicationServiceHandler> GetHandlers() 
    { 
     Contract.Ensures(Contract.Result<IEnumerable<ApplicationServiceHandler>>() != null); 

     if (_instances.Count == 0) 
     { 
      yield break; 
     } 

     foreach (var asm in _assemblies) 
     { 
      IEnumerable<MethodInfo> methods = GetMethods(asm); 

      foreach (var method in methods) 
      { 
       ParameterInfo[] @params = method.GetParameters(); 

       if (@params.Length > 0) 
       { 
        int instanceCount = 0; 

        object[] args = new object[@params.Length]; 

        for (int i = 0; i < @params.Length; i++) 
        { 
         ParameterInfo param = @params[i]; 

         var instance = GetInstance(param); 

         if (instance != null) 
         { 
          instanceCount++; 

          args[i] = instance; 
         } 
        } 

        if (instanceCount > 0) 
        { 
         yield return new ApplicationServiceHandler(method, args); 
        } 
       } 
      } 
     } 
    } 

    public bool RegisterInstance(object instance) 
    { 
     Contract.Requires(instance != null); 

     return AddInstance(instance); 
    } 

    private static ApplicationServiceHandlerAttribute GetApplicationServiceHandlerAttribute(MethodInfo method) 
    { 
     ApplicationServiceHandlerAttribute attribute = null; 

     try 
     { 
      attribute = method.GetCustomAttribute<ApplicationServiceHandlerAttribute>(false); 
     } 
     catch (TypeLoadException) 
     { 
      // We don't need to do anything here for now. 
     } 

     return attribute; 
    } 

    private static IEnumerable<Type> GetDefinedTypes(Assembly assembly) 
    { 
     Contract.Requires(assembly != null); 
     Contract.Ensures(Contract.Result<IEnumerable<Type>>() != null); 

     try 
     { 
      return assembly.DefinedTypes; 
     } 
     catch (ReflectionTypeLoadException ex) 
     { 
      return ex.Types.Where(type => type != null); 
     } 
    } 

    /// <summary> 
    /// Gets the methods that are marked with <see cref="ApplicationServiceHandlerAttribute"/> from the assembly. 
    /// </summary> 
    /// <remarks> 
    /// Eyal Shilony, 21/11/2012. 
    /// </remarks> 
    /// <param name="assembly"> 
    /// The assembly. 
    /// </param> 
    /// <returns> 
    /// The methods that are marked with <see cref="ApplicationServiceHandlerAttribute"/> from the assembly. 
    /// </returns> 
    private static IEnumerable<MethodInfo> GetMethods(Assembly assembly) 
    { 
     Contract.Requires(assembly != null); 
     Contract.Ensures(Contract.Result<IEnumerable<MethodInfo>>() != null); 

     const TypeAttributes STATIC_TYPE_ATTRIBUTES = TypeAttributes.AutoLayout | TypeAttributes.AnsiClass | TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit; 

     var methods = (from type in GetDefinedTypes(assembly) 
         where type.Attributes == STATIC_TYPE_ATTRIBUTES 
         from method in type.GetMethods().AsParallel() 
         where GetApplicationServiceHandlerAttribute(method) != null 
         select method).ToArray(); 

     return methods; 
    } 

    private bool AddInstance(object instance) 
    { 
     Type type = instance.GetType(); 

     return AddInstance(type, instance); 
    } 

    private bool AddInstance(Type type, object instance) 
    { 
     if (!_instances.ContainsKey(type)) 
     { 
      _instances.Add(type, instance); 

      return true; 
     } 

     return false; 
    } 

    private object GetInstance(ParameterInfo param) 
    { 
     object instance = null; 

     Type paramType = param.ParameterType; 

     if (_instances.ContainsKey(paramType)) 
     { 
      instance = _instances[paramType]; 
     } 
     else 
     { 
      foreach (var type in _instances.Keys.Where(type => type.IsSubclassOf(paramType))) 
      { 
       instance = _instances[type]; 

       break; 
      } 
     } 

     return instance; 
    } 
} 

回答

0

我希望,我已經明白你correctly.if你的意思是標誌着一個什麼類作爲與屬性的依賴關係,那麼你可以通過crea來完成婷定製attribute.following是實現這種屬性的例子:

public class DependencyAttribute : Attribute 
    { 
     public DependencyAttribute() 
     { 

     } 

     //The type of service the attributed class represents 
     public Type ServiceType { get; set; } 

     //Optional key to associate with the service 
     public string Key { get; set; } 

     public virtual void RegisterService(AttributeInfo<DependencyAttribute> attributeInfo, IContainer container) 
     { 
      Type serviceType = attributeInfo.Attribute.ServiceType ?? attributeInfo.DecoratedType; 
      Containerbuilder builder = new ContainerBuilder(); 
      builder.RegisterType(attributeInfo.DecoratedType).As(serviceType).Keyed(
             attributeInfo.Attribute.Key ?? attributeInfo.DecoratedType.FullName); 
      builder.Update(container) 
     } 
    } 

那麼你就必須找到標有此屬性的所有類型和調用這些屬性的RegisterService方法。

public class DependencyAttributeRegistrator 
    { 
     public DependencyAttributeRegistrator() 
     { 

     } 

     public IEnumerable<AttributeInfo<DependencyAttribute>> FindServices() 
     { 
      //replace this line with you'r own 
      var types = Assembly.GetExecutingAssembly().GetTypes(); 
      foreach (Type type in types) 
      { 
       var attributes = type.GetCustomAttributes(typeof(DependencyAttribute), false); 
       foreach (DependencyAttribute attribute in attributes) 
       { 
        yield return new AttributeInfo<DependencyAttribute> { Attribute = attribute, DecoratedType = type }; 
       } 
      } 
     } 

     public void RegisterServices(IEnumerable<AttributeInfo<DependencyAttribute>> services) 
     { 
      foreach (var info in services) 
      { 
       //replace following two line with you'r own global container 
       var builder = new ContainerBuilder(); 
       IContainer container = builder.Build(); 
       info.Attribute.RegisterService(info, container); 
      } 
     } 

    } 
+0

不,我不想要標記一個類爲依賴與屬性,我想注入,我做了一個實例,使用Autofac註冊實例,使Autofac注入實例具體方法,我標記一個屬性,在我的情況'ApplicationServiceProviderAttribute'。 –

+0

你能提供一個類似代碼的例子嗎? –

+0

嗯,我想我可以在我的項目中發佈當前的解決方案,對它有幫助嗎? –