1

在我正在处理的 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
{
}

应用服务处理器.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);
    }
}

应用服务提供者.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;
    }
}
4

1 回答 1

0

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

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

    }
于 2012-12-05T07:59:48.853 回答