您可以在提供程序後面提取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
}