将 LuisResult 传递给子对话框
Pass LuisResult to child dialog
我有一个根对话框,一个 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);
}
当我调用 "ShowIncident()" 对话框时,我想转发 LuisResult 而不是消息,因为我需要子对话框中 LuisResult 的实体。所以我尝试使用以下代码调用子对话框:
await context.Forward(new ShowIncident(), ResumeAfter,result,CancellationToken.None);
我尝试按如下方式实现 "ShowIncident" 对话框:
[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>
。
我意识到我可以使用多种解决方法,例如将实体作为消息放置或使用 public 静态 class 来定义事件。但是 'proper way' 是什么?
向 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)
;
接受的答案有问题,因为 LuisResult 不可序列化。这可能会导致您的对话在 运行 时失败。
有两个选项,您可以在构造函数中设置它,但是这会阻止您使用带有依赖项注入的对话框。
另一种选择是添加一个 属性 并在构建对话框后设置 LuisResult 值,这与使用依赖注入兼容。
无论您选择如何执行此操作,您都需要如下内容
[NonSerialized]
private LuisResult _luisData;
public LuisResult LuisData {
get => _luisData;
set => _luisData = value;
}
这是为了确保您不会造成 运行 时间错误。
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 中的一种常用方法。
我有一个根对话框,一个 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);
}
当我调用 "ShowIncident()" 对话框时,我想转发 LuisResult 而不是消息,因为我需要子对话框中 LuisResult 的实体。所以我尝试使用以下代码调用子对话框:
await context.Forward(new ShowIncident(), ResumeAfter,result,CancellationToken.None);
我尝试按如下方式实现 "ShowIncident" 对话框:
[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>
。
我意识到我可以使用多种解决方法,例如将实体作为消息放置或使用 public 静态 class 来定义事件。但是 'proper way' 是什么?
向 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)
;
接受的答案有问题,因为 LuisResult 不可序列化。这可能会导致您的对话在 运行 时失败。
有两个选项,您可以在构造函数中设置它,但是这会阻止您使用带有依赖项注入的对话框。
另一种选择是添加一个 属性 并在构建对话框后设置 LuisResult 值,这与使用依赖注入兼容。
无论您选择如何执行此操作,您都需要如下内容
[NonSerialized]
private LuisResult _luisData;
public LuisResult LuisData {
get => _luisData;
set => _luisData = value;
}
这是为了确保您不会造成 运行 时间错误。
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 中的一种常用方法。