GithubHelp home page GithubHelp logo

microsoft / botbuilder-dotnet Goto Github PK

View Code? Open in Web Editor NEW
848.0 83.0 478.0 49.04 MB

Welcome to the Bot Framework SDK for .NET repository, which is the home for the libraries and packages that enable developers to build sophisticated bot applications using .NET.

Home Page: https://github.com/Microsoft/botframework

License: MIT License

C# 97.11% Batchfile 0.05% HTML 2.13% PowerShell 0.32% Shell 0.03% ANTLR 0.25% JavaScript 0.03% Smarty 0.09% ASP.NET 0.01%
bots bot bot-framework sdk dotnet dotnet-core dotnet-core2 microsoft-bot-framework microsoft-cognitive-services

botbuilder-dotnet's Introduction

Bot Framework for dotnet

This repository contains code for the .NET version of the Microsoft Bot Framework SDK, which is part of the Microsoft Bot Framework - a comprehensive framework for building enterprise-grade conversational AI experiences.

This SDK enables developers to model conversation and build sophisticated bot applications using .NET. SDKs for JavaScript, Python and Java (preview) are also available.

To get started building bots using the SDK, see the Azure Bot Service Documentation.

For more information jump to a section below.

Build Status

Branch Description Build Status Coverage Status Windows Bot Test Status Linux Bot Test Status
Main 4.19.* Preview Builds Build Status Coverage Status Tests Status Tests Status

Packages

Name Released Package Daily Build
Microsoft.Bot.Builder BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Adapters.Facebook BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Adapters.Slack BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Adapters.Twilio BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Adapters.Webex BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.AI.LUIS BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.AI.Orchestrator BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.AI.QnA BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.ApplicationInsights BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Azure BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Azure.Blobs BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Azure.Queues BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Dialogs BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Dialogs.Adaptive BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Dialogs.Adaptive.Runtime BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Dialogs.Adaptive.Testing BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Dialogs.Debugging BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Dialogs.Declarative BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Integration.ApplicationInsights.Core BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Integration.ApplicationInsights.WebApi BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Integration.AspNet.Core BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Integration.AspNet.WebApi BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.LanguageGeneration BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Parsers.LU BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.TemplateManager BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Builder.Testing BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Configuration BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Connector BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Schema BotBuilder Badge BotBuilder Badge
Microsoft.Bot.Streaming BotBuilder Badge BotBuilder Badge

Daily Feeds

The daily feeds are published to Azure Artifacts and MyGet.

  • The Azure Artifacts daily feed is our preferred method to obtain the most recent Bot Framework NuGet packages. To use the daily builds published to Azure Artifacts, use: https://pkgs.dev.azure.com/ConversationalAI/BotFramework/_packaging/SDK/nuget/v3/index.json

  • For detailed instructions to consume the daily builds in Azure Artifacts visit this page.

  • To use the daily builds published to MyGet, please follow the instructions here. NOTE: The MyGet feed will be depecrated soon. Please use the Azure Artifacts daily feed instead.

Dependency Graph

To view our libraries' interdependencies, you can refer to the dependency graph for our libraries.

Getting Started

To get started building bots using the SDK, see the Azure Bot Service Documentation.

The Bot Framework Samples includes a rich set of samples repository.

If you want to debug an issue, would like to contribute, or understand how the Bot Builder SDK works, instructions for building and testing the SDK are below.

Prerequisites

Clone

Clone a copy of the repo:

git clone https://github.com/Microsoft/botbuilder-dotnet.git

Change to the SDK's directory:

cd botbuilder-dotnet

Build and test locally

Open Microsoft.Bot.Builder.sln in Visual Studio. On the menu bar, choose Build > Build Solution.

When the solution is built, local NuGet package files (.nupkg) are generated for each project and are available under the outputPackages directory. You can add this folder to your NuGet Package Manager source list in Visual Studio (choose Tools > NuGet Package Manager > Package Manager Settings from the Visual Studio menu and add an additional Package Sources from there), allowing you to consume these in your local projects.

Getting support and providing feedback

Below are the various channels that are available to you for obtaining support and providing feedback. Please pay carful attention to which channel should be used for which type of content. e.g. general "how do I..." questions should be asked on Stack Overflow, Twitter or Gitter, with GitHub issues being for feature requests and bug reports.

