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

enterprise notification sample #1954

Merged
merged 10 commits into from
Jul 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added docs/media/emulator-userid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/enterprisenotification-demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 110 additions & 0 deletions samples/EnterpriseNotification/Configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Enterprise Notifications Configuration

Follow the steps below to configure the Enterprise Notifications sample introduced [here](./readme.md)
## Prerequisites

1. A deployed Virtual Assistant. Follow the [Create your Virtual Assistant tutorial](https://github.com/microsoft/botframework-solutions/tree/master/docs#tutorials) to complete this step which will create the core Azure services required. You can use this [sample project](/samples/EnterpriseNotification/VirtualAssistant) if preferred which has the extensions applied for you, otherwise the steps are included below.

2. In addition to the core Virtual Assistant Azure services, you'll need to manually create the following Azure services:

- [Azure Event Hub](https://azure.microsoft.com/en-us/services/event-hubs/) - Create [Here](https://ms.portal.azure.com/#create/Microsoft.EventHub)
- [Azure Function](https://azure.microsoft.com/en-us/services/functions/) - Create [Here](https://ms.portal.azure.com/#create/Microsoft.FunctionApp)
- [Azure Notification Hub](https://azure.microsoft.com/en-us/services/notification-hubs/) - Create [Here](https://ms.portal.azure.com/#create/Microsoft.NotificationHub)
- [Azure Cosmos DB](https://azure.microsoft.com/en-us/services/cosmos-db/) - Create [Here]()

## Event Producer

This sample includes an example [Event Producer](/samples/EnterpriseNotification/EventProducer) console application that sends an Event to the Event Hub for processing simulating creation of a notification.

- Update `appSettings.json` with the `EventHubName` and `EventHubConnectionString` which you can find by going to your EventHub resource, creating an instance and then a `Shared Access Policy`

### Azure Function - Event Handler

This sample includes an example [EventHandler Azure Function](/samples/EnterpriseNotification/EventHandler) which is triggered by Event delivery and handles Event processing.

1. Update [Function1.cs](/samples/EnterpriseNotification/EventHandler/Function1.cs) and change the `EventHubTrigger` to reflect your Event Hub name.
```csharp
public static async Task Run([EventHubTrigger("YourEventHubName", Connection = "EventHubConnection")] EventData[] events, ILogger log)`
```
2. The Azure Functions blade in the Azure Portal provides a wide range of routes to deploy the provided code to your newly created Azure Function including Visual Studio and VSCode. Follow this to deploy the sample EventHandler project.
3. Once deployed, go to the Azure Function in Azure and choose Configuration.
4. Create a new `ConnectionString` called `EventHubConnection` property and provide the same EventHub connection string as in the previous section.
5. In the `Application Settings` section create the following settings which are used bvy the Event Handler.
- `DirectLineSecret` - Located within the Channels section of your Azure Bot Service registration. Required to communicate with your assistant and send events.
- `DocumentDbEndpointUrl` - Located within the CosmoDB Azure Portal blade. Required to access the User Preference store.
- `DocumentDbPrimaryKey`- Located within the CosmoDB Azure Portal blade.

## Virtual Assistant

### ProactiveState Middleware

In order to be able to deliver messages to a conversation the end user must already have had an interaction with the assistant. As part of this interaction a `ConversationReference` needs to be persisted and used to resume the conversation.

We provide a middleware component to perform this ConversationReference storage which can be found in the Bot.Builder.Solutions package.

1. Add this line to your `Startup.cs` to register the proactive state.
```csharp
services.AddSingleton<ProactiveState>();
```
2. Within your `DefaultAdapter.cs` add this line to the constructor
```csharp
ProactiveState proactiveState
```
3. Within your `DefaultAdapter.cs` add this line:
```csharp
Use(new ProactiveStateMiddleware(proactiveState));
```

### Event Handling

The following code handles the `BroadcastEvent` event type sent by the Azure function and is added to the Event Handling code. Within Virtual Assistant this is handled by `OnEventAsync` within MainDialog.cs.

The `_proactiveStateAccessor` is the state that contains a mapping between UserId and previously persisted conversation. It retrieves the proactive state from a store previously saved by enabling the `ProactiveStateMiddleware`.

Within `MainDialog.cs` add the following changes:

1. Add this variable to your `MainDialog` class.
```csharp
private IStatePropertyAccessor<ProactiveModel> _proactiveStateAccessor;
```
2. Add this line to the constructor
```csharp
ProactiveState proactiveState
```
and initialise the state in the constructor
```csharp
_proactiveStateAccessor = proactiveState.CreateProperty<ProactiveModel>(nameof(ProactiveModel));
```
3. Add this event handler to your `OnEventAsync` handler to handle the `BroadcastEvent`

```csharp
case "BroadcastEvent":
var eventData = JsonConvert.DeserializeObject<EventData>(dc.Context.Activity.Value.ToString());

var proactiveModel = await _proactiveStateAccessor.GetAsync(dc.Context, () => new ProactiveModel());

var conversationReference = proactiveModel[MD5Util.ComputeHash(eventData.UserId)].Conversation;
await dc.Context.Adapter.ContinueConversationAsync(_appCredentials.MicrosoftAppId, conversationReference, ContinueConversationCallback(dc.Context, eventData.Message), cancellationToken);
break;
```

## Testing

With these changes in place, when an event is being sent to a user through the bot the user will get the message in the ongoing conversation in a channel. Follow the instructions below to test the end to end flow.

### Bot Framework Emulator

Event generation must generate Events with the same `UserId` as the Emulator is using so the existing conversation can be matched and notifications can be delivered.

1. Using the [Bot Framework Emulator](https://github.com/Microsoft/BotFramework-Emulator) navigate to the Settings section and provide a Guid to represent your simulated UserId. This will ensure any conversations with your Assistant will use this UserId

![UserId Settings](/docs/media/emulator-userid.png)
2. Start a conversation with your assistant which will ensure a proactive state record is persisted for future use.

## Event Producer

Update `SendMessagesToEventHub` within `Program.cs` of the example [EventProducer](/samples/EnterpriseNotification/EventProducer) project to change the UserId to the one created in the previous step. This will ensure any notifications sent are routed to your active conversation.

Run the Event Producer to generate a message and observe that the message is shown within your Emulator session.

![Enterprise Notification Demo](/docs/media/enterprisenotification-demo.png)
51 changes: 51 additions & 0 deletions samples/EnterpriseNotification/EnterpriseNotification.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29102.190
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventHandler", "EventHandler\EventHandler.csproj", "{CC6E0387-FED1-4D72-A089-6B2B81011A23}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VirtualAssistant", "VirtualAssistant\VirtualAssistant.csproj", "{E0A0D813-0D6A-45D8-BF09-4F0AC0269FE3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventProducer", "EventProducer\EventProducer.csproj", "{843204E6-EA50-4DFF-8B8B-E6814D8E6642}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug - NuGet Packages|Any CPU = Debug - NuGet Packages|Any CPU
Debug|Any CPU = Debug|Any CPU
Documentation|Any CPU = Documentation|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CC6E0387-FED1-4D72-A089-6B2B81011A23}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU
{CC6E0387-FED1-4D72-A089-6B2B81011A23}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU
{CC6E0387-FED1-4D72-A089-6B2B81011A23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CC6E0387-FED1-4D72-A089-6B2B81011A23}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC6E0387-FED1-4D72-A089-6B2B81011A23}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU
{CC6E0387-FED1-4D72-A089-6B2B81011A23}.Documentation|Any CPU.Build.0 = Debug|Any CPU
{CC6E0387-FED1-4D72-A089-6B2B81011A23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC6E0387-FED1-4D72-A089-6B2B81011A23}.Release|Any CPU.Build.0 = Release|Any CPU
{E0A0D813-0D6A-45D8-BF09-4F0AC0269FE3}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU
{E0A0D813-0D6A-45D8-BF09-4F0AC0269FE3}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU
{E0A0D813-0D6A-45D8-BF09-4F0AC0269FE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E0A0D813-0D6A-45D8-BF09-4F0AC0269FE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0A0D813-0D6A-45D8-BF09-4F0AC0269FE3}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU
{E0A0D813-0D6A-45D8-BF09-4F0AC0269FE3}.Documentation|Any CPU.Build.0 = Debug|Any CPU
{E0A0D813-0D6A-45D8-BF09-4F0AC0269FE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0A0D813-0D6A-45D8-BF09-4F0AC0269FE3}.Release|Any CPU.Build.0 = Release|Any CPU
{843204E6-EA50-4DFF-8B8B-E6814D8E6642}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU
{843204E6-EA50-4DFF-8B8B-E6814D8E6642}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU
{843204E6-EA50-4DFF-8B8B-E6814D8E6642}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{843204E6-EA50-4DFF-8B8B-E6814D8E6642}.Debug|Any CPU.Build.0 = Debug|Any CPU
{843204E6-EA50-4DFF-8B8B-E6814D8E6642}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU
{843204E6-EA50-4DFF-8B8B-E6814D8E6642}.Documentation|Any CPU.Build.0 = Debug|Any CPU
{843204E6-EA50-4DFF-8B8B-E6814D8E6642}.Release|Any CPU.ActiveCfg = Release|Any CPU
{843204E6-EA50-4DFF-8B8B-E6814D8E6642}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0CBBA70E-7242-4EC3-A76B-FF444246A980}
EndGlobalSection
EndGlobal
Loading