[#4366] [TestBot] Consolidate duplicate Test project and test code (#4736)

* Add TestBot.Shared project

* Move duplicated code into TestBot.Shared project

* Combine TestBot.Tests and TestBot.NetCore21.Tests

Co-authored-by: Joel Mut <joel.mut@southworks.com>
This commit is contained in:
Denise Scollo 2020-10-13 17:53:18 -03:00 коммит произвёл GitHub
Родитель b8982b2a2f
Коммит 2e852e299b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
87 изменённых файлов: 1035 добавлений и 3761 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,48 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Xunit;
namespace Microsoft.BotBuilderSamples.Tests.Bots
{
public class DialogAndWelcomeBotTests
{
[Fact]
public async Task ReturnsWelcomeCardOnConversationUpdate()
{
// Arrange
var mockRootDialog = SimpleMockFactory.CreateMockDialog<Dialog>(null, "mockRootDialog");
// TODO: do we need state here?
var memoryStorage = new MemoryStorage();
var sut = new DialogAndWelcomeBot<Dialog>(new ConversationState(memoryStorage), new UserState(memoryStorage), mockRootDialog.Object, null);
var conversationUpdateActivity = new Activity
{
Type = ActivityTypes.ConversationUpdate,
MembersAdded = new List<ChannelAccount>
{
new ChannelAccount { Id = "theUser" },
},
Recipient = new ChannelAccount { Id = "theBot" },
};
var testAdapter = new TestAdapter(Channels.Test);
// Act
// Note: it is kind of obscure that we need to use OnTurnAsync to trigger OnMembersAdded so we get the card
await testAdapter.ProcessActivityAsync(conversationUpdateActivity, sut.OnTurnAsync, CancellationToken.None);
var reply = testAdapter.GetNextReply();
// Assert
var m = (IMessageActivity)reply;
Assert.Equal(1, m.Attachments.Count);
Assert.Equal("application/vnd.microsoft.card.adaptive", m.Attachments.FirstOrDefault()?.ContentType);
}
}
}

Просмотреть файл

@ -1,100 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
namespace Microsoft.BotBuilderSamples.Tests.Bots
{
public class DialogBotTests
{
//[Fact]
//public async Task LogsInformationToILogger()
//{
// // Arrange
// var memoryStorage = new MemoryStorage();
// var conversationState = new ConversationState(memoryStorage);
// var userState = new UserState(memoryStorage);
// var mockRootDialog = SimpleMockFactory.CreateMockDialog<Dialog>(null, "mockRootDialog");
// var mockLogger = new Mock<ILogger<DialogBot<Dialog>>>();
// mockLogger.Setup(x =>
// x.Log(It.IsAny<LogLevel>(), It.IsAny<EventId>(), It.IsAny<object>(), null, It.IsAny<Func<object, Exception, string>>()));
// // Run the bot
// var sut = new DialogBot<Dialog>(conversationState, userState, mockRootDialog.Object, mockLogger.Object);
// var testAdapter = new TestAdapter();
// var testFlow = new TestFlow(testAdapter, sut);
// await testFlow.Send("Hi").StartTestAsync();
// // Assert that log was changed with the expected parameters
// mockLogger.Verify(
// x => x.Log(
// LogLevel.Information,
// It.IsAny<EventId>(),
// It.Is<object>(o => o.ToString() == "Running dialog with Message Activity."),
// null,
// It.IsAny<Func<object, Exception, string>>()),
// Times.Once);
//}
[Fact]
public async Task SavesTurnStateUsingMockWithVirtualSaveChangesAsync()
{
// Note: this test requires that SaveChangesAsync is made virtual in order to be able to create a mock.
var memoryStorage = new MemoryStorage();
var mockConversationState = new Mock<ConversationState>(memoryStorage)
{
CallBase = true,
};
var mockUserState = new Mock<UserState>(memoryStorage)
{
CallBase = true,
};
var mockRootDialog = SimpleMockFactory.CreateMockDialog<Dialog>(null, "mockRootDialog");
var mockLogger = new Mock<ILogger<DialogBot<Dialog>>>();
// Act
var sut = new DialogBot<Dialog>(mockConversationState.Object, mockUserState.Object, mockRootDialog.Object, mockLogger.Object);
var testAdapter = new TestAdapter();
var testFlow = new TestFlow(testAdapter, sut);
await testFlow.Send("Hi").StartTestAsync();
// Assert that SaveChangesAsync was called
mockConversationState.Verify(x => x.SaveChangesAsync(It.IsAny<TurnContext>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()), Times.Once);
mockUserState.Verify(x => x.SaveChangesAsync(It.IsAny<TurnContext>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()), Times.Once);
}
[Fact(Skip = "TODO: need to figure out how to implement this version of the test")]
public async Task SavesTurnStateUsingMemoryStorage()
{
// TODO: Figure out how to implement this test.
// Note: this doesn't require a virtual SaveChangesAsync and it manually inspects storage to ensure the save methods were called.
var memoryStorage = new MemoryStorage();
var conversationState = new ConversationState(memoryStorage);
var userState = new UserState(memoryStorage);
var mockRootDialog = new Mock<Dialog>("mockRootDialog");
mockRootDialog.Setup(x => x.ContinueDialogAsync(It.IsAny<DialogContext>(), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(new DialogTurnResult(DialogTurnStatus.Empty)));
var mockLogger = new Mock<ILogger<DialogBot<Dialog>>>();
// Run the bot
var sut = new DialogBot<Dialog>(conversationState, userState, mockRootDialog.Object, mockLogger.Object);
var testAdapter = new TestAdapter();
var testFlow = new TestFlow(testAdapter, sut);
await testFlow.Send("Hi").StartTestAsync();
// Assert that SaveChangesAsyncWasCalled
Assert.True(false, "TODO");
}
}
}

Просмотреть файл

@ -1,56 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Routing;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Moq;
using Xunit;
namespace Microsoft.BotBuilderSamples.Tests.Controllers
{
public class BotControllerTests
{
[Fact]
public async Task PostAsyncCallsProcessAsyncOnAdapter()
{
// Create MVC infrastructure mocks and objects
var request = new Mock<HttpRequest>();
var response = new Mock<HttpResponse>();
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(x => x.Request).Returns(request.Object);
mockHttpContext.Setup(x => x.Response).Returns(response.Object);
var actionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ControllerActionDescriptor());
// Create BF mocks
var mockAdapter = new Mock<IBotFrameworkHttpAdapter>();
mockAdapter
.Setup(x => x.ProcessAsync(It.IsAny<HttpRequest>(), It.IsAny<HttpResponse>(), It.IsAny<IBot>(), It.IsAny<CancellationToken>()))
.Returns(Task.CompletedTask);
var mockBot = new Mock<IBot>();
// Create and initialize controller
var sut = new BotController(mockAdapter.Object, (s) => mockBot.Object)
{
ControllerContext = new ControllerContext(actionContext),
};
// Invoke the controller
await sut.PostAsync("doesn't matter");
// Assert
mockAdapter.Verify(
x => x.ProcessAsync(
It.Is<HttpRequest>(o => o == request.Object),
It.Is<HttpResponse>(o => o == response.Object),
It.Is<IBot>(o => o == mockBot.Object),
It.IsAny<CancellationToken>()),
Times.Once);
}
}
}

Просмотреть файл

@ -1,63 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Testing;
using Microsoft.Bot.Builder.Testing.XUnit;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.Services;
using Microsoft.BotBuilderSamples.Tests.Dialogs.TestData;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Moq;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs
{
public class BookingDialogTests : BotTestBase
{
private readonly XUnitDialogTestLogger[] _middlewares;
public BookingDialogTests(ITestOutputHelper output)
: base(output)
{
_middlewares = new[] { new XUnitDialogTestLogger(output) };
}
[Theory]
[MemberData(nameof(BookingDialogTestsDataGenerator.BookingFlows), MemberType = typeof(BookingDialogTestsDataGenerator))]
public async Task DialogFlowUseCases(TestDataObject testData)
{
// Arrange
var bookingTestData = testData.GetObject<BookingDialogTestCase>();
var mockFlightBookingService = new Mock<IFlightBookingService>();
mockFlightBookingService
.Setup(x => x.BookFlight(It.IsAny<BookingDetails>(), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(bookingTestData.FlightBookingServiceResult));
var mockGetBookingDetailsDialog = SimpleMockFactory.CreateMockDialog<GetBookingDetailsDialog>(bookingTestData.GetBookingDetailsDialogResult).Object;
var sut = new BookingDialog(mockGetBookingDetailsDialog, mockFlightBookingService.Object);
var testClient = new DialogTestClient(Channels.Test, sut, middlewares: _middlewares);
// Act/Assert
Output.WriteLine($"Test Case: {bookingTestData.Name}");
for (var i = 0; i < bookingTestData.UtterancesAndReplies.GetLength(0); i++)
{
var utterance = bookingTestData.UtterancesAndReplies[i, 0];
// Send the activity and receive the first reply or just pull the next
// activity from the queue if there's nothing to send
var reply = !string.IsNullOrEmpty(utterance)
? await testClient.SendActivityAsync<IMessageActivity>(utterance)
: testClient.GetNextReply<IMessageActivity>();
Assert.Equal(bookingTestData.UtterancesAndReplies[i, 1], reply.Text);
}
Assert.Equal(bookingTestData.ExpectedDialogResult.Status, testClient.DialogTurnResult.Status);
}
}
}

Просмотреть файл

@ -1,92 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Testing;
using Microsoft.Bot.Builder.Testing.XUnit;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs
{
public class CancelAndHelpDialogTests : BotTestBase
{
private readonly XUnitDialogTestLogger[] _middlewares;
public CancelAndHelpDialogTests(ITestOutputHelper output)
: base(output)
{
_middlewares = new[] { new XUnitDialogTestLogger(output) };
}
[Theory]
[InlineData("hi", "Hi there", "cancel")]
[InlineData("hi", "Hi there", "quit")]
public async Task ShouldBeAbleToCancel(string utterance, string response, string cancelUtterance)
{
var sut = new TestCancelAndHelpDialog();
var testClient = new DialogTestClient(Channels.Test, sut, middlewares: _middlewares);
var reply = await testClient.SendActivityAsync<IMessageActivity>(utterance);
Assert.Equal(response, reply.Text);
Assert.Equal(DialogTurnStatus.Waiting, testClient.DialogTurnResult.Status);
reply = await testClient.SendActivityAsync<IMessageActivity>(cancelUtterance);
Assert.Equal("Cancelling", reply.Text);
Assert.Equal(DialogTurnStatus.Complete, testClient.DialogTurnResult.Status);
}
[Theory]
[InlineData("hi", "Hi there", "help")]
[InlineData("hi", "Hi there", "?")]
public async Task ShouldBeAbleToGetHelp(string utterance, string response, string cancelUtterance)
{
var sut = new TestCancelAndHelpDialog();
var testClient = new DialogTestClient(Channels.Test, sut, middlewares: _middlewares);
var reply = await testClient.SendActivityAsync<IMessageActivity>(utterance);
Assert.Equal(response, reply.Text);
Assert.Equal(DialogTurnStatus.Waiting, testClient.DialogTurnResult.Status);
reply = await testClient.SendActivityAsync<IMessageActivity>(cancelUtterance);
Assert.Equal("Show Help...", reply.Text);
Assert.Equal(DialogTurnStatus.Waiting, testClient.DialogTurnResult.Status);
}
/// <summary>
/// A concrete instance of <see cref="CancelAndHelpDialog"/> for testing.
/// </summary>
private class TestCancelAndHelpDialog : CancelAndHelpDialog
{
public TestCancelAndHelpDialog()
: base(nameof(TestCancelAndHelpDialog))
{
AddDialog(new TextPrompt(nameof(TextPrompt)));
var steps = new WaterfallStep[]
{
PromptStep,
FinalStep,
};
AddDialog(new WaterfallDialog("testWaterfall", steps));
InitialDialogId = "testWaterfall";
}
private async Task<DialogTurnResult> PromptStep(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Hi there") }, cancellationToken);
}
private Task<DialogTurnResult> FinalStep(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
}
}

Просмотреть файл

@ -1,45 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Testing;
using Microsoft.Bot.Builder.Testing.XUnit;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.Tests.Dialogs.TestData;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs
{
public class DateResolverDialogTests : BotTestBase
{
public DateResolverDialogTests(ITestOutputHelper output)
: base(output)
{
}
[Theory]
[MemberData(nameof(DateResolverDialogTestsDataGenerator.DateResolverCases), MemberType = typeof(DateResolverDialogTestsDataGenerator))]
public async Task DialogFlowTests(TestDataObject testData)
{
// Arrange
var testCaseData = testData.GetObject<DateResolverDialogTestCase>();
var sut = new DateResolverDialog();
var testClient = new DialogTestClient(Channels.Test, sut, testCaseData.InitialData, new[] { new XUnitDialogTestLogger(Output) });
// Act/Assert
Output.WriteLine($"Test Case: {testCaseData.Name}");
Output.WriteLine($"\r\nDialog Input: {testCaseData.InitialData}");
for (var i = 0; i < testCaseData.UtterancesAndReplies.GetLength(0); i++)
{
var reply = await testClient.SendActivityAsync<IMessageActivity>(testCaseData.UtterancesAndReplies[i, 0]);
Assert.Equal(testCaseData.UtterancesAndReplies[i, 1], reply?.Text);
}
Output.WriteLine($"\r\nDialog result: {testClient.DialogTurnResult.Result}");
Assert.Equal(testCaseData.ExpectedResult, testClient.DialogTurnResult.Result);
}
}
}

Просмотреть файл

@ -1,51 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Testing;
using Microsoft.Bot.Builder.Testing.XUnit;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.Tests.Dialogs.TestData;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs
{
public class GetBookingDetailsDialogTests : BotTestBase
{
public GetBookingDetailsDialogTests(ITestOutputHelper output)
: base(output)
{
}
[Theory]
[MemberData(nameof(GetBookingDetailsDialogTestsDataGenerator.BookingFlows), MemberType = typeof(GetBookingDetailsDialogTestsDataGenerator))]
[MemberData(nameof(GetBookingDetailsDialogTestsDataGenerator.CancelFlows), MemberType = typeof(GetBookingDetailsDialogTestsDataGenerator))]
public async Task DialogFlowUseCases(TestDataObject testData)
{
// Arrange
var bookingTestData = testData.GetObject<GetBookingDetailsDialogTestCase>();
var sut = new GetBookingDetailsDialog();
var testClient = new DialogTestClient(Channels.Test, sut, bookingTestData.InitialBookingDetails, new[] { new XUnitDialogTestLogger(Output) });
// Act/Assert
Output.WriteLine($"Test Case: {bookingTestData.Name}");
for (var i = 0; i < bookingTestData.UtterancesAndReplies.GetLength(0); i++)
{
var reply = await testClient.SendActivityAsync<IMessageActivity>(bookingTestData.UtterancesAndReplies[i, 0]);
Assert.Equal(bookingTestData.UtterancesAndReplies[i, 1], reply?.Text);
}
if (testClient.DialogTurnResult.Result != null)
{
var bookingResults = (BookingDetails)testClient.DialogTurnResult.Result;
Assert.Equal(bookingTestData.ExpectedBookingDetails.Origin, bookingResults.Origin);
Assert.Equal(bookingTestData.ExpectedBookingDetails.Destination, bookingResults.Destination);
Assert.Equal(bookingTestData.ExpectedBookingDetails.TravelDate, bookingResults.TravelDate);
}
}
}
}

Просмотреть файл

@ -1,89 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.Services;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs
{
/// <summary>
/// This sample uses the current classes and approach for testing bot conversations.
/// Note: this is included just as a reference.
/// </summary>
public class MainDialogTestFlowTests : BotTestBase
{
[Fact(Skip = "Ignoring this one, this is just a sample on the old way of writing tests")]
public async Task WholeEnchilada()
{
var mockFlightBookingService = new Mock<IFlightBookingService>();
mockFlightBookingService.Setup(x => x.BookFlight(It.IsAny<BookingDetails>(), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(true));
var mockBookingDialog = SimpleMockFactory.CreateMockDialog<BookingDialog>(null, mockFlightBookingService.Object).Object;
var mockLogger = new Mock<ILogger<MainDialog>>();
var sut = new MainDialog(mockLogger.Object, null, mockBookingDialog);
var testFlow = BuildTestFlow(sut);
await testFlow.Send("hi")
.AssertReply("What can I help you with today?")
.Send("hi")
.AssertReply("Where would you like to travel to?")
.Send("Bahamas")
.AssertReply("Where are you traveling from?")
.Send("New York")
.AssertReply("When would you like to travel?")
.Send("tomorrow at 5 PM")
.AssertReply(activity =>
{
// TODO: I had to add the Yes No for the channelId = test, the emulator displays suggested actions instead.
var message = (IMessageActivity)activity;
Assert.Equal(
"Please confirm, I have you traveling to: Bahamas from: New York on: 2019-04-18T17 (1) Yes or (2) No",
message.Text);
})
.Send("Yes")
.AssertReply("I have you booked to Bahamas from New York on tomorrow 5PM")
.StartTestAsync();
}
private static TestFlow BuildTestFlow(Dialog targetDialog)
{
var convoState = new ConversationState(new MemoryStorage());
var testAdapter = new TestAdapter()
.Use(new AutoSaveStateMiddleware(convoState));
var dialogState = convoState.CreateProperty<DialogState>("DialogState");
var testFlow = new TestFlow(testAdapter, async (turnContext, cancellationToken) =>
{
var state = await dialogState.GetAsync(turnContext, () => new DialogState(), cancellationToken);
var dialogs = new DialogSet(dialogState);
dialogs.Add(targetDialog);
var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken);
var results = await dc.ContinueDialogAsync(cancellationToken);
switch (results.Status)
{
case DialogTurnStatus.Empty:
await dc.BeginDialogAsync(targetDialog.Id, null, cancellationToken);
break;
case DialogTurnStatus.Complete:
{
// TODO: Dialog has ended, figure out a way of asserting that this is the case.
break;
}
}
});
return testFlow;
}
}
}

Просмотреть файл

@ -1,108 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Testing;
using Microsoft.Bot.Builder.Testing.XUnit;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.CognitiveModels;
using Microsoft.BotBuilderSamples.Services;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs
{
public class MainDialogTests : BotTestBase
{
private readonly BookingDialog _mockBookingDialog;
private readonly Mock<ILogger<MainDialog>> _mockLogger;
public MainDialogTests(ITestOutputHelper output)
: base(output)
{
_mockLogger = new Mock<ILogger<MainDialog>>();
var mockFlightBookingService = new Mock<IFlightBookingService>();
mockFlightBookingService
.Setup(x => x.BookFlight(It.IsAny<BookingDetails>(), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(true));
_mockBookingDialog = SimpleMockFactory.CreateMockDialog<BookingDialog>(null, new Mock<GetBookingDetailsDialog>().Object, mockFlightBookingService.Object).Object;
}
[Fact]
public void DialogConstructor()
{
var sut = new MainDialog(_mockLogger.Object, null, _mockBookingDialog);
Assert.Equal("MainDialog", sut.Id);
Assert.IsType<TextPrompt>(sut.FindDialog("TextPrompt"));
Assert.NotNull(sut.FindDialog("BookingDialog"));
Assert.IsType<WaterfallDialog>(sut.FindDialog("WaterfallDialog"));
}
[Fact]
public async Task ShowsMessageIfLuisNotConfigured()
{
// Arrange
var sut = new MainDialog(_mockLogger.Object, null, _mockBookingDialog);
var testClient = new DialogTestClient(Channels.Test, sut, middlewares: new[] { new XUnitDialogTestLogger(Output) });
// Act/Assert
var reply = await testClient.SendActivityAsync<IMessageActivity>("hi");
Assert.Equal("NOTE: LUIS is not configured. To enable all capabilities, add 'LuisAppId', 'LuisAPIKey' and 'LuisAPIHostName' to the appsettings.json file.", reply.Text);
reply = testClient.GetNextReply<IMessageActivity>();
Assert.Equal("What can I help you with today?", reply.Text);
}
[Fact]
public async Task ShowsPromptIfLuisIsConfigured()
{
// Arrange
var sut = new MainDialog(_mockLogger.Object, SimpleMockFactory.CreateMockLuisRecognizer<IRecognizer>(null).Object, _mockBookingDialog);
var testClient = new DialogTestClient(Channels.Test, sut, middlewares: new[] { new XUnitDialogTestLogger(Output) });
// Act/Assert
var reply = await testClient.SendActivityAsync<IMessageActivity>("hi");
Assert.Equal("What can I help you with today?", reply.Text);
}
[Theory]
[InlineData("I want to book a flight", "BookFlight", "BookingDialog mock invoked")]
[InlineData("What's the weather like?", "GetWeather", "TODO: get weather flow here")]
[InlineData("bananas", "None", "Sorry, I didn't get that. Please try asking in a different way (intent was None)")]
public async Task TaskSelector(string utterance, string intent, string invokedDialogResponse)
{
var mockLuisRecognizer = SimpleMockFactory.CreateMockLuisRecognizer<IRecognizer, FlightBooking>(
new FlightBooking
{
Intents = new Dictionary<FlightBooking.Intent, IntentScore>
{
{ Enum.Parse<FlightBooking.Intent>(intent), new IntentScore() { Score = 1 } },
},
Entities = new FlightBooking._Entities(),
});
var sut = new MainDialog(_mockLogger.Object, mockLuisRecognizer.Object, _mockBookingDialog);
var testClient = new DialogTestClient(Channels.Test, sut, middlewares: new[] { new XUnitDialogTestLogger(Output) });
var reply = await testClient.SendActivityAsync<IMessageActivity>("hi");
Assert.Equal("What can I help you with today?", reply.Text);
reply = await testClient.SendActivityAsync<IMessageActivity>(utterance);
Assert.Equal(invokedDialogResponse, reply.Text);
reply = testClient.GetNextReply<IMessageActivity>();
Assert.Equal("What else can I do for you?", reply.Text);
}
}
}

Просмотреть файл

@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Dialogs;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs.TestData
{
public class BookingDialogTestCase
{
/// <summary>
/// Gets or sets the name for the test case.
/// </summary>
/// <value>The test case name.</value>
public string Name { get; set; }
public BookingDetails GetBookingDetailsDialogResult { get; set; }
public string[,] UtterancesAndReplies { get; set; }
public DialogTurnResult ExpectedDialogResult { get; set; }
public bool BookedSuccessfully { get; set; }
public bool FlightBookingServiceResult { get; set; }
}
}

Просмотреть файл

@ -1,95 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Testing.XUnit;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs.TestData
{
[SuppressMessage("Microsoft.StyleCop.CSharp.OrderingRules", "SA1118:ParameterMustNotSpanMultipleLines", Justification = "Ignoring to make code more readable")]
public class BookingDialogTestsDataGenerator
{
public static IEnumerable<object[]> BookingFlows()
{
yield return BuildTestCaseObject(
"Full flow",
new BookingDetails
{
Destination = "Seattle",
Origin = "New York",
TravelDate = $"{DateTime.Now.AddDays(1):yyyy-MM-dd}",
},
new[,]
{
{ "hi", "GetBookingDetailsDialog mock invoked" },
{ null, $"Please confirm, I have you traveling to: Seattle from: New York on: {DateTime.Now.AddDays(1):yyyy-MM-dd} (1) Yes or (2) No" },
{ "yes", "Booking your flight, this shouldn't take long..." },
{ null, "I have you booked to Seattle from New York on tomorrow" },
});
yield return BuildTestCaseObject(
"Full flow with 'no' at confirmation",
new BookingDetails
{
Destination = "Seattle",
Origin = "New York",
TravelDate = $"{DateTime.Now.AddDays(1):yyyy-MM-dd}",
},
new[,]
{
{ "hi", "GetBookingDetailsDialog mock invoked" },
{ null, $"Please confirm, I have you traveling to: Seattle from: New York on: {DateTime.Now.AddDays(1):yyyy-MM-dd} (1) Yes or (2) No" },
{ "no", "OK, we can do this later" },
});
yield return BuildTestCaseObject(
"Full flow with 'cancel' at confirmation",
new BookingDetails
{
Destination = "Seattle",
Origin = "New York",
TravelDate = $"{DateTime.Now.AddDays(1):yyyy-MM-dd}",
},
new[,]
{
{ "hi", "GetBookingDetailsDialog mock invoked" },
{ null, $"Please confirm, I have you traveling to: Seattle from: New York on: {DateTime.Now.AddDays(1):yyyy-MM-dd} (1) Yes or (2) No" },
{ "cancel", "Cancelling" },
},
true,
new DialogTurnResult(DialogTurnStatus.Complete));
yield return BuildTestCaseObject(
"Full flow with failed call to FlightBookingService",
new BookingDetails
{
Destination = "Seattle",
Origin = "New York",
TravelDate = $"{DateTime.Now.AddDays(1):yyyy-MM-dd}",
},
new[,]
{
{ "hi", "GetBookingDetailsDialog mock invoked" },
{ null, $"Please confirm, I have you traveling to: Seattle from: New York on: {DateTime.Now.AddDays(1):yyyy-MM-dd} (1) Yes or (2) No" },
{ "yes", "Booking your flight, this shouldn't take long..." },
{ null, "Sorry, I was unable to secure your reservation, please try another flight" },
}, false);
}
private static object[] BuildTestCaseObject(string testCaseName, BookingDetails inputBookingInfo, string[,] utterancesAndReplies, bool flightBookingServiceResult = true, DialogTurnResult expectedDialogTurnResult = null)
{
var testData = new BookingDialogTestCase
{
Name = testCaseName,
GetBookingDetailsDialogResult = inputBookingInfo,
UtterancesAndReplies = utterancesAndReplies,
FlightBookingServiceResult = flightBookingServiceResult,
ExpectedDialogResult = expectedDialogTurnResult ?? new DialogTurnResult(DialogTurnStatus.Complete),
};
return new object[] { new TestDataObject(testData) };
}
}
}

Просмотреть файл

@ -1,20 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.BotBuilderSamples.Tests.Dialogs.TestData
{
public class DateResolverDialogTestCase
{
/// <summary>
/// Gets or sets the name for the test case.
/// </summary>
/// <value>The test case name.</value>
public string Name { get; set; }
public string InitialData { get; set; }
public string ExpectedResult { get; set; }
public string[,] UtterancesAndReplies { get; set; }
}
}

Просмотреть файл

@ -1,91 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Bot.Builder.Testing.XUnit;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs.TestData
{
[SuppressMessage("Microsoft.StyleCop.CSharp.OrderingRules", "SA1118:ParameterMustNotSpanMultipleLines", Justification = "Ignoring to make code more readable")]
public class DateResolverDialogTestsDataGenerator
{
public static IEnumerable<object[]> DateResolverCases()
{
yield return BuildTestCaseObject(
"tomorrow",
null,
$"{DateTime.Now.AddDays(1):yyyy-MM-dd}",
new[,]
{
{ "hi", "When would you like to travel?" },
{ "tomorrow", null },
});
yield return BuildTestCaseObject(
"the day after tomorrow",
null,
$"{DateTime.Now.AddDays(2):yyyy-MM-dd}",
new[,]
{
{ "hi", "When would you like to travel?" },
{ "the day after tomorrow", null },
});
yield return BuildTestCaseObject(
"two days from now",
null,
$"{DateTime.Now.AddDays(2):yyyy-MM-dd}",
new[,]
{
{ "hi", "When would you like to travel?" },
{ "two days from now", null },
});
yield return BuildTestCaseObject(
"valid input given (tomorrow)",
$"{DateTime.Now.AddDays(1):yyyy-MM-dd}",
$"{DateTime.Now.AddDays(1):yyyy-MM-dd}",
new[,]
{
{ "hi", null },
});
yield return BuildTestCaseObject(
"retry prompt",
null,
$"{DateTime.Now.AddDays(1):yyyy-MM-dd}",
new[,]
{
{ "hi", "When would you like to travel?" },
{ "bananas", "I'm sorry, to make your booking please enter a full travel date including Day Month and Year." },
{ "tomorrow", null },
});
yield return BuildTestCaseObject(
"fuzzy time ",
null,
$"2055-05-05",
new[,]
{
{ "hi", "When would you like to travel?" },
{ "may 5th", "I'm sorry, to make your booking please enter a full travel date including Day Month and Year." },
{ "may 5th 2055", null },
});
}
private static object[] BuildTestCaseObject(string testCaseName, string input, string result, string[,] utterancesAndReplies)
{
var testData = new DateResolverDialogTestCase
{
Name = testCaseName,
InitialData = input,
ExpectedResult = result,
UtterancesAndReplies = utterancesAndReplies,
};
return new object[] { new TestDataObject(testData) };
}
}
}

Просмотреть файл

@ -1,20 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.BotBuilderSamples.Tests.Dialogs.TestData
{
public class GetBookingDetailsDialogTestCase
{
/// <summary>
/// Gets or sets the name for the test case.
/// </summary>
/// <value>The test case name.</value>
public string Name { get; set; }
public BookingDetails InitialBookingDetails { get; set; }
public string[,] UtterancesAndReplies { get; set; }
public BookingDetails ExpectedBookingDetails { get; set; }
}
}

Просмотреть файл

@ -1,142 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Bot.Builder.Testing.XUnit;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs.TestData
{
[SuppressMessage("Microsoft.StyleCop.CSharp.OrderingRules", "SA1118:ParameterMustNotSpanMultipleLines", Justification = "Ignoring to make code more readable")]
public class GetBookingDetailsDialogTestsDataGenerator
{
public static IEnumerable<object[]> BookingFlows()
{
yield return BuildTestCaseObject(
"Full flow",
new BookingDetails(),
new[,]
{
{ "hi", "Where would you like to travel to?" },
{ "Seattle", "Where are you traveling from?" },
{ "New York", "When would you like to travel?" },
{ $"{DateTime.UtcNow.AddDays(1):yyyy-MM-dd}", null },
},
new BookingDetails
{
Destination = "Seattle",
Origin = "New York",
TravelDate = $"{DateTime.UtcNow.AddDays(1):yyyy-MM-dd}",
});
yield return BuildTestCaseObject(
"Destination given",
new BookingDetails
{
Destination = "Bahamas",
Origin = null,
TravelDate = null,
},
new[,]
{
{ "hi", "Where are you traveling from?" },
{ "New York", "When would you like to travel?" },
{ $"{DateTime.UtcNow.AddDays(1):yyyy-MM-dd}", null },
},
new BookingDetails
{
Destination = "Bahamas",
Origin = "New York",
TravelDate = $"{DateTime.UtcNow.AddDays(1):yyyy-MM-dd}",
});
yield return BuildTestCaseObject(
"Destination and Origin given",
new BookingDetails
{
Destination = "Seattle",
Origin = "New York",
TravelDate = null,
},
new[,]
{
{ "hi", "When would you like to travel?" },
{ $"{DateTime.UtcNow.AddDays(1):yyyy-MM-dd}", null },
},
new BookingDetails
{
Destination = "Seattle",
Origin = "New York",
TravelDate = $"{DateTime.UtcNow.AddDays(1):yyyy-MM-dd}",
});
yield return BuildTestCaseObject(
"All booking details given for today",
new BookingDetails
{
Destination = "Seattle",
Origin = "Bahamas",
TravelDate = $"{DateTime.UtcNow:yyyy-MM-dd}",
},
new[,]
{
{ "hi", null },
},
new BookingDetails
{
Destination = "Seattle",
Origin = "Bahamas",
TravelDate = $"{DateTime.UtcNow:yyyy-MM-dd}",
});
}
public static IEnumerable<object[]> CancelFlows()
{
yield return BuildTestCaseObject(
"Cancel on origin prompt",
new BookingDetails(),
new[,]
{
{ "hi", "Where would you like to travel to?" },
{ "cancel", "Cancelling" },
},
null);
yield return BuildTestCaseObject(
"Cancel on destination prompt",
new BookingDetails(),
new[,]
{
{ "hi", "Where would you like to travel to?" },
{ "Seattle", "Where are you traveling from?" },
{ "cancel", "Cancelling" },
},
null);
yield return BuildTestCaseObject(
"Cancel on date prompt",
new BookingDetails(),
new[,]
{
{ "hi", "Where would you like to travel to?" },
{ "Seattle", "Where are you traveling from?" },
{ "New York", "When would you like to travel?" },
{ "cancel", "Cancelling" },
},
null);
}
private static object[] BuildTestCaseObject(string testCaseName, BookingDetails inputBookingInfo, string[,] utterancesAndReplies, BookingDetails expectedBookingInfo)
{
var testData = new GetBookingDetailsDialogTestCase
{
Name = testCaseName,
InitialBookingDetails = inputBookingInfo,
UtterancesAndReplies = utterancesAndReplies,
ExpectedBookingDetails = expectedBookingInfo,
};
return new object[] { new TestDataObject(testData) };
}
}
}

Просмотреть файл

@ -1,2 +0,0 @@
# Note
This folder contains data generators and test case object definitions for Theory tests.

Просмотреть файл

@ -1,90 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.IO;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit.Abstractions;
namespace Microsoft.BotBuilderSamples.Tests.Framework
{
/// <summary>
/// A base class with helper methods and properties to write bot tests.
/// </summary>
public abstract class BotTestBase
{
// A lazy configuration object that gets instantiated once during execution when is needed
private static readonly Lazy<IConfiguration> _configurationLazy = new Lazy<IConfiguration>(() =>
{
LoadLaunchSettingsIntoEnvVariables("Properties//launchSettings.json");
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
return config.Build();
});
/// <summary>
/// Initializes a new instance of the <see cref="BotTestBase"/> class.
/// </summary>
protected BotTestBase()
: this(null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BotTestBase"/> class.
/// </summary>
/// <param name="output">
/// An XUnit <see cref="ITestOutputHelper"/> instance.
/// See <see href="https://xunit.net/docs/capturing-output.html">Capturing Output</see> in the XUnit documentation for additional details.
/// </param>
protected BotTestBase(ITestOutputHelper output)
{
Output = output;
}
public virtual IConfiguration Configuration => _configurationLazy.Value;
protected ITestOutputHelper Output { get; }
/// <summary>
/// Test runners don't load environment variables defined in launchSettings.json
/// so this helper code loads it manually if the file is present.
/// This is useful to be able to have your own key files in your local machine without
/// having to put them in git.
/// If you use launch settings, make sure you set the Copy to Output Directory property to Copy Always.
/// </summary>
/// <param name="launchSettingsFile">The relative path to the launch settings file (i.e.: "Properties//launchSettings.json").</param>
private static void LoadLaunchSettingsIntoEnvVariables(string launchSettingsFile)
{
if (!File.Exists(launchSettingsFile))
{
return;
}
using (var file = File.OpenText(launchSettingsFile))
{
var reader = new JsonTextReader(file);
var fileData = JObject.Load(reader);
var variables = fileData
.GetValue("profiles")
.SelectMany(profiles => profiles.Children())
.SelectMany(profile => profile.Children<JProperty>())
.Where(prop => prop.Name == "environmentVariables")
.SelectMany(prop => prop.Value.Children<JProperty>())
.ToList();
foreach (var variable in variables)
{
Environment.SetEnvironmentVariable(variable.Name, variable.Value.ToString());
}
}
}
}
}

Просмотреть файл

@ -1,2 +0,0 @@
# Note
This folder contains a set of helper classes and extensions that could eventually be moved to the testing framework.

Просмотреть файл

@ -1,75 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Moq;
namespace Microsoft.BotBuilderSamples.Tests.Framework
{
/// <summary>
/// Contains utility methods for creating simple mock objects based on <see href="https://github.com/moq/moq">moq</see>/>.
/// </summary>
public static class SimpleMockFactory
{
/// <summary>
/// Creates a simple mock dialog.
/// </summary>
/// <typeparam name="T">A <see cref="Dialog"/> derived type.</typeparam>
/// <param name="expectedResult">An object containing the results returned by the dialog ind the Dialog in the <see cref="DialogTurnResult"/>.</param>
/// <param name="constructorParams">Optional constructor parameters for the dialog.</param>
/// <returns>A <see cref="Mock{T}"/> object for the desired dialog type.</returns>
public static Mock<T> CreateMockDialog<T>(object expectedResult = null, params object[] constructorParams)
where T : Dialog
{
var mockDialog = new Mock<T>(constructorParams);
var mockDialogNameTypeName = typeof(T).Name;
mockDialog
.Setup(x => x.BeginDialogAsync(It.IsAny<DialogContext>(), It.IsAny<object>(), It.IsAny<CancellationToken>()))
.Returns(async (DialogContext dialogContext, object options, CancellationToken cancellationToken) =>
{
await dialogContext.Context.SendActivityAsync($"{mockDialogNameTypeName} mock invoked", cancellationToken: cancellationToken);
return await dialogContext.EndDialogAsync(expectedResult, cancellationToken);
});
return mockDialog;
}
/// <summary>
/// Creates a simple <see cref="IRecognizer"/> mock object that returns the desired <see cref="IRecognizerConvert"/> result.
/// </summary>
/// <typeparam name="TRecognizer">The type of <see cref="IRecognizer"/>to create.</typeparam>
/// <typeparam name="TReturns">The type of <see cref="IRecognizerConvert"/> to return.</typeparam>
/// <param name="returns">The value to return when <see cref="IRecognizer.RecognizeAsync{T}"/> gets called.</param>
/// <returns>A <see cref="Mock{TRecognizer}"/> instance.</returns>
public static Mock<TRecognizer> CreateMockLuisRecognizer<TRecognizer, TReturns>(TReturns returns)
where TRecognizer : class, IRecognizer
where TReturns : IRecognizerConvert, new()
{
var mockRecognizer = new Mock<TRecognizer>();
mockRecognizer
.Setup(x => x.RecognizeAsync<TReturns>(It.IsAny<ITurnContext>(), It.IsAny<CancellationToken>()))
.Returns(() => Task.FromResult(returns));
return mockRecognizer;
}
/// <summary>
/// Creates a simple <see cref="IRecognizer"/> mock object that returns the desired <see cref="RecognizerResult"/> result.
/// </summary>
/// <typeparam name="TRecognizer">The type of <see cref="IRecognizer"/>to create.</typeparam>
/// <param name="returns">The value to return when <see cref="IRecognizer.RecognizeAsync"/> gets called.</param>
/// <returns>A <see cref="Mock{TRecognizer}"/> instance.</returns>
public static Mock<TRecognizer> CreateMockLuisRecognizer<TRecognizer>(RecognizerResult returns)
where TRecognizer : class, IRecognizer
{
var mockRecognizer = new Mock<TRecognizer>();
mockRecognizer
.Setup(x => x.RecognizeAsync(It.IsAny<ITurnContext>(), It.IsAny<CancellationToken>()))
.Returns(() => Task.FromResult(returns));
return mockRecognizer;
}
}
}

Просмотреть файл

@ -1,45 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
<AssemblyName>Microsoft.Bot.Builder.TestBot.NetCore21.Tests</AssemblyName>
<RootNamespace>Microsoft.BotBuilderSamples.Tests</RootNamespace>
</PropertyGroup>
<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Testing\Microsoft.Bot.Builder.Testing.csproj" />
<ProjectReference Include="..\Microsoft.Bot.Builder.TestBot.NetCore21\Microsoft.Bot.Builder.TestBot.NetCore21.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Properties\launchSettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Update="xunit.runner.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,9 +0,0 @@
{
"cognitiveModels": {
"flightBooking": {
"luisAppId": "Set the value here or in launchSettings.json for local dev",
"luisEndpointKey": "Set the value here or in launchSettings.json for local dev",
"luisEndpoint": "Set the value here or in launchSettings.json for local dev"
}
}
}

Просмотреть файл

@ -1,10 +0,0 @@
{
"settings": {
"namingRules": {
"allowCommonHungarianPrefixes": true,
"allowedHungarianPrefixes": [
"lu"
]
}
}
}

Просмотреть файл

@ -1,4 +0,0 @@
{
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
"parallelizeAssembly": true
}

Просмотреть файл

@ -1,14 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.BotBuilderSamples
{
public class BookingDetails
{
public string Destination { get; set; }
public string Origin { get; set; }
public string TravelDate { get; set; }
}
}

Просмотреть файл

@ -1,68 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Microsoft.BotBuilderSamples
{
public class DialogAndWelcomeBot<T> : DialogBot<T>
where T : Dialog
{
public DialogAndWelcomeBot(ConversationState conversationState, UserState userState, T dialog, ILogger<DialogBot<T>> logger)
: base(conversationState, userState, dialog, logger)
{
}
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
foreach (var member in membersAdded)
{
// Greet anyone that was not the target (recipient) of this message.
// To learn more about Adaptive Cards, see https://aka.ms/msbot-adaptivecards for more details.
if (member.Id != turnContext.Activity.Recipient.Id)
{
var welcomeCard = CreateAdaptiveCardAttachment();
var response = CreateResponse(turnContext.Activity, welcomeCard);
await turnContext.SendActivityAsync(response, cancellationToken);
await Dialog.Run(turnContext, ConversationState.CreateProperty<DialogState>("DialogState"), cancellationToken);
}
}
}
// Load attachment from embedded resource.
private Attachment CreateAdaptiveCardAttachment()
{
var rootNamespace = typeof(Startup).Namespace;
var cardResourcePath = $"{rootNamespace}.Cards.welcomeCard.json";
using (var stream = GetType().Assembly.GetManifestResourceStream(cardResourcePath))
{
using (var reader = new StreamReader(stream))
{
var adaptiveCard = reader.ReadToEnd();
return new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(adaptiveCard),
};
}
}
}
// Create an attachment message response.
private Activity CreateResponse(IActivity activity, Attachment attachment)
{
var response = ((Activity)activity).CreateReply();
response.Attachments = new List<Attachment>() { attachment };
return response;
}
}
}

Просмотреть файл

@ -1,54 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
namespace Microsoft.BotBuilderSamples
{
// This IBot implementation can run any type of Dialog. The use of type parameterization is to allows multiple different bots
// to be run at different endpoints within the same project. This can be achieved by defining distinct Controller types
// each with dependency on distinct IBot types, this way ASP Dependency Injection can glue everything together without ambiguity.
// The ConversationState is used by the Dialog system. The UserState isn't, however, it might have been used in a Dialog implementation,
// and the requirement is that all BotState objects are saved at the end of a turn.
public class DialogBot<T> : ActivityHandler
where T : Dialog
{
public DialogBot(ConversationState conversationState, UserState userState, T dialog, ILogger<DialogBot<T>> logger)
{
ConversationState = conversationState;
UserState = userState;
Dialog = dialog;
Logger = logger;
}
protected Dialog Dialog { get; }
protected BotState ConversationState { get; }
protected BotState UserState { get; }
protected ILogger Logger { get; }
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
await base.OnTurnAsync(turnContext, cancellationToken);
// Save any state changes that might have occurred during the turn.
await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
Logger.LogInformation("Running dialog with Message Activity.");
// Run the Dialog with the new message Activity.
await Dialog.Run(turnContext, ConversationState.CreateProperty<DialogState>("DialogState"), cancellationToken);
}
}
}

Просмотреть файл

@ -1,101 +0,0 @@
// <auto-generated>
// Code generated by LUISGen C:\Projects\Repos\botbuilder-dotnet\tests\Microsoft.Bot.Builder.TestBot\CognitiveModels\FlightBooking.json -cs Microsoft.BotBuilderSamples.CognitiveModels.FlightBooking -o C:\Projects\Repos\botbuilder-dotnet\tests\Microsoft.Bot.Builder.TestBot\CognitiveModels
// Tool github: https://github.com/microsoft/botbuilder-tools
// Changes may cause incorrect behavior and will be lost if the code is
// regenerated.
// </auto-generated>
using Newtonsoft.Json;
using System.Collections.Generic;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.Luis;
namespace Microsoft.BotBuilderSamples.CognitiveModels
{
public class FlightBooking: IRecognizerConvert
{
public string Text;
public string AlteredText;
public enum Intent {
BookFlight,
Cancel,
GetWeather,
None
};
public Dictionary<Intent, IntentScore> Intents;
public class _Entities
{
// Built-in entities
public DateTimeSpec[] datetime;
// Lists
public string[][] Airport;
// Composites
public class _InstanceFrom
{
public InstanceData[] Airport;
}
public class FromClass
{
public string[][] Airport;
[JsonProperty("$instance")]
public _InstanceFrom _instance;
}
public FromClass[] From;
public class _InstanceTo
{
public InstanceData[] Airport;
}
public class ToClass
{
public string[][] Airport;
[JsonProperty("$instance")]
public _InstanceTo _instance;
}
public ToClass[] To;
// Instance
public class _Instance
{
public InstanceData[] datetime;
public InstanceData[] Airport;
public InstanceData[] From;
public InstanceData[] To;
}
[JsonProperty("$instance")]
public _Instance _instance;
}
public _Entities Entities;
[JsonExtensionData(ReadData = true, WriteData = true)]
public IDictionary<string, object> Properties {get; set; }
public void Convert(dynamic result)
{
var app = JsonConvert.DeserializeObject<FlightBooking>(JsonConvert.SerializeObject(result));
Text = app.Text;
AlteredText = app.AlteredText;
Intents = app.Intents;
Entities = app.Entities;
Properties = app.Properties;
}
public (Intent intent, double score) TopIntent()
{
Intent maxIntent = Intent.None;
var max = 0.0;
foreach (var entry in Intents)
{
if (entry.Value.Score > max)
{
maxIntent = entry.Key;
max = entry.Value.Score.Value;
}
}
return (maxIntent, max);
}
}
}

Просмотреть файл

@ -1,8 +0,0 @@
using Microsoft.Bot.Builder.Integration.AspNet.Core;
namespace Microsoft.Bot.Builder.TestBot.Debugging
{
public class DebugAdapter : BotFrameworkHttpAdapter
{
}
}

Просмотреть файл

@ -1,88 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.BotBuilderSamples.Services;
using Microsoft.Recognizers.Text.DataTypes.TimexExpression;
namespace Microsoft.BotBuilderSamples
{
public class BookingDialog : CancelAndHelpDialog
{
private readonly IFlightBookingService _flightBookingService;
public BookingDialog(GetBookingDetailsDialog getBookingDetailsDialog, IFlightBookingService flightBookingService)
: base(nameof(BookingDialog))
{
_flightBookingService = flightBookingService;
AddDialog(getBookingDetailsDialog);
AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));
var steps = new WaterfallStep[]
{
GetBookingDetailsActionAsync,
ConfirmActionAsync,
FinalActionAsync,
};
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), steps));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
private async Task<DialogTurnResult> GetBookingDetailsActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var bookingDetails = (BookingDetails)stepContext.Options ?? new BookingDetails();
return await stepContext.BeginDialogAsync(nameof(GetBookingDetailsDialog), bookingDetails, cancellationToken);
}
private async Task<DialogTurnResult> ConfirmActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var bookingDetails = (BookingDetails)stepContext.Result;
// Store the booking details in the waterfall state so we can use it once the user confirms
stepContext.Values["BookingInfo"] = bookingDetails;
var msg = $"Please confirm, I have you traveling to: {bookingDetails.Destination} from: {bookingDetails.Origin} on: {bookingDetails.TravelDate}";
return await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = MessageFactory.Text(msg) }, cancellationToken);
}
private async Task<DialogTurnResult> FinalActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
string msg;
if ((bool)stepContext.Result)
{
// Pull the booking details from the waterfall state.
var bookingDetails = (BookingDetails)stepContext.Values["BookingInfo"];
// Now we have all the booking information to call the booking service.
await stepContext.Context.SendActivityAsync(MessageFactory.Text("Booking your flight, this shouldn't take long..."), cancellationToken);
var flightBooked = await _flightBookingService.BookFlight(bookingDetails, cancellationToken);
if (flightBooked)
{
// If the call to the booking service was successful tell the user.
var timeProperty = new TimexProperty(bookingDetails.TravelDate);
var travelDateMsg = timeProperty.ToNaturalLanguage(DateTime.Now);
msg = $"I have you booked to {bookingDetails.Destination} from {bookingDetails.Origin} on {travelDateMsg}";
}
else
{
msg = "Sorry, I was unable to secure your reservation, please try another flight";
}
}
else
{
msg = "OK, we can do this later";
}
await stepContext.Context.SendActivityAsync(MessageFactory.Text(msg), cancellationToken);
return await stepContext.EndDialogAsync(null, cancellationToken);
}
}
}

