在 autofac 中使用模块和配置文件
虽然我通常认为 Autofac 文档(在 wiki 上)很有帮助,但关于 XML 配置和模块的部分对我来说有点不清楚。现在,我有一个示例工作(我在下面介绍),但我不确定它是否代表了 Autofac 上下文中的一种混蛋配置方法。特别是,我不确定配置文件和代码文件中是否有更多或更少的我真正需要的内容。
这是代码:
using System;
using System.IO;
using Autofac;
using Autofac.Configuration;
namespace AutofacTest.Animals
{
interface IAnimal
{
void Speak ( );
}
abstract class Animal : IAnimal
{
protected TextWriter Writer
{
get;
private set;
}
protected Animal ( TextWriter writer )
{
this.Writer = writer;
}
public abstract void Speak ( );
}
class Dog : Animal
{
public Dog ( TextWriter writer )
: base ( writer )
{
}
public override void Speak ( )
{
this.Writer.WriteLine ( "Arf!" );
}
}
class Cat : Animal
{
public Cat ( TextWriter writer )
: base ( writer )
{
}
public override void Speak ( )
{
this.Writer.WriteLine ( "Meow" );
}
}
// In actual practice, this would be in a separate assembly, right?
class AnimalModule : Module
{
protected override void Load ( ContainerBuilder builder )
{
builder.RegisterInstance ( Console.Out ).As<TextWriter> ( ).SingleInstance ( );
builder.Register ( d => new Dog ( d.Resolve<TextWriter> ( ) ) ).As<IAnimal> ( );
}
}
class Program
{
static void Main ( )
{
Console.ForegroundColor = ConsoleColor.Yellow;
ContainerBuilder builder = new ContainerBuilder ( );
ConfigurationSettingsReader reader = new ConfigurationSettingsReader();
builder.RegisterModule ( reader );
//builder.RegisterModule ( new AnimalModule ( ) );
builder.Build ( ).Resolve<IAnimal> ( ).Speak ( );
Console.ReadKey ( );
}
}
}
这是一个关联的配置文件:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
</configSections>
<autofac defaultAssembly="AutofacTest">
<components>
<component
type="AutofacTest.Animals.Cat"
service="AutofacTest.Animals.IAnimal" />
<component type="System.IO.StreamWriter" service="System.IO.TextWriter">
<parameters>
<parameter name="path" value="C:\AutofacTest.txt"/>
<parameter name="append" value="false" />
</parameters>
<properties>
<property name="AutoFlush" value="true" />
</properties>
</component>
</components>
<modules>
<module type="AutofacTest.Animals.AnimalModule, AutofacTest"/>
</modules>
</autofac>
</configuration>
这一切都工作正常。应用程序将“Meow”输出到文本文件。如果我注释掉组件元素,应用程序会输出“Arf!”到控制台。
那么,这里一切都好吗?或者有更好的方法来解决这个问题吗?
我对基于模块的配置背后的想法有点不确定:
在实际实践中,模块应该与应用程序的其余部分位于单独的程序集中,我是否正确?
我是否正确理解模块的主要功能之一是为 DI 容器提供默认配置设置集?
理想情况下,我的配置文件应该有多大?换句话说,在使用 Autofac 时,我需要注意哪些配置文件反模式?
提前感谢(我认为)您的回复。
音乐学家
While I'm generally finding the Autofac documentation (on the wiki) to be helpful, the sections on XML configuration and modules is a bit unclear to me. Now, I have a sample working (which I present below), but I'm unsure whether it represents a sort of bastardized approach to configuration within the context of Autofac. In particular, I'm not sure if I have more or less of what I really need in the config files and the code files.
Here's the code:
using System;
using System.IO;
using Autofac;
using Autofac.Configuration;
namespace AutofacTest.Animals
{
interface IAnimal
{
void Speak ( );
}
abstract class Animal : IAnimal
{
protected TextWriter Writer
{
get;
private set;
}
protected Animal ( TextWriter writer )
{
this.Writer = writer;
}
public abstract void Speak ( );
}
class Dog : Animal
{
public Dog ( TextWriter writer )
: base ( writer )
{
}
public override void Speak ( )
{
this.Writer.WriteLine ( "Arf!" );
}
}
class Cat : Animal
{
public Cat ( TextWriter writer )
: base ( writer )
{
}
public override void Speak ( )
{
this.Writer.WriteLine ( "Meow" );
}
}
// In actual practice, this would be in a separate assembly, right?
class AnimalModule : Module
{
protected override void Load ( ContainerBuilder builder )
{
builder.RegisterInstance ( Console.Out ).As<TextWriter> ( ).SingleInstance ( );
builder.Register ( d => new Dog ( d.Resolve<TextWriter> ( ) ) ).As<IAnimal> ( );
}
}
class Program
{
static void Main ( )
{
Console.ForegroundColor = ConsoleColor.Yellow;
ContainerBuilder builder = new ContainerBuilder ( );
ConfigurationSettingsReader reader = new ConfigurationSettingsReader();
builder.RegisterModule ( reader );
//builder.RegisterModule ( new AnimalModule ( ) );
builder.Build ( ).Resolve<IAnimal> ( ).Speak ( );
Console.ReadKey ( );
}
}
}
And here's an associated config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
</configSections>
<autofac defaultAssembly="AutofacTest">
<components>
<component
type="AutofacTest.Animals.Cat"
service="AutofacTest.Animals.IAnimal" />
<component type="System.IO.StreamWriter" service="System.IO.TextWriter">
<parameters>
<parameter name="path" value="C:\AutofacTest.txt"/>
<parameter name="append" value="false" />
</parameters>
<properties>
<property name="AutoFlush" value="true" />
</properties>
</component>
</components>
<modules>
<module type="AutofacTest.Animals.AnimalModule, AutofacTest"/>
</modules>
</autofac>
</configuration>
This all works fine. The application outputs "Meow" to a text file. If I comment out the component elements, the application outputs "Arf!" to the console.
So, is everything all right here? Or is there a better way of going about this?
And I'm a little unsure about the thinking behind module-based configuration:
Am I correct that, in actual practice, modules should be in separate assemblies from the rest of the app?
Do I understand correctly that one of the chief functions of modules are to provide sets of default configuration settings for DI containers?
Ideally, how extensive should my config files be? In other words, when using Autofac, what are some config file anti-patterns for which I need to be on the lookout?
Thanks (I think) in advance for your responses.
musicologyman
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(2)
从您的示例中我不能 100% 确定预期的行为是什么 - 似乎您多次注册同一组组件,如果这是您的意图,请忽略这些建议。
- 如果您在 XML 中注册模块,则无需注册该模块内的组件。
- 同样,如果您在 XML 中注册模块,则无需在代码中也注册该模块。
关于“最佳实践”,我认为 Jim 提出的谨慎使用 XML 的建议是一个很好的建议。就我个人而言,我倾向于完成模块内部的所有繁重工作,然后通过 XML 注册模块以利用可在其中应用的配置。
我提出的另一个建议是仅使用 XML 来配置模块。在您的示例中,您正在组件上设置配置;如果您将参数应用于模块,然后在该模块内部根据需要将它们传递给组件,那么配置就不那么脆弱了。模块不会频繁变动,而组件需要能够在不破坏配置的情况下进行更改。
HTH,
尼克
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我个人的建议是谨慎使用 XML 配置。我只会将它用于您知道需要重新配置而无需重新编译的部分。例如,如果您正在构建一个可重用的库,这可能比您正在构建一个整体的 Web 应用程序要多。我尝试做的另一件事是使用以下代码使我的大多数类型可自动注册:
其中
RegisterServiceAttribute
是我的根项目中的一个属性:注意:
MeansImplicitUse
来自 Resharper 。然后,我将
[RegisterService]
放在我想要自动注册的任何类上。我至少95%的注册都是这样处理的。剩余的注册发生在调用AutoRegister()
之后。My personal recommendation is to use XML configuration sparingly. I would only use it for the parts that you know need to be reconfigurable without recompilation. If you're building a reusable library, this is probably more than if you are building a monolithic webapp, for example. The other thing I try to do is make most of my types auto-registerable using this code:
where
RegisterServiceAttribute
is an attribute in my root project:Note:
MeansImplicitUse
is from Resharper.I then put
[RegisterService]
on any class I want to auto register. At least 95% of my registrations are handled this way. The remaining registrations happen after the call toAutoRegister()
.