Initial config support of proactive for WebAPI

This commit is contained in:
Drew Marsh 2018-03-06 15:28:41 -08:00
Родитель 87ceda1c5c
Коммит 69d849cff7
10 изменённых файлов: 145 добавлений и 37 удалений

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

@ -2,10 +2,12 @@
// Licensed under the MIT License.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Net;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder.Integration.AspNet.Core
{
@ -47,7 +49,7 @@ namespace Microsoft.Bot.Builder.Integration.AspNet.Core
}
applicationBuilder.Map(
paths.BasePath + paths.ActivitiesPath,,
paths.BasePath + paths.ActivitiesPath,
botActivitiesAppBuilder => botActivitiesAppBuilder.Run(new BotActivitiesHandler(botFrameworkAdapter).HandleAsync));
return applicationBuilder;

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

@ -2,6 +2,7 @@
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Middleware;
using System;
using Microsoft.Bot.Connector.Authentication;
namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
@ -10,9 +11,9 @@ namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
{
private BotFrameworkOptions _options;
public BotFrameworkConfigurationBuilder()
public BotFrameworkConfigurationBuilder(BotFrameworkOptions botFrameworkOptions)
{
_options = new BotFrameworkOptions();
_options = botFrameworkOptions;
}
public BotFrameworkOptions BotFrameworkOptions { get => _options; }
@ -33,5 +34,25 @@ namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
return this;
}
public BotFrameworkConfigurationBuilder EnableProactiveMessages(string proactiveMessagesPath = default(string))
{
_options.EnableProactiveMessages = true;
if (proactiveMessagesPath != null)
{
_options.Paths.ProactiveMessagesPath = proactiveMessagesPath;
}
return this;
}
public BotFrameworkConfigurationBuilder UsePaths(Action<BotFrameworkPaths> configurePaths)
{
configurePaths(_options.Paths);
return this;
}
}
}

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

@ -10,15 +10,17 @@ namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
public class BotFrameworkOptions
{
private readonly List<IMiddleware> _middleware;
private readonly BotFrameworkPaths _paths;
public BotFrameworkOptions()
{
RouteBaseUrl = "api/";
_middleware = new List<IMiddleware>();
_paths = new BotFrameworkPaths();
}
public string RouteBaseUrl { get; set; }
public ICredentialProvider CredentialProvider { get; set; }
public List<IMiddleware> Middleware { get => _middleware; }
public bool EnableProactiveMessages { get; set; }
public BotFrameworkPaths Paths { get => _paths; }
}
}

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

@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
{
public class BotFrameworkPaths
{
public BotFrameworkPaths()
{
this.BasePath = "api/";
this.MessagesPath = "messages";
this.ProactiveMessagesPath = "messages/proactive";
}
public string BasePath { get; set; }
public string MessagesPath { get; set; }
public string ProactiveMessagesPath { get; set; }
}
}

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

@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Schema;
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi.Handlers
{
internal sealed class BotMessageHandler : BotMessageHandlerBase
{
public BotMessageHandler(BotFrameworkAdapter botFrameworkAdapter) : base(botFrameworkAdapter)
{
}
protected override async Task ProcessMessageRequestAsync(HttpRequestMessage request, BotFrameworkAdapter botFrameworkAdapter, Func<IBotContext, Task> botCallbackHandler, CancellationToken cancellationToken)
{
var activity = await request.Content.ReadAsAsync<Activity>(BotMessageHandlerBase.BotMessageMediaTypeFormatters, cancellationToken);
await botFrameworkAdapter.ProcessActivity(
request.Headers.Authorization?.Parameter,
activity,
botCallbackHandler);
}
}
}

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

