问题
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
回答1:
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:
public static void AutoRegister(ContainerBuilder builder, params Assembly[] assemblies)
{
builder.RegisterAssemblyTypes(assemblies)
.Where(t => t.GetCustomAttributes(typeof (RegisterServiceAttribute), false).Any())
.AsSelf()
.AsImplementedInterfaces();
}
where RegisterServiceAttribute
is an attribute in my root project:
[AttributeUsage(AttributeTargets.Class)]
[MeansImplicitUse]
public class RegisterServiceAttribute : Attribute
{
}
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 to AutoRegister()
.
回答2:
I'm not 100% sure from your example what the expected behaviour is - it seems like you're registering the same set of components many times over, if that's your intention please ignore these suggestions.
- If you register a module in XML, you don't also need to register the components within the module.
- Likewise, if you register a module in XML, you don't need to also register the module in code.
Regarding 'best practices' I'd say Jim's recommendation to use XML sparingly is a good one. Personally, I tend to do all of the heavy lifting inside modules, and then register the modules via XML to take advantage of the configuration that can be applied there.
Another recommendation I'd make is to use XML to configure modules only. In your example you're setting configuration on a component; configuration is less fragile if you apply the parameters to a module, and then internal to that module pass them on to components as needed. Modules don't tend to churn very much, while components need to be able to be changed without breaking configuration.
HTH,
Nick
来源:https://stackoverflow.com/questions/5735992/using-modules-and-config-files-in-autofac