Github issues

Github issues should be used for bugs and feature requests.

Stack overflow

Stack Overflow is a great place for getting high-quality answers. Our support team, as well as many of our community members are already on Stack Overflow providing answers to 'how-to' questions.

Azure Support

If you issues relates to Azure Bot Service, you can take advantage of the available Azure support options.

Twitter

We use the @msbotframework account on twitter for announcements and members from the development team watch for tweets for @msbotframework.

Gitter Chat Room

The Gitter Channel provides a place where the Community can get together and collaborate.

Contributing and our code of conduct

We welcome contributions and suggestions. Please see our contributing guidelines for more information.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

Reporting Security Issues

Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC) at [email protected]. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the Security TechCenter.

Copyright (c) Microsoft Corporation. All rights reserved.

Licensed under the MIT License.

botbuilder-dotnet's People

Contributors

boydc2014 avatar carlosscastro avatar ceciliaavila avatar chrimc62 avatar cleemullins avatar cosmicshuai avatar danieladu avatar daveta avatar ddefromor avatar denscollo avatar enzocano avatar ericdahlvang avatar feich-ms avatar gabog avatar garypretty avatar gurvsing avatar jeffders avatar johnataylor avatar jonathanfingold avatar juanar avatar luhan2017 avatar matiasroldan6 avatar mrivera-ms avatar pcostantini avatar ramjotsingh avatar stevengum avatar tomlm avatar tracyboehrer avatar victorgrycuk avatar willportnoy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

botbuilder-dotnet's Issues

QnAMaker HttpClient disposal anti-pattern

I've already filed #106 regarding some issues regarding the HttpClient disposal anti-pattern, but QnAMaker is a little more nuanced. The QnAMaker class at least holds onto its HttpClient instance in a field and will reuse it across calls to an instance, but should someone dispose of the QnAMaker instance it will also dispose of that underlying HttpClient. This could lead to developers to using the QnAMaker class in a non-singleton style and thus lead to the same resource starvation issues as mentioned in #106.

Recommend moving the HttpClient into a static field in the class and removing the IDisposable implementation altogether.

Perf - FlexObject::TryGetMember double dictionary access

The implementation of FlexObject::TryGetMember uses a pattern of calling ContainsKey to determine if the underlying Dictionary<K,V> contains a key and then, if it does, uses the indexer to actually get the value. This is more costly than it needs to be as it has to hash the key twice and do two hash lookups into the dictionary:

  1. just to see if it contains the key
  2. to go get the value

A better pattern for this is to use the Dictionary<K,V>::TryGetValue method which will simultaneously look up the key and, if it exists, return the value via the out parameter while simultaneously returning a bool to indicate whether or not an entry with the specified key exists.

NOTE: this technically only impacts users that choose to use the dynamic programming model when working with FlexBox types.

Sample code snippets

Snippets
add state
Simple Conversation Modeling (Echo Bot, primitives)
Complex Conversation Modeling (Alarm Bot, multi-dialogs, cards)
LUIS
QnA
Cards
Proactive Messages
Middleware
Directline
Support

Add dialog version middleware

v3 has a dialog version middleware which is useful for you adding a major.minor version to your bots conversational system. This version number gets stamped on every conversation state object an anytime the conversations major versions no longer match the state will be automatically deleted and the user will be sent a message saying "A system update has occurred and we need to start over." Why do you need to do that?

If you deploy a major update to your bot you run the risk of users getting into a stuck state due to the fact their current conversation state no longer reflects the structure of the bot that was just deployed. In some cases this can result in your bot throwing an exception which is actual a good thing because we'll catch that and automatically deleted the conversation state. The more difficult scenario is that instead of throwing an exception you can end up trapping the user in an infinite loop that they can't get out of. Given the user a way to always say "goodbye" and force a conversation state deletion is one way to get them out but incrementing your bots major version number is a more automatic way of doing this and prevent the user just having to know they can say "goodbye".

I can't say enough how critical a feature this is so while it could be done as a sample its probably best as a piece of middleware that we encourage all developers to always include in their bot somewhere after the ConversationStateStore middleware.

Context.Request.Type being mapped to ActivityTypes class is misleading - suggest RequestTypes (the pattern we used in v3)

When switching on request types coming in from the user, developers would like to use constants/enums to get type safety and avoid fat-fingering errors.

