如何将运行时参数值转换为 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
}