Просмотреть файл

@ -1,63 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
namespace Microsoft.BotBuilderSamples
{
public abstract class CancelAndHelpDialog : ComponentDialog
{
protected CancelAndHelpDialog(string id)
: base(id)
{
}
protected override async Task<DialogTurnResult> OnBeginDialogAsync(DialogContext innerDc, object options, CancellationToken cancellationToken = default(CancellationToken))
{
var result = await InterruptAsync(innerDc, cancellationToken);
if (result != null)
{
return result;
}
return await base.OnBeginDialogAsync(innerDc, options, cancellationToken);
}
protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
{
var result = await InterruptAsync(innerDc, cancellationToken);
if (result != null)
{
return result;
}
return await base.OnContinueDialogAsync(innerDc, cancellationToken);
}
private async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc, CancellationToken cancellationToken)
{
if (innerDc.Context.Activity.Type == ActivityTypes.Message)
{
var text = innerDc.Context.Activity.Text.ToLowerInvariant();
switch (text)
{
case "help":
case "?":
await innerDc.Context.SendActivityAsync("Show Help...", cancellationToken: cancellationToken);
return new DialogTurnResult(DialogTurnStatus.Waiting);
case "cancel":
case "quit":
await innerDc.Context.SendActivityAsync("Cancelling", cancellationToken: cancellationToken);
return await innerDc.CancelAllDialogsAsync(cancellationToken: cancellationToken);
}
}
return null;
}
}
}