That said, in BBv3 we had "ActivityTypes" class full of string constants to use for this purpose. In v4, we have context.*Request*.Type yet no accompanying RequestTypes class with the constants to be used for comparison. Users are left guessing if ActivityTypes really is the thing they need, or if they simply need to debug, see what comes through, and switch on that.

Phase 1 packages

1. Microsoft.bot.builder
2. Microsoft.bot.builder.ai (LUIS, QnA, translator)
3. Microsoft.bot.builder.azure (table storage)
4. Microsoft.bot.builder.botframework

SDK v4 initial UA content

Provide the following:

  • Overview
  • Architecture (boxology)
  • Quickstart (simple bot)
  • How-tos (based on CSE snippets)
  • Readme
    • Short intro, download packages and tools, link to existing connector docs
  • FAQ
  • Roadmap

Add warning if requests take longer then 10 seconds to process

The bot has roughly 10-12 seconds to respond to a received activity before the channel times out. A channel timing out can result in some cases the message being re-delivered and in the case of cortana the skill being prematurely ended.

This feature would add a piece of middleware or sample that would log out that the bot is taking too long and the developer should investigate why. It could for instance log a warning for requests longer than 8 seconds and an error for requests longer then 12 seconds.

Need simple prompting mechanism

In keeping with the desire to be unopinionated with the core framework, we understand that simple prompting (eg: PromptDialog...) isn't built in.
However, bots almost always have a need to prompt the user for data entry so having an add-on package that provides this functionality in a very clean & concise way is highly desired.

Add support for "invoke" activity to adapter

We need to support "invoke" activities which are complex because the protocol changes such that we need to send an HTTP StatusCode and Body in response to the received "invoke" activity. To do that we need to somehow get that code and body down to the connector while it holds open the response object.

The idea we've come up with is to add a new "result" or "invoke-result" activity type (we can discuss name more) that is a fake activity much like the "delay" activity. This activity will contain the StatusCode & Body the bot would like to return and when the connector receives this activity in it's post() method it will store it in a table keyed by channelId+activityId. Then when the request naturally unwinds the connector can retrieve the result from the table and complete the response.

This feature is used by payments and heavily used by Teams so we need it before //build.

[bug]: No obvious way to add a HeroCard to a MessageActivity

For .NET, HeroCard is not of type Attachment, so I can't translate the following Node.js snippet to C#:

const { MessageStyler, CardStyler } = require('botbuilder');

const message = MessageStyler.attachment(
    CardStyler.heroCard(
        'White T-Shirt',   // cards title 
        ['https://example.com/whiteShirt.jpg'],   // cards image(s)
        ['buy']   // cards button(s)
     )
);

context.reply(message);

Also, there is not yet a CardFactory or CardStyler class on the .NET side.

Add goodbye middleware

Another important piece of middleware is a component that is always listening for the user to say "goodbye" or "I'd like to start over". When it detects either of these intents it should first clear the conversation sand then send a reply to the user or return them to the beginning of the conversation.

This could be done as a sample or middleware but it's another important feature that every production bot needs to help combat users getting into a stuck state.

Bug in c# context.Reply update

re: #92, fix for #76

The following code:

            var activity = Activity.CreateMessageActivity();
            var attachment = new Attachment()
            {
                ContentUrl = "http://example.com/sample.jpg",
                ContentType = "image/jpg"
            };
            activity.Attachments.Add(attachment);

            // Send the activity as a reply to the user.
            context.Reply(activity);

Generates on the context object the following response object, which is missing key information: channelData, channelId, conversation, from, replyToId, and serviceUrl. This causes a null argument exception in BotFrameworkAdapter.cs line 47.

[
  {
    "type": "message",
    "id": null,
    "timestamp": null,
    "localTimestamp": null,
    "serviceUrl": null,
    "channelId": null,
    "from": null,
    "conversation": null,
    "recipient": null,
    "textFormat": null,
    "attachmentLayout": null,
    "membersAdded": null,
    "membersRemoved": null,
    "reactionsAdded": null,
    "reactionsRemoved": null,
    "topicName": null,
    "historyDisclosed": null,
    "locale": null,
    "text": null,
    "speak": null,
    "inputHint": null,
    "summary": null,
    "suggestedActions": null,
    "attachments": [
      {
        "contentType": "image/jpg",
        "contentUrl": "http://example.com/sample.jpg",
        "content": null,
        "name": null,
        "thumbnailUrl": null
      }
    ],
    "entities": [],
    "channelData": null,
    "action": null,
    "replyToId": null,
    "value": null,
    "name": null,
    "relatesTo": null,
    "code": null,
    "expiration": null,
    "importance": null,
    "deliveryMode": null,
    "textHighlights": null
  }
]

