您可以在提供程序后面提取TextWriter
,并将提供程序注入记录器(因为TextWriter
明显是运行时数据,应直接使用prevent injecting it into your components)。这允许您在调用MyQueueHandler时将此值设置到提供程序中。例如:
// Definition
public interface ITextWriterProvider // by lack of a better name
{
TextWriter Current { get; }
}
// Used as dependency of MyLogger
public MyLogger(ITextWriterProvider logProvider)
// Implementation visible to your composition root
public class TextWriterProvider : ITextWriterProvider
{
public TextWriter Current { get; set; }
}
// Registration
container.Register<ITextWriterProvider, TextWriterProvider>(Lifestyle.Scoped);
container.Register<TextWriterProvider>(Lifestyle.Scoped);
// Wrap the start of the request in a scope and assign the log value to the scope.
public Task MyQueueHandler(TextWriter log)
{
using (AsyncScopedLifestyle.BeginScope(container))
{
container.GetInstance<TextWriterProvider>().Current = log;
// execute rest of request
}
}
这种设计的变化也可以使TextWriterProvider
独立的,并使其价值AsyncLocal
,如下所示:
public class TextWriterProvider : ITextWriterProvider
{
private static readonly AsyncLocal<TextWriter> current =
new AsyncLocal<TextWriter>();
public TextWriter Current
{
get => current.Value;
set => current.Value = value;
}
}
// Registration
container.Register<ITextWriterProvider, TextWriterProvider>(Lifestyle.Singleton);
container.Register<TextWriterProvider>(Lifestyle.Singleton);
或者更简单:
public class TextWriterProvider : ITextWriterProvider
{
public static readonly AsyncLocal<TextWriter> CurrentWriter =
new AsyncLocal<TextWriter>();
public TextWriter Current => CurrentWriter.Value;
}
// Registration
container.Register<ITextWriterProvider, TextWriterProvider>(Lifestyle.Singleton);
// Assign the log to the CurrentWriter at the start of the request
public Task MyQueueHandler(TextWriter log)
{
TextWriterProvider.CurrentWriter = log;
// execute rest of request
}
这些都是同一设计的所有变体,我们从构造函数中提取运行时数据并允许在之后解析它对象图已经构建完成。
如果全部失败,可以将此运行时值直接注入到对象图中。请注意,我强烈反对此建议,但将其视为最后的选择:
// Part of your Composition Root
public static AsyncLocal<TextWriter> Writer = new AsyncLocal<TextWriter>();
// Registration
container.Register<ILogger>(() => new MyLogger(
Writer ?? (container.IsVerifying ? new TextWriter() : null)));
// Assign the log to the CurrentWriter at the start of the request
public Task MyQueueHandler(TextWriter log)
{
CompositionRoot.CurrentWriter = log;
// execute rest of request
}