Просмотреть файл

@ -1,89 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Recognizers.Text.DataTypes.TimexExpression;
namespace Microsoft.BotBuilderSamples
{
public class DateResolverDialog : CancelAndHelpDialog
{
public DateResolverDialog(string id = null)
: base(id ?? nameof(DateResolverDialog))
{
AddDialog(new DateTimePrompt(nameof(DateTimePrompt), DateTimePromptValidator));
var steps = new WaterfallStep[]
{
InitialActionAsync,
FinalActionAsync,
};
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), steps));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
private static Task<bool> DateTimePromptValidator(PromptValidatorContext<IList<DateTimeResolution>> promptContext, CancellationToken cancellationToken)
{
if (promptContext.Recognized.Succeeded)
{
// This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
// TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year.
var timex = promptContext.Recognized.Value[0].Timex.Split('T')[0];
// If this is a definite Date including year, month and day we are good otherwise reprompt.
// A better solution might be to let the user know what part is actually missing.
var isDefinite = new TimexProperty(timex).Types.Contains(Constants.TimexTypes.Definite);
return Task.FromResult(isDefinite);
}
return Task.FromResult(false);
}
private async Task<DialogTurnResult> InitialActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var timex = (string)stepContext.Options;
var promptMsg = "When would you like to travel?";
var repromptMsg = "I'm sorry, to make your booking please enter a full travel date including Day Month and Year.";
if (timex == null)
{
// We were not given any date at all so prompt the user.
return await stepContext.PromptAsync(
nameof(DateTimePrompt),
new PromptOptions
{
Prompt = MessageFactory.Text(promptMsg),
RetryPrompt = MessageFactory.Text(repromptMsg),
}, cancellationToken);
}
// We have a Date we just need to check it is unambiguous.
var timexProperty = new TimexProperty(timex);
if (!timexProperty.Types.Contains(Constants.TimexTypes.Definite))
{
// This is essentially a "reprompt" of the data we were given up front.
return await stepContext.PromptAsync(
nameof(DateTimePrompt),
new PromptOptions
{
Prompt = MessageFactory.Text(repromptMsg),
}, cancellationToken);
}
return await stepContext.NextAsync(new List<DateTimeResolution> { new DateTimeResolution { Timex = timex } }, cancellationToken);
}
private async Task<DialogTurnResult> FinalActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var timex = ((List<DateTimeResolution>)stepContext.Result)[0].Timex;
return await stepContext.EndDialogAsync(timex, cancellationToken);
}
}
}