ReplyWIth doesn't work anymore with proactive messages

Hi, I am trying the latest version of the framework, I used to be able to use proactive messages with ReplyWith, but for some reason it stopped working since my last update (Monday AM).
From debugging it seems that context.Request in TemplateManager seems to be null and it can't find the template for the response, is this a known issue?

I'm adding the source of a Controller that received a rest call and initiates a proactive message for reference.

Thanks

FlexObject indexer returns dynamic which forces dynamic programming model even if developer wants to stick to strongly typed model

Currently the indexer of the FlexObject class is typed as dynamic. The problem with this is that, as a .NET developer, if I'm choosing not to use the dynamic programming model of FlexObject and am trying to get/set values through the indexer, it is "forcing" me into the dynamic model.

The indexer should instead be typed as object which would prevent developers being opted into the dynamic model when they don't want/need to be. Note that this doesn't prevent them from treating the values coming out of the indexer as dynamic if they want to, it just won't force it any more.

Wiki needs better instruction on referencing locally-built nuget packages

When building the current BotBuilder project libraries, nupkg files are created. Due to the workflow of VS 2017, these can't be put in a post-build step to copy to a central location (eg: /build).

Users aren't directed to take those nuget packages and put them in a common spot, nor how to create a nuget package source for use in their own bot.

Suggest adding direction to do relevant steps (manually copy from location x, y, z to here, then go to VS and add nuget package source to that location) or simply run the following operations from a VS 2017 command line in the bot builder repo root directory:

for /R "%cd%\libraries" %%f in (*.nupkg) do xcopy /Y "%%f" "%cd%\build"

nuget sources Remove -Name bfv4-local
nuget sources Add -Name bfv4-local -Source %__startPath%\build

Restart VS after running the above commands, and local nuget packages are available as dependencies to any bot solution

[bug]: Missing an IBotContext.Reply(IMessageActivity) overload

This is the only signature for IBotContext.Reply on the dotnet side:

BotContext Reply(string text);

Thus, the following Node.js code cannot be translated to .NET:

const message = MessageStyler.contentUrl('http://example.com/sample.jpg', 'image/jpeg');
context.reply(message);

Phase 0 packages

All published as 4.x versions

  1. microsoft.bot.connector
  2. Microsoft.bot.aspnet
  3. Microsoft.bot.aspnetcore

QoL - Microsoft.Bot namespace collides with Bot class name

Because the root namespace is Microsoft.Bot and there is a class named Bot, there is no way to use the plain class name in code without either aliasing it or prefixing it with the Builder namespace. That means that a new user sitting down and writing the following code:

Bot myBot = new Bot(...);

Will immediately run into errors with intellisense finding the class and putting red squigglies under the class name, and the following compile time error:

Error	 CS0118 'Bot' is a namespace but is used like a type

Instead you are forced to use either explicit namespace scoping:

Builder.Bot myBot = new Builder.Bot(...);

Or you would have to alias the Bot class to a name that doesn't collide like:

using BotIMean = Microsoft.Bot.Builder.Bot;
.
.
.

BotIMean myBot = new BotIMean(...);

This is going to be a problem for those who just sit down to use the SDK for the first time and also seems like a silly thing to have to constantly work around. Either the namespace could be renamed to something like Microsoft.Bots or the class could be renamed, but that seems less appropriate since that really is the "thing" that the noun represents.

FlexObject::Clone issues

First, FlexObject::Clone actually deserializes to a more specific subclass of StoreItem which could lead to some very strange behavior. A couple of scenarios that this would be produce unexpected results for:

  • You're just cloning a "raw" FlexObject instance... why would you get back a StoreItem?
  • You're cloning a subclass of StoreItem, maybe a FooItem... one would expect an instance of FooItem to come back, not just a StoreItem.

