Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
df0dd58
allow for messages with no content (e.g. OPTIONS)
negativeeddy Jun 8, 2021
4deb9a9
upgrade project to .NET 5
negativeeddy Jun 8, 2021
3800edb
updating nuget packages to latest and re-add Newtonsoft back in
negativeeddy Jun 8, 2021
4363fa9
enable using user-secrets
negativeeddy Jun 8, 2021
353464b
quick convert to default hosting
negativeeddy Jun 9, 2021
3f35048
remove Newtonsoft dependency
negativeeddy Jun 9, 2021
6ad2670
refactoring
negativeeddy Jun 9, 2021
bab03dd
switch to logger from console
negativeeddy Jun 9, 2021
4a41f1f
add command line parsing for options
negativeeddy Jun 9, 2021
e5ebdec
refactor
negativeeddy Jun 9, 2021
d85e696
publishing info
negativeeddy Jun 9, 2021
2bd60da
update logging
negativeeddy Jun 9, 2021
57089bf
remove publishing options from project (defer that to devops pipeline)
negativeeddy Jun 9, 2021
218bc78
add arm template for relay
negativeeddy Jun 9, 2021
454f66a
add Deploy to Azure button
negativeeddy Jun 9, 2021
164b508
encode url
negativeeddy Jun 9, 2021
14c8f90
fix name of output variable
negativeeddy Jun 9, 2021
19a5f6a
update readme for console command line
negativeeddy Jun 9, 2021
96e8300
Merge pull request #1 from negativeeddy/commandline
negativeeddy Jun 9, 2021
5a13623
working nuget package
negativeeddy Aug 10, 2021
7c9993a
moved log message to correct place
negativeeddy Aug 10, 2021
47d9c24
docs for composer
negativeeddy Aug 12, 2021
126fe83
set package version
negativeeddy Aug 12, 2021
cba40fe
update package
negativeeddy Aug 12, 2021
4faf7e6
publishing edits
negativeeddy Aug 12, 2021
b14c0d9
Merge pull request #2 from negativeeddy/composer
negativeeddy Aug 12, 2021
7d609be
change CLI exe name to AzureServiceBiusRelay.exe
negativeeddy Aug 24, 2021
0d2ac67
Merge pull request #5 from negativeeddy/renamecli
negativeeddy Aug 24, 2021
1e30bfc
update to project and dependencies to .NET 6
negativeeddy Oct 5, 2022
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
92 changes: 92 additions & 0 deletions Deployment/deploy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"namespaceName": {
"type": "string",
"metadata": {
"description": "Name of the Azure Relay namespace"
}
},
"relayName": {
"type": "string",
"defaultValue": "botrelay",
"metadata": {
"description": "Name of the relay connection"
}
},
"relaySharedAccessPolicyName": {
"type": "string",
"defaultValue": "SendAndListenPolicy",
"metadata": {
"description": "Name of the relay's Shared Access Policy"
}
}
},
"variables": {
"apiVersion": "2017-04-01",
"location": "[resourceGroup().location]",
"hcAuthorizationRuleResourceId": "[resourceId('Microsoft.Relay/namespaces/HybridConnections/authorizationRules', parameters('namespaceName'), parameters('relayName'), parameters ('relaySharedAccessPolicyName'))]"
},
"resources": [
{
"apiVersion": "[variables('apiVersion')]",
"name": "[parameters('namespaceName')]",
"type": "Microsoft.Relay/Namespaces",
"location": "[variables('location')]",
"kind": "Relay",
"resources": [
{
"apiVersion": "[variables('apiVersion')]",
"name": "[parameters('relayName')]",
"type": "HybridConnections",
"dependsOn": [
"[concat('Microsoft.Relay/namespaces/', parameters('namespaceName'))]"
],
"properties": {
"requiresClientAuthorization": "false",
"userMetadata": "Meta Data supplied by user hybridConnections"
},
"resources": [
{
"apiVersion": "[variables('apiVersion')]",
"name": "[parameters('relaySharedAccessPolicyName')]",
"type": "authorizationRules",
"dependsOn": [
"[parameters('relayName')]"
],
"properties": {
"Rights": [
"Send",
"Listen"
]
}
}
]
}
]
}
],
"outputs": {
"SharedAccessPolicyKey": {
"type": "string",
"value": "[listkeys(variables('hcAuthorizationRuleResourceId'), variables('apiVersion')).primaryKey]"
},
"SharedAccessPolicyName": {
"type": "string",
"value": "[parameters ('relaySharedAccessPolicyName')]"
},
"RelayName": {
"type": "string",
"value": "[parameters('relayName')]"
},
"Namespace": {
"type": "string",
"value": "[concat(parameters('namespaceName'),'.servicebus.windows.net')]"
},
"MessagingEndpoint": {
"type": "string",
"value": "[concat('https://', parameters('namespaceName'), '.servicebus.windows.net/', parameters('relayName'), '/api/messages')]"
}
}
}
49 changes: 49 additions & 0 deletions Docs/CommandLine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Command Line Instructions