Просмотреть файл

@ -1,86 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Recognizers.Text.DataTypes.TimexExpression;
namespace Microsoft.BotBuilderSamples
{
public class GetBookingDetailsDialog : CancelAndHelpDialog
{
public GetBookingDetailsDialog()
: base(nameof(GetBookingDetailsDialog))
{
AddDialog(new TextPrompt(nameof(TextPrompt)));
AddDialog(new DateResolverDialog());
var steps = new WaterfallStep[]
{
DestinationActionAsync,
OriginActionAsync,
TravelDateActionAsync,
FinalActionAsync,
};
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), steps));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
private static bool IsAmbiguous(string timex)
{
var timexProperty = new TimexProperty(timex);
return !timexProperty.Types.Contains(Constants.TimexTypes.Definite);
}
private async Task<DialogTurnResult> DestinationActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var bookingDetails = (BookingDetails)stepContext.Options ?? new BookingDetails();
if (bookingDetails.Destination == null)
{
return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Where would you like to travel to?") }, cancellationToken);
}
return await stepContext.NextAsync(bookingDetails.Destination, cancellationToken);
}
private async Task<DialogTurnResult> OriginActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var bookingDetails = (BookingDetails)stepContext.Options;
bookingDetails.Destination = (string)stepContext.Result;
if (bookingDetails.Origin == null)
{
return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Where are you traveling from?") }, cancellationToken);
}
return await stepContext.NextAsync(bookingDetails.Origin, cancellationToken);
}
private async Task<DialogTurnResult> TravelDateActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var bookingDetails = (BookingDetails)stepContext.Options;
bookingDetails.Origin = (string)stepContext.Result;
if (bookingDetails.TravelDate == null || IsAmbiguous(bookingDetails.TravelDate))
{
// Run the DateResolverDialog giving it whatever details we have from the LUIS call, it will fill out the remainder.
return await stepContext.BeginDialogAsync(nameof(DateResolverDialog), bookingDetails.TravelDate, cancellationToken);
}
return await stepContext.NextAsync(bookingDetails.TravelDate, cancellationToken);
}
private async Task<DialogTurnResult> FinalActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var bookingDetails = (BookingDetails)stepContext.Options;
bookingDetails.TravelDate = (string)stepContext.Result;
// We are done collection booking details, return the data to the caller.
return await stepContext.EndDialogAsync(bookingDetails, cancellationToken);
}
}
}

