【问题标题】:Dependency Injection for Azure chat bot middleware?Azure 聊天机器人中间件的依赖注入?
【发布时间】:2018-10-30 14:44:42
【问题描述】:

我正在使用 Azure 机器人服务和 QnAMaker 开发一个新的聊天机器人。我们正在使用 BotBuilder 中间件(包括自定义中间件)来定制机器人行为。

其中一个中间件将调用 Azure 函数,我想将新的 HttpClientFactory 功能与自定义中间件一起使用 - 但这需要依赖注入。

如何像使用常规 .NET Core 中间件一样在 BotBuilder 中间件中使用依赖注入?

当您查看 Startup.cs 中的机器人配置时,您会发现它需要您new机器人依赖:

services.AddHttpClient<MyFunctionClient>(client =>
{
    client.BaseAddress = new Uri(mySettings.GetValue<string>("myFunctionUrl"));
    client.DefaultRequestHeaders.Add("x-functions-key", mySettings.GetValue<string>("myFunctionKey"));
});

services.AddBot<QnAMakerBot>(options =>
{  
    options.CredentialProvider = new ConfigurationCredentialProvider(Configuration);

    options.ConnectorClientRetryPolicy = new RetryPolicy(
        new BotFrameworkHttpStatusCodeErrorDetectionStrategy(),
        3,
        TimeSpan.FromSeconds(2), 
        TimeSpan.FromSeconds(20),
        TimeSpan.FromSeconds(1));

    var middleware = options.Middleware;
    middleware.Add(new ConversationState<ChatLog>(new MemoryStorage()));
    middleware.Add(new MyCustomMiddleware()); // <- I want to inject a typed HttpClient here

//... etc. ....

是否有不同的方式来配置允许依赖注入的机器人?

如果MyCustomMiddleware 在其构造函数中需要一个类型化的HttpClient,我必须在此处创建一个新实例,因此我无法从 DI 和我刚刚设置的配置中受益。

【问题讨论】:

    标签: c# asp.net-core .net-core asp.net-core-2.1 azure-bot-service


    【解决方案1】:

    虽然我不喜欢服务定位器模式,但当前的机器人配置设计对依赖注入不是很友好。

    利用 bot 中间件的设置方式但必须在启动期间提供新实例的性质,我想出了以下解决方法。

    public class BotMiddlewareAdapter<TMiddleware> : IMiddleware
        where TMiddleware : IMiddleware {
        private readonly Lazy<TMiddleware> middleware;
    
        public BotMiddlewareAdapter(IServiceCollection services) {
            middleware = new Lazy<TMiddleware>(() =>
                services.BuildServiceProvider().GetRequiredService<TMiddleware>());
        }
    
        public Task OnTurn(ITurnContext context, MiddlewareSet.NextDelegate next) {
            return middleware.Value.OnTurn(context, next);
        }
    }
    

    它将IServiceCollection 作为显式依赖项,并延迟创建服务提供者和最终解析工厂委托中的实际中间件。

    然后可以使用

    middleware.Add(new BotMiddlewareAdapter<MyCustomMiddleware>(services));
    

    当适配器被调用时,它会在初始调用时延迟解析预期的中间件,然后调用它。

    其实你可以更进一步,将其转换为扩展方法

    public static class BotBuilderMiddlewareExtension {
        public static void Add<TMiddleware>(this IList<IMiddleware> middleware, IServiceCollection services) 
            where TMiddleware : IMiddleware {
            middleware.Add(new BotMiddlewareAdapter<TMiddleware>(services));
        }
    }
    

    这简化了设置

    middleware.Add<MyCustomMiddleware>(services);
    

    【讨论】:

    • 这看起来不对。任何需要您调用 BuildServiceProvider 的解决方案总是可疑。这将创建一个新的宇宙,您最终会得到多个单例实例,不会共享任何内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-03
    • 1970-01-01
    • 2020-03-31
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2020-07-30
    相关资源
    最近更新 更多