botframework - Bot Composer 自定义操作中的依赖注入
问题描述
我想将 Bot composer 与自定义操作集成。自定义操作依次调用不同的 API 来执行一些业务逻辑。我想将接口和服务提供者注入自定义操作。我在执行此操作时遇到了麻烦,因为它失败并进入空指针异常,尽管我已在 startup.cs 中正确添加了所有内容。你能解释一下我怎么能做到这一点吗?
[JsonConstructor]
public MultiplyDialog(IServiceProvider serviceProvider, [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
: base()
{
serviceProvider.GetService<ApiService>() // serviceprovider always null
this.RegisterSourceLocation(sourceFilePath, sourceLineNumber);
}
解决方案
You have to keep in mind that when using Adaptive Dialogs (that is, the core of Composer) Dialogs are singletons and, when using Composer, they're not instantiated from dependency injection (DI).
Also, since dialogs are singletons, you can't (well, you could but you shouldn't) use services like constructor injected DbContexts and similar (when working with the SDK, that is, coding).
The easiest way to solve this is by using HTTP requests using the HttpRequest
action. This is the way that's built into the whole adaptive dialogs ecosystem to achieve this kind of functionality.
If you really insist on doing it with DI into the dialogs, you'd have to solve DI from the TurnContext
and you'd have to set it up in the adapter. However, that's a bit convoluted an requires you to use a custom runtime.
UPDATE Added the way to implement DI with adaptive dialogs.
1 - Register the service class in the turn state in the adapter
public class AdapterWithErrorHandler : BotFrameworkHttpAdapter
{
public AdapterWithErrorHandler(
IConfiguration configuration,
ILogger<BotFrameworkHttpAdapter> logger,
//...
QnAClient qnaClient)
: base(configuration, logger)
{
// Add QnAClient to TurnState so we can use it while in the turn
Use(new RegisterClassMiddleware<QnAClient>(qnaClient));
//...
}
}
In the code above QnAClient
is an typed HttpClient created with IHttpClientFactory
so it's a safe to use singleton.
2 - Get the service from the TurnState
wherever you need it
public async Task SetPropertiesAsync(DialogContext context, ...)
{
var qnaClient = context.Context.TurnState.Get<QnAClient>();
//...
}
BTW, this is a nice way to get an HttpClient
properly managed by IHttpClientFactory
when you register it like this in ConfigureServices
:
services.AddHttpClient<QnAClient>()
.AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(new[] { 1, 2, 3, 5, 8, 13 }.Select(t => TimeSpan.FromSeconds(t))))
.AddTransientHttpErrorPolicy(p => p.CircuitBreakerAsync(6, TimeSpan.FromSeconds(30)));
In this case with retry policies from Polly.
推荐阅读
- javascript - 转换可读流以将其保存为本地文件
- javascript - Applet 类未加载到 JSP 中
- java - 如何检查字符串是否包含集合中的字符串之一
- ios - Objective C - 在视图控制器中调用方法,该方法已经在应用程序委托的导航顶部
- batch-processing - 在 apache Beam 中根据批量大小获取记录
- angular - mat-grid-list 未正确显示
- arrays - Excel:按分隔符拆分单元格并遍历值
- python - 正则表达式在 Python 中查找两个字符串之间的字符串
- vb.net - vb.net - 如何在多线程下获取 webbrowser InnerHtml
- rabbitmq - Spring Cloud Stream - 从具有相同路由键和不同标头的同一队列发布和消费