Просмотреть файл

@ -1,145 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Choices;
namespace Microsoft.BotBuilderSamples
{
public class UserProfileDialog : ComponentDialog
{
private IStatePropertyAccessor<UserProfile> _userProfileAccessor;
public UserProfileDialog(UserState userState)
: base("root")
{
_userProfileAccessor = userState.CreateProperty<UserProfile>("UserProfile");
// This array defines how the Waterfall will execute.
var waterfallActions = new WaterfallStep[]
{
TransportActionAsync,
NameActionAsync,
NameConfirmActionAsync,
AgeActionAsync,
ConfirmActionAsync,
SummaryActionAsync,
};
// Add named dialogs to the DialogSet. These names are saved in the dialog state.
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallActions));
AddDialog(new TextPrompt(nameof(TextPrompt)));
AddDialog(new NumberPrompt<int>(nameof(NumberPrompt<int>), AgePromptValidatorAsync));
AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
private static async Task<DialogTurnResult> TransportActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
// Running a prompt here means the next WaterfallStep will be run when the users response is received.
return await stepContext.PromptAsync(
nameof(ChoicePrompt),
new PromptOptions
{
Prompt = MessageFactory.Text("Please enter your mode of transport."),
Choices = ChoiceFactory.ToChoices(new List<string> { "Car", "Bus", "Bicycle" }),
}, cancellationToken);
}
private static async Task<DialogTurnResult> NameActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["transport"] = ((FoundChoice)stepContext.Result).Value;
return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Please enter your name.") }, cancellationToken);
}
private static Task<bool> AgePromptValidatorAsync(PromptValidatorContext<int> promptContext, CancellationToken cancellationToken)
{
// This condition is our validation rule. You can also change the value at this point.
return Task.FromResult(promptContext.Recognized.Value >= 0 && promptContext.Recognized.Value < 150);
}
private async Task<DialogTurnResult> NameConfirmActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["name"] = (string)stepContext.Result;
// We can send messages to the user at any point in the WaterfallStep.
await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Thanks {stepContext.Result}."), cancellationToken);
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
return await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = MessageFactory.Text("Would you like to give your age?") }, cancellationToken);
}
private async Task<DialogTurnResult> AgeActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
if ((bool)stepContext.Result)
{
// User said "yes" so we will be prompting for the age.
// WaterfallStep always finishes with the end of the Waterfall or with another dialog, here it is a Prompt Dialog.
var promptOptions = new PromptOptions
{
Prompt = MessageFactory.Text("Please enter your age."),
RetryPrompt = MessageFactory.Text("The value entered must be greater than 0 and less than 150."),
};
return await stepContext.PromptAsync(nameof(NumberPrompt<int>), promptOptions, cancellationToken);
}
else
{
// User said "no" so we will skip the next step. Give -1 as the age.
return await stepContext.NextAsync(-1, cancellationToken);
}
}
private async Task<DialogTurnResult> ConfirmActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["age"] = (int)stepContext.Result;
// We can send messages to the user at any point in the WaterfallStep.
// var msg = userProfile.Age == -1 ? "No age given." : $"I have your age as {userProfile.Age}.";
var msg = (int)stepContext.Values["age"] == -1 ? "No age given." : $"I have your age as {stepContext.Values["age"]}.";
// We can send messages to the user at any point in the WaterfallStep.
await stepContext.Context.SendActivityAsync(MessageFactory.Text(msg), cancellationToken);
// WaterfallStep always finishes with the end of the Waterfall or with another dialog, here it is a Prompt Dialog.
return await stepContext.PromptAsync(nameof(ConfirmPrompt), new PromptOptions { Prompt = MessageFactory.Text("Is this ok?") }, cancellationToken);
}
private async Task<DialogTurnResult> SummaryActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
if ((bool)stepContext.Result)
{
// Get the current profile object from user state.
var userProfile = await _userProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken);
userProfile.Transport = (string)stepContext.Values["transport"];
userProfile.Name = (string)stepContext.Values["name"];
userProfile.Age = (int)stepContext.Values["age"];
var msg = $"I have your mode of transport as {userProfile.Transport} and your name as {userProfile.Name}.";
if (userProfile.Age != -1)
{
msg += $" And age as {userProfile.Age}.";
}
await stepContext.Context.SendActivityAsync(MessageFactory.Text(msg), cancellationToken);
}
else
{
await stepContext.Context.SendActivityAsync(MessageFactory.Text("Thanks. Your profile will not be kept."), cancellationToken);
}
// WaterfallStep always finishes with the end of the Waterfall or with another dialog, here it is the end.
return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
}
}
}