## Overview

The Azure Bot Relay command line works similar to ngrok. It is a command line tool that will connect to your Azure Service Bus and forward all the incoming bot messages to your local bot.

## Setup

### Deploy an Azure Relay service

Set up the bot relay in the same way indicated in the [README.md](../README.md)

#### Launch your bot locally

1. Start your bot as usual on your local machine

2. Once your bot is running, note the localhost endpoint it is attached to

#### Building and run the relay tool

1. Clone the solution to your machine, open and build the solution in Visual Studio.

2. Run the command line tool with the settings you have captured up until now. The tool has five required options. Four of these are from the deployment outputs of the relaye. The fifth is the URI to your bot (do not include the "/api/messages" portion).

````text
-n, --namespace The name of the relay's namespace, e.g. '[Your Namespace].servicebus.windows.net'

-r, --relay The name of the relay

-p, --policy The name of the relay's Shared Access Policy

-k, --key The Shared Access Policy's key

-b, --botUri The url to your local bot e.g. 'http://localhost:[PORT]'
````

You can specify the parameters either through the Visual Studio project's properties page, or you can run the tool from a command prompt.

Here is an example command line

````text

ServiceBusRelayUtilNetCore.exe -n benwillidemorelay.servicebus.windows.net -r botrelay
-p SendAndListenPolicy -k XOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOX -b http://localhost:3980
````

### Test your bot

1. Test your bot on a channel (Test in Web Chat, Skype, Teams, etc.).
Binary file added Docs/architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
131 changes: 43 additions & 88 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,114 +1,69 @@
# Overview
A relay utility for bots based on Azure Service Bus.
# AzureServiceBusBotRelay

## Overview

