Skip to content

Commit 10ecc09

Browse files
Create bot-service-proactive-messages.md
1 parent 1842bfe commit 10ecc09

File tree

1 file changed

+157
-0
lines changed

1 file changed

+157
-0
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
When you think about the exchange of messages between your bot and the user, you're probably thinking about the scenario where the user sends a message to your bot and your bot then replies to the user with a message of its own. We call this _reactive messaging_ and it's by far the most common flow that you should optimize your bot's code for.
2+
3+
It is possible, however, for your bot to initiate a conversation with the user by sending them a message first. We call this _proactive messaging_ and while the code you'll write to send a proactive message is very similar to what you'd write in the reactive case, there are a few differences that are worth exploring.
4+
5+
The first thing to note is that before you can send a proactive message to a user, the user will have to send at least one reactive style message to your bot. There are two reasons for this.
6+
7+
1. You need to get the user's `ConversationReference` and save it somewhere for future use. You can think of the conversation reference as the user's address, as it contains information about the channel they came in on, their user ID, the conversation ID, and even the server that should receive any future messages. This object is simple JSON and should be saved whole without tampering.
8+
9+
1. Most channels by policy won't let a bot initiate conversations with users they've never spoken to before. Depending on the channel the user might need to explicitly add the bot to a conversation or at a minimum send an initial message to the bot.
10+
11+
> ![NOTE]
12+
> This bot currently runs properly only when deployed to Azure. However, you can test the bot without publishing it.
13+
14+
## Set up your development environment
15+
16+
The features used in this article aren't available in the Bot Builder SDK v4.0.0-alpha2018031301 NuGet packages.
17+
18+
1. Clone the repo and build the packages locally (see [Building the SDK](Building-the-SDK)).
19+
20+
1. Create an empty ASP.NET Core Web Application project.
21+
22+
1. Add references to the following packages:
23+
```text
24+
Microsoft.Bot.Builder
25+
Microsoft.Bot.Builder.Core
26+
Microsoft.Bot.Builder.Core.Extensions
27+
Microsoft.Bot.Builder.Integration.AspNet.Core
28+
Microsoft.Bot.Connector
29+
Microsoft.Bot.Schema
30+
```
31+
32+
1. Add a `default.html` file under the `wwwroot` folder.
33+
34+
1. In the `Program.cs` file, change the namespace to `Microsoft.Bot.Samples`.
35+
36+
## Define your bot
37+
38+
The following bot definition uses the conversation reference to send a proactive message to the user.
39+
- When the user enters `subscribe`, the bot immediately confirms the request, and then sends a proactive message after a 2 second delay.
40+
- When the users types anything else, the bot prompts the user to type `subscribe`.
41+
42+
Create a `ProactiveBot.cs` class file and update the file to this:
43+
44+
```csharp
45+
using Microsoft.Bot.Builder;
46+
using Microsoft.Bot.Builder.Adapters;
47+
using Microsoft.Bot.Schema;
48+
using System.Threading.Tasks;
49+
50+
namespace Microsoft.Bot.Samples
51+
{
52+
public class ProactiveBot : IBot
53+
{
54+
public async Task OnReceiveActivity(ITurnContext context)
55+
{
56+
if (context.Request.Type is ActivityTypes.Message)
57+
{
58+
var messageText = context.Request?.AsMessageActivity()?.Text;
59+
if (messageText?.Trim().ToLowerInvariant() is "subscrie")
60+
{
61+
// Confirm the request.
62+
await context.SendActivity("Thank You! We will message you shortly.");
63+
64+
// Send the proactive message.
65+
var reference = TurnContext.GetConversationReference(context.Request);
66+
SubscribeUser((BotFrameworkAdapter)context.Adapter,
67+
((BotFrameworkTurnContext)context).BotAppId, reference);
68+
}
69+
else
70+
{
71+
// Prompt the user to type "subscribe".
72+
await context.SendActivity("Type `subscribe` to receive a proactive message.");
73+
}
74+
}
75+
}
76+
77+
private async void SubscribeUser(BotFrameworkAdapter adapter, string appId, ConversationReference reference)
78+
{
79+
await adapter.ContinueConversation(appId, reference, async context =>
80+
{
81+
await Task.Delay(2000);
82+
await context.SendActivity("You've been notified!");
83+
});
84+
}
85+
}
86+
}
87+
```
88+
89+
The bot does not store the conversation reference for later, but you can save this data in your actual code. The bot calls the `SubscribeUser` method and notifies the user that they're now subscribed, and you're then free to do pretty much anything you would normally do in your bot's `OnReceiveActivity` handler.
90+
91+
The `SubscribeUser` method passes the conversation reference, along with the bot's application ID, to the adapter's `ContinueConversation` method. The adapter creates a `context` object and passes it to your callback method, which uses the context to send the message.
92+
93+
> ![NOTE]
94+
> Within the callback, no activity was received so `context.Request` is null.
95+
96+
## Update your Startup.cs file
97+
98+
We still need to add the bot and use the Bot Framework in the `Startus.cs` file. Replace its contents:
99+
100+
```csharp
101+
using Microsoft.AspNetCore.Builder;
102+
using Microsoft.AspNetCore.Hosting;
103+
using Microsoft.Bot.Builder.BotFramework;
104+
using Microsoft.Bot.Builder.Core.Extensions;
105+
using Microsoft.Bot.Builder.Integration.AspNet.Core;
106+
using Microsoft.Extensions.Configuration;
107+
using Microsoft.Extensions.DependencyInjection;
108+
using System;
109+
using System.Diagnostics;
110+
using System.Threading.Tasks;
111+
112+
namespace Microsoft.Bot.Samples
113+
{
114+
public class Startup
115+
{
116+
public IConfiguration Configuration { get; }
117+
118+
public Startup(IHostingEnvironment env)
119+
{
120+
var builder = new ConfigurationBuilder()
121+
.SetBasePath(env.ContentRootPath)
122+
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
123+
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
124+
.AddEnvironmentVariables();
125+
Configuration = builder.Build();
126+
}
127+
128+
// This method gets called by the runtime. Use this method to add services to the container.
129+
public void ConfigureServices(IServiceCollection services)
130+
{
131+
services.AddSingleton(_ => Configuration);
132+
services.AddBot<ProactiveBot>(options =>
133+
{
134+
options.CredentialProvider = new ConfigurationCredentialProvider(Configuration);
135+
options.EnableProactiveMessages = true;
136+
});
137+
}
138+
139+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
140+
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
141+
{
142+
if (env.IsDevelopment())
143+
{
144+
app.UseDeveloperExceptionPage();
145+
}
146+
147+
app.UseDefaultFiles();
148+
app.UseStaticFiles();
149+
app.UseBotFramework();
150+
}
151+
}
152+
}
153+
```
154+
155+
## Test your bot
156+
157+
To test your bot, deploy it to Azure as a registration only bot, and test it in Web Chat.

0 commit comments

Comments
 (0)