Просмотреть файл

@ -1,72 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.Bot.Schema;
using Microsoft.Rest.Serialization;
using Newtonsoft.Json;
namespace Microsoft.Bot.Builder.TestBot
{
internal static class HttpHelper
{
public static readonly JsonSerializer BotMessageSerializer = JsonSerializer.Create(new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
Formatting = Formatting.Indented,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
ContractResolver = new ReadOnlyJsonContractResolver(),
Converters = new List<JsonConverter> { new Iso8601TimeSpanConverter() },
});
public static Activity ReadRequest(HttpRequest request)
{
if (request == null)
{
throw new ArgumentNullException(nameof(request));
}
var activity = default(Activity);
using (var bodyReader = new JsonTextReader(new StreamReader(request.Body, Encoding.UTF8)))
{
activity = BotMessageSerializer.Deserialize<Activity>(bodyReader);
}
return activity;
}
public static void WriteResponse(HttpResponse response, InvokeResponse invokeResponse)
{
if (response == null)
{
throw new ArgumentNullException(nameof(response));
}
if (invokeResponse == null)
{
response.StatusCode = (int)HttpStatusCode.OK;
}
else
{
response.ContentType = "application/json";
response.StatusCode = invokeResponse.Status;
using (var writer = new StreamWriter(response.Body))
{
using (var jsonWriter = new JsonTextWriter(writer))
{
BotMessageSerializer.Serialize(jsonWriter, invokeResponse.Body);
}
}
}
}
}
}

Просмотреть файл

@ -6,23 +6,15 @@
<RootNamespace>Microsoft.BotBuilderSamples</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Content Remove="Cards\welcomeCard.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Cards\welcomeCard.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.Recognizers.Text.DataTypes.TimexExpression" Version="1.2.9" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libraries\integration\Microsoft.Bot.Builder.Integration.AspNet.Core\Microsoft.Bot.Builder.Integration.AspNet.Core.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.AI.LUIS\Microsoft.Bot.Builder.AI.Luis.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Dialogs\Microsoft.Bot.Builder.Dialogs.csproj" />
<ProjectReference Include="..\Microsoft.Bot.Builder.TestBot.Shared\Microsoft.Bot.Builder.TestBot.Shared.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,13 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.BotBuilderSamples.Services
{
public class FlightBookingService : IFlightBookingService
{
public Task<bool> BookFlight(BookingDetails booking, CancellationToken cancellationToken = default(CancellationToken)) => Task.FromResult(true);
}
}

Просмотреть файл

@ -8,9 +8,10 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.Luis;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Builder.TestBot.Bots;
using Microsoft.Bot.Builder.TestBot.Shared.Bots;
using Microsoft.Bot.Builder.TestBot.Shared.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared.Services;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.BotBuilderSamples.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared
{
public class BookingDetails
{

Просмотреть файл

@ -5,13 +5,12 @@ using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared.Bots
{
public class DialogAndWelcomeBot<T> : DialogBot<T>
where T : Dialog
@ -40,7 +39,7 @@ namespace Microsoft.BotBuilderSamples
// Load attachment from embedded resource.
private Attachment CreateAdaptiveCardAttachment()
{
var rootNamespace = typeof(Startup).Namespace;
var rootNamespace = typeof(UserProfile).Namespace;
var cardResourcePath = $"{rootNamespace}.Cards.welcomeCard.json";
using (var stream = GetType().Assembly.GetManifestResourceStream(cardResourcePath))

Просмотреть файл

@ -3,12 +3,11 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared.Bots
{
// This IBot implementation can run any type of Dialog. The use of type parameterization is to allows multiple different bots
// to be run at different endpoints within the same project. This can be achieved by defining distinct Controller types

Просмотреть файл

@ -5,7 +5,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Schema;
namespace Microsoft.Bot.Builder.TestBot.Bots
namespace Microsoft.Bot.Builder.TestBot.Shared.Bots
{
public class MyBot : ActivityHandler
{

Просмотреть файл

@ -6,10 +6,9 @@
// </auto-generated>
using Newtonsoft.Json;
using System.Collections.Generic;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.Luis;
namespace Microsoft.BotBuilderSamples.CognitiveModels
namespace Microsoft.Bot.Builder.TestBot.Shared.CognitiveModels
{
public class FlightBooking: IRecognizerConvert
{

Просмотреть файл

@ -4,10 +4,9 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared.Controllers
{
// This ASP Controller is created to handle a request. Dependency Injection will provide the Adapter and IBot
// implementation at runtime. Multiple different IBot implementations running at different endpoints can be

Просмотреть файл

@ -1,6 +1,6 @@
using Microsoft.Bot.Builder.Integration.AspNet.Core;
namespace Microsoft.Bot.Builder.TestBot.Debugging
namespace Microsoft.Bot.Builder.TestBot.Shared.Debugging
{
public class DebugAdapter : BotFrameworkHttpAdapter
{

Просмотреть файл

@ -5,7 +5,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Schema;
namespace Microsoft.Bot.Builder.TestBot.Debugging
namespace Microsoft.Bot.Builder.TestBot.Shared.Debugging
{
public class DebugBot : ActivityHandler
{

Просмотреть файл

@ -1,8 +1,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder.TestBot.Debugging;
namespace Microsoft.Bot.Builder.TestBot.Controllers
namespace Microsoft.Bot.Builder.TestBot.Shared.Debugging
{
[Route("api/debug")]
[ApiController]

Просмотреть файл

@ -3,10 +3,9 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared
{
public static class DialogExtensions
{

Просмотреть файл

@ -4,12 +4,11 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.BotBuilderSamples.Services;
using Microsoft.Bot.Builder.TestBot.Shared.Services;
using Microsoft.Recognizers.Text.DataTypes.TimexExpression;
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared.Dialogs
{
public class BookingDialog : CancelAndHelpDialog
{

Просмотреть файл

@ -6,7 +6,7 @@ using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared.Dialogs
{
public abstract class CancelAndHelpDialog : ComponentDialog
{

Просмотреть файл

@ -8,7 +8,7 @@ using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Recognizers.Text.DataTypes.TimexExpression;
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared.Dialogs
{
public class DateResolverDialog : CancelAndHelpDialog
{

Просмотреть файл

@ -7,7 +7,7 @@ using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Recognizers.Text.DataTypes.TimexExpression;
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared.Dialogs
{
public class GetBookingDetailsDialog : CancelAndHelpDialog
{

Просмотреть файл

@ -4,13 +4,12 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared.CognitiveModels;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.CognitiveModels;
using Microsoft.Extensions.Logging;
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared.Dialogs
{
// A root dialog responsible of understanding user intents and dispatching them sub tasks.
public class MainDialog : ComponentDialog

Просмотреть файл

@ -4,11 +4,10 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Choices;
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared.Dialogs
{
public class UserProfileDialog : ComponentDialog
{

Просмотреть файл

@ -11,7 +11,7 @@ using Microsoft.Bot.Schema;
using Microsoft.Rest.Serialization;
using Newtonsoft.Json;
namespace Microsoft.Bot.Builder.TestBot
namespace Microsoft.Bot.Builder.TestBot.Shared
{
internal static class HttpHelper
{

Просмотреть файл

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Content Remove="Cards\welcomeCard.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Cards\welcomeCard.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Recognizers.Text.DataTypes.TimexExpression" Version="1.2.9" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libraries\integration\Microsoft.Bot.Builder.Integration.AspNet.Core\Microsoft.Bot.Builder.Integration.AspNet.Core.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.AI.LUIS\Microsoft.Bot.Builder.AI.Luis.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Dialogs\Microsoft.Bot.Builder.Dialogs.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -4,7 +4,7 @@
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.BotBuilderSamples.Services
namespace Microsoft.Bot.Builder.TestBot.Shared.Services
{
public class FlightBookingService : IFlightBookingService
{

Просмотреть файл

@ -4,7 +4,7 @@
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.BotBuilderSamples.Services
namespace Microsoft.Bot.Builder.TestBot.Shared.Services
{
public interface IFlightBookingService
{

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.BotBuilderSamples
namespace Microsoft.Bot.Builder.TestBot.Shared
{
/// <summary>
/// This is our application state. Just a regular serializable .NET class.

Просмотреть файл

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared.Bots;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.Tests.Framework;

Просмотреть файл

@ -4,6 +4,7 @@ using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared.Bots;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Microsoft.Extensions.Logging;
using Moq;

Просмотреть файл

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Routing;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Builder.TestBot.Shared.Controllers;
using Moq;
using Xunit;

Просмотреть файл

@ -3,11 +3,13 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.TestBot.Shared;
using Microsoft.Bot.Builder.TestBot.Shared.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared.Services;
using Microsoft.Bot.Builder.Testing;
using Microsoft.Bot.Builder.Testing.XUnit;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.Services;
using Microsoft.BotBuilderSamples.Tests.Dialogs.TestData;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Moq;

Просмотреть файл

@ -6,6 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared.Dialogs;
using Microsoft.Bot.Builder.Testing;
using Microsoft.Bot.Builder.Testing.XUnit;
using Microsoft.Bot.Connector;

Просмотреть файл

@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System.Threading.Tasks;
using Microsoft.Bot.Builder.TestBot.Shared.Dialogs;
using Microsoft.Bot.Builder.Testing;
using Microsoft.Bot.Builder.Testing.XUnit;
using Microsoft.Bot.Connector;

Просмотреть файл

@ -3,6 +3,8 @@
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared;
using Microsoft.Bot.Builder.TestBot.Shared.Dialogs;
using Microsoft.Bot.Builder.Testing;
using Microsoft.Bot.Builder.Testing.XUnit;
using Microsoft.Bot.Connector;

Просмотреть файл

@ -6,8 +6,10 @@ using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared;
using Microsoft.Bot.Builder.TestBot.Shared.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared.Services;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.Services;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Microsoft.Extensions.Logging;
using Moq;

Просмотреть файл

@ -7,12 +7,14 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared;
using Microsoft.Bot.Builder.TestBot.Shared.CognitiveModels;
using Microsoft.Bot.Builder.TestBot.Shared.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared.Services;
using Microsoft.Bot.Builder.Testing;
using Microsoft.Bot.Builder.Testing.XUnit;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.CognitiveModels;
using Microsoft.BotBuilderSamples.Services;
using Microsoft.BotBuilderSamples.Tests.Framework;
using Microsoft.Extensions.Logging;
using Moq;

Просмотреть файл

@ -2,6 +2,7 @@
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs.TestData
{

Просмотреть файл

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared;
using Microsoft.Bot.Builder.Testing.XUnit;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs.TestData

Просмотреть файл

@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.TestBot.Shared;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs.TestData
{
public class GetBookingDetailsDialogTestCase

Просмотреть файл

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Bot.Builder.TestBot.Shared;
using Microsoft.Bot.Builder.Testing.XUnit;
namespace Microsoft.BotBuilderSamples.Tests.Dialogs.TestData

Просмотреть файл

@ -1,10 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework Condition="'$(BuildTarget)' == 'netcoreapp21'">netcoreapp2.1</TargetFramework>
<TargetFramework Condition="'$(BuildTarget)' == 'netcoreapp31'">netcoreapp3.1</TargetFramework>
<TargetFrameworks Condition="'$(BuildTarget)' == ''">netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
<IsPackable>false</IsPackable>
<AssemblyName>Microsoft.Bot.Builder.TestBot.Tests</AssemblyName>
<RootNamespace>Microsoft.BotBuilderSamples.Tests</RootNamespace>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<Configurations>Debug;Release</Configurations>
</PropertyGroup>
<ItemGroup>
@ -17,8 +21,15 @@
</Content>
</ItemGroup>
<ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">
<PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2">
@ -29,7 +40,7 @@
<ItemGroup>
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Testing\Microsoft.Bot.Builder.Testing.csproj" />
<ProjectReference Include="..\Microsoft.Bot.Builder.TestBot\Microsoft.Bot.Builder.TestBot.csproj" />
<ProjectReference Include="..\Microsoft.Bot.Builder.TestBot.Shared\Microsoft.Bot.Builder.TestBot.Shared.csproj" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -1,17 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Schema;
namespace Microsoft.Bot.Builder.TestBot.Bots
{
public class MyBot : ActivityHandler
{
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
await turnContext.SendActivityAsync(MessageFactory.Text($"Echo: {turnContext.Activity.Text}"), cancellationToken);
}
}
}

Просмотреть файл

@ -1,46 +0,0 @@
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "Image",
"url": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQtB3AwMUeNoq4gUBGe6Ocj8kyh3bXa9ZbV7u1fVKQoyKFHdkqU",
"size": "stretch"
},
{
"type": "TextBlock",
"spacing": "medium",
"size": "default",
"weight": "bolder",
"text": "Welcome to Bot Framework!",
"wrap": true,
"maxLines": 0
},
{
"type": "TextBlock",
"size": "default",
"isSubtle": "yes",
"text": "Now that you have successfully run your bot, follow the links in this Adaptive Card to expand your knowledge of Bot Framework.",
"wrap": true,
"maxLines": 0
}
],
"actions": [
{
"type": "Action.OpenUrl",
"title": "Get an overview",
"url": "https://docs.microsoft.com/en-us/azure/bot-service/?view=azure-bot-service-4.0"
},
{
"type": "Action.OpenUrl",
"title": "Ask a question",
"url": "https://stackoverflow.com/questions/tagged/botframework"
},
{
"type": "Action.OpenUrl",
"title": "Learn how to deploy",
"url": "https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-deploy-azure?view=azure-bot-service-4.0"
}
]
}

Просмотреть файл

@ -1,334 +0,0 @@
{
"luis_schema_version": "3.2.0",
"versionId": "0.1",
"name": "FlightBooking",
"desc": "Luis Model for CoreBot",
"culture": "en-us",
"tokenizerVersion": "1.0.0",
"intents": [
{
"name": "BookFlight"
},
{
"name": "Cancel"
},
{
"name": "GetWeather"
},
{
"name": "None"
}
],
"entities": [],
"composites": [
{
"name": "From",
"children": [
"Airport"
],
"roles": []
},
{
"name": "To",
"children": [
"Airport"
],
"roles": []
}
],
"closedLists": [
{
"name": "Airport",
"subLists": [
{
"canonicalForm": "Paris",
"list": [
"paris"
]
},
{
"canonicalForm": "London",
"list": [
"london"
]
},
{
"canonicalForm": "Berlin",
"list": [
"berlin"
]
},
{
"canonicalForm": "New York",
"list": [
"new york"
]
},
{
"canonicalForm": "Seattle",
"list": [
"seattle"
]
}
],
"roles": []
}
],
"patternAnyEntities": [],
"regex_entities": [],
"prebuiltEntities": [
{
"name": "datetimeV2",
"roles": []
}
],
"model_features": [],
"regex_features": [],
"patterns": [],
"utterances": [
{
"text": "book a flight",
"intent": "BookFlight",
"entities": []
},
{
"text": "book a flight from new york",
"intent": "BookFlight",
"entities": [
{
"entity": "From",
"startPos": 19,
"endPos": 26
}
]
},
{
"text": "book a flight from seattle",
"intent": "BookFlight",
"entities": [
{
"entity": "From",
"startPos": 19,
"endPos": 25
}
]
},
{
"text": "book a hotel in new york",
"intent": "None",
"entities": []
},
{
"text": "book a restaurant",
"intent": "None",
"entities": []
},
{
"text": "book flight from london to paris on feb 14th",
"intent": "BookFlight",
"entities": [
{
"entity": "From",
"startPos": 17,
"endPos": 22
},
{
"entity": "To",
"startPos": 27,
"endPos": 31
}
]
},
{
"text": "book flight to berlin on feb 14th",
"intent": "BookFlight",
"entities": [
{
"entity": "To",
"startPos": 15,
"endPos": 20
}
]
},
{
"text": "book me a flight from london to paris",
"intent": "BookFlight",
"entities": [
{
"entity": "From",
"startPos": 22,
"endPos": 27
},
{
"entity": "To",
"startPos": 32,
"endPos": 36
}
]
},
{
"text": "bye",
"intent": "Cancel",
"entities": []
},
{
"text": "cancel booking",
"intent": "Cancel",
"entities": []
},
{
"text": "exit",
"intent": "Cancel",
"entities": []
},
{
"text": "find an airport near me",
"intent": "None",
"entities": []
},
{
"text": "flight to paris",
"intent": "BookFlight",
"entities": [
{
"entity": "To",
"startPos": 10,
"endPos": 14
}
]
},
{
"text": "flight to paris from london on feb 14th",
"intent": "BookFlight",
"entities": [
{
"entity": "To",
"startPos": 10,
"endPos": 14
},
{
"entity": "From",
"startPos": 21,
"endPos": 26
}
]
},
{
"text": "fly from berlin to paris on may 5th",
"intent": "BookFlight",
"entities": [
{
"entity": "From",
"startPos": 9,
"endPos": 14
},
{
"entity": "To",
"startPos": 19,
"endPos": 23
}
]
},
{
"text": "go to paris",
"intent": "BookFlight",
"entities": [
{
"entity": "To",
"startPos": 6,
"endPos": 10
}
]
},
{
"text": "going from paris to berlin",
"intent": "BookFlight",
"entities": [
{
"entity": "From",
"startPos": 11,
"endPos": 15
},
{
"entity": "To",
"startPos": 20,
"endPos": 25
}
]
},
{
"text": "i'd like to rent a car",
"intent": "None",
"entities": []
},
{
"text": "ignore",
"intent": "Cancel",
"entities": []
},
{
"text": "travel from new york to paris",
"intent": "BookFlight",
"entities": [
{
"entity": "From",
"startPos": 12,
"endPos": 19
},
{
"entity": "To",
"startPos": 24,
"endPos": 28
}
]
},
{
"text": "travel to new york",
"intent": "BookFlight",
"entities": [
{
"entity": "To",
"startPos": 10,
"endPos": 17
}
]
},
{
"text": "travel to paris",
"intent": "BookFlight",
"entities": [
{
"entity": "To",
"startPos": 10,
"endPos": 14
}
]
},
{
"text": "what's the forecast for this friday?",
"intent": "GetWeather",
"entities": []
},
{
"text": "what's the weather like for tomorrow",
"intent": "GetWeather",
"entities": []
},
{
"text": "what's the weather like in new york",
"intent": "GetWeather",
"entities": []
},
{
"text": "what's the weather like?",
"intent": "GetWeather",
"entities": []
},
{
"text": "winter is coming",
"intent": "None",
"entities": []
}
],
"settings": []
}

Просмотреть файл

@ -1,41 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
namespace Microsoft.BotBuilderSamples
{
// This ASP Controller is created to handle a request. Dependency Injection will provide the Adapter and IBot
// implementation at runtime. Multiple different IBot implementations running at different endpoints can be
// achieved by specifying a more specific type for the bot constructor argument.
[Route("api")]
[ApiController]
public class BotController : ControllerBase
{
private readonly IBotFrameworkHttpAdapter _adapter;
private IBot _bot;
private readonly Func<string, IBot> _service;
public BotController(IBotFrameworkHttpAdapter adapter, Func<string, IBot> service)
{
_adapter = adapter;
_service = service;
}
[Route("{*botname}")]
[HttpPost]
[HttpGet]
public async Task PostAsync(string botname)
{
// Delegate the processing of the HTTP POST to the adapter.
// The adapter will invoke the bot.
_bot = _service(botname) ?? throw new Exception($"The endpoint '{botname}' is not associated with a bot.");
await _adapter.ProcessAsync(Request, Response, _bot);
}
}
}

Просмотреть файл

@ -1,24 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Schema;
namespace Microsoft.Bot.Builder.TestBot.Debugging
{
public class DebugBot : ActivityHandler
{
private InspectionMiddleware _inspectionMiddleware;
public DebugBot(InspectionMiddleware inspectionMiddleware)
{
_inspectionMiddleware = inspectionMiddleware;
}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
await _inspectionMiddleware.ProcessCommandAsync(turnContext);
}
}
}

Просмотреть файл

@ -1,26 +0,0 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder.TestBot.Debugging;
namespace Microsoft.Bot.Builder.TestBot.Controllers
{
[Route("api/debug")]
[ApiController]
public class DebugController : ControllerBase
{
private DebugAdapter _adapter;
private DebugBot _bot;
public DebugController(DebugAdapter adapter, DebugBot bot)
{
_adapter = adapter;
_bot = bot;
}
[HttpPost]
public async Task PostAsync()
{
await _adapter.ProcessAsync(Request, Response, _bot);
}
}
}

Просмотреть файл

@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
namespace Microsoft.BotBuilderSamples
{
public static class DialogExtensions
{
public static async Task Run(this Dialog dialog, ITurnContext turnContext, IStatePropertyAccessor<DialogState> accessor, CancellationToken cancellationToken)
{
var dialogSet = new DialogSet(accessor);
dialogSet.Add(dialog);
var dialogContext = await dialogSet.CreateContextAsync(turnContext, cancellationToken);
var results = await dialogContext.ContinueDialogAsync(cancellationToken);
if (results.Status == DialogTurnStatus.Empty)
{
await dialogContext.BeginDialogAsync(dialog.Id, null, cancellationToken);
}
}
}
}

Просмотреть файл

@ -1,130 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.BotBuilderSamples.CognitiveModels;
using Microsoft.Extensions.Logging;
namespace Microsoft.BotBuilderSamples
{
// A root dialog responsible of understanding user intents and dispatching them sub tasks.
public class MainDialog : ComponentDialog
{
private readonly ILogger _logger;
private readonly IRecognizer _luisRecognizer;
public MainDialog(ILogger<MainDialog> logger, BookingDialog bookingDialog)
: this(logger, null, bookingDialog)
{
}
public MainDialog(ILogger<MainDialog> logger, IRecognizer luisRecognizer, BookingDialog bookingDialog)
: base(nameof(MainDialog))
{
_logger = logger;
_luisRecognizer = luisRecognizer;
AddDialog(new TextPrompt(nameof(TextPrompt)));
// Add bookingDialog intents
AddDialog(bookingDialog);
// Create and add waterfall for main conversation loop
// NOTE: we use a different task step if LUIS is not configured.
WaterfallStep[] steps;
if (luisRecognizer == null)
{
steps = new WaterfallStep[]
{
PromptForTaskActionAsync,
InvokeTaskActionAsyncNoLuis,
ResumeMainLoopActionAsync,
};
}
else
{
// LUIS is configured
steps = new WaterfallStep[]
{
PromptForTaskActionAsync,
InvokeTaskActionAsync,
ResumeMainLoopActionAsync,
};
}
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), steps));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
private async Task<DialogTurnResult> PromptForTaskActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
if (_luisRecognizer == null)
{
var activity = MessageFactory.Text("NOTE: LUIS is not configured. To enable all capabilities, add 'LuisAppId', 'LuisAPIKey' and 'LuisAPIHostName' to the appsettings.json file.");
activity.InputHint = InputHints.IgnoringInput;
await stepContext.Context.SendActivityAsync(activity, cancellationToken);
}
// Use the text provided in ResumeMainLoopActionAsync or the default if it is the first time.
var promptText = stepContext.Options?.ToString() ?? "What can I help you with today?";
return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text(promptText) }, cancellationToken);
}
private async Task<DialogTurnResult> InvokeTaskActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var luisResult = await _luisRecognizer.RecognizeAsync<FlightBooking>(stepContext.Context, cancellationToken);
switch (luisResult.TopIntent().intent)
{
case FlightBooking.Intent.BookFlight:
// Initialize BookingDetails with any entities we may have found in the response.
var bookingDetails = new BookingDetails()
{
// Get destination and origin from the composite entities arrays.
Destination = luisResult.Entities.To?.FirstOrDefault()?.Airport?.FirstOrDefault()?.FirstOrDefault(),
Origin = luisResult.Entities.From?.FirstOrDefault()?.Airport?.FirstOrDefault()?.FirstOrDefault(),
// This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
// TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year.
TravelDate = luisResult.Entities.datetime?.FirstOrDefault()?.Expressions.FirstOrDefault()?.Split('T')[0],
};
// Run the BookingDialog giving it whatever details we have from the LUIS call, it will fill out the remainder.
return await stepContext.BeginDialogAsync(nameof(BookingDialog), bookingDetails, cancellationToken);
case FlightBooking.Intent.GetWeather:
// We haven't implemented the GetWeatherDialog so we just display a TODO message.
await stepContext.Context.SendActivityAsync("TODO: get weather flow here", cancellationToken: cancellationToken);
break;
default:
// Catch all for unhandled intents
await stepContext.Context.SendActivityAsync($"Sorry, I didn't get that. Please try asking in a different way (intent was {luisResult.TopIntent().intent})", cancellationToken: cancellationToken);
break;
}
return await stepContext.NextAsync(null, cancellationToken);
}
private async Task<DialogTurnResult> InvokeTaskActionAsyncNoLuis(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// We only handle book a flight if LUIS is not configured
return await stepContext.BeginDialogAsync(nameof(BookingDialog), new BookingDetails(), cancellationToken);
}
private async Task<DialogTurnResult> ResumeMainLoopActionAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// We have completed the task (or the user cancelled), we restart main dialog with a different prompt text.
var promptMessage = "What else can I do for you?";
return await stepContext.ReplaceDialogAsync(Id, promptMessage, cancellationToken);
}
}
}

Просмотреть файл

@ -6,14 +6,6 @@
<RootNamespace>Microsoft.BotBuilderSamples</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Content Remove="Cards\welcomeCard.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Cards\welcomeCard.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.1" />
<PackageReference Include="Microsoft.Recognizers.Text.DataTypes.TimexExpression" Version="1.2.9" />
@ -23,6 +15,7 @@
<ProjectReference Include="..\..\libraries\integration\Microsoft.Bot.Builder.Integration.AspNet.Core\Microsoft.Bot.Builder.Integration.AspNet.Core.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.AI.LUIS\Microsoft.Bot.Builder.AI.Luis.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Dialogs\Microsoft.Bot.Builder.Dialogs.csproj" />
<ProjectReference Include="..\Microsoft.Bot.Builder.TestBot.Shared\Microsoft.Bot.Builder.TestBot.Shared.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,13 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.BotBuilderSamples.Services
{
public interface IFlightBookingService
{
Task<bool> BookFlight(BookingDetails booking, CancellationToken cancellationToken = default(CancellationToken));
}
}

Просмотреть файл

@ -7,9 +7,10 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.Luis;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Builder.TestBot.Bots;
using Microsoft.Bot.Builder.TestBot.Shared.Bots;
using Microsoft.Bot.Builder.TestBot.Shared.Dialogs;
using Microsoft.Bot.Builder.TestBot.Shared.Services;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.BotBuilderSamples.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

Просмотреть файл

@ -1,17 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.BotBuilderSamples
{
/// <summary>
/// This is our application state. Just a regular serializable .NET class.
/// </summary>
public class UserProfile
{
public string Transport { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}