Skip to content
This repository was archived by the owner on Jun 30, 2022. It is now read-only.

Commit 92af3db

Browse files
lauren-millsdarrenj
authored andcommitted
[Lib] Refactored routerDialog (#2458)
* refactored routerDialog * updated method documentation
1 parent dd32c7a commit 92af3db

File tree

4 files changed

+76
-87
lines changed

4 files changed

+76
-87
lines changed

sdk/csharp/libraries/microsoft.bot.builder.solutions/CognitiveModelSet.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ public class CognitiveModelSet
88
{
99
public IRecognizer DispatchService { get; set; }
1010

11-
public Dictionary<string, ITelemetryRecognizer> LuisServices { get; set; } = new Dictionary<string, ITelemetryRecognizer>();
11+
public Dictionary<string, LuisRecognizer> LuisServices { get; set; } = new Dictionary<string, LuisRecognizer>();
1212

13-
public Dictionary<string, ITelemetryQnAMaker> QnAServices { get; set; } = new Dictionary<string, ITelemetryQnAMaker>();
13+
public Dictionary<string, QnAMaker> QnAServices { get; set; } = new Dictionary<string, QnAMaker>();
1414
}
1515
}

sdk/csharp/libraries/microsoft.bot.builder.solutions/Dialogs/InterruptableDialog.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogCont
3737
{
3838
var status = await OnInterruptDialogAsync(dc, cancellationToken).ConfigureAwait(false);
3939

40-
if (status == InterruptionAction.MessageSentToUser)
40+
if (status == InterruptionAction.Resume)
4141
{
4242
// Resume the waiting dialog after interruption
4343
await dc.RepromptDialogAsync().ConfigureAwait(false);
4444
return EndOfTurn;
4545
}
46-
else if (status == InterruptionAction.StartedDialog)
46+
else if (status == InterruptionAction.Waiting)
4747
{
4848
// Stack is already waiting for a response, shelve inner stack
4949
return EndOfTurn;

sdk/csharp/libraries/microsoft.bot.builder.solutions/Dialogs/InterruptionAction.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@
33

44
namespace Microsoft.Bot.Builder.Solutions.Dialogs
55
{
6+
/// <summary>
7+
/// Indicates the current status of a dialog interruption.
8+
/// </summary>
69
public enum InterruptionAction
710
{
11+
/// <summary>
12+
/// Indicates that the active dialog was interrupted and should end.
13+
/// </summary>
14+
End,
15+
816
/// <summary>
917
/// Indicates that the active dialog was interrupted and needs to resume.
1018
/// </summary>
11-
MessageSentToUser,
19+
Resume,
1220

1321
/// <summary>
1422
/// Indicates that there is a new dialog waiting and the active dialog needs to be shelved.
1523
/// </summary>
16-
StartedDialog,
24+
Waiting,
1725

1826
/// <summary>
1927
/// Indicates that no interruption action is required.
Lines changed: 62 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Threading;
1+
using System;
2+
using System.Threading;
23
using System.Threading.Tasks;
34
using Microsoft.Bot.Builder.Dialogs;
45
using Microsoft.Bot.Builder.Solutions.Extensions;
@@ -14,176 +15,156 @@ public RouterDialog(string dialogId, IBotTelemetryClient telemetryClient)
1415
TelemetryClient = telemetryClient;
1516
}
1617

17-
protected override Task<DialogTurnResult> OnBeginDialogAsync(DialogContext innerDc, object options, CancellationToken cancellationToken = default(CancellationToken))
18+
protected override Task<DialogTurnResult> OnBeginDialogAsync(DialogContext innerDc, object options, CancellationToken cancellationToken = default)
1819
{
1920
return OnContinueDialogAsync(innerDc, cancellationToken);
2021
}
2122

22-
protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
23+
protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
2324
{
25+
// Check for any interruptions.
2426
var status = await OnInterruptDialogAsync(innerDc, cancellationToken).ConfigureAwait(false);
2527

26-
if (status == InterruptionAction.MessageSentToUser)
28+
if (status == InterruptionAction.Resume)
2729
{
28-
// Resume the waiting dialog after interruption
30+
// Interruption message was sent, and the waiting dialog should resume/reprompt.
2931
await innerDc.RepromptDialogAsync().ConfigureAwait(false);
30-
return EndOfTurn;
3132
}
32-
else if (status == InterruptionAction.StartedDialog)
33+
else if (status == InterruptionAction.Waiting)
3334
{
34-
// Stack is already waiting for a response, shelve inner stack
35+
// Interruption intercepted conversation and is waiting for user to respond.
3536
return EndOfTurn;
3637
}
37-
else
38+
else if (status == InterruptionAction.End)
39+
{
40+
// Interruption ended conversation, and current dialog should end.
41+
return await innerDc.EndDialogAsync().ConfigureAwait(false);
42+
}
43+
else if (status == InterruptionAction.NoAction)
3844
{
45+
// No interruption was detected. Process activity normally.
3946
var activity = innerDc.Context.Activity;
4047

41-
if (activity.IsStartActivity())
42-
{
43-
await OnStartAsync(innerDc).ConfigureAwait(false);
44-
}
45-
4648
switch (activity.Type)
4749
{
4850
case ActivityTypes.Message:
4951
{
50-
// Note: This check is a workaround for adaptive card buttons that should map to an event (i.e. startOnboarding button in intro card)
51-
if (activity.Value != null)
52-
{
53-
await OnEventAsync(innerDc).ConfigureAwait(false);
54-
}
55-
else
56-
{
57-
var result = await innerDc.ContinueDialogAsync().ConfigureAwait(false);
58-
59-
switch (result.Status)
60-
{
61-
case DialogTurnStatus.Empty:
62-
{
63-
await RouteAsync(innerDc).ConfigureAwait(false);
64-
break;
65-
}
66-
67-
case DialogTurnStatus.Complete:
68-
{
69-
if (result.Result is RouterDialogTurnResult routerDialogTurnResult && routerDialogTurnResult.Status == RouterDialogTurnStatus.Restart)
70-
{
71-
await RouteAsync(innerDc).ConfigureAwait(false);
72-
break;
73-
}
74-
75-
// End active dialog
76-
await innerDc.EndDialogAsync().ConfigureAwait(false);
77-
break;
78-
}
79-
80-
default:
81-
{
82-
break;
83-
}
84-
}
85-
}
52+
// Pass message to waiting child dialog.
53+
var result = await innerDc.ContinueDialogAsync().ConfigureAwait(false);
8654

87-
// If the active dialog was ended on this turn (either on single-turn dialog, or on continueDialogAsync) run CompleteAsync method.
88-
if (innerDc.ActiveDialog == null)
55+
if (result.Status == DialogTurnStatus.Empty
56+
|| (result.Result is RouterDialogTurnResult routerDialogTurnResult && routerDialogTurnResult.Status == RouterDialogTurnStatus.Restart))
8957
{
90-
await CompleteAsync(innerDc).ConfigureAwait(false);
58+
// There was no waiting dialog on the stack, process message normally.
59+
await OnMessageActivityAsync(innerDc).ConfigureAwait(false);
9160
}
9261

9362
break;
9463
}
9564

9665
case ActivityTypes.Event:
9766
{
98-
await OnEventAsync(innerDc).ConfigureAwait(false);
67+
await OnEventActivityAsync(innerDc).ConfigureAwait(false);
9968
break;
10069
}
10170

102-
case ActivityTypes.Invoke:
71+
case ActivityTypes.ConversationUpdate:
10372
{
104-
// Used by Teams for Authentication scenarios.
105-
await innerDc.ContinueDialogAsync().ConfigureAwait(false);
73+
await OnMembersAddedAsync(innerDc).ConfigureAwait(false);
10674
break;
10775
}
10876

10977
default:
11078
{
111-
await OnSystemMessageAsync(innerDc).ConfigureAwait(false);
79+
// All other activity types will be routed here. Custom handling should be added in implementation.
80+
await OnUnhandledActivityTypeAsync(innerDc).ConfigureAwait(false);
11281
break;
11382
}
11483
}
84+
}
11585

116-
return EndOfTurn;
86+
if (innerDc.ActiveDialog == null)
87+
{
88+
// If the inner dialog stack completed during this turn, this component should be ended.
89+
return await innerDc.EndDialogAsync().ConfigureAwait(false);
11790
}
118-
}
11991

120-
protected override Task OnEndDialogAsync(ITurnContext context, DialogInstance instance, DialogReason reason, CancellationToken cancellationToken = default(CancellationToken))
121-
{
122-
return base.OnEndDialogAsync(context, instance, reason, cancellationToken);
92+
return EndOfTurn;
12393
}
12494

125-
protected override Task OnRepromptDialogAsync(ITurnContext turnContext, DialogInstance instance, CancellationToken cancellationToken = default(CancellationToken))
95+
protected override async Task<DialogTurnResult> EndComponentAsync(DialogContext outerDc, object result, CancellationToken cancellationToken)
12696
{
127-
return base.OnRepromptDialogAsync(turnContext, instance, cancellationToken);
97+
// This happens when an inner dialog ends. Could call complete here
98+
await OnDialogCompleteAsync(outerDc, result, cancellationToken).ConfigureAwait(false);
99+
return await base.EndComponentAsync(outerDc, result, cancellationToken).ConfigureAwait(false);
128100
}
129101

130102
/// <summary>
131-
/// Called when the inner dialog stack is empty.
103+
/// Called on every turn, enabling interruption scenarios.
132104
/// </summary>
133105
/// <param name="innerDc">The dialog context for the component.</param>
134106
/// <param name="cancellationToken">The cancellation token.</param>
135-
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
136-
protected abstract Task RouteAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken));
107+
/// <returns>A <see cref="Task"/> returning an <see cref="InterruptionAction">
108+
/// which indicates what action should be taken after interruption.</returns>.
109+
protected override Task<InterruptionAction> OnInterruptDialogAsync(DialogContext innerDc, CancellationToken cancellationToken)
110+
{
111+
return Task.FromResult(InterruptionAction.NoAction);
112+
}
137113

138114
/// <summary>
139-
/// Called when the inner dialog stack is complete.
115+
/// Called when an event activity is received.
140116
/// </summary>
141117
/// <param name="innerDc">The dialog context for the component.</param>
142-
/// <param name="result">The dialog result when inner dialog completed.</param>
143118
/// <param name="cancellationToken">The cancellation token.</param>
144119
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
145-
protected virtual Task CompleteAsync(DialogContext innerDc, DialogTurnResult result = null, CancellationToken cancellationToken = default(CancellationToken))
120+
protected virtual Task OnEventActivityAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
146121
{
147-
innerDc.EndDialogAsync(result).Wait(cancellationToken);
148122
return Task.CompletedTask;
149123
}
150124

151125
/// <summary>
152-
/// Called when an event activity is received.
126+
/// Called when a message activity is received.
153127
/// </summary>
154128
/// <param name="innerDc">The dialog context for the component.</param>
155129
/// <param name="cancellationToken">The cancellation token.</param>
156130
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
157-
protected virtual Task OnEventAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
131+
protected virtual Task OnMessageActivityAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
158132
{
159133
return Task.CompletedTask;
160134
}
161135

162136
/// <summary>
163-
/// Called when a system activity is received.
137+
/// Called when a conversationUpdate activity is received.
164138
/// </summary>
165139
/// <param name="innerDc">The dialog context for the component.</param>
166140
/// <param name="cancellationToken">The cancellation token.</param>
167141
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
168-
protected virtual Task OnSystemMessageAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
142+
protected virtual Task OnMembersAddedAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
169143
{
170144
return Task.CompletedTask;
171145
}
172146

173147
/// <summary>
174-
/// Called when a conversation update activity is received.
148+
/// Called when an activity type other than event, message, or conversationUpdate is received.
175149
/// </summary>
176150
/// <param name="innerDc">The dialog context for the component.</param>
177151
/// <param name="cancellationToken">The cancellation token.</param>
178152
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
179-
protected virtual Task OnStartAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
153+
protected virtual Task OnUnhandledActivityTypeAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
180154
{
181155
return Task.CompletedTask;
182156
}
183157

184-
protected override Task<InterruptionAction> OnInterruptDialogAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
158+
/// <summary>
159+
/// Called when the inner dialog stack completes.
160+
/// </summary>
161+
/// <param name="outerDc">The dialog context for the component.</param>
162+
/// <param name="result">The dialog turn result for the component.</param>
163+
/// <param name="cancellationToken">The cancellation token.</param>
164+
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
165+
protected virtual Task OnDialogCompleteAsync(DialogContext outerDc, object result, CancellationToken cancellationToken)
185166
{
186-
return Task.FromResult(InterruptionAction.NoAction);
167+
return Task.CompletedTask;
187168
}
188169
}
189-
}
170+
}

0 commit comments

Comments
 (0)