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