私が取り組んでいる 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;
}
}