At bare minimum, the FlexObject::Clone implementation should produce an instance of the exact type that is being cloned (e.g. use this.GetType()).

Bigger picture, implementing ICloneable in .NET is generally frowned upon these days for many reasons, this being one of them. Therefore, I strongly suggest reconsidering whether the Bot Framework support any type of cloning at all. As a .NET user, I don't expect it because I am already aware of this can of worms. Guidance can always be given to those who might find a need for cloning to implement it themselves.

Q and A tests are disabled

The remote Q and A service is returning 404 and so the tests have been disabled.

This issue is here to track re-enabling these tests which will require fixing the remote Q and A model.

HttpClient disposal anti-pattern

There are several instances of the HttpClient disposal anti-pattern within the code base. Under a sufficient amount of load this will cause socket level resource exhaustion that will result in intermittent connection failures and, ultimately, prevent bots from scaling.

The following classes are currently using this anti-pattern:

  • Microsoft.Bot.Builder.Ai
    • Translator
  • Microsoft.Bot.Builder.Connector
    • EndorsementsRetriever
    • MicrosoftAppCredentials
    • AttachmentsEx

Middleware.postActivity() should execute bottom to top

The first piece of middleware added should be the last one executed for postActivity(). The rational for this is that your analytics middleware is likely the first thing in the pipe and it would be the last thing you want to run so that can accurately log timing data.

Same thing goes for state middleware. Components added after any state manager could add stuff to state that needs to be flushed and if that code runs after the state manager has already flushed its state it won't get saved.

add error message middleware

This could be done as a sample versus an actual piece of middleware we ship but we need a piece of middleware that you install first in your bot and it listens for an error to be thrown and then simply sends a message to the user telling the something wen't wrong. Other middleware on the stack should have already processed/logged the error so this middleware is just about telling the user something happened.

I think the general strategy we want for all middleware error wise is to handle the error and then re-throw it so someone else can handle it.

In JS I think this middleware looks like:

bot.use({
    contextCreated: (context, next) => {
        return new Promise((resolve, reject) => {
            next().then(
                () => { resolve() },
                (err) => {
                    context.responses.push({ type: 'message', text: `Oops... Something went wrong.`});
                    reject(err);
                }
            );
        });
    }
});

.NET/StateManager(FileStorage): [bug] save state contingent on context.Reply

The following code describes a bot that asks a user for their name on a ConversationUpdate activity (if the bot hasn't already saved their name to the user state).

The following ASP.NET controller defines a bot that runs locally and can ask a user for their name. It successfully stores that name in context.State.User storage when tested via the emulator.

Issue:

  1. Comment out the line context.Reply($"Pleased to meet you, {name}.");
  2. Relaunch the bot and refresh the conversation in the emulator.
  3. Use the ellipsis menu to delete user data.
  4. Refresh the conversation.
  5. The bot now asks for the user's name, but no longer persists the user's answer.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Storage;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using System.IO;
using System.Threading.Tasks;
using System.Linq;

namespace ConciergeBot.Controllers
{
    [Route("api/[controller]"), Produces("application/json")]
    public class MessagesController : Controller
    {
        const string waitingOnName = "greeter_namePrompted";
        const string nameValue = "greeter_name";

        Bot _bot;
        BotFrameworkAdapter _adapter;

        public MessagesController(IConfiguration configuration)
        {
            string appId = configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value ?? string.Empty;
            string appKey = configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppPasswordKey)?.Value ?? string.Empty;

            _adapter = new BotFrameworkAdapter(appId, appKey);

            _bot = new Bot(_adapter)
                .Use(new BotStateManager(new FileStorage(Path.GetTempPath())))
                .OnReceive(async (context, next) =>
                {
                    switch (context.Request.Type)
                    {
                        case ActivityTypes.Message:
                            var message = context.Request.AsMessageActivity();
                            bool areWaitingOnName = context.State.Conversation[waitingOnName] ?? false;
                            if (areWaitingOnName && !string.IsNullOrWhiteSpace(message.Text))
                            {
                                string name = message.Text.Trim();
                                context.State.User[nameValue] = name;
                                context.State.Conversation.Remove(waitingOnName);
                                // State is not saved if the following line is commented out.
                                context.Reply($"Pleased to meet you, {name}.");
                            }
                            else
                            {
                                context.Reply($"You typed: {message.Text}");
                            }
                            break;
                        case ActivityTypes.ConversationUpdate:
                            var update = context.Request.AsConversationUpdateActivity();
                            if (update.MembersAdded.Any() &&
                                update.MembersAdded[0].Id != update.Recipient.Id)
                            {
                                if (context.State.User.ContainsKey(nameValue))
                                {
                                    string name = context.State.User[nameValue];
                                    context.Reply($"Hi {name}");
                                }
                                else
                                {
                                    context.Reply("Hi user, what is your name?");
                                    context.State.Conversation[waitingOnName] = true;
                                }
                            }
                            if (update.MembersRemoved.Any() &&
                            update.MembersRemoved[0].Id != update.Recipient.Id)
                            {
                                if (context.State.User.ContainsKey(nameValue))
                                {
                                    string name = context.State.User[nameValue];
                                    context.Reply($"Goodbye, {name}.");
                                }
                                else
                                {
                                    context.Reply("Goodbye.");
                                }
                            }
                            break;
                        case ActivityTypes.DeleteUserData:
                            context.State.User.Clear();
                            context.Reply("Deleted your data.");
                            return;
                        default:
                            break;
                    }
                    await Task.Yield();
                });
        }

        [HttpPost, Authorize(Roles = "Bot")]
        public async void Post([FromBody]Activity activity)
        {
            await _adapter.Receive(HttpContext.Request.Headers, activity);
        }
    }
}

