C# 如何在 AutoFac 中使用属性注入?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15600440/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use Property Injection with AutoFac?
提问by The Light
In a Console application, I'm using Log4Net and in the Main method I'm getting the logger object. Now, I'd like to make this log object available in all my classes by letting all the classes inherit from a BaseClass which has a ILog property and is supposed to be set by Property Injection rather than Constructor Injection.
在控制台应用程序中,我使用的是 Log4Net,而在 Main 方法中,我正在获取记录器对象。现在,我想让所有类都从具有 ILog 属性的 BaseClass 继承并应该通过属性注入而不是构造函数注入来设置,从而使这个日志对象在我的所有类中可用。
I'm using AutoFac IoC container, how to inject my log Object to the Log property of my every class?
我正在使用 AutoFac IoC 容器,如何将我的日志对象注入每个类的 Log 属性?
What's the best/easiest way to achieve this?
实现这一目标的最佳/最简单的方法是什么?
Is there any way to automatically resolve types?
有没有办法自动解析类型?
Below is my test application:
以下是我的测试应用程序:
namespace ConsoleApplication1
{
class Program
{
static ILog Log;
static IContainer Container;
static void Main(string[] args)
{
InitializeLogger();
InitializeAutoFac();
// the below works but could it be done automatically (without specifying the name of each class)?
Product.Log = Container.Resolve<ILog>();
// tried below but didn't inject ILog object into the Product
Container.Resolve<Product>();
RunTest();
Console.ReadLine();
}
private static void RunTest()
{
var product = new Product();
product.Do();
}
private static void InitializeAutoFac()
{
var builder = new ContainerBuilder();
builder.Register(c => Log).As<ILog>();
builder.RegisterType<Product>().PropertiesAutowired();
Container = builder.Build();
}
private static void InitializeLogger()
{
log4net.Config.XmlConfigurator.Configure();
Log = LogManager.GetLogger("LoggerName");
}
}
public class Product
{
public static ILog Log { get; set; }
public void Do()
{
// this throws exception because Log is not set
Log.Debug("some Debug");
}
}
}
回答by cuongle
Use Property Injection:
使用属性注入:
builder.Register(c => LogManager.GetLogger("LoggerName"))
.As<ILog>();
builder.RegisterType<CustomClass>()
.PropertiesAutowired();
回答by Naresh Mittal
Property injection works for Propertiesand not for Fields. In your class, Log is a field and not a property and hence it will never get resolved by the Autofac.
属性注入适用于Properties而不适用于Fields。在您的课程中,Log 是一个字段而不是一个属性,因此它永远不会被 Autofac 解析。
回答by Hans Leautaud
In my opinion the solution Ninject createdis much nicer than the propertyinjectionin Autofac. Therefore I created a a custom attribute which is a postsharp aspect which automatically injects my classes:
在我看来,Ninject创建的解决方案比Autofac 中的propertyinjection好得多。因此,我创建了一个自定义属性,它是一个 postsharp 方面,它会自动注入我的类:
[AutofacResolve]
public IStorageManager StorageManager { get; set; }
My aspect:
我的方面:
[Serializable]
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class AutofacResolveAttribute : LocationInterceptionAspect
{
public override void OnGetValue(LocationInterceptionArgs args)
{
args.ProceedGetValue();
if (!args.Location.LocationType.IsInterface) return;
if ( args.Value != null )
{
args.Value = DependencyResolver.Current.GetService(args.Location.LocationType);
args.ProceedSetValue();
}
}
}
I know the answer on the question is already given but I thought this was a really neat way of solving automatic property injection in Autofac. Maybe it'll be useful to somebody in the future.
我知道这个问题的答案已经给出,但我认为这是在 Autofac 中解决自动属性注入的一种非常巧妙的方法。也许将来对某人有用。
回答by Morten Holmgaard
I didn't want to use postsharp so I made a quick solution, but it doesn't auto inject. I am new to Autofac, and it should be possible to build on to this solution.
我不想使用 postsharp,所以我做了一个快速的解决方案,但它不会自动注入。我是 Autofac 的新手,应该可以在此解决方案的基础上进行构建。
[Serializable]
[AttributeUsage(AttributeTargets.Property)]
public class AutofacResolveAttribute : Attribute
{
}
public class AutofactResolver
{
/// <summary>
/// Injecting objects into properties marked with "AutofacResolve"
/// </summary>
/// <param name="obj">Source object</param>
public static void InjectProperties(object obj)
{
var propertiesToInject = obj.GetType().GetProperties()
.Where(x => x.CustomAttributes.Any(y => y.AttributeType.Name == nameof(AutofacResolveAttribute))).ToList();
foreach (var property in propertiesToInject)
{
var objectToInject = Autofact.SharedContainer.Resolve(property.PropertyType);
property.SetValue(obj, objectToInject, null);
}
}
}
Use it with this call:
与此调用一起使用它:
AutofactResolver.InjectProperties(sourceObject);
回答by Shahar Shokrani
Use Property Injection(In addition to @cuongle answer).
使用属性注入(除了@cuongle 答案)。
Option 1:
选项1:
builder.Register(c => LogManager.GetLogger("LoggerName")).As<ILog>();
builder.RegisterType<Product>()
.WithProperty("Log", LogManager.GetLogger("LoggerName"));
Option 2:
选项 2:
Or you can add a SetLog
method to the Product
class:
或者你可以SetLog
在Product
类中添加一个方法:
public class Product
{
public static ILog Log { get; set; }
public SetLog(Log log)
{
this.Log = log;
}
}
This way you won't have to call LogManager.GetLogger("LoggerName")
twice but to use the context of the builder in order to resolve the Log
.
这样您就不必LogManager.GetLogger("LoggerName")
两次调用,而是使用构建器的上下文来解析Log
.
builder.Register(c => LogManager.GetLogger("LoggerName")).As<ILog>();
builder.Register(c =>
var product = new Product();
product.SetLog(c.Resolve<Log>());
return product;
);
Option 3:
选项 3:
Use the OnActvated:
使用OnActvated:
The OnActivated event is raised once a component is fully constructed. Here you can perform application-level tasks that depend on the component being fully constructed - these should be rare.
一旦完全构造了组件,就会引发 OnActivated 事件。在这里,您可以执行依赖于完全构建的组件的应用程序级任务 - 这些应该很少见。
builder.RegisterType<Product>()
.OnActivated((IActivatedEventArgs<Log> e) =>
{
var product = e.Context.Resolve<Parent>();
e.Instance.SetParent(product);
});
These options gives more control, and you will not have to worry about @steven comment:
这些选项提供了更多控制,您不必担心@steven 评论:
The scary thing with PropertiesAutowired however is that it does implicit property injection, which means that any unresolvable dependencies will be skipped. This makes it easy to miss configuration errors and can result in application that fails at runtime
然而,PropertiesAutowired 的可怕之处在于它进行了隐式属性注入,这意味着将跳过任何无法解析的依赖项。这使得很容易错过配置错误,并可能导致应用程序在运行时失败