将LuisResult传递给子对话框

时间:2017-02-16 11:46:39

标签: botframework

我有一个根对话框,一个LuisDialog,我从中调用一些子对话框,如下所示

    [LuisModel("8869ccea-7c5f-4cce-8639-64bbc7ecd62b", "c5835534ed7746449356c62dcdf48fde")]
[Serializable]
public class DefaultDialog : LuisDialog<object>
{

    [LuisIntent("showIncidents")]
    public async Task ShowIncidents(IDialogContext context, IAwaitable<IMessageActivity> _message, LuisResult result)
    {
        var message = await _message;
        await context.Forward(new ShowIncident(), ResumeAfter,message,CancellationToken.None);
    }

    [LuisIntent("CreateIncident")]
    public async Task CreateIncident(IDialogContext context, LuisResult result)
    {
        //context.Call(new CreateIncident(), ResumeAfter);
        context.Call(new CreateIncident(), ResumeAfter);
    }

当我打电话给&#34; ShowIncident()&#34;拨号,我想转发LuisResult而不是消息,因为我需要来自子对话框中LuisResult的实体。所以我尝试使用以下代码调用子对话框:

await context.Forward(new ShowIncident(), ResumeAfter,result,CancellationToken.None);

我尝试实施我的&#34; ShowIncident&#34;对话框如下:

    [Serializable]
public class ShowIncident : IDialog<object>
{
    public async Task StartAsync(IDialogContext context)
    {
        context.Wait(MessageReceivedAsync);
    }

    public async Task MessageReceivedAsync(IDialogContext context, IAwaitable<LuisResult> _result)
    {
        var result = await _result;
         // Get and post Incidents
         Incidents incidents = await ServiceNow.GetIncidentsAsync();
         await context.PostAsync(incidents.toText());
    }
}

这会引发错误,我认为这是因为IAwaitable<LuisResult>必须是IAwaitable<IMessageActivity>。 我意识到我可以使用几种解决方法,比如将实体定位为消息或使用公共静态类来定义事件。但是什么是正确的方式&#39;

3 个答案:

答案 0 :(得分:2)

将构造函数添加到ShowIncident

public class ShowIncident : IDialog<object>
{
       private LuisResult _luisResult;
       public ShowIncident(LuisResult luisResult) 
       {
         _luisResult = _luisResult;
       }

       public async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> activity)
       { //....

并将其称为此context.Call(new CreateIncident(result), ResumeAfter);

答案 1 :(得分:1)

接受的答案有问题,因为LuisResult不可序列化。这可能会导致对话框在运行时失败。

有两个选项,您可以在构造函数中设置它,但是这会阻止您使用具有依赖项注入的对话框。

另一个选择是添加一个属性并在构造对话框后设置LuisResult值,然后使用依赖注入兼容。

但是,如果您选择这样做,您将需要以下内容

[NonSerialized]
private LuisResult _luisData;
public LuisResult LuisData {
    get => _luisData;
    set => _luisData = value;
}

这是为了确保您不会创建运行时错误。

答案 2 :(得分:0)

David Manton关于LuisResult不可序列化是正确的。最好的选择是将所需的部分提取到自己的可序列化对象中,然后将其传递给对话框构造函数。

但是,他对给定答案的依赖项注入是错误的。 在您的AutoFac模块中,或在执行注册的位置,您将像这样注册对话框:

builder.Register((c, p) => new ShowIncident (p.Named<string("luisResult"))).InstancePerDependency();

然后,当您要调用ShowIncident时,将为对话框进行如下解析:

            using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
            {
                context.Call(scope.Resolve<ShowIncident>(new NamedParameter("luisResult", luisResult)), ResumeAfterIncidentDialog);
            }

当对象具有一个或多个只能在运行时解析的参数时,这是Autofac中的常用方法。