StoreItems<StoreItemT> doesn't really "do" anything

The StoreItems<StoreItemT> type is a subclass of the "vanilla", StoreItems class which is capable of storing a heterogeneous set of StoreItem instances which can be retrieved via the Get<T> method. It seems like the intention of creating StoreItems<StoreItemT> was to allow the user to control the exact subset of types that could be stored (via StoreItemT), but ultimately it doesn't provide any further implementation and thus the consumer still has to provide T to the Get<T> call each time which could, theoretically, mean I could ask for a T that is not a subset of StoreItemT anyway.

There's actually no way to express exactly what I think was being attempted here in C#/.NET. If the framework wants to provide both then two separate classes are probably the way to go:

  1. StoreItems as it exists today with T Get<T>(string name)
  2. StoreItems<TStoreItem> that doesn't subclass StoreItems and provides its own TStoreItem Get (string name) method.

EndorsementsComparer in the Connector should be removed

This private class is used in a single spot, simply to enable the .Distinct() method. There are also no tests around this.

Remove this class, and switch to a simpler method for returning the distinct set of endorsements. Include tests.

OnReceive() adds handler to middleware pipeline. Every time it's executed.

In a case where a user registers their bot as a Singleton in Startup.cs like so:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(
        new Bot(new BotFrameworkAdapter(Configuration))
            .Use(new BotStateManager(new MemoryStorage())
        )
    );

    services.AddMvc();
}

And then adds the bot logic inside their MessagesController like so:

public MessagesController(Bot b, BotFrameworkAdapter adapter)
{
    _bot = b;

    _bot.OnReceive(async (context, nextDelegate) =>
    {
        var userMessage = context.Request.AsMessageActivity().Text;

        var turnNumber = (int)(context.State.Conversation[@"turnNumber"] ?? 1);
        context.Reply($@"#{turnNumber++}: You said {userMessage}");

        context.State.Conversation[@"turnNumber"] = turnNumber;

        await nextDelegate();
    });
}

They will get n+1 messages echo'd back to them for response N.

In other words, say 'hi'
and get

you said hi

say 'hi' again and get

you said hi
you said hi

This is due to:
https://github.com/Microsoft/botbuilder-dotnet/blob/master/libraries/Microsoft.Bot.Builder/Middleware/MiddlewareSet.cs#L29

however the other methods in MiddlewareSet will also result in this anomaly; we're wrapping every OnReceive in a new Anonymous middleware and adding it to the pipeline.

cc @cleemullins, @cmayomsft

Break QnA client functionality out from middleware

The QnAMaker class is currently written as a piece of middleware, but it is technically also a client implementation in that you could use it purely to call GetAnswers. It would be great to decouple the client functionality from the middleware implementation so that the client could be used on its own for other scenarios (e.g. custom middleware).

NOTE: the Translator and TranslatorMiddleware is a good example of the functionality already being decoupled.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.