如何将运行时参数值转换为 WebJobs 函数和 Simple Injector 中的依赖项?
How to convert runtime parameter value into dependency within WebJobs function and Simple Injector?
我有一个具有 method/trigger 的 WebJobs 函数。它的参数之一对应于 WebJobs 仪表板记录器:
public Task MyQueueHandler(TextWriter log)
如何在容器中转换或注册此 TextWriter log
,以便将其注入我的另一个 class 的构造函数:
public MyLogger(TextWriter log)
有没有类似ExecutionContextScoping的方法?
您可以提取提供程序后面的 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
}
我有一个具有 method/trigger 的 WebJobs 函数。它的参数之一对应于 WebJobs 仪表板记录器:
public Task MyQueueHandler(TextWriter log)
如何在容器中转换或注册此 TextWriter log
,以便将其注入我的另一个 class 的构造函数:
public MyLogger(TextWriter log)
有没有类似ExecutionContextScoping的方法?
您可以提取提供程序后面的 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
}