{"id":20003301,"url":"https://github.com/tompaana/remote-control-bot-sample","last_synced_at":"2025-05-04T15:34:52.165Z","repository":{"id":79870586,"uuid":"84961868","full_name":"tompaana/remote-control-bot-sample","owner":"tompaana","description":"This sample demonstrates how to control a chatbot, built on the Microsoft Bot Framework, utilizing backchannel messages.","archived":false,"fork":false,"pushed_at":"2018-05-30T13:21:10.000Z","size":277,"stargazers_count":11,"open_issues_count":0,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-08T08:05:58.291Z","etag":null,"topics":["chatbots","microsoft-bot-framework","notifications"],"latest_commit_sha":null,"homepage":"http://tomipaananen.azurewebsites.net/?p=2231","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tompaana.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-03-14T14:57:56.000Z","updated_at":"2023-08-29T11:08:06.000Z","dependencies_parsed_at":null,"dependency_job_id":"8cffddc5-143a-4eeb-9545-eb95fba5a124","html_url":"https://github.com/tompaana/remote-control-bot-sample","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tompaana%2Fremote-control-bot-sample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tompaana%2Fremote-control-bot-sample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tompaana%2Fremote-control-bot-sample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tompaana%2Fremote-control-bot-sample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tompaana","download_url":"https://codeload.github.com/tompaana/remote-control-bot-sample/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252357349,"owners_count":21735125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chatbots","microsoft-bot-framework","notifications"],"created_at":"2024-11-13T05:25:03.106Z","updated_at":"2025-05-04T15:34:52.153Z","avatar_url":"https://github.com/tompaana.png","language":"C#","readme":"# Remote Control Bot Sample #\n\nThis sample demonstrates how to control a chatbot, built on the\n[Microsoft Bot Framework](https://dev.botframework.com/), utilizing backchannel\nmessages. The covering note (a blog post) for this sample is here:\n[Remotely Controlled Bots](http://tomipaananen.azurewebsites.net/?p=2231).\nIt is recommended to read that first to understand how the backchannel messages\nwork.\n\n![Sample in action](Documentation/Screenshot.png?raw=true)\n\n## Running and testing ##\n\n1. Clone or copy the repository\n2. Register a bot for this sample in [the bot portal](https://dev.botframework.com/)\n   * Unfortunately registering and publishing the bot is the easiest way to get\n     to test drive it, because the implementation is dependent on\n     [Direct Line](https://docs.botframework.com/en-us/restapi/directline3/)\n3. Get the **app ID** and **app password** (a step in registration phase) and\n   insert them into the [Web.config](RemoteControlBotSample/Web.config)\n4. Publish the bot (and insert the newly created endpoint to the bot portal)\n5. In the portal, activate Direct Line and get the first secret key\n6. Insert the secret key into [Program.cs](RemoteControlBotControllerSample/Program.cs)\n7. Say something to the bot so that it knows who you are (your virtual address),\n   you can do this on any channel the bot is on or using emulator\n   * If you don't say anything the bot won't know you and cannot notify you\n8. Run the console app (RemoteControlBotControllerSample)\n9. Enjoy your three notifications\n\n## Implementation ##\n\nThe implementation consists of roughly 3 different concepts:\n\n1. Backchannel receiver (implemented in this sample by\n   [NotificationsScorable](RemoteControlBotSample/Notifications/NotificationsScorable.cs),\n   see `PrepareAsync` method)\n2. Notification type and handler (in [Notifications](RemoteControlBotSample/Notifications) folder)\n3. Message routing for delivering the notifications to (specific) users\n   * This message routing logic is a subset of features implemented and documented\n     in [Bot Message Routing (component) project](https://github.com/tompaana/bot-message-routing)\n\n### How does it work? ###\n\nLet's look at two scenarios. First, when the bot receives a normal message from\nthe user:\n\n1. A user sends a message to the bot\n   * The Microsoft Bot Framework translates this to an object called `Activity`,\n     where its `Text` property will contain the message\n2. The received `Activity` instance  is **seemingly** passed to the root dialog in\n   [MessagesController](RemoteControlBotSample/Controllers/MessagesController.cs)\n   class\n3. Autofac checks for registered handlers at the previous step (step 2)\n   * It will find two: [MessageRouterScorable](RemoteControlBotSample/MessageRouting/MessageRouterScorable.cs)\n     and [NotificationsScorable](RemoteControlBotSample/Notifications/NotificationsScorable.cs)\n   * `MessageRouterScorable` always stores the sender and the receiver of a\n     message, if they have not been seen before (see\n     [Chatbots as Middlemen article](http://tomipaananen.azurewebsites.net/?p=1851)\n     to understand why)\n   * `NotificationsScorable` on the other hand will look for specific\n     backchannel messages, where the `Text` property of the `Activity` will read\n     `\"notification\"` and then extracts the actual notification content from\n     another property of `Activity` named `ChannelData`\n   * In this case no backchannel message is detected and the root dialog is\n     invoked\n4. Root dialog handles the message as it is defined to\n\nIn the second scenario a backend (or other entity) sends a backchannel message\nto the bot according to the notifications protocol we've agreed on:\n\n1. A notification specific backchannel message is sent to the bot\n2. The received `Activity` instance  is **seemingly** passed to the root dialog\n   in `MessagesController` class - however it the dialog will never receive the\n   `Activity` because of the `NotificationsScorable` class, and that is because...\n3. Autofac happens\n   * Now a backchannel message is detected by `NotificationScorable`, the score\n     will exist and its value will be `1.0d` (fancy way of saying the value of\n     action double type is exactly 1), and as a result,\n     [NotificationsManager](RemoteControlBotSample/Notifications/NotificationsManager.cs)\n     will be told to handle the `Activity` instance and the root dialog is never\n     invoked\n4. `NotificationsManager` uses `MessageRouterManager` to deliver the\n   notifications to desired users\n\n### Why Autofac? ###\n\nAs you noticed from the descriptions of the previous scenarios,\n[Autofac](https://autofac.org/) - an implementation of inversion of control\n(IoC) container - makes it harder to understand the execution flow of the code\nwithout a thorough inspection (or proper documentation). In other words, IoC\nmakes it more difficult to have self-documenting code. That's why I don't like\nAutofac or IoC containers in general. I'd rather have the backchannel detection\n(and other things) written in\n[MessagesController class](/RemoteControlBotSample/Controllers/MessagesController.cs),\nbefore the decision to forward the `Activity` instance to the root dialog is made:\n\n```cs\nWebApiConfig.MessageRouterManager.MakeSurePartiesAreTracked(activity);\nstring notificationData = string.Empty;\n\nif (NotificationsManager.TryGetNotificationData(activity, out notificationData))\n{\n    // A notification related backchannel message was detected\n    await NotificationsManager.SendNotificationAsync(notificationData);\n}\nelse\n{\n    await Conversation.SendAsync(activity, () =\u003e new RootDialog());\n}\n```\n\nHowever, if you are using the Microsoft Bot Builder SDK, there is no escape from\nAutofac since the SDK is built using it. You can still avoid the use in the code\nyou write. But that's my preference. You will have yours and it's neither right\nnor wrong. Only debatable :)\n\n## See also ##\n\n* [Remotely Controlled Bots article](http://tomipaananen.azurewebsites.net/?p=2231)\n* [Interruption Bot Sample](https://github.com/svandenhoven/Bots/tree/master/BotNotificationInteruptions): *\"Contains a bot that can handle interuptions from a proactive bot. Low Prio interruptions are stacked and only shown when a defined dialog has stopped.\"*\n* [Bot Message Routing (component) project](https://github.com/tompaana/bot-message-routing)\n* [Intermediator Bot Sample](https://github.com/tompaana/intermediator-bot-sample)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftompaana%2Fremote-control-bot-sample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftompaana%2Fremote-control-bot-sample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftompaana%2Fremote-control-bot-sample/lists"}