【问题标题】:Injecting external dependencies in Microsoft Bot Framework Dialog using Autofac使用 Autofac 在 Microsoft Bot Framework 对话框中注入外部依赖项
【发布时间】:2016-11-15 19:14:29
【问题描述】:

我一直在尝试将服务从 MessagesController 传递给 LuisDialog,如下所示:

public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
...
await Conversation.SendAsync(activity, () => new ActionDialog(botService));

botService 使用依赖注入注入到 MessageController 中。

当我开始机器人对话时出现错误:

程序集“ThetaBot.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”中的类型“ThetaBot.Services.BotService”未标记为可序列化。

四处寻找我能找到的解决方案: https://github.com/Microsoft/BotBuilder/issues/106

我现在更好地理解了你的问题。对于我们想要从容器而不是序列化的 blob 实例化的服务对象,我们也有类似的问题。以下是我们在容器中注册这些对象的方式 - 我们在反序列化期间对所有具有键 Key_DoNotSerialize 的对象应用特殊处理:

builder
        .RegisterType<BotToUserQueue>()
        .Keyed<IBotToUser>(FiberModule.Key_DoNotSerialize)
        .AsSelf()
        .As<IBotToUser>()
        .SingleInstance();

但是我找不到详细说明如何将您自己的依赖项注册到现有 Bot Framework 模块的示例或文档。

我还发现了https://github.com/Microsoft/BotBuilder/issues/252,它表明应该可以从容器中实例化对话框。

我已经尝试过这个建议:

Func<IDialog<object>> makeRoot = () => actionDialog;
await Conversation.SendAsync(activity, makeRoot);

与:

builder
            .RegisterType<ActionDialog>()
            .Keyed<ActionDialog>(FiberModule.Key_DoNotSerialize)
            .AsSelf()
            .As<ActionDialog>()
            .SingleInstance();

这不起作用。

我也试过了:

var builder = new ContainerBuilder();
builder.RegisterModule(new DialogModule_MakeRoot());

// My application module
builder.RegisterModule(new ApplicationModule());

using (var container = builder.Build())
using (var scope = DialogModule.BeginLifetimeScope(container, activity))
{
    await Conversation.SendAsync(activity, () => scope.Resolve<ActionDialog>());
}

与ApplicationModule中的以下内容一起:

            builder
            .RegisterType<ActionDialog>()
            .Keyed<ActionDialog>(FiberModule.Key_DoNotSerialize)
            .AsSelf()
            .As<ActionDialog>()
            .SingleInstance();

这不起作用,我遇到了同样的问题。

如果我只是将所有服务及其依赖项标记为可序列化,我可以让它工作而无需使用 FiberModule.Key_DoNotSerialize。

问题是 - 将依赖项注册和注入 Bot Framework 对话框的正确/首选/推荐方式是什么?

【问题讨论】:

  • 我相信,你有这个异常不是因为注入错误,而是因为你的对话框中有一个ThetaBot.Services.BotService 类型的非静态字段。虽然该类型未标记为可序列化,但它不能以这种方式使用,独立于它是否被注入。如果你很擅长使所有服务及其依赖项可序列化并将它们与 Dialog 状态一起存储,则不需要使用FiberModule.Key_DoNotSerialize。在其他情况下,您可以在其他地方注入您的服务,并从对话框中使用它们而不存储在那里。
  • 嗨@jim.taylor,你有没有解决这个问题。我也在尝试将服务传递给 formflow 对话框。
  • @MurtazaTahirAli - 我现在使用了一种解决方法。我将注入的服务设为静态。 [可序列化] public class ActionDialog : LuisDialog { private static IBotService _botService;公共 ActionDialog(IBotService botService) { _botService = botService; }

标签: c# autofac botframework


【解决方案1】:

在 Global.asax.cs 中,您可以执行以下操作来注册您的服务/对话框:

ContainerBuilder builder = new ContainerBuilder();

builder.RegisterType<IntroDialog>()
  .As<IDialog<object>>()
  .InstancePerDependency();

builder.RegisterType<JobsMapper>()
    .Keyed<IMapper<DocumentSearchResult, GenericSearchResult>>(FiberModule.Key_DoNotSerialize)
    .AsImplementedInterfaces()
    .SingleInstance();

builder.RegisterType<AzureSearchClient>()
    .Keyed<ISearchClient>(FiberModule.Key_DoNotSerialize)
    .AsImplementedInterfaces()
    .SingleInstance();

builder.Update(Conversation.Container);

在您的控制器中,您可以将主对话框解析为:

using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
{
    await Conversation.SendAsync(activity, () => scope.Resolve<IDialog<object>>());
}

【讨论】:

  • 这些天更新是过时(容器被认为是不可变的,lardidadi),希望正在进行替换:github.com/Microsoft/BotBuilder/issues/1966
  • 替换是使用Conversation.UpdateContainer
  • 对于那些想知道如何使用 UpdateContainer 的人,请参阅ContosoFlower上的示例
  • 那么,这样做的正确方法是什么?我知道接受的答案是一种过时的方法。请向我们展示示例代码 :) 提前致谢。
猜你喜欢
  • 2011-11-22
  • 1970-01-01
  • 2017-04-27
  • 1970-01-01
  • 2020-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
相关资源
最近更新 更多