【问题标题】:Autofac and injection of instancesAutofac和实例注入
【发布时间】:2012-12-05 06:26:48
【问题描述】:

在我正在处理的一个 ASP.NET MVC 项目中,我有以下一段代码,它们基本上将实例注入到我的程序集中的特定方法中。

因此,在应用程序根目录中,我有一个类可以像这样注册实例并最终处理注入。

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;
    }
}

【问题讨论】:

    标签: asp.net-mvc ioc-container autofac


    【解决方案1】:

    我希望,我已经正确理解了您。如果您的意思是将类标记为具有属性的依赖项,那么您可以通过创建自定义属性来做到这一点。以下是实现此类属性的示例:

     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);
                }
            }
    
        }
    

    【讨论】:

    • 不,我不想将类标记为具有属性的依赖项,我想注入我创建的实例,使用 Autofac 注册实例并使 Autofac 将实例注入特定方法我用一个属性标记,在我的例子中是“ApplicationServiceProviderAttribute”。
    • 好吧,我想我可以在我的项目中发布我对此的当前解决方案,会有帮助吗?
    • @EyalShilony 是您的目标是将实例注入方法,如注入类构造函数?
    • 是的,这就是我想要做的,但我知道大多数容器都不是为了做到这一点而设计的。
    • 现在,我正在考虑它,我想我知道该怎么做!我太傻了,我可以遍历容器并使用 Resolve 来获取实例...
    猜你喜欢
    • 2016-09-07
    • 2015-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多