A relay utility for bots based on [Azure Relay](https://docs.microsoft.com/en-us/azure/azure-relay/relay-what-is-it).

This utility allows you to forward a message sent to a bot hosted on any channel to your local machine.

It is useful for debug scenarios or for more complex situations where the BotEmulator is not enough (i.e.: you use the WebChat control hosted on a site and you need to receive ChannelData in your requests).
It is useful for debug scenarios or for more complex situations where the BotEmulator is not enough (i.e.: you use the WebChat control hosted on a site and you need to receive ChannelData in your requests or you are testing Teams specific events).

It uses the Azure Relay service along with a small local service to recieve messages from the bot service and forward them to your locally hosted bot. This service can be hosted with the command line tool or installed into your Bot Composer bot as an Adapter package from Nuget.

![architecture diagram](Docs/architecture.png)

### Acknowledgments

Part of this code is based on the work that [Pedro Felix](https://github.com/pmhsfelix/WebApi.Explorations.ServiceBusRelayHost)
and [Gabo Gilbert](https://github.com/gabog/AzureServiceBusBotRelay) have previously done

## Acknowledgments
Part of this code is based on the work that [Pedro Felix](https://github.com/pmhsfelix) did in his project [here](https://github.com/pmhsfelix/WebApi.Explorations.ServiceBusRelayHost).
## Setup

# How to configure and run the utility
### Building with .Net Framework
The relay can be used with traditional code based bots or as a simple add in component to Bot Composer

1. Once the solution has been cloned to your machine, open the solution in Visual Studio.
To setup the Azure Bot Service to connect to your local bot you need to

2. In Solution Explorer, expand the **ServiceBusRelayUtil** folder.
1. Deploy an Azure Relay service
2. Configure your Azure Bot Service to send messages to the Azure Relay
3. Connect to the relay from Bot Composer

3. Open the **App.config** file and replace the following values with those from your service bus (not the hybrid connection).

a. "RelayNamespace" is the name of your service bus created earlier. Enter the value in place of **[Your Namespace]**.

b. "RelayName" is the name of the shared access policy created in steps 9 through 11 during the service bus set up process. Enter the value in place of **[Your Relay Name]**.

c. "PolicyName" is the value to the shared access policy created in steps 9 through 11 during the service bus set up process. Enter the value in place of **[Your Shared Access Policy Name]**.

d. "PolicyKey" is the WCF relay to be used. Remember, this relay is programmatically created and only exists on your machine. Create a new, unused name and enter the value in place of **[Your Policy's Key]**.

e. "TargetServiceAddress" sets the port to be used for localhost. The address and port number should match the address and port used by your bot. Enter a value in place of the "TODO" string part. For example, "http://localhost:[PORT]".

4. Before testing the relay, your Azure Web Bot's messaging endpoint must be updated to match the relay.

a. Login to the Azure portal and open your Web App Bot.

b. Select **Settings** under Bot management to open the settings blade.

c. In the **Messaging endpoint** field, enter the service bus namespace and relay. The relay should match the relay name entered in the **App.config** file and should not exist in Azure.

d. Append **"/api/messages"** to the end to create the full endpoint to be used. For example, “https://example-service-bus.servicebus.windows.net/wcf-example-relay/api/messages".

e. Click **Save** when completed.

5. In Visual Studio, press **F5** to run the project.

6. Open and run your locally hosted bot.

7. Test your bot on a channel (Test in Web Chat, Skype, Teams, etc.). User data is captured and logged as activity occurs.
* If you are using a code only bot and not using Bot Composer, once you set up the Azure Service Bus Relay, see the [command line instructions](Docs/Commandline.md) to connect it to your bot)

- When using the Bot Framework Emulator: The endpoint entered in Emulator must be the service bus endpoint saved in your Azure Web Bot **Settings** blade, under **Messaging Endpoint**.
### Deploy an Azure Relay service

8. Once testing is completed, you can compile the project into an executable.
You can use this button to deploy an Azure Relay service with the correct configuration. You will just need to supply it with a unique name for the Azure Service Bus namespace.

a. Right click the project folder in Visual Studio and select **Build**.
After it completes, select the Outputs tab and copy the 5 values. You will need those to configure the bot relay tool and your bot service.

b. The .exe will output to the **/bin/debug** folder, along with other necessary files, located in the project’s directory folder. All the files are necessary to run and should be included when moving the .exe to a new folder/location.
- The **app.config** is in the same folder and can be edited as credentials change without needing to recompile the project.
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fnegativeeddy%2FAzureServiceBusBotRelay%2Fcommandline%2FDeployment%2Fdeploy.json)

### Building with .Net Core
If you want to deploy the relay service manually you will need to

1. Once the solution has been cloned to your machine, open the solution in Visual Studio.
1. ensure the relay does not require authentication
2. add a shared access policy to the hybrid relay that has permission to send & listen

2. In Solution Explorer, expand the **ServiceBusRelayUtilNetCore** folder.
### Configure your Azure Web App Bot or Azure Bot Registration

3. Open the **appsettings.json** file and replace the following values with those from your service bus hybrid connection.

a. "RelayNamespace" is the name of your service bus created earlier. Enter the value in place of **[Your Namespace]**.
Before testing the relay, your Azure Web App Bot's messaging endpoint must be updated to match the relay.

b. "RelayName" is the name of the hybrid connection created in step 12. Enter the value in place of **[Your Relay Name]**.
1. Login to the Azure portal and open your Web App Bot or Bot Registration.

c. "PolicyName" is the name of the shared access policy created in steps 9 through 11 during the service bus set up process. Enter the value in place of **[Your Shared Access Policy Name]**.
2. Select **Settings** under Bot management to open the settings blade.

d. "PolicyKey" is the value to the shared access policy created in steps 9 through 11 during the service bus set up process. Enter the value in place of **[Your Policy's Key]**.

e. "TargetServiceAddress" sets the port to be used for localhost. The address and port number should match the address and port used by your bot. Enter a value in place of the **"http://localhost:[PORT]"**. For example, "http://localhost:3978".

4. Before testing the relay, your Azure Web App Bot's messaging endpoint must be updated to match the relay.

a. Login to the Azure portal and open your Web App Bot.

b. Select **Settings** under Bot management to open the settings blade.

c. In the **Messaging endpoint** field, enter the service bus namespace and relay.

d. Append **"/api/messages"** to the end to create the full endpoint to be used. For example, “https://example-service-bus.servicebus.windows.net/hc1/api/messages".

e. Click **Save** when completed.

5. In Visual Studio, press **F5** to run the project.

6. Open and run your locally hosted bot.

7. Test your bot on a channel (Test in Web Chat, Skype, Teams, etc.). User data is captured and logged as activity occurs.
3. In the **Messaging endpoint** field, enter the service bus namespace and relay. This is the "messagingEndpoint" value from the output of the deployment step above.

- When using the Bot Framework Emulator: The endpoint entered in Emulator must be the service bus endpoint saved in your Azure Web Bot **Settings** blade, under **Messaging Endpoint**.
Ensure that the URI ends with "/api/messages"

8. Once testing is completed, you can compile the project into an executable.
For example, “https://example-service-bus.servicebus.windows.net/hc1/api/messages".

a. Right click the project folder in Visual Studio and select **Publish**.
4. Click **Save** when completed. (You might have to click save twice)

b. For **Pick a publish Target**, select **Folder**.
### Connect to the relay from Bot Composer

c. For **Folder or File Share**, choose an output location or keep the default.
1. Add the [NegativeEddy.Bots.AzureServiceBusRelay.Adapter]([https://www.nuget.org/packages/NegativeEddy.Bots.AzureServiceBusRelay.Adapter) package to your bot
2. Enable the bot in the External Connections section and fill in the options from the values captured when you deployed the Azure Service Bus
3. Restart your bot

d. Click **Create Profile** to create a publish profile.
### Test your bot

e. Click **Configure...** to change the build configuration and change the following:

- **Configuration** to "Debug | Any CPU"
- **Deployment Mode** to "Self-contained"
- **Target Runtime** to "win-x64"

f. Click **Save** and then **Publish**

g. The .exe will output to the **/bin/debug** folder, along with other necessary files, located in the project’s directory folder. All the files are necessary to run and should be included when moving the .exe to a new folder/location.
- The **appsettings.json** is in the same folder and can be edited as credentials change without needing to recompile the project.
1. Test your bot on a channel (Test in Web Chat, Skype, Teams, etc.).
31 changes: 31 additions & 0 deletions Src/BotServiceBusRelay.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31515.178
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NegativeEddy.Bots.AzureServiceBusRelay.Adapter", "NegativeEddy.Bots.AzureServiceBusRelay.Adapter\NegativeEddy.Bots.AzureServiceBusRelay.Adapter.csproj", "{94BAD246-4EDE-45FA-B5F3-14A6D01BFE16}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NegativeEddy.Bots.AzureServiceBusRelay.CommandLine", "NegativeEddy.Bots.AzureServiceBusRelay.CommandLine\NegativeEddy.Bots.AzureServiceBusRelay.CommandLine.csproj", "{4E7F7A58-BB94-4167-B7FD-DF747DB5412E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{94BAD246-4EDE-45FA-B5F3-14A6D01BFE16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{94BAD246-4EDE-45FA-B5F3-14A6D01BFE16}.Debug|Any CPU.Build.0 = Debug|Any CPU
{94BAD246-4EDE-45FA-B5F3-14A6D01BFE16}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94BAD246-4EDE-45FA-B5F3-14A6D01BFE16}.Release|Any CPU.Build.0 = Release|Any CPU
{4E7F7A58-BB94-4167-B7FD-DF747DB5412E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E7F7A58-BB94-4167-B7FD-DF747DB5412E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E7F7A58-BB94-4167-B7FD-DF747DB5412E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E7F7A58-BB94-4167-B7FD-DF747DB5412E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2C96A03F-F825-402A-B109-0F1FC60BA3CE}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace NegativeEddy.Bots.AzureServiceBusRelay.Adapter
{
public class AzureServiceBusRelayAdapter : BotAdapter
{
public AzureServiceBusRelayAdapter(ILogger<AzureServiceBusRelayAdapter> logger)
{
logger.LogInformation("Created AzureServiceBusRelayAdapter");
}

public override Task DeleteActivityAsync(ITurnContext turnContext, ConversationReference reference, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}

public override Task<ResourceResponse[]> SendActivitiesAsync(ITurnContext turnContext, Activity[] activities, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}

public override Task<ResourceResponse> UpdateActivityAsync(ITurnContext turnContext, Activity activity, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Bot.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using NegativeEddy.Bots.AzureServiceBusRelay.Service;

namespace NegativeEddy.Bots.AzureServiceBusRelay.Adapter
{
public class AzureServiceBusRelayAdapterBotComponent : BotComponent
{
public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
if (configuration != null)
{
services.AddSingleton(new RelayOptions
{
PolicyKey = configuration["SASKey"],
PolicyName = configuration["SASPolicy"],
RelayNamespace = configuration["Namespace"],
RelayName = configuration["Relay"],
});
services.AddHostedService<DispatcherService>();
}
}
}
}
Loading