@ -2,7 +2,6 @@
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Schema;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
@ -12,11 +11,11 @@ using System.Net.Http.Formatting;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi.Handlers
{
internal sealed class BotActivitiesHandler : HttpMessageHandler
public abstract class BotMessageHandlerBase : HttpMessageHandler
{
private static readonly MediaTypeFormatter[] BotActivityMediaTypeFormatters = new [] {
public static readonly MediaTypeFormatter[] BotMessageMediaTypeFormatters = new [] {
new JsonMediaTypeFormatter
{
SerializerSettings =
@ -30,7 +29,7 @@ namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
private readonly BotFrameworkAdapter _botFrameworkAdapter;
public BotActivitiesHandler(BotFrameworkAdapter botFrameworkAdapter)
public BotMessageHandlerBase(BotFrameworkAdapter botFrameworkAdapter)
{
_botFrameworkAdapter = botFrameworkAdapter;
}
@ -42,26 +41,23 @@ namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
return request.CreateResponse(HttpStatusCode.MethodNotAllowed);
}
var requestContent = request.Content;
var requestContentHeaders = requestContent.Headers;
var requestContentHeaders = request.Content.Headers;
if (requestContentHeaders.ContentLength == 0)
{
return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Request body should not be empty.");
}
if (!BotActivityMediaTypeFormatters[0].SupportedMediaTypes.Contains(requestContentHeaders.ContentType))
if (!BotMessageMediaTypeFormatters[0].SupportedMediaTypes.Contains(requestContentHeaders.ContentType))
{
return request.CreateErrorResponse(HttpStatusCode.NotAcceptable, $"Expecting Content-Type of \"{BotActivityMediaTypeFormatters[0].SupportedMediaTypes[0].MediaType}\".");
return request.CreateErrorResponse(HttpStatusCode.NotAcceptable, $"Expecting Content-Type of \"{BotMessageMediaTypeFormatters[0].SupportedMediaTypes[0].MediaType}\".");
}
var activity = await requestContent.ReadAsAsync<Activity>(BotActivitiesHandler.BotActivityMediaTypeFormatters, cancellationToken);
try
{
await _botFrameworkAdapter.ProcessActivity(
request.Headers.Authorization?.Parameter,
activity,
await ProcessMessageRequestAsync(
request,
_botFrameworkAdapter,
botContext =>
{
cancellationToken.ThrowIfCancellationRequested();
@ -77,13 +73,14 @@ namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
bot = null;
}
if(bot == null)
if (bot == null)
{
throw new InvalidOperationException($"Did not find an {typeof(IBot).Name} service via the dependency resolver. Please make sure you have registered your bot with your dependency injection container.");
}
return bot.OnReceiveActivity(botContext);
});
},
cancellationToken);
return request.CreateResponse(HttpStatusCode.OK);
}
@ -96,5 +93,7 @@ namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
return request.CreateErrorResponse(HttpStatusCode.NotFound, e.Message);
}
}
protected abstract Task ProcessMessageRequestAsync(HttpRequestMessage request, BotFrameworkAdapter botFrameworkAdapter, Func<IBotContext, Task> botCallbackHandler, CancellationToken cancellationToken);
}
}

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

@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Schema;
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi.Handlers
{
public sealed class BotProactiveMessageHandler : BotMessageHandlerBase
{
public BotProactiveMessageHandler(BotFrameworkAdapter botFrameworkAdapter) : base(botFrameworkAdapter)
{
}
protected override async Task ProcessMessageRequestAsync(HttpRequestMessage request, BotFrameworkAdapter botFrameworkAdapter, Func<IBotContext, Task> botCallbackHandler, CancellationToken cancellationToken)
{
var conversationReference = await request.Content.ReadAsAsync<ConversationReference>(BotMessageHandlerBase.BotMessageMediaTypeFormatters, cancellationToken);
await botFrameworkAdapter.ContinueConversation(conversationReference, botCallbackHandler);
}
}
}

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

@ -2,6 +2,7 @@
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Integration.AspNet.WebApi.Handlers;
using System;
using System.Web.Http;
@ -11,13 +12,12 @@ namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
{
public static HttpConfiguration MapBotFramework(this HttpConfiguration httpConfiguration, Action<BotFrameworkConfigurationBuilder> configurer)
{
var optionsBuilder = new BotFrameworkConfigurationBuilder();
var options = new BotFrameworkOptions();
var optionsBuilder = new BotFrameworkConfigurationBuilder(options);
configurer(optionsBuilder);
var options = optionsBuilder.BotFrameworkOptions;
ConfigureBotRoute(BuildAdapter());
ConfigureBotRoutes(BuildAdapter());
return httpConfiguration;
@ -33,23 +33,32 @@ namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
return adapter;
}
void ConfigureBotRoute(BotFrameworkAdapter adapter)
void ConfigureBotRoutes(BotFrameworkAdapter adapter)
{
var botActivitiesRouteUrl = options.RouteBaseUrl;
var routes = httpConfiguration.Routes;
var baseUrl = options.Paths.BasePath;
if (!botActivitiesRouteUrl.EndsWith("/"))
if (!baseUrl.EndsWith("/"))
{
botActivitiesRouteUrl += "/";
baseUrl += "/";
}
botActivitiesRouteUrl += "messages";
httpConfiguration.Routes.MapHttpRoute(
"BotFrameworkV4 Activities Controller",
botActivitiesRouteUrl,
if (options.EnableProactiveMessages)
{
routes.MapHttpRoute(
"BotFramework - Proactive Message Handler",
baseUrl + options.Paths.ProactiveMessagesPath,
defaults: null,
constraints: null,
handler: new BotActivitiesHandler(adapter));
handler: new BotProactiveMessageHandler(adapter));
}
routes.MapHttpRoute(
"BotFramework - Message Handler",
baseUrl + options.Paths.MessagesPath,
defaults: null,
constraints: null,
handler: new BotMessageHandler(adapter));
}
}
}

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

@ -18,6 +18,7 @@ namespace Microsoft.Bot.Samples.EchoBot_AspNet461
{
botConfig
.UseMicrosoftApplicationIdentity(ConfigurationManager.AppSettings["BotFramework.MicrosoftApplicationId"], ConfigurationManager.AppSettings["BotFramework.MicrosoftApplicationPassword"])
.EnableProactiveMessages()
.UseMiddleware(new ConversationState<EchoState>(new MemoryStorage()));
});
}

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

@ -8,8 +8,8 @@ namespace Microsoft.Bot.Samples.EchoBot_AspNet461
{
GlobalConfiguration.Configure(config =>
{
WebApiConfig.Register(config);
BotConfig.Register(config);
WebApiConfig.Register(config);
});
}
}