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を使用して作業を行うことができるかどうか疑問に思います.

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;
    }
}
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 に答える