Merge branch 'master' into tomlm/moreprompts

This commit is contained in:
Tom Laird-McConnell 2018-03-08 19:14:49 -08:00
Родитель 0532b10368 b5e392af69
Коммит 053e96f94e
92 изменённых файлов: 4613 добавлений и 960 удалений

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

@ -40,9 +40,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Connector.Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Samples.Ai.QnA", "samples\Microsoft.Bot.Samples.Ai.QnA\Microsoft.Bot.Samples.Ai.QnA.csproj", "{A8CE6B0F-E054-45F7-B4D7-23D2C65D2D26}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Bot.Builder.Prompts", "libraries\Microsoft.Bot.Builder.Prompts\Microsoft.Bot.Builder.Prompts.csproj", "{7A197F41-3411-47BF-87A6-5BC8A44CDB74}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Integration", "Integration", "{276EBE79-A13A-46BD-A566-B01DC0477A9B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Bot.Builder.Prompts.Tests", "tests\Microsoft.Bot.Builder.Prompts.Tests\Microsoft.Bot.Builder.Prompts.Tests.csproj", "{5D145BFC-1C30-4FC5-989A-82260F8225BE}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Bot.Builder.LUIS", "libraries\Microsoft.Bot.Builder.LUIS\Microsoft.Bot.Builder.LUIS.csproj", "{67AA3C00-E2C5-4D13-BA5E-72EB0E5B8DAA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.LUIS.Tests", "tests\Microsoft.Bot.Builder.LUIS.Tests\Microsoft.Bot.Builder.LUIS.Tests.csproj", "{7BCEBDC1-D57F-4717-9B15-4FACD5473489}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Prompts", "libraries\Microsoft.Bot.Builder.Prompts\Microsoft.Bot.Builder.Prompts.csproj", "{7A197F41-3411-47BF-87A6-5BC8A44CDB74}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Prompts.Tests", "tests\Microsoft.Bot.Builder.Prompts.Tests\Microsoft.Bot.Builder.Prompts.Tests.csproj", "{5D145BFC-1C30-4FC5-989A-82260F8225BE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EchoBot", "samples\EchoBot\EchoBot.csproj", "{30B77905-0BAB-44C1-A011-0245F220C30C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Integration.AspNet.WebApi", "libraries\integration\Microsoft.Bot.Builder.Integration.AspNet.WebApi\Microsoft.Bot.Builder.Integration.AspNet.WebApi.csproj", "{BD0B82EF-1601-4E87-B78A-B43DE7EB36B0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Integration.AspNet.Core", "libraries\integration\Microsoft.Bot.Builder.Integration.AspNet.Core\Microsoft.Bot.Builder.Integration.AspNet.Core.csproj", "{053BD8B8-B5C1-4C45-81D4-C9BA8D5B3CE2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -122,6 +134,26 @@ Global
{5D145BFC-1C30-4FC5-989A-82260F8225BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5D145BFC-1C30-4FC5-989A-82260F8225BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5D145BFC-1C30-4FC5-989A-82260F8225BE}.Release|Any CPU.Build.0 = Release|Any CPU
{30B77905-0BAB-44C1-A011-0245F220C30C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{30B77905-0BAB-44C1-A011-0245F220C30C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{30B77905-0BAB-44C1-A011-0245F220C30C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{30B77905-0BAB-44C1-A011-0245F220C30C}.Release|Any CPU.Build.0 = Release|Any CPU
{BD0B82EF-1601-4E87-B78A-B43DE7EB36B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD0B82EF-1601-4E87-B78A-B43DE7EB36B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD0B82EF-1601-4E87-B78A-B43DE7EB36B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD0B82EF-1601-4E87-B78A-B43DE7EB36B0}.Release|Any CPU.Build.0 = Release|Any CPU
{053BD8B8-B5C1-4C45-81D4-C9BA8D5B3CE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{053BD8B8-B5C1-4C45-81D4-C9BA8D5B3CE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{053BD8B8-B5C1-4C45-81D4-C9BA8D5B3CE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{053BD8B8-B5C1-4C45-81D4-C9BA8D5B3CE2}.Release|Any CPU.Build.0 = Release|Any CPU
{67AA3C00-E2C5-4D13-BA5E-72EB0E5B8DAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67AA3C00-E2C5-4D13-BA5E-72EB0E5B8DAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67AA3C00-E2C5-4D13-BA5E-72EB0E5B8DAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67AA3C00-E2C5-4D13-BA5E-72EB0E5B8DAA}.Release|Any CPU.Build.0 = Release|Any CPU
{7BCEBDC1-D57F-4717-9B15-4FACD5473489}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7BCEBDC1-D57F-4717-9B15-4FACD5473489}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7BCEBDC1-D57F-4717-9B15-4FACD5473489}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BCEBDC1-D57F-4717-9B15-4FACD5473489}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -143,8 +175,14 @@ Global
{C8DF8AE3-0A4D-445D-993E-F7A1784BFDD4} = {3ADFB27A-95FA-4330-B211-1D66A29A17AB}
{BF414C86-DB3B-4022-9B29-DCE8AA954C12} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{A8CE6B0F-E054-45F7-B4D7-23D2C65D2D26} = {3ADFB27A-95FA-4330-B211-1D66A29A17AB}
{276EBE79-A13A-46BD-A566-B01DC0477A9B} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{67AA3C00-E2C5-4D13-BA5E-72EB0E5B8DAA} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{7BCEBDC1-D57F-4717-9B15-4FACD5473489} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{7A197F41-3411-47BF-87A6-5BC8A44CDB74} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{5D145BFC-1C30-4FC5-989A-82260F8225BE} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{30B77905-0BAB-44C1-A011-0245F220C30C} = {3ADFB27A-95FA-4330-B211-1D66A29A17AB}
{BD0B82EF-1601-4E87-B78A-B43DE7EB36B0} = {276EBE79-A13A-46BD-A566-B01DC0477A9B}
{053BD8B8-B5C1-4C45-81D4-C9BA8D5B3CE2} = {276EBE79-A13A-46BD-A566-B01DC0477A9B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7173C9F3-A7F9-496E-9078-9156E35D6E16}

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

@ -1,5 +1,7 @@
# Bot Builder SDK v4
![Build Status](https://fuselabs.visualstudio.com/_apis/public/build/definitions/86659c66-c9df-418a-a371-7de7aed35064/211/badge)
This repository contains code for the .NET version of the [Microsoft Bot Builder SDK](https://github.com/Microsoft/botbuilder).
The 4.x version of the SDK is being actively developed and should therefore be used for **EXPERIMENTATION PURPOSES ONLY**.
Production bots should continue to be developed using the [v3 SDK](https://github.com/Microsoft/BotBuilder/tree/master/CSharp). In addition to the .NET SDK, Bot Builder supports creating bots in other popular programming languages like [JavaScript](https://github.com/Microsoft/botbuilder-js), [Python](https://github.com/Microsoft/botbuilder-python), and [Java](https://github.com/Microsoft/botbuilder-java).
@ -28,10 +30,3 @@ Security issues and bugs should be reported privately, via email, to the Microso
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the [MIT](https://github.com/Microsoft/vscode/blob/master/LICENSE.txt) License.
<!--
## Current Build Status
| Project | Status |
| --- | --- |
| Microsoft.Bot.Connector | ![Build Status](https://fuselabs.visualstudio.com/_apis/public/build/definitions/86659c66-c9df-418a-a371-7de7aed35064/212/badge) |
-->

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

@ -1,28 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;1705;1998</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Microsoft.Recognizers.Text.DateTime" Version="1.0.0.36" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Core\Microsoft.Bot.Builder.Core.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder\Microsoft.Bot.Builder.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Connector\Microsoft.Bot.Connector.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Schema\Microsoft.Bot.Schema.csproj" />
</ItemGroup>
</Project>

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

@ -35,7 +35,7 @@ namespace Microsoft.Bot.Builder.Azure
if (_checkedTables.Add($"{storageAccount.TableStorageUri.PrimaryUri.Host}-{tableName}"))
this.Table.CreateIfNotExistsAsync().Wait();
}
protected EntityKey GetEntityKey(string key)
{
return new EntityKey() { PartitionKey = SanitizeKey(key), RowKey = "0" };
@ -58,9 +58,11 @@ namespace Microsoft.Bot.Builder.Azure
var result = await this.Table.ExecuteAsync(TableOperation.Retrieve<StoreItemEntity>(entityKey.PartitionKey, entityKey.RowKey)).ConfigureAwait(false);
if ((HttpStatusCode)result.HttpStatusCode == HttpStatusCode.OK)
{
var storeItem = ((StoreItemEntity)result.Result).As<StoreItem>();
storeItem.eTag = result.Etag;
storeItems[key] = storeItem;
var value = ((StoreItemEntity)result.Result).AsObject();
IStoreItem valueStoreItem = value as IStoreItem;
if (valueStoreItem != null)
valueStoreItem.eTag = result.Etag;
storeItems[key] = value;
}
}
return storeItems;
@ -72,8 +74,8 @@ namespace Microsoft.Bot.Builder.Azure
foreach (var change in changes)
{
var entityKey = GetEntityKey(change.Key);
var storeItem = (StoreItem)change.Value;
StoreItemEntity entity = new StoreItemEntity(entityKey, storeItem);
var newValue = change.Value;
StoreItemEntity entity = new StoreItemEntity(entityKey, newValue);
if (entity.ETag == null || entity.ETag == "*")
{
var result = await this.Table.ExecuteAsync(TableOperation.InsertOrReplace(entity)).ConfigureAwait(false);
@ -99,23 +101,26 @@ namespace Microsoft.Bot.Builder.Azure
public StoreItemEntity() { }
public StoreItemEntity(EntityKey key, StoreItem obj)
public StoreItemEntity(EntityKey key, object obj)
: this(key.PartitionKey, key.RowKey, obj)
{ }
public StoreItemEntity(string partitionKey, string rowKey, StoreItem obj)
public StoreItemEntity(string partitionKey, string rowKey, object obj)
: base(partitionKey, rowKey)
{
this.ETag = obj.eTag;
this.ETag = (obj as IStoreItem)?.eTag;
this.Json = JsonConvert.SerializeObject(obj, Formatting.None, serializationSettings);
}
public string Json { get; set; }
public T As<T>()
where T : StoreItem
public object AsObject()
{
return JsonConvert.DeserializeObject<T>(Json, serializationSettings);
var obj = JsonConvert.DeserializeObject(Json, serializationSettings);
IStoreItem storeItem = obj as IStoreItem;
if (storeItem != null)
storeItem.eTag = this.ETag;
return obj;
}
}
@ -153,6 +158,6 @@ namespace Microsoft.Bot.Builder.Azure
sb.Append(ch);
}
return sb.ToString();
}
}
}
}

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

@ -67,24 +67,34 @@ namespace Microsoft.Bot.Builder
return this;
}
public void Set(string objectId, object service)
/// <summary>
/// Set the value associated with a key.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value to set.</param>
public void Set(string key, object value)
{
if (String.IsNullOrWhiteSpace(objectId))
throw new ArgumentNullException(nameof(objectId));
if (String.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(nameof(key));
lock (_services)
{
this._services[objectId] = service;
this._services[key] = value;
}
}
public object Get(string serviceId)
/// <summary>
/// Get a value by a key.
/// </summary>
/// <param name="key">The key of the value to get.</param>
/// <returns>The value.</returns>
public object Get(string key)
{
if (String.IsNullOrWhiteSpace(serviceId))
throw new ArgumentNullException(nameof(serviceId));
if (String.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(nameof(key));
object service = null;
lock (_services)
{
this._services.TryGetValue(serviceId, out service);
this._services.TryGetValue(key, out service);
}
return service;
}

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

@ -30,9 +30,14 @@ namespace Microsoft.Bot.Builder
public ConversationReference ConversationReference => this._innerContext.ConversationReference;
public object Get(string serviceId)
/// <summary>
/// Get a value by a key.
/// </summary>
/// <param name="key">The key of the value to get.</param>
/// <returns>The value.</returns>
public object Get(string key)
{
return this._innerContext.Get(serviceId);
return this._innerContext.Get(key);
}
public IBotContext Reply(string text, string speak = null)
@ -47,9 +52,14 @@ namespace Microsoft.Bot.Builder
return this;
}
public void Set(string serviceId, object service)
/// <summary>
/// Set the value associated with a key.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value to set.</param>
public void Set(string key, object value)
{
this._innerContext.Set(serviceId, service);
this._innerContext.Set(key, value);
}
}
}

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

@ -203,9 +203,17 @@ namespace Microsoft.Bot.Builder
public object Clone()
{
return JsonConvert.DeserializeObject<StoreItem>(
JsonConvert.SerializeObject(this, SerializationSettings),
SerializationSettings);
return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(this, SerializationSettings),SerializationSettings);
}
public static T Clone<T>(object obj)
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj, SerializationSettings), SerializationSettings);
}
public static object Clone(object obj)
{
return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(obj, SerializationSettings), SerializationSettings);
}
}
}

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

@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder;
using System.Threading.Tasks;
namespace Microsoft.Bot
{
public interface IBot
{
Task OnReceiveActivity(IBotContext botContext);
}
}

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

@ -45,33 +45,47 @@ namespace Microsoft.Bot.Builder
IBotContext Reply(IActivity activity);
/// <summary>
/// Set object by Id
/// Set the value associated with a key.
/// </summary>
/// <param name="objectId"></param>
/// <param name="object"></param>
void Set(string objectId, object @object);
/// <param name="key">The key.</param>
/// <param name="value">The value to set.</param>
void Set(string key, object value);
/// <summary>
/// Get object by id
/// Get a value by a key.
/// </summary>
/// <param name="objectId"></param>
/// <returns>service</returns>
object Get(string objectId);
/// <param name="key">The key of the value to get.</param>
/// <returns>The value.</returns>
object Get(string key);
}
public static partial class BotContextExtension
{
public static void Set<ObjectT>(this IBotContext context, ObjectT service)
/// <summary>
/// Set a value of a specific type on a context object.
/// </summary>
/// <typeparam name="ObjectT">The value's type.</typeparam>
/// <param name="context">The context object.</param>
/// <param name="value">The value.</param>
/// <remarks>Uses the value type's name as the key.</remarks>
public static void Set<ObjectT>(this IBotContext context, ObjectT value)
{
var objectId = $"{typeof(ObjectT).Namespace}.{typeof(ObjectT).Name}";
context.Set(objectId, service);
var key = $"{typeof(ObjectT).Namespace}.{typeof(ObjectT).Name}";
context.Set(key, value);
}
public static ObjectT Get<ObjectT>(this IBotContext context, string objectId = null)
/// <summary>
/// Get a value of a specific type from a context object.
/// </summary>
/// <typeparam name="ObjectT">The value's type.</typeparam>
/// <param name="context">The context object.</param>
/// <param name="key">An optional lookup key. The default is the value type's name.</param>
/// <returns>The value.</returns>
public static ObjectT Get<ObjectT>(this IBotContext context, string key = null)
{
if (objectId == null)
objectId = $"{typeof(ObjectT).Namespace}.{typeof(ObjectT).Name}";
return (ObjectT)context.Get(objectId);
if (key == null)
key = $"{typeof(ObjectT).Namespace}.{typeof(ObjectT).Name}";
return (ObjectT)context.Get(key);
}
}

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

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder
{
@ -49,7 +49,7 @@ namespace Microsoft.Bot.Builder
/// </summary>
public string eTag { get; set; }
public T ToObject<T>()
public T ToObject<T>() where T : class
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(this, serializationSettings), serializationSettings);
}
@ -57,16 +57,15 @@ namespace Microsoft.Bot.Builder
public class StoreItems : FlexObject
{
public T Get<T>(string name)
public T Get<T>(string name) where T : class
{
if (this.TryGetValue(name, out dynamic value) && value != null)
return value.ToObject<T>();
return default(T);
this.TryGetValue(name, out object value);
return value as T;
}
}
public class StoreItems<StoreItemT> : StoreItems
where StoreItemT : IStoreItem
public class StoreItems<StoreItemT> : StoreItems where StoreItemT : class
{
}
@ -86,8 +85,7 @@ namespace Microsoft.Bot.Builder
/// <param name="storage"></param>
/// <param name="keys"></param>
/// <returns></returns>
public static async Task<StoreItems<StoreItemT>> Read<StoreItemT>(this IStorage storage, params string[] keys)
where StoreItemT : StoreItem
public static async Task<StoreItems<StoreItemT>> Read<StoreItemT>(this IStorage storage, params string[] keys) where StoreItemT : class
{
var storeItems = await storage.Read(keys).ConfigureAwait(false);
var newResults = new StoreItems<StoreItemT>();

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

@ -1,12 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Schema;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Middleware;
using Microsoft.Bot.Schema;
namespace Microsoft.Bot.Builder.Middleware
{
@ -21,7 +19,7 @@ namespace Microsoft.Bot.Builder.Middleware
/// </summary>
/// <typeparam name="StateT"></typeparam>
public abstract class BotState<StateT> : IContextCreated, ISendActivity
where StateT : IStoreItem, new()
where StateT : class, new()
{
private readonly StateSettings _settings;
private readonly IStorage _storage;
@ -88,7 +86,10 @@ namespace Microsoft.Bot.Builder.Middleware
{
foreach (var item in changes)
{
((StoreItem)changes[item.Key]).eTag = "*";
if(item.Value is IStoreItem valueStoreItem)
{
valueStoreItem.eTag = "*";
}
}
}
@ -102,7 +103,7 @@ namespace Microsoft.Bot.Builder.Middleware
/// </summary>
/// <typeparam name="StateT"></typeparam>
public class ConversationState<StateT> : BotState<StateT>
where StateT : IStoreItem, new()
where StateT : class, new()
{
public static string PropertyName = $"ConversationState:{typeof(ConversationState<StateT>).Namespace}.{typeof(ConversationState<StateT>).Name}";
@ -126,7 +127,7 @@ namespace Microsoft.Bot.Builder.Middleware
/// </summary>
/// <typeparam name="StateT"></typeparam>
public class UserState<StateT> : BotState<StateT>
where StateT : IStoreItem, new()
where StateT : class, new()
{
public static readonly string PropertyName = $"UserState:{typeof(UserState<StateT>).Namespace}.{typeof(UserState<StateT>).Name}";
@ -148,13 +149,13 @@ namespace Microsoft.Bot.Builder.Middleware
public static class StateContextExtensions
{
public static T GetConversationState<T>(this IBotContext context)
where T : IStoreItem, new()
where T : class, new()
{
return ConversationState<T>.Get(context);
}
public static T GetUserState<T>(this IBotContext context)
where T : IStoreItem, new()
where T : class, new()
{
return UserState<T>.Get(context);
}

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

@ -28,7 +28,7 @@ namespace Microsoft.Bot.Builder.Storage
{
this.folder = folder;
}
public Task Delete(string[] keys)
{
foreach (var key in keys)
@ -43,14 +43,14 @@ namespace Microsoft.Bot.Builder.Storage
var storeItems = new StoreItems();
foreach (var key in keys)
{
var item = await ReadStoreItem(key).ConfigureAwait(false);
var item = await ReadIStoreItem(key).ConfigureAwait(false);
if (item != null)
storeItems[key] = item;
}
return storeItems;
}
private async Task<StoreItem> ReadStoreItem(string key)
private async Task<object> ReadIStoreItem(string key)
{
// The funky threading in here is due to concurrency and async methods.
// When this method is called, it may happen (in parallel) from any number of
@ -76,7 +76,7 @@ namespace Microsoft.Bot.Builder.Storage
json = await file.ReadToEndAsync().ConfigureAwait(false);
}
return JsonConvert.DeserializeObject<StoreItem>(json, serializationSettings);
return JsonConvert.DeserializeObject(json, serializationSettings);
}
catch (FileNotFoundException)
{
@ -114,18 +114,22 @@ namespace Microsoft.Bot.Builder.Storage
{
try
{
StoreItem newValue = change.Value as StoreItem;
StoreItem oldValue = await this.ReadStoreItem(change.Key).ConfigureAwait(false);
object newValue = change.Value;
object oldValue = await this.ReadIStoreItem(change.Key).ConfigureAwait(false);
IStoreItem newStoreItem = newValue as IStoreItem;
IStoreItem oldStoreItem = oldValue as IStoreItem;
if (oldValue == null ||
newValue.eTag == "*" ||
oldValue.eTag == newValue.eTag)
newStoreItem?.eTag == "*" ||
oldStoreItem?.eTag == newStoreItem?.eTag)
{
string key = SanitizeKey(change.Key);
string path = Path.Combine(this.folder, key);
var oldTag = newValue.eTag;
newValue.eTag = (this.eTag++).ToString();
var oldTag = newStoreItem?.eTag;
if (newStoreItem != null)
newStoreItem.eTag = (this.eTag++).ToString();
var json = JsonConvert.SerializeObject(newValue, serializationSettings);
newValue.eTag = oldTag;
if (newStoreItem != null)
newStoreItem.eTag = oldTag;
using (TextWriter file = new StreamWriter(path))
{
await file.WriteAsync(json).ConfigureAwait(false);
@ -169,6 +173,6 @@ namespace Microsoft.Bot.Builder.Storage
sb.Append(ch);
}
return sb.ToString();
}
}
}
}

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

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Newtonsoft.Json;
using System;
using System.Threading.Tasks;
@ -42,7 +43,7 @@ namespace Microsoft.Bot.Builder.Storage
if (_memory.TryGetValue(key, out object value))
{
if (value != null)
storeItems[key] = (StoreItem)((ICloneable)value).Clone();
storeItems[key] = FlexObject.Clone(value);
else
storeItems[key] = null;
}
@ -58,18 +59,23 @@ namespace Microsoft.Bot.Builder.Storage
{
foreach (var change in changes)
{
StoreItem newValue = change.Value as StoreItem;
StoreItem oldValue = null;
object newValue = change.Value;
object oldValue = null;
if (_memory.TryGetValue(change.Key, out object x))
oldValue = x as StoreItem;
oldValue = x;
IStoreItem newStoreItem = newValue as IStoreItem;
IStoreItem oldStoreItem = oldValue as IStoreItem;
if (oldValue == null ||
newValue.eTag == "*" ||
oldValue.eTag == newValue.eTag)
newStoreItem?.eTag == "*" ||
oldStoreItem?.eTag == newStoreItem?.eTag)
{
// clone and set etag
newValue = newValue.Clone() as StoreItem;
newValue.eTag = (_eTag++).ToString();
newValue = FlexObject.Clone(newValue);
newStoreItem = newValue as IStoreItem;
if (newStoreItem != null)
newStoreItem.eTag = (_eTag++).ToString();
_memory[change.Key] = newValue;
}
else
@ -80,6 +86,7 @@ namespace Microsoft.Bot.Builder.Storage
}
return Task.CompletedTask;
}
}
/// <summary>

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

@ -0,0 +1,99 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Builder SDK GitHub:
// https://github.com/Microsoft/BotBuilder
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Cognitive.LUIS.Models;
namespace Microsoft.Cognitive.LUIS
{
/// <summary>
/// LUIS extension methods.
/// </summary>
public static partial class Extensions
{
/// <summary>
/// Try to find an entity within the result.
/// </summary>
/// <param name="result">The LUIS result.</param>
/// <param name="type">The entity type.</param>
/// <param name="entity">The found entity.</param>
/// <returns>True if the entity was found, false otherwise.</returns>
public static bool TryFindEntity(this LuisResult result, string type, out EntityRecommendation entity)
{
entity = result.Entities?.FirstOrDefault(e => e.Type == type);
return entity != null;
}
/// <summary>
/// Parse all resolutions from a LUIS result.
/// </summary>
/// <param name="parser">The resolution parser.</param>
/// <param name="entities">The LUIS entities.</param>
/// <returns>The parsed resolutions.</returns>
public static IEnumerable<Resolution> ParseResolutions(this IResolutionParser parser, IEnumerable<EntityRecommendation> entities)
{
if (entities != null)
{
foreach (var entity in entities)
{
Resolution resolution;
if (parser.TryParse(entity.Resolution, out resolution))
{
yield return resolution;
}
}
}
}
/// <summary>
/// Return the next <see cref="BuiltIn.DateTime.DayPart"/>.
/// </summary>
/// <param name="part">The <see cref="BuiltIn.DateTime.DayPart"/> query.</param>
/// <returns>The next <see cref="BuiltIn.DateTime.DayPart"/> after the query.</returns>
public static BuiltIn.DateTime.DayPart Next(this BuiltIn.DateTime.DayPart part)
{
switch (part)
{
case BuiltIn.DateTime.DayPart.MO: return BuiltIn.DateTime.DayPart.MI;
case BuiltIn.DateTime.DayPart.MI: return BuiltIn.DateTime.DayPart.AF;
case BuiltIn.DateTime.DayPart.AF: return BuiltIn.DateTime.DayPart.EV;
case BuiltIn.DateTime.DayPart.EV: return BuiltIn.DateTime.DayPart.NI;
case BuiltIn.DateTime.DayPart.NI: return BuiltIn.DateTime.DayPart.MO;
default: throw new NotImplementedException();
}
}
}
}

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

@ -0,0 +1,229 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Builder SDK GitHub:
// https://github.com/Microsoft/BotBuilder
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
namespace Microsoft.Cognitive.LUIS
{
/// <summary>
/// Luis api version.
/// </summary>
public enum LuisApiVersion
{
[Obsolete]
V1,
V2
}
/// <summary>
/// A mockable interface for the LUIS model.
/// </summary>
public interface ILuisModel
{
/// <summary>
/// The LUIS model ID.
/// </summary>
string ModelID { get; }
/// <summary>
/// The LUIS subscription key.
/// </summary>
string SubscriptionKey { get; }
/// <summary>
/// The base Uri for accessing LUIS.
/// </summary>
Uri UriBase { get; }
/// <summary>
/// Luis Api Version.
/// </summary>
LuisApiVersion ApiVersion { get; }
/// <summary>
/// Threshold for top scoring intent
/// </summary>
double Threshold { get; }
/// <summary>
/// Modify a Luis request to specify query parameters like spelling or logging.
/// </summary>
/// <param name="request">Request so far.</param>
/// <returns>Modified request.</returns>
LuisRequest ModifyRequest(LuisRequest request);
}
/// <summary>
/// The LUIS model information.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Method, AllowMultiple = true)]
[Serializable]
public class LuisModelAttribute : Attribute, ILuisModel, ILuisOptions, IEquatable<ILuisModel>
{
private readonly string modelID;
/// <summary>
/// The GUID for the LUIS model.
/// </summary>
public string ModelID => modelID;
private readonly string subscriptionKey;
/// <summary>
/// The subscription key for LUIS.
/// </summary>
public string SubscriptionKey => subscriptionKey;
private readonly string domain;
/// <summary>
/// Domain where LUIS application is located.
/// </summary>
/// <remarks>Null means default which is api.projectoxford.ai for V1 API and westus.api.cognitive.microsoft.com for V2 api.</remarks>
public string Domain => domain;
private readonly Uri uriBase;
/// <summary>
/// Base URI for LUIS calls.
/// </summary>
public Uri UriBase => uriBase;
private readonly LuisApiVersion apiVersion;
/// <summary>
/// Version of query API to call.
/// </summary>
public LuisApiVersion ApiVersion => apiVersion;
private readonly double threshold;
/// <summary>
/// Threshold for top scoring intent
/// </summary>
public double Threshold => threshold;
private ILuisOptions Options => (ILuisOptions)this;
/// <summary>
/// Indicates if logging of queries to LUIS is allowed.
/// </summary>
public bool Log { get { return Options.Log.Value; } set { Options.Log = value; } }
/// <summary>
/// Turn on spell checking.
/// </summary>
public bool SpellCheck { get { return Options.SpellCheck.Value; } set { Options.SpellCheck = value; } }
/// <summary>
/// Use the staging endpoint.
/// </summary>
public bool Staging { get { return Options.Staging.Value; } set { Options.Staging = value; } }
/// <summary>
/// The time zone offset.
/// </summary>
public double TimezoneOffset { get { return Options.TimezoneOffset.Value; } set { Options.TimezoneOffset = value; } }
/// <summary>
/// The verbose flag.
/// </summary>
public bool Verbose { get { return Options.Verbose.Value; } set { Options.Verbose = value; } }
/// <summary>
/// The Bing Spell Check subscription key.
/// </summary>
public string BingSpellCheckSubscriptionKey { get { return Options.BingSpellCheckSubscriptionKey; } set { Options.BingSpellCheckSubscriptionKey = value; } }
bool? ILuisOptions.Log { get; set; }
bool? ILuisOptions.SpellCheck { get; set; }
bool? ILuisOptions.Staging { get; set; }
double? ILuisOptions.TimezoneOffset { get; set; }
bool? ILuisOptions.Verbose { get; set; }
string ILuisOptions.BingSpellCheckSubscriptionKey { get; set; }
public static Uri UriFor(LuisApiVersion apiVersion, string domain = null)
{
if (domain == null)
{
domain = apiVersion == LuisApiVersion.V2 ? "westus.api.cognitive.microsoft.com" : "api.projectoxford.ai/luis/v1/application";
}
return new Uri(apiVersion == LuisApiVersion.V2 ? $"https://{domain}/luis/v2.0/apps/" : $"https://api.projectoxford.ai/luis/v1/application");
}
/// <summary>
/// Construct the LUIS model information.
/// </summary>
/// <param name="modelID">The LUIS model ID.</param>
/// <param name="subscriptionKey">The LUIS subscription key.</param>
/// <param name="apiVersion">The LUIS API version.</param>
/// <param name="domain">Domain where LUIS model is located.</param>
/// <param name="threshold">Threshold for the top scoring intent.</param>
public LuisModelAttribute(string modelID, string subscriptionKey,
LuisApiVersion apiVersion = LuisApiVersion.V2, string domain = null, double threshold = 0.0d)
{
SetField.NotNull(out this.modelID, nameof(modelID), modelID);
SetField.NotNull(out this.subscriptionKey, nameof(subscriptionKey), subscriptionKey);
this.apiVersion = apiVersion;
this.domain = domain;
this.uriBase = UriFor(apiVersion, domain);
this.threshold = threshold;
this.Log = true;
}
public bool Equals(ILuisModel other)
{
return other != null
&& object.Equals(this.ModelID, other.ModelID)
&& object.Equals(this.SubscriptionKey, other.SubscriptionKey)
&& object.Equals(this.ApiVersion, other.ApiVersion)
&& object.Equals(this.UriBase, other.UriBase)
;
}
public override bool Equals(object other)
{
return this.Equals(other as ILuisModel);
}
public override int GetHashCode()
{
return ModelID.GetHashCode()
^ SubscriptionKey.GetHashCode()
^ UriBase.GetHashCode()
^ ApiVersion.GetHashCode();
}
public LuisRequest ModifyRequest(LuisRequest request)
{
Options.Apply(request);
return request;
}
}
}

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

@ -0,0 +1,86 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Builder SDK GitHub:
// https://github.com/Microsoft/BotBuilder
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
namespace Microsoft.Cognitive.LUIS
{
/// <summary>
/// Interface containing optional parameters for a LUIS request.
/// </summary>
public interface ILuisOptions
{
/// <summary>
/// Indicates if logging of queries to LUIS is allowed.
/// </summary>
bool? Log { get; set; }
/// <summary>
/// Turn on spell checking.
/// </summary>
bool? SpellCheck { get; set; }
/// <summary>
/// Use the staging endpoint.
/// </summary>
bool? Staging { get; set; }
/// <summary>
/// The time zone offset.
/// </summary>
double? TimezoneOffset { get; set; }
/// <summary>
/// The verbose flag.
/// </summary>
bool? Verbose { get; set; }
/// <summary>
/// The Bing Spell Check subscription key.
/// </summary>
string BingSpellCheckSubscriptionKey { get; set; }
}
public static partial class Extensions
{
public static void Apply(this ILuisOptions source, ILuisOptions target)
{
if (source.Log.HasValue) target.Log = source.Log.Value;
if (source.SpellCheck.HasValue) target.SpellCheck = source.SpellCheck.Value;
if (source.Staging.HasValue) target.Staging = source.Staging.Value;
if (source.TimezoneOffset.HasValue) target.TimezoneOffset = source.TimezoneOffset.Value;
if (source.Verbose.HasValue) target.Verbose = source.Verbose.Value;
if (!string.IsNullOrWhiteSpace(source.BingSpellCheckSubscriptionKey)) target.BingSpellCheckSubscriptionKey = source.BingSpellCheckSubscriptionKey;
}
}
}

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

@ -0,0 +1,351 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Builder SDK GitHub:
// https://github.com/Microsoft/BotBuilder
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Cognitive.LUIS.Models;
using Microsoft.Rest;
using Newtonsoft.Json;
namespace Microsoft.Cognitive.LUIS
{
/// <summary>
/// Object that contains all the possible parameters to build Luis request.
/// </summary>
public sealed class LuisRequest : ILuisOptions
{
/// <summary>
/// The text query.
/// </summary>
public string Query { get; set; }
/// <summary>
/// Indicates if logging of queries to LUIS is allowed.
/// </summary>
public bool? Log { get; set; }
/// <summary>
/// Turn on spell checking.
/// </summary>
public bool? SpellCheck { get; set; }
/// <summary>
/// Use the staging endpoint.
/// </summary>
public bool? Staging { get; set; }
/// <summary>
/// The time zone offset.
/// </summary>
public double? TimezoneOffset { get; set; }
/// <summary>
/// The verbose flag.
/// </summary>
public bool? Verbose { get; set; }
/// <summary>
/// The Bing Spell Check subscription key.
/// </summary>
public string BingSpellCheckSubscriptionKey { get; set; }
/// <summary>
/// Any extra query parameters for the URL.
/// </summary>
public string ExtraParameters { get; set; }
/// <summary>
/// The context id.
/// </summary>
[Obsolete("Action binding in LUIS should be replaced with code.")]
public string ContextId { get; set; }
/// <summary>
/// Force setting the parameter when using action binding.
/// </summary>
[Obsolete("Action binding in LUIS should be replaced with code.")]
public string ForceSet { get; set; }
/// <summary>
/// Constructs an instance of the LuisReqeuest.
/// </summary>
public LuisRequest() : this(string.Empty)
{
}
/// <summary>
/// Constructs an instance of the LuisReqeuest.
/// </summary>
/// <param name="query"> The text query.</param>
public LuisRequest(string query)
{
this.Query = query;
this.Log = true;
}
/// <summary>
/// Build the Uri for issuing the request for the specified Luis model.
/// </summary>
/// <param name="model"> The Luis model.</param>
/// <returns> The request Uri.</returns>
public Uri BuildUri(ILuisModel model)
{
if (model.ModelID == null)
{
throw new ValidationException(ValidationRules.CannotBeNull, "id");
}
if (model.SubscriptionKey == null)
{
throw new ValidationException(ValidationRules.CannotBeNull, "subscriptionKey");
}
var queryParameters = new List<string>();
queryParameters.Add($"subscription-key={Uri.EscapeDataString(model.SubscriptionKey)}");
queryParameters.Add($"q={Uri.EscapeDataString(Query)}");
UriBuilder builder;
var id = Uri.EscapeDataString(model.ModelID);
switch (model.ApiVersion)
{
#pragma warning disable CS0612
case LuisApiVersion.V1:
builder = new UriBuilder(model.UriBase);
queryParameters.Add($"id={id}");
break;
#pragma warning restore CS0612
case LuisApiVersion.V2:
//v2.0 have the model as path parameter
builder = new UriBuilder(new Uri(model.UriBase, id));
break;
default:
throw new ArgumentException($"{model.ApiVersion} is not a valid Luis api version.");
}
if (Log != null)
{
queryParameters.Add($"log={Uri.EscapeDataString(Convert.ToString(Log))}");
}
if (SpellCheck != null)
{
queryParameters.Add($"spellCheck={Uri.EscapeDataString(Convert.ToString(SpellCheck))}");
}
if (Staging != null)
{
queryParameters.Add($"staging={Uri.EscapeDataString(Convert.ToString(Staging))}");
}
if (TimezoneOffset != null)
{
queryParameters.Add($"timezoneOffset={Uri.EscapeDataString(Convert.ToString(TimezoneOffset))}");
}
if (Verbose != null)
{
queryParameters.Add($"verbose={Uri.EscapeDataString(Convert.ToString(Verbose))}");
}
if (!string.IsNullOrWhiteSpace(BingSpellCheckSubscriptionKey))
{
queryParameters.Add($"bing-spell-check-subscription-key={Uri.EscapeDataString(BingSpellCheckSubscriptionKey)}");
}
#pragma warning disable CS0618
if (ContextId != null)
{
queryParameters.Add($"contextId={Uri.EscapeDataString(ContextId)}");
}
if (ForceSet != null)
{
queryParameters.Add($"forceSet={Uri.EscapeDataString(ForceSet)}");
}
#pragma warning restore CS0618
if (ExtraParameters != null)
{
queryParameters.Add(ExtraParameters);
}
builder.Query = string.Join("&", queryParameters);
return builder.Uri;
}
}
/// <summary>
/// A mockable interface for the LUIS service.
/// </summary>
public interface ILuisService
{
/// <summary>
/// Modify the incoming LUIS request.
/// </summary>
/// <param name="request">Request so far.</param>
/// <returns>Modified request.</returns>
LuisRequest ModifyRequest(LuisRequest request);
/// <summary>
/// Build the query uri for the <see cref="LuisRequest"/>.
/// </summary>
/// <param name="luisRequest">The luis request text.</param>
/// <returns>The query uri.</returns>
Uri BuildUri(LuisRequest luisRequest);
/// <summary>
/// Query the LUIS service using this uri.
/// </summary>
/// <param name="uri">The query uri.</param>
/// <param name="token">The cancellation token.</param>
/// <returns>The LUIS result.</returns>
Task<LuisResult> QueryAsync(Uri uri, CancellationToken token);
}
/// <summary>
/// Standard implementation of ILuisService against actual LUIS service.
/// </summary>
[Serializable]
public sealed class LuisService : ILuisService
{
private readonly ILuisModel model;
/// <summary>
/// Construct the LUIS service using the model information.
/// </summary>
/// <param name="model">The LUIS model information.</param>
public LuisService(ILuisModel model)
{
SetField.NotNull(out this.model, nameof(model), model);
}
public LuisRequest ModifyRequest(LuisRequest request)
{
return model.ModifyRequest(request);
}
Uri ILuisService.BuildUri(LuisRequest luisRequest)
{
return luisRequest.BuildUri(this.model);
}
public static void Fix(LuisResult result)
{
// fix up Luis result for backward compatibility
// v2 api is not returning list of intents if verbose query parameter
// is not set. This will move IntentRecommendation in TopScoringIntent
// to list of Intents.
if (result.Intents == null || result.Intents.Count == 0)
{
if (result.TopScoringIntent != null)
{
result.Intents = new List<IntentRecommendation> { result.TopScoringIntent };
}
}
}
public void ApplyThreshold(LuisResult result)
{
if (result.TopScoringIntent.Score > model.Threshold)
{
return;
}
result.TopScoringIntent.Intent = "None";
result.TopScoringIntent.Score = 1.0d;
}
async Task<LuisResult> ILuisService.QueryAsync(Uri uri, CancellationToken token)
{
string json;
using (var client = new HttpClient())
using (var response = await client.GetAsync(uri, HttpCompletionOption.ResponseContentRead, token))
{
response.EnsureSuccessStatusCode();
json = await response.Content.ReadAsStringAsync();
}
try
{
var result = JsonConvert.DeserializeObject<LuisResult>(json);
Fix(result);
ApplyThreshold(result);
return result;
}
catch (JsonException ex)
{
throw new ArgumentException("Unable to deserialize the LUIS response.", ex);
}
}
}
/// <summary>
/// LUIS extension methods.
/// </summary>
public static partial class Extensions
{
/// <summary>
/// Query the LUIS service using this text.
/// </summary>
/// <param name="service">LUIS service.</param>
/// <param name="text">The query text.</param>
/// <param name="token">The cancellation token.</param>
/// <returns>The LUIS result.</returns>
public static async Task<LuisResult> QueryAsync(this ILuisService service, string text, CancellationToken token)
{
var luisRequest = service.ModifyRequest(new LuisRequest(query: text));
return await service.QueryAsync(luisRequest, token);
}
/// <summary>
/// Query the LUIS service using this request.
/// </summary>
/// <param name="service">LUIS service.</param>
/// <param name="request">Query request.</param>
/// <param name="token">Cancellation token.</param>
/// <returns>LUIS result.</returns>
public static async Task<LuisResult> QueryAsync(this ILuisService service, LuisRequest request, CancellationToken token)
{
service.ModifyRequest(request);
var uri = service.BuildUri(request);
return await service.QueryAsync(uri, token);
}
/// <summary>
/// Builds luis uri with text query.
/// </summary>
/// <param name="service">LUIS service.</param>
/// <param name="text">The query text.</param>
/// <returns>The LUIS request Uri.</returns>
public static Uri BuildUri(this ILuisService service, string text)
{
return service.BuildUri(service.ModifyRequest(new LuisRequest(query: text)));
}
}
}

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

@ -0,0 +1,60 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for
// license information.
//
// Code generated by Microsoft (R) AutoRest Code Generator 0.16.0.0
// Changes may cause incorrect behavior and will be lost if the code is
// regenerated.
namespace Microsoft.Cognitive.LUIS.Models
{
using Newtonsoft.Json;
using Microsoft.Rest;
/// <summary>
/// Child entity in Luis composite entity.
/// </summary>
public partial class CompositeChild
{
/// <summary>
/// Initializes a new instance of the CompositeChild class.
/// </summary>
public CompositeChild() { }
/// <summary>
/// Initializes a new instance of the CompositeChild class.
/// </summary>
public CompositeChild(string type, string value)
{
Type = type;
Value = value;
}
/// <summary>
/// Type of child entity.
/// </summary>
[JsonProperty(PropertyName = "type")]
public string Type { get; set; }
/// <summary>
/// Value extracted by Luis.
/// </summary>
[JsonProperty(PropertyName = "value")]
public string Value { get; set; }
/// <summary>
/// Validate the object. Throws ValidationException if validation fails.
/// </summary>
public virtual void Validate()
{
if (Type == null)
{
throw new ValidationException(ValidationRules.CannotBeNull, "Type");
}
if (Value == null)
{
throw new ValidationException(ValidationRules.CannotBeNull, "Value");
}
}
}
}

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

@ -0,0 +1,82 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for
// license information.
//
// Code generated by Microsoft (R) AutoRest Code Generator 0.16.0.0
// Changes may cause incorrect behavior and will be lost if the code is
// regenerated.
namespace Microsoft.Cognitive.LUIS.Models
{
using System.Collections.Generic;
using Newtonsoft.Json;
using Microsoft.Rest;
/// <summary>
/// Luis composite entity. Look at https://www.luis.ai/Help for more
/// information.
/// </summary>
public partial class CompositeEntity
{
/// <summary>
/// Initializes a new instance of the CompositeEntity class.
/// </summary>
public CompositeEntity() { }
/// <summary>
/// Initializes a new instance of the CompositeEntity class.
/// </summary>
public CompositeEntity(string parentType, string value, IList<CompositeChild> children)
{
ParentType = parentType;
Value = value;
Children = children;
}
/// <summary>
/// Type of parent entity.
/// </summary>
[JsonProperty(PropertyName = "parentType")]
public string ParentType { get; set; }
/// <summary>
/// Value for entity extracted by LUIS.
/// </summary>
[JsonProperty(PropertyName = "value")]
public string Value { get; set; }
/// <summary>
/// </summary>
[JsonProperty(PropertyName = "children")]
public IList<CompositeChild> Children { get; set; }
/// <summary>
/// Validate the object. Throws ValidationException if validation fails.
/// </summary>
public virtual void Validate()
{
if (ParentType == null)
{
throw new ValidationException(ValidationRules.CannotBeNull, "ParentType");
}
if (Value == null)
{
throw new ValidationException(ValidationRules.CannotBeNull, "Value");
}
if (Children == null)
{
throw new ValidationException(ValidationRules.CannotBeNull, "Children");
}
if (this.Children != null)
{
foreach (var element in this.Children)
{
if (element != null)
{
element.Validate();
}
}
}
}
}
}

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

@ -0,0 +1,203 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for
// license information.
//
// Code generated by Microsoft (R) AutoRest Code Generator 0.16.0.0
// Changes may cause incorrect behavior and will be lost if the code is
// regenerated.
namespace Microsoft.Cognitive.LUIS.Models
{
using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
using Microsoft.Rest;
using Microsoft.Rest.Serialization;
using Newtonsoft.Json.Linq;
/// <summary>
/// Luis entity recommendation. Look at https://www.luis.ai/Help for more
/// information.
/// </summary>
public partial class EntityRecommendation
{
/// <summary>
/// Initializes a new instance of the EntityRecommendation class.
/// </summary>
public EntityRecommendation() { }
/// <summary>
/// Initializes a new instance of the EntityRecommendation class.
/// </summary>
public EntityRecommendation(string type, string role = default(string), string entity = default(string), int? startIndex = default(int?), int? endIndex = default(int?), double? score = default(double?), IDictionary<string, object> resolution = default(IDictionary<string, object>))
{
Role = role;
Entity = entity;
Type = type;
StartIndex = startIndex;
EndIndex = endIndex;
Score = score;
Resolution = resolution;
}
/// <summary>
/// Role of the entity.
/// </summary>
[JsonProperty(PropertyName = "role")]
public string Role { get; set; }
/// <summary>
/// Entity extracted by LUIS.
/// </summary>
[JsonProperty(PropertyName = "entity")]
public string Entity { get; set; }
/// <summary>
/// Type of the entity.
/// </summary>
[JsonProperty(PropertyName = "type")]
public string Type { get; set; }
/// <summary>
/// Start index of the entity in the LUIS query string.
/// </summary>
[JsonProperty(PropertyName = "startIndex")]
public int? StartIndex { get; set; }
/// <summary>
/// End index of the entity in the LUIS query string.
/// </summary>
[JsonProperty(PropertyName = "endIndex")]
public int? EndIndex { get; set; }
/// <summary>
/// Score assigned by LUIS to detected entity.
/// </summary>
[JsonProperty(PropertyName = "score")]
public double? Score { get; set; }
/// <summary>
/// A machine interpretable resolution of the entity. For example the
/// string "one thousand" would have the resolution "1000". The
/// exact form of the resolution is defined by the entity type and is
/// documented here: https://www.luis.ai/Help#PreBuiltEntities.
/// </summary>
[JsonProperty(PropertyName = "resolution", ItemConverterType = typeof(ResolutionConverter))]
public IDictionary<string, object> Resolution { get; set; }
/// <summary>
/// Validate the object. Throws ValidationException if validation fails.
/// </summary>
public virtual void Validate()
{
if (Type == null)
{
throw new ValidationException(ValidationRules.CannotBeNull, "Type");
}
}
internal class ResolutionConverter : JsonConverter
{
private const string UnexpectedEndError = "Unexpected end when reading IDictionary<string, object>";
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(IDictionary<string, object>));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return ReadValue(reader);
}
private static object ReadValue(JsonReader reader)
{
while (reader.TokenType == JsonToken.Comment)
{
if (!reader.Read())
{
throw new JsonSerializationException("Unexpected token when converting IDictionary<string, object>");
}
}
switch (reader.TokenType)
{
case JsonToken.StartObject:
return ReadObject(reader);
case JsonToken.StartArray:
return ReadArray(reader);
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Undefined:
case JsonToken.Null:
case JsonToken.Date:
case JsonToken.Bytes:
return reader.Value;
default:
throw new JsonSerializationException
(string.Format("Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType));
}
}
private static object ReadArray(JsonReader reader)
{
IList<object> list = new List<object>();
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.Comment:
break;
default:
var value = ReadValue(reader);
list.Add(value);
break;
case JsonToken.EndArray:
return list;
}
}
throw new JsonSerializationException(UnexpectedEndError);
}
private static object ReadObject(JsonReader reader)
{
var dictionary = new Dictionary<string, object>();
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.PropertyName:
var propertyName = reader.Value.ToString();
if (!reader.Read())
{
throw new JsonSerializationException(UnexpectedEndError);
}
var value = ReadValue(reader);
dictionary[propertyName] = value;
break;
case JsonToken.Comment:
break;
case JsonToken.EndObject:
return dictionary;
}
}
throw new JsonSerializationException(UnexpectedEndError);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
}
}

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

@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for
// license information.
//
// Code generated by Microsoft (R) AutoRest Code Generator 0.16.0.0
// Changes may cause incorrect behavior and will be lost if the code is
// regenerated.
namespace Microsoft.Cognitive.LUIS.Models
{
using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
using Microsoft.Rest;
using Microsoft.Rest.Serialization;
/// <summary>
/// LUIS intent recommendation. Look at https://www.luis.ai/Help for more
/// information.
/// </summary>
public partial class IntentRecommendation
{
/// <summary>
/// Initializes a new instance of the IntentRecommendation class.
/// </summary>
public IntentRecommendation() { }
/// <summary>
/// Initializes a new instance of the IntentRecommendation class.
/// </summary>
public IntentRecommendation(string intent = default(string), double? score = default(double?), IList<Action> actions = default(IList<Action>))
{
Intent = intent;
Score = score;
Actions = actions;
}
/// <summary>
/// The LUIS intent detected by LUIS service in response to a query.
/// </summary>
[JsonProperty(PropertyName = "intent")]
public string Intent { get; set; }
/// <summary>
/// The score for the detected intent.
/// </summary>
[JsonProperty(PropertyName = "score")]
public double? Score { get; set; }
/// <summary>
/// The action associated with this Luis intent.
/// </summary>
[JsonProperty(PropertyName = "actions")]
public IList<Action> Actions { get; set; }
}
}

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

@ -0,0 +1,108 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for
// license information.
//
// Code generated by Microsoft (R) AutoRest Code Generator 0.16.0.0
// Changes may cause incorrect behavior and will be lost if the code is
// regenerated.
namespace Microsoft.Cognitive.LUIS.Models
{
using System;
using System.Collections.Generic;
using Microsoft.Rest;
using Newtonsoft.Json;
public class LuisResult
{
/// <summary>
/// Initializes a new instance of the LuisResult class.
/// </summary>
public LuisResult() { }
/// <summary>
/// Initializes a new instance of the LuisResult class.
/// </summary>
public LuisResult(string query, IList<EntityRecommendation> entities, IntentRecommendation topScoringIntent = default(IntentRecommendation), IList<IntentRecommendation> intents = default(IList<IntentRecommendation>), IList<CompositeEntity> compositeEntities = default(IList<CompositeEntity>), string alteredQuery = default(string))
{
Query = query;
TopScoringIntent = topScoringIntent;
Intents = intents;
Entities = entities;
CompositeEntities = compositeEntities;
AlteredQuery = alteredQuery;
}
/// <summary>
/// The query sent to LUIS.
/// </summary>
[JsonProperty(PropertyName = "query")]
public string Query { get; set; }
/// <summary>
/// </summary>
[JsonProperty(PropertyName = "topScoringIntent")]
public IntentRecommendation TopScoringIntent { get; set; }
/// <summary>
/// The intents found in the query text.
/// </summary>
[JsonProperty(PropertyName = "intents")]
public IList<IntentRecommendation> Intents { get; set; } = Array.Empty<IntentRecommendation>();
/// <summary>
/// The entities found in the query text.
/// </summary>
[JsonProperty(PropertyName = "entities")]
public IList<EntityRecommendation> Entities { get; set; } = Array.Empty<EntityRecommendation>();
/// <summary>
/// The composite entities found in the utterance.
/// </summary>
[JsonProperty(PropertyName = "compositeEntities")]
public IList<CompositeEntity> CompositeEntities { get; set; } = Array.Empty<CompositeEntity>();
/// <summary>
/// The altered query used by LUIS to extract intent and entities. For
/// example, when Bing spell check is enabled for a model, this field
/// will contain the spell checked utterance.
/// </summary>
[JsonProperty(PropertyName = "alteredQuery")]
public string AlteredQuery { get; set; }
/// <summary>
/// Validate the object. Throws ValidationException if validation fails.
/// </summary>
public virtual void Validate()
{
if (Query == null)
{
throw new ValidationException(ValidationRules.CannotBeNull, "Query");
}
if (Entities == null)
{
throw new ValidationException(ValidationRules.CannotBeNull, "Entities");
}
if (this.Entities != null)
{
foreach (var element in this.Entities)
{
if (element != null)
{
element.Validate();
}
}
}
if (this.CompositeEntities != null)
{
foreach (var element1 in this.CompositeEntities)
{
if (element1 != null)
{
element1.Validate();
}
}
}
}
}
}

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

@ -0,0 +1,355 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Builder SDK GitHub:
// https://github.com/Microsoft/BotBuilder
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Text.RegularExpressions;
namespace Microsoft.Cognitive.LUIS
{
public abstract class Resolution
{
public override string ToString()
{
var builder = new StringBuilder();
var properties = this.GetType().GetProperties();
foreach (var property in properties)
{
var value = property.GetValue(this);
if (value != null)
{
if (builder.Length > 0)
{
builder.Append(",");
}
builder.Append(property.Name);
builder.Append("=");
builder.Append(value);
}
}
return builder.ToString();
}
}
public static partial class BuiltIn
{
public static partial class DateTime
{
public enum DayPart
{
[Description("morning")]
MO,
[Description("midday")]
MI,
[Description("afternoon")]
AF,
[Description("evening")]
EV,
[Description("night")]
NI
}
public enum Reference
{
[Description("past")]
PAST_REF,
[Description("present")]
PRESENT_REF,
[Description("future")]
FUTURE_REF
}
[Serializable]
public sealed class DateTimeResolution : Resolution, IEquatable<DateTimeResolution>
{
public Reference? Reference { get; }
public int? Year { get; }
public int? Month { get; }
public int? Day { get; }
public int? Week { get; }
public DayOfWeek? DayOfWeek { get; }
public DayPart? DayPart { get; }
public int? Hour { get; }
public int? Minute { get; }
public int? Second { get; }
public DateTimeResolution(
Reference? reference = null,
int? year = null, int? month = null, int? day = null,
int? week = null, DayOfWeek? dayOfWeek = null,
DayPart? dayPart = null,
int? hour = null, int? minute = null, int? second = null
)
{
this.Reference = reference;
this.Year = year;
this.Month = month;
this.Day = day;
this.Week = week;
this.DayOfWeek = dayOfWeek;
this.DayPart = dayPart;
this.Hour = hour;
this.Minute = minute;
this.Second = second;
}
public DateTimeResolution(System.DateTime dateTime)
{
this.Year = dateTime.Year;
this.Month = dateTime.Month;
this.Day = dateTime.Day;
this.Hour = dateTime.Hour;
this.Minute = dateTime.Minute;
this.Second = dateTime.Second;
}
public bool Equals(DateTimeResolution other)
{
return other != null
&& this.Reference == other.Reference
&& this.Year == other.Year
&& this.Month == other.Month
&& this.Day == other.Day
&& this.Week == other.Week
&& this.DayOfWeek == other.DayOfWeek
&& this.DayPart == other.DayPart
&& this.Hour == other.Hour
&& this.Minute == other.Minute
&& this.Second == other.Second;
}
public override bool Equals(object other)
{
return this.Equals(other as DateTimeResolution);
}
public override int GetHashCode()
{
throw new NotImplementedException();
}
public const string PatternDate =
@"
(?:
(?<year>X+|\d+)
(?:
-
(?<weekM>W)?
(?<month>X+|\d+)
(?:
-
(?<weekD>W)?
(?<day>X+|\d+)
)?
)?
)
";
public const string PatternTime =
@"
(?:
T
(?:
(?<part>MO|MI|AF|EV|NI)
|
(?<hour>X+|\d+)
(?:
:
(?<minute>X+|\d+)
(?:
:
(?<second>X+|\d+)
)?
)?
)
)
";
public static readonly string Pattern = $"^({PatternDate}{PatternTime} | {PatternDate} | {PatternTime})$";
public const RegexOptions Options = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace;
public static readonly Regex Regex = new Regex(Pattern, Options);
private static int? ParseIntOrNull(Group group)
{
if (group.Success)
{
var text = group.Value;
int number;
if (int.TryParse(text, out number))
{
return number;
}
else if (text.Length > 0)
{
for (int index = 0; index < text.Length; ++index)
{
switch (text[index])
{
case 'X':
case 'x':
continue;
default:
throw new NotImplementedException();
}
}
// -1 means some variable X rather than missing "null" or specified constant value
return -1;
}
}
return null;
}
private static E? ParseEnumOrNull<E>(Group group) where E : struct
{
if (group.Success)
{
var text = group.Value;
E result;
if (Enum.TryParse<E>(text, out result))
{
return result;
}
}
return null;
}
private static readonly IReadOnlyDictionary<string, Reference> ReferenceByText
= new Dictionary<string, Reference>(StringComparer.OrdinalIgnoreCase)
{
{ "PAST_REF", DateTime.Reference.PAST_REF },
{ "PRESENT_REF", DateTime.Reference.PRESENT_REF },
{ "FUTURE_REF", DateTime.Reference.FUTURE_REF },
};
public static bool TryParse(string text, out DateTimeResolution resolution)
{
DateTime.Reference reference;
if (ReferenceByText.TryGetValue(text, out reference))
{
resolution = new DateTimeResolution(reference);
return true;
}
var match = Regex.Match(text);
if (match.Success)
{
var groups = match.Groups;
bool weekM = groups["weekM"].Success;
bool weekD = weekM || groups["weekD"].Success;
resolution = new DateTimeResolution
(
year: ParseIntOrNull(groups["year"]),
week: weekM ? ParseIntOrNull(groups["month"]) : null,
month: !weekM ? ParseIntOrNull(groups["month"]) : null,
dayOfWeek: weekD ? (DayOfWeek?)ParseIntOrNull(groups["day"]) : null,
day: !weekD ? ParseIntOrNull(groups["day"]) : null,
dayPart: ParseEnumOrNull<DayPart>(groups["part"]),
hour: ParseIntOrNull(groups["hour"]),
minute: ParseIntOrNull(groups["minute"]),
second: ParseIntOrNull(groups["second"])
);
return true;
}
resolution = null;
return false;
}
}
public sealed class DurationResolution
{
}
}
}
public interface IResolutionParser
{
bool TryParse(IDictionary<string, object> properties, out Resolution resolution);
}
public sealed class ResolutionParser : IResolutionParser
{
bool IResolutionParser.TryParse(IDictionary<string, object> properties, out Resolution resolution)
{
if (properties != null)
{
object value;
if (properties.TryGetValue("resolution_type", out value) && value is string)
{
switch (value as string)
{
case "builtin.datetime.date":
if (properties.TryGetValue("date", out value) && value is string)
{
BuiltIn.DateTime.DateTimeResolution dateTime;
if (BuiltIn.DateTime.DateTimeResolution.TryParse(value as string, out dateTime))
{
resolution = dateTime;
return true;
}
}
break;
case "builtin.datetime.time":
case "builtin.datetime.set":
if (properties.TryGetValue("time", out value) && value is string)
{
BuiltIn.DateTime.DateTimeResolution dateTime;
if (BuiltIn.DateTime.DateTimeResolution.TryParse(value as string, out dateTime))
{
resolution = dateTime;
return true;
}
}
break;
}
}
}
resolution = null;
return false;
}
}
}

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

@ -0,0 +1,67 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Builder SDK GitHub:
// https://github.com/Microsoft/BotBuilder
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Runtime.Serialization;
namespace Microsoft.Cognitive.LUIS
{
public static class SetField
{
public static void NotNull<T>(out T field, string name, T value) where T : class
{
CheckNull(name, value);
field = value;
}
public static void CheckNull<T>(string name, T value) where T : class
{
if (value == null)
{
throw new ArgumentNullException(name);
}
}
public static void NotNullFrom<T>(out T field, string name, SerializationInfo info) where T : class
{
var value = (T)info.GetValue(name, typeof(T));
NotNull(out field, name, value);
}
public static void From<T>(out T field, string name, SerializationInfo info)
{
var value = (T)info.GetValue(name, typeof(T));
field = value;
}
}
}

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

@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Bot.Builder.LUIS
{
/// <summary>
/// Options for the Luis Recognizer
/// </summary>
public interface ILuisRecognizerOptions
{
/// <summary>
/// If set to true, metadata is added to the recognizer's results
/// </summary>
bool Verbose { get; }
}
}

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

@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder.LUIS
{
/// <summary>
/// Interface for Recognizers.
/// This should be moved to the Core Bot Builder Library once it's stable enough
/// </summary>
public interface IRecognizer
{
/// <summary>
/// Runs an utterance through a recognizer and returns the recognizer results
/// </summary>
/// <param name="utterance">utterance</param>
/// <param name="ct">cancellation token</param>
/// <returns>Recognizer Results</returns>
Task<RecognizerResult> Recognize(string utterance, CancellationToken ct);
}
}

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

@ -0,0 +1,40 @@
using System;
using Microsoft.Cognitive.LUIS;
namespace Microsoft.Bot.Builder.LUIS
{
public class LuisModel : ILuisModel
{
public LuisModel(string modelId, string subscriptionKey, Uri uriBase, LuisApiVersion apiVersion)
{
if(string.IsNullOrEmpty(modelId))
throw new ArgumentNullException(nameof(modelId));
if (string.IsNullOrEmpty(subscriptionKey))
throw new ArgumentNullException(nameof(subscriptionKey));
if (uriBase == null)
throw new ArgumentNullException(nameof(uriBase));
ModelID = modelId;
SubscriptionKey = subscriptionKey;
UriBase = uriBase;
ApiVersion = apiVersion;
}
public string ModelID { get; }
public string SubscriptionKey { get; }
public Uri UriBase { get; }
public LuisApiVersion ApiVersion { get; }
public double Threshold => 0.0d;
public LuisRequest ModifyRequest(LuisRequest request)
{
return request;
}
}
}

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

@ -0,0 +1,219 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Cognitive.LUIS;
using Microsoft.Cognitive.LUIS.Models;
using Newtonsoft.Json.Linq;
using System.Text.RegularExpressions;
namespace Microsoft.Bot.Builder.LUIS
{
/// <inheritdoc />
/// <summary>
/// A Luis based implementation of IRecognizer
/// </summary>
public class LuisRecognizer : IRecognizer
{
private readonly LuisService _luisService;
private readonly ILuisOptions _luisOptions;
private readonly ILuisRecognizerOptions _luisRecognizerOptions;
private const string MetadataKey = "$instance";
public LuisRecognizer(ILuisModel luisModel, ILuisRecognizerOptions luisRecognizerOptions = null, ILuisOptions options = null)
{
_luisService = new LuisService(luisModel);
_luisOptions = options ?? new LuisRequest();
_luisRecognizerOptions = luisRecognizerOptions ?? new LuisRecognizerOptions { Verbose = true };
}
/// <inheritdoc />
public Task<RecognizerResult> Recognize(string utterance, CancellationToken ct)
{
if(string.IsNullOrEmpty(utterance))
throw new ArgumentNullException(nameof(utterance));
var luisRequest = new LuisRequest(utterance);
_luisOptions.Apply(luisRequest);
return Recognize(luisRequest, ct, _luisRecognizerOptions.Verbose);
}
private async Task<RecognizerResult> Recognize(LuisRequest request, CancellationToken ct, bool verbose)
{
var luisResult = await _luisService.QueryAsync(request, ct).ConfigureAwait(false);
var recognizerResult = new RecognizerResult
{
Text = request.Query,
Intents = GetIntents(luisResult),
Entities = GetEntitiesAndMetadata(luisResult.Entities, luisResult.CompositeEntities, verbose)
};
return recognizerResult;
}
private static JObject GetIntents(LuisResult luisResult)
{
return luisResult.Intents != null ?
JObject.FromObject(luisResult.Intents.ToDictionary(i => i.Intent, i => i.Score ?? 0)) :
new JObject { [luisResult.TopScoringIntent.Intent] = luisResult.TopScoringIntent.Score ?? 0 };
}
private static JObject GetEntitiesAndMetadata(IList<EntityRecommendation> entities, IList<CompositeEntity> compositeEntities, bool verbose)
{
var entitiesAndMetadata = new JObject();
if (verbose)
{
entitiesAndMetadata[MetadataKey] = new JObject();
}
var compositeEntityTypes = new HashSet<string>();
// We start by populating composite entities so that entities covered by them are removed from the entities list
if (compositeEntities != null && compositeEntities.Any())
{
compositeEntityTypes = new HashSet<string>(compositeEntities.Select(ce => ce.ParentType));
entities = compositeEntities.Aggregate(entities, (current, compositeEntity) => PopulateCompositeEntity(compositeEntity, current, entitiesAndMetadata, verbose));
}
foreach (var entity in entities)
{
// we'll address composite entities separately
if (compositeEntityTypes.Contains(entity.Type))
continue;
AddProperty(entitiesAndMetadata, GetNormalizedEntityType(entity), GetEntityValue(entity));
if (verbose)
{
AddProperty((JObject) entitiesAndMetadata[MetadataKey], GetNormalizedEntityType(entity), GetEntityMetadata(entity));
}
}
return entitiesAndMetadata;
}
private static JToken GetEntityValue(EntityRecommendation entity)
{
if (entity.Resolution == null)
return entity.Entity;
if (entity.Type.StartsWith("builtin.datetimeV2."))
{
return new JValue(entity.Resolution?.Values != null && entity.Resolution.Values.Count > 0
? ((IDictionary<string, object>)((IList<object>)entity.Resolution.Values.First()).First())["timex"]
: entity.Resolution);
}
if (entity.Type.StartsWith("builtin.number"))
{
var value = (string) entity.Resolution.Values.First();
return long.TryParse(value, out var longVal) ?
new JValue(longVal) :
new JValue(double.Parse(value));
}
return entity.Resolution.Count > 1 ?
JObject.FromObject(entity.Resolution) :
entity.Resolution.ContainsKey("value") ?
(JToken) JObject.FromObject(entity.Resolution["value"]) :
JArray.FromObject(entity.Resolution["values"]);
}
private static JObject GetEntityMetadata(EntityRecommendation entity)
{
return JObject.FromObject(new
{
startIndex = entity.StartIndex,
endIndex = entity.EndIndex,
text = entity.Entity,
score = entity.Score
});
}
private static string GetNormalizedEntityType(EntityRecommendation entity)
{
return Regex.Replace(entity.Type, "\\.", "_");
}
private static IList<EntityRecommendation> PopulateCompositeEntity(CompositeEntity compositeEntity, IList<EntityRecommendation> entities, JObject entitiesAndMetadata, bool verbose)
{
var childrenEntites = new JObject();
var childrenEntitiesMetadata = new JObject();
if (verbose)
{
childrenEntites[MetadataKey] = new JObject();
}
// This is now implemented as O(n^2) search and can be reduced to O(2n) using a map as an optimization if n grows
var compositeEntityMetadata = entities.FirstOrDefault(e => e.Type == compositeEntity.ParentType && e.Entity == compositeEntity.Value);
// This is an error case and should not happen in theory
if (compositeEntityMetadata == null)
return entities;
if (verbose)
{
childrenEntitiesMetadata = GetEntityMetadata(compositeEntityMetadata);
childrenEntites[MetadataKey] = new JObject();
}
var coveredSet = new HashSet<EntityRecommendation>();
foreach (var child in compositeEntity.Children)
{
foreach(var entity in entities)
{
// We already covered this entity
if (coveredSet.Contains(entity))
continue;
// This entity doesn't belong to this composite entity
if (child.Type != entity.Type || !CompositeContainsEntity(compositeEntityMetadata, entity))
continue;
// Add to the set to ensure that we don't consider the same child entity more than once per composite
coveredSet.Add(entity);
AddProperty(childrenEntites, GetNormalizedEntityType(entity), GetEntityValue(entity));
if (verbose)
{
AddProperty((JObject)childrenEntites[MetadataKey], GetNormalizedEntityType(entity), GetEntityMetadata(entity));
}
}
}
AddProperty(entitiesAndMetadata, compositeEntity.ParentType, childrenEntites);
if (verbose)
{
AddProperty((JObject)entitiesAndMetadata[MetadataKey], compositeEntity.ParentType, childrenEntitiesMetadata);
}
// filter entities that were covered by this composite entity
return entities.Except(coveredSet).ToList();
}
private static bool CompositeContainsEntity(EntityRecommendation compositeEntityMetadata, EntityRecommendation entity)
{
return entity.StartIndex >= compositeEntityMetadata.StartIndex &&
entity.EndIndex <= compositeEntityMetadata.EndIndex;
}
/// <summary>
/// If a property doesn't exist add it to a new array, otherwise append it to the existing array
/// </summary>
private static void AddProperty(JObject obj, string key, JToken value)
{
if (obj.ContainsKey(key))
{
((JArray) obj[key]).Add(value);
}
else
{
obj[key] = new JArray(value);
}
}
}
}

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

@ -0,0 +1,44 @@
// 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.Middleware;
using Microsoft.Bot.Schema;
using Microsoft.Cognitive.LUIS;
namespace Microsoft.Bot.Builder.LUIS
{
/// <summary>
/// A Middleware for running the Luis recognizer
/// This could eventually be generalized and moved to the core Bot Builder library
/// in order to support multiple recognizers
/// </summary>
public class LuisRecognizerMiddleware : IReceiveActivity
{
public const string LuisRecognizerResultKey = "LuisRecognizerResult";
private readonly IRecognizer _luisRecognizer;
public LuisRecognizerMiddleware(ILuisModel luisModel, ILuisRecognizerOptions luisRecognizerOptions = null, ILuisOptions luisOptions = null)
{
if(luisModel == null)
throw new ArgumentNullException(nameof(luisModel));
_luisRecognizer = new LuisRecognizer(luisModel, luisRecognizerOptions, luisOptions);
}
public async Task ReceiveActivity(IBotContext context, MiddlewareSet.NextDelegate next)
{
BotAssert.ContextNotNull(context);
if (context.Request.Type == ActivityTypes.Message)
{
var utterance = context.Request.AsMessageActivity().Text;
var result = await _luisRecognizer.Recognize(utterance, CancellationToken.None).ConfigureAwait(false);
context.Set(LuisRecognizerResultKey, result);
}
await next().ConfigureAwait(false);
}
}
}

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

@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Bot.Builder.LUIS
{
/// <inheritdoc />
public class LuisRecognizerOptions : ILuisRecognizerOptions
{
public bool Verbose { get; set; }
}
}

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

@ -0,0 +1,50 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version Condition=" '$(BUILD_BUILDNUMBER)' == '' ">4.0.0-local</Version>
<Version Condition=" '$(BUILD_BUILDNUMBER)' != '' ">$(BUILD_BUILDNUMBER)</Version>
<PackageVersion Condition=" '$(PackageVersion)' == '' ">4.0.0-local</PackageVersion>
<PackageVersion Condition=" '$(PackageVersion)' != '' ">$(PackageVersion)</PackageVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<SignAssembly>true</SignAssembly>
<DelaySign>true</DelaySign>
<AssemblyOriginatorKeyFile>..\..\build\35MSSharedLib1024.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Microsoft.Bot.Builder.LUIS</PackageId>
<Description>LUIS Middleware and Recognizers for the Microsoft Bot Builder SDK</Description>
<Summary>This library implements C# classes for building bots using LUIS.</Summary>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup>
<Company>Microsoft</Company>
<Authors>microsoft,BotFramework,nugetbotbuilder</Authors>
<Product>Microsoft Bot Builder SDK</Product>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<PackageProjectUrl>https://github.com/Microsoft/botbuilder-dotnet</PackageProjectUrl>
<PackageIconUrl>http://docs.botframework.com/images/bot_icon.png</PackageIconUrl>
<PackageLicenseUrl>https://github.com/Microsoft/BotBuilder/blob/master/LICENSE</PackageLicenseUrl>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<RepositoryUrl>https://github.com/Microsoft/botbuilder-dotnet</RepositoryUrl>
<LicenseUrl>https://github.com/Microsoft/BotBuilder-dotnet/blob/master/LICENSE</LicenseUrl>
<RepositoryType />
<PackageTags>bots;ai;botframework;botbuilder;luis</PackageTags>
<NeutralLanguage />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Bot.Builder.Core" Condition=" '$(PackageVersion)' == '' " Version="4.0.0-local" />
<PackageReference Include="Microsoft.Bot.Builder.Core" Condition=" '$(PackageVersion)' != '' " Version="$(PackageVersion)" />
<PackageReference Include="Microsoft.Rest.ClientRuntime" Version="2.3.10" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.Bot.Builder.Core\Microsoft.Bot.Builder.Core.csproj" />
<ProjectReference Include="..\Microsoft.Bot.Schema\Microsoft.Bot.Schema.csproj" />
</ItemGroup>
</Project>

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

@ -0,0 +1,11 @@
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.LUIS
{
public class RecognizerResult
{
public string Text { set; get; }
public JObject Intents { get; set; }
public JObject Entities { get; set; }
}
}

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

@ -104,8 +104,12 @@ namespace Microsoft.Bot.Builder.Adapters
/// <returns>App credentials.</returns>
protected virtual async Task<MicrosoftAppCredentials> GetAppCredentials(string appId)
{
MicrosoftAppCredentials appCredentials;
if (!_appCredentialMap.TryGetValue(appId, out appCredentials))
if (appId == null)
{
return MicrosoftAppCredentials.Empty;
}
if (!_appCredentialMap.TryGetValue(appId, out var appCredentials))
{
string appPassword = await _credentialProvider.GetAppPasswordAsync(appId);
appCredentials = new MicrosoftAppCredentials(appId, appPassword);

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

@ -15,34 +15,6 @@ namespace Microsoft.Bot.Connector.Authentication
{
private static HttpClient _httpClient = new HttpClient();
/// <summary>
/// Validates the security tokens required by the Bot Framework Protocol. Throws on any exceptions.
/// </summary>
/// <param name="activity">The incoming Activity from the Bot Framework or the Emulator</param>
/// <param name="authHeader">The Bearer token included as part of the request</param>
/// <param name="credentials">The set of valid credentials, such as the Bot Application ID</param>
/// <param name="httpClient">Validating an Activity requires validating the claimset on the security token. This
/// validation may require outbound calls for Endorsement validation and other checks. Those calls are made to
/// TLS services, which are (latency wise) expensive resources. The httpClient passed in here, if shared by the layers
/// above from call to call, enables connection reuse which is a significant performance and resource improvement.</param>
/// <returns>Task tracking operation</returns>
public static async Task AssertValidActivity(IActivity activity, string authHeader, ICredentialProvider credentials, HttpClient httpClient = null)
{
if (string.IsNullOrWhiteSpace(authHeader))
{
// No auth header was sent. We might be on the anonymous code path.
bool isAuthDisabled = await credentials.IsAuthenticationDisabledAsync();
if (isAuthDisabled)
{
// We are on the anonymous code path.
return;
}
}
// Go through the standard authentication path.
await JwtTokenValidation.AuthenticateRequest(activity, authHeader, credentials, httpClient ?? _httpClient);
}
/// <summary>
/// Authenticates the request and sets the service url in the set of trusted urls.
/// </summary>
@ -52,16 +24,6 @@ namespace Microsoft.Bot.Connector.Authentication
/// <param name="httpClient">The HTTP client.</param>
/// <returns>ClaimsIdentity for the request.</returns>
public static async Task<ClaimsIdentity> AuthenticateRequest(IActivity activity, string authHeader, ICredentialProvider credentials, HttpClient httpClient = null)
{
ClaimsIdentity claimsIdentity = await ValidateAuthHeader(authHeader, credentials, activity.ServiceUrl, httpClient ?? _httpClient);
// On the standard Auth path, we need to trust the URL that was incoming.
MicrosoftAppCredentials.TrustServiceUrl(activity.ServiceUrl);
return claimsIdentity;
}
public static async Task<ClaimsIdentity> ValidateAuthHeader(string authHeader, ICredentialProvider credentials, string serviceUrl = null, HttpClient httpClient = null)
{
if (string.IsNullOrWhiteSpace(authHeader))
{
@ -71,15 +33,26 @@ namespace Microsoft.Bot.Connector.Authentication
// In the scenario where Auth is disabled, we still want to have the
// IsAuthenticated flag set in the ClaimsIdentity. To do this requires
// adding in an empty claim.
ClaimsIdentity anonymousAuthenticatedIdentity = new ClaimsIdentity(new List<Claim>(), "anonymous");
return anonymousAuthenticatedIdentity;
return new ClaimsIdentity(new List<Claim>(), "anonymous");
}
// No Auth Header. Auth is required. Request is not authorized.
throw new UnauthorizedAccessException();
}
var claimsIdentity = await ValidateAuthHeader(authHeader, credentials, activity.ServiceUrl, httpClient ?? _httpClient);
MicrosoftAppCredentials.TrustServiceUrl(activity.ServiceUrl);
return claimsIdentity;
}
public static async Task<ClaimsIdentity> ValidateAuthHeader(string authHeader, ICredentialProvider credentials, string serviceUrl = null, HttpClient httpClient = null)
{
if (string.IsNullOrEmpty(authHeader)) throw new ArgumentNullException(nameof(authHeader));
bool usingEmulator = EmulatorValidation.IsTokenFromEmulator(authHeader);
if (usingEmulator)
{
return await EmulatorValidation.AuthenticateEmulatorToken(authHeader, credentials, httpClient ?? _httpClient);

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

@ -17,6 +17,11 @@ namespace Microsoft.Bot.Connector.Authentication
/// </summary>
public class MicrosoftAppCredentials : ServiceClientCredentials
{
/// <summary>
/// An empty set of credentials.
/// </summary>
public static readonly MicrosoftAppCredentials Empty = new MicrosoftAppCredentials(null, null);
/// <summary>
/// The key for Microsoft app Id.
/// </summary>

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

@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.AspNetCore.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Integration.AspNet.Core.Handlers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
namespace Microsoft.Bot.Builder.Integration.AspNet.Core
{
public static class ApplicationBuilderExtensions
{
public static IApplicationBuilder UseBotFramework(this IApplicationBuilder applicationBuilder) =>
applicationBuilder.UseBotFramework(paths => {});
public static IApplicationBuilder UseBotFramework(this IApplicationBuilder applicationBuilder, Action<BotFrameworkPaths> configurePaths)
{
if (applicationBuilder == null)
{
throw new ArgumentNullException(nameof(applicationBuilder));
}
if (configurePaths == null)
{
throw new ArgumentNullException(nameof(configurePaths));
}
var options = applicationBuilder.ApplicationServices.GetRequiredService<IOptions<BotFrameworkOptions>>().Value;
var botFrameworkAdapter = new BotFrameworkAdapter(options.CredentialProvider);
foreach (var middleware in options.Middleware)
{
botFrameworkAdapter.Use(middleware);
}
var paths = new BotFrameworkPaths();
configurePaths(paths);
if (options.EnableProactiveMessages)
{
applicationBuilder.Map(
paths.BasePath + paths.ProactiveMessagesPath,
botProactiveAppBuilder => botProactiveAppBuilder.Run(new BotProactiveMessageHandler(botFrameworkAdapter).HandleAsync));
}
applicationBuilder.Map(
paths.BasePath + paths.MessagesPath,
botActivitiesAppBuilder => botActivitiesAppBuilder.Run(new BotMessageHandler(botFrameworkAdapter).HandleAsync));
return applicationBuilder;
}
}
}

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

@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
using BotMiddleware = Microsoft.Bot.Builder.Middleware;
using Microsoft.Bot.Connector.Authentication;
namespace Microsoft.Bot.Builder.Integration.AspNet.Core
{
public class BotFrameworkOptions
{
private readonly List<BotMiddleware.IMiddleware> _middleware;
public BotFrameworkOptions()
{
_middleware = new List<BotMiddleware.IMiddleware>();
}
public ICredentialProvider CredentialProvider { get; set; }
public IList<BotMiddleware.IMiddleware> Middleware { get => _middleware; }
public bool EnableProactiveMessages { get; set; }
}
}

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

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

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

@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.AspNetCore.Http;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Schema;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder.Integration.AspNet.Core.Handlers
{
public class BotMessageHandler : BotMessageHandlerBase
{
public BotMessageHandler(BotFrameworkAdapter botFrameworkAdapter) : base(botFrameworkAdapter)
{
}
protected override async Task ProcessMessageRequestAsync(HttpRequest request, BotFrameworkAdapter botFrameworkAdapter, Func<IBotContext, Task> botCallbackHandler)
{
var activity = default(Activity);
using (var bodyReader = new JsonTextReader(new StreamReader(request.Body, Encoding.UTF8)))
{
activity = BotMessageHandlerBase.BotMessageSerializer.Deserialize<Activity>(bodyReader);
}
await botFrameworkAdapter.ProcessActivity(
request.Headers["Authorization"],
activity,
botCallbackHandler);
}
}
}

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

@ -0,0 +1,82 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.AspNetCore.Http;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Net;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder.Integration.AspNet.Core.Handlers
{
public abstract class BotMessageHandlerBase
{
public static readonly JsonSerializer BotMessageSerializer = JsonSerializer.Create(new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Newtonsoft.Json.Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
});
private BotFrameworkAdapter _botFrameworkAdapter;
public BotMessageHandlerBase(BotFrameworkAdapter botFrameworkAdapter)
{
_botFrameworkAdapter = botFrameworkAdapter;
}
public async Task HandleAsync(HttpContext httpContext)
{
var request = httpContext.Request;
var response = httpContext.Response;
if (request.Method != HttpMethods.Post)
{
response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
return;
}
if (request.ContentLength == 0)
{
response.StatusCode = (int)HttpStatusCode.BadRequest;
return;
}
if (!MediaTypeHeaderValue.TryParse(request.ContentType, out var mediaTypeHeaderValue)
||
mediaTypeHeaderValue.MediaType != "application/json")
{
response.StatusCode = (int)HttpStatusCode.NotAcceptable;
return;
}
try
{
await ProcessMessageRequestAsync(
request,
_botFrameworkAdapter,
botContext =>
{
var bot = httpContext.RequestServices.GetRequiredService<IBot>();
return bot.OnReceiveActivity(botContext);
});
response.StatusCode = (int)HttpStatusCode.OK;
}
catch (UnauthorizedAccessException)
{
response.StatusCode = (int)HttpStatusCode.Forbidden;
}
}
protected abstract Task ProcessMessageRequestAsync(HttpRequest request, BotFrameworkAdapter botFrameworkAdapter, Func<IBotContext, Task> botCallbackHandler);
}
}

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

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.AspNetCore.Http;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Schema;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder.Integration.AspNet.Core.Handlers
{
public class BotProactiveMessageHandler : BotMessageHandlerBase
{
public BotProactiveMessageHandler(BotFrameworkAdapter botFrameworkAdapter) : base(botFrameworkAdapter)
{
}
protected override async Task ProcessMessageRequestAsync(HttpRequest request, BotFrameworkAdapter botFrameworkAdapter, Func<IBotContext, Task> botCallbackHandler)
{
var conversationReference = default(ConversationReference);
using (var bodyReader = new JsonTextReader(new StreamReader(request.Body, Encoding.UTF8)))
{
conversationReference = BotMessageHandlerBase.BotMessageSerializer.Deserialize<ConversationReference>(bodyReader);
}
await botFrameworkAdapter.ContinueConversation(conversationReference, botCallbackHandler);
}
}
}

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

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Middleware;
using System.Collections.Generic;
namespace Microsoft.Bot.Builder.Integration.AspNet.Core
{
public interface IBotConfigurationBuilder
{
List<IMiddleware> Middleware { get; }
}
}

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

@ -0,0 +1,59 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version Condition=" '$(BUILD_BUILDNUMBER)' == '' ">4.0.0-local</Version>
<Version Condition=" '$(BUILD_BUILDNUMBER)' != '' ">$(BUILD_BUILDNUMBER)</Version>
<PackageVersion Condition=" '$(PackageVersion)' == '' ">4.0.0-local</PackageVersion>
<PackageVersion Condition=" '$(PackageVersion)' != '' ">$(PackageVersion)</PackageVersion>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Microsoft.Bot.Builder.Integration.AspNet.Core</PackageId>
<Description>This library integrates the Microsoft Bot Builder SDK with ASP.NET Core. It offers idiomatic configuration APIs in addition to providing all the plumbing to direct incoming bot messages to a configured bot.</Description>
<Summary>This library provides integration between the Microsoft Bot Builder SDK and ASP.NET Core.</Summary>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<SignAssembly>true</SignAssembly>
<DelaySign>true</DelaySign>
<AssemblyOriginatorKeyFile>..\..\..\build\35MSSharedLib1024.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Company>Microsoft</Company>
<Authors>microsoft,BotFramework,nugetbotbuilder</Authors>
<Product>Microsoft Bot Builder SDK</Product>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<PackageProjectUrl>https://github.com/Microsoft/botbuilder-dotnet</PackageProjectUrl>
<PackageIconUrl>http://docs.botframework.com/images/bot_icon.png</PackageIconUrl>
<PackageLicenseUrl>https://github.com/Microsoft/BotBuilder/blob/master/LICENSE</PackageLicenseUrl>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<RepositoryUrl>https://github.com/Microsoft/botbuilder-dotnet</RepositoryUrl>
<LicenseUrl>https://github.com/Microsoft/BotBuilder-dotnet/blob/master/LICENSE</LicenseUrl>
<RepositoryType />
<PackageTags>bots;ai;botframework;botbuilder</PackageTags>
<NeutralLanguage />
<AssemblyName>Microsoft.Bot.Builder.Integration.AspNet.Core</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
<PackageReference Include="Microsoft.Bot.Builder.Core" Condition=" '$(PackageVersion)' == '' " Version="4.0.0-local" />
<PackageReference Include="Microsoft.Bot.Builder.Core" Condition=" '$(PackageVersion)' != '' " Version="$(PackageVersion)" />
<PackageReference Include="Microsoft.Bot.Connector" Condition=" '$(PackageVersion)' == '' " Version="4.0.0-local" />
<PackageReference Include="Microsoft.Bot.Connector" Condition=" '$(PackageVersion)' != '' " Version="$(PackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Options" Version="2.0.0" />
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Microsoft.Bot.Builder.Core\Microsoft.Bot.Builder.Core.csproj" />
<ProjectReference Include="..\..\Microsoft.Bot.Builder\Microsoft.Bot.Builder.csproj" />
<ProjectReference Include="..\..\Microsoft.Bot.Connector\Microsoft.Bot.Connector.csproj" />
</ItemGroup>
</Project>

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

@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System;
namespace Microsoft.Bot.Builder.Integration.AspNet.Core
{
public static class ServiceCollectionExtensions
{
private static readonly JsonSerializer ActivitySerializer = JsonSerializer.Create();
public static IServiceCollection AddBot<TBot>(this IServiceCollection services, Action<BotFrameworkOptions> setupAction = null) where TBot : class, IBot
{
services.AddTransient<IBot, TBot>();
services.Configure(setupAction);
return services;
}
}
}

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

@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Middleware;
using System;
using Microsoft.Bot.Connector.Authentication;
namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
{
public class BotFrameworkConfigurationBuilder
{
private BotFrameworkOptions _options;
public BotFrameworkConfigurationBuilder(BotFrameworkOptions botFrameworkOptions)
{
_options = botFrameworkOptions;
}
public BotFrameworkOptions BotFrameworkOptions { get => _options; }
public BotFrameworkConfigurationBuilder UseMicrosoftApplicationIdentity(string applicationId, string applicationPassword) =>
UseCredentialProvider(new SimpleCredentialProvider(applicationId, applicationPassword));
public BotFrameworkConfigurationBuilder UseCredentialProvider(ICredentialProvider credentialProvider)
{
_options.CredentialProvider = credentialProvider;
return this;
}
public BotFrameworkConfigurationBuilder UseMiddleware(IMiddleware middleware)
{
_options.Middleware.Add(middleware);
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;
}
}
}

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

@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Middleware;
using Microsoft.Bot.Connector.Authentication;
using System.Collections.Generic;
namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
{
public class BotFrameworkOptions
{
private readonly List<IMiddleware> _middleware;
private readonly BotFrameworkPaths _paths;
public BotFrameworkOptions()
{
_middleware = new List<IMiddleware>();
_paths = new BotFrameworkPaths();
}
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);
}
}
}

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

@ -0,0 +1,99 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Adapters;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi.Handlers
{
public abstract class BotMessageHandlerBase : HttpMessageHandler
{
public static readonly MediaTypeFormatter[] BotMessageMediaTypeFormatters = new [] {
new JsonMediaTypeFormatter
{
SerializerSettings =
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Newtonsoft.Json.Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
}
}
};
private readonly BotFrameworkAdapter _botFrameworkAdapter;
public BotMessageHandlerBase(BotFrameworkAdapter botFrameworkAdapter)
{
_botFrameworkAdapter = botFrameworkAdapter;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Method != HttpMethod.Post)
{
return request.CreateResponse(HttpStatusCode.MethodNotAllowed);
}
var requestContentHeaders = request.Content.Headers;
if (requestContentHeaders.ContentLength == 0)
{
return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Request body should not be empty.");
}
if (!BotMessageMediaTypeFormatters[0].SupportedMediaTypes.Contains(requestContentHeaders.ContentType))
{
return request.CreateErrorResponse(HttpStatusCode.NotAcceptable, $"Expecting Content-Type of \"{BotMessageMediaTypeFormatters[0].SupportedMediaTypes[0].MediaType}\".");
}
try
{
await ProcessMessageRequestAsync(
request,
_botFrameworkAdapter,
botContext =>
{
cancellationToken.ThrowIfCancellationRequested();
IBot bot;
try
{
bot = (IBot)request.GetDependencyScope().GetService(typeof(IBot));
}
catch
{
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);
}
catch (UnauthorizedAccessException e)
{
return request.CreateErrorResponse(HttpStatusCode.Unauthorized, e.Message);
}
catch (InvalidOperationException e)
{
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);
}
}
}

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

@ -0,0 +1,65 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Integration.AspNet.WebApi.Handlers;
using System;
using System.Web.Http;
namespace Microsoft.Bot.Builder.Integration.AspNet.WebApi
{
public static class HttpConfigurationExtensions
{
public static HttpConfiguration MapBotFramework(this HttpConfiguration httpConfiguration, Action<BotFrameworkConfigurationBuilder> configurer)
{
var options = new BotFrameworkOptions();
var optionsBuilder = new BotFrameworkConfigurationBuilder(options);
configurer(optionsBuilder);
ConfigureBotRoutes(BuildAdapter());
return httpConfiguration;
BotFrameworkAdapter BuildAdapter()
{
var adapter = new BotFrameworkAdapter(options.CredentialProvider);
foreach (var middleware in options.Middleware)
{
adapter.Use(middleware);
}
return adapter;
}
void ConfigureBotRoutes(BotFrameworkAdapter adapter)
{
var routes = httpConfiguration.Routes;
var baseUrl = options.Paths.BasePath;
if (!baseUrl.EndsWith("/"))
{
baseUrl += "/";
}
if (options.EnableProactiveMessages)
{
routes.MapHttpRoute(
"BotFramework - Proactive Message Handler",
baseUrl + options.Paths.ProactiveMessagesPath,
defaults: null,
constraints: null,
handler: new BotProactiveMessageHandler(adapter));
}
routes.MapHttpRoute(
"BotFramework - Message Handler",
baseUrl + options.Paths.MessagesPath,
defaults: null,
constraints: null,
handler: new BotMessageHandler(adapter));
}
}
}
}

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

@ -0,0 +1,62 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version Condition=" '$(BUILD_BUILDNUMBER)' == '' ">4.0.0-local</Version>
<Version Condition=" '$(BUILD_BUILDNUMBER)' != '' ">$(BUILD_BUILDNUMBER)</Version>
<PackageVersion Condition=" '$(PackageVersion)' == '' ">4.0.0-local</PackageVersion>
<PackageVersion Condition=" '$(PackageVersion)' != '' ">$(PackageVersion)</PackageVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<SignAssembly>true</SignAssembly>
<DelaySign>true</DelaySign>
<AssemblyOriginatorKeyFile>..\..\..\build\35MSSharedLib1024.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<PackageId>Microsoft.Bot.Builder.Integration.AspNet.WebApi</PackageId>
<Description>This library integrates the Microsoft Bot Builder SDK with ASP.NET WebAPI. It offers idiomatic configuration APIs in addition to providing all the plumbing to direct incoming bot messages to a configured bot.</Description>
<Summary>This library provides integration between the Microsoft Bot Builder SDK and ASP.NET WebAPI.</Summary>
</PropertyGroup>
<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Company>Microsoft</Company>
<Authors>microsoft,BotFramework,nugetbotbuilder</Authors>
<Product>Microsoft Bot Builder SDK</Product>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<PackageProjectUrl>https://github.com/Microsoft/botbuilder-dotnet</PackageProjectUrl>
<PackageIconUrl>http://docs.botframework.com/images/bot_icon.png</PackageIconUrl>
<PackageLicenseUrl>https://github.com/Microsoft/BotBuilder/blob/master/LICENSE</PackageLicenseUrl>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<RepositoryUrl>https://github.com/Microsoft/botbuilder-dotnet</RepositoryUrl>
<LicenseUrl>https://github.com/Microsoft/BotBuilder-dotnet/blob/master/LICENSE</LicenseUrl>
<RepositoryType />
<PackageTags>bots;ai;botframework;botbuilder</PackageTags>
<NeutralLanguage />
<AssemblyName>Microsoft.Bot.Builder.Integration.AspNet.WebApi</AssemblyName>
<RootNamespace>Microsoft.Bot.Builder.Integration.AspNet.NetFx</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNet.WebApi" Version="5.2.4" />
<PackageReference Include="Microsoft.Bot.Builder.Core" Condition=" '$(PackageVersion)' == '' " Version="4.0.0-local" />
<PackageReference Include="Microsoft.Bot.Builder.Core" Condition=" '$(PackageVersion)' != '' " Version="$(PackageVersion)" />
<PackageReference Include="Microsoft.Bot.Connector" Condition=" '$(PackageVersion)' == '' " Version="4.0.0-local" />
<PackageReference Include="Microsoft.Bot.Connector" Condition=" '$(PackageVersion)' != '' " Version="$(PackageVersion)" />
<PackageReference Include="Microsoft.Bot.Builder" Condition=" '$(PackageVersion)' == '' " Version="4.0.0-local" />
<PackageReference Include="Microsoft.Bot.Builder" Condition=" '$(PackageVersion)' != '' " Version="$(PackageVersion)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Microsoft.Bot.Builder.Core\Microsoft.Bot.Builder.Core.csproj" />
<ProjectReference Include="..\..\Microsoft.Bot.Connector\Microsoft.Bot.Connector.csproj" />
<ProjectReference Include="..\..\Microsoft.Bot.Builder\Microsoft.Bot.Builder.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Web" />
</ItemGroup>
</Project>

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

@ -8,7 +8,12 @@
<NoWarn>1701;1702;1705;1998</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1701;1702;1705;1998</NoWarn>
</PropertyGroup>
<ItemGroup>
<Folder Include="Controllers\" />
<Folder Include="Properties\PublishProfiles\" />
</ItemGroup>
@ -24,6 +29,7 @@
</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\Microsoft.Bot.Builder.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Connector\Microsoft.Bot.Connector.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Schema\Microsoft.Bot.Schema.csproj" />

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

@ -1,50 +1,46 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using AlarmBot.Models;
using AlarmBot.Topics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Middleware;
using System.Threading.Tasks;
namespace AlarmBot.Controllers
{
[Route("api/[controller]")]
public class MessagesController : BotController
{
public MessagesController(BotFrameworkAdapter adapter) : base(adapter) { }
protected override async Task OnReceiveActivity(IBotContext context)
{
// --- Our receive handler simply inspects the persisted ITopic class and calls to it as appropriate ---
bool handled = false;
// Get the current ActiveTopic from my persisted conversation state
var conversation = ConversationState<ConversationData>.Get(context);
//var conversation = context.GetConversationState<ConversationData>();
// if we don't have an active topic yet
if (conversation.ActiveTopic== null)
{
// use the default topic
conversation.ActiveTopic = new DefaultTopic();
handled = await conversation.ActiveTopic.StartTopic(context);
}
else
{
// we do have an active topic, so call it
handled = await conversation.ActiveTopic.ContinueTopic(context);
}
// if activeTopic's result is false and the activeTopic is NOT already the default topic
if (handled == false && !(conversation.ActiveTopic is DefaultTopic))
{
// USe DefaultTopic as the active topic
conversation.ActiveTopic = new DefaultTopic();
handled = await conversation.ActiveTopic.ResumeTopic(context);
}
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using AlarmBot.Models;
using AlarmBot.Topics;
using Microsoft.Bot;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Middleware;
using System.Threading.Tasks;
namespace AlarmBot
{
public class AlarmBot : IBot
{
public async Task OnReceiveActivity(IBotContext context)
{
// --- Our receive handler simply inspects the persisted ITopic class and calls to it as appropriate ---
bool handled = false;
// Get the current ActiveTopic from my persisted conversation state
var conversation = ConversationState<ConversationData>.Get(context);
//var conversation = context.GetConversationState<ConversationData>();
// if we don't have an active topic yet
if (conversation.ActiveTopic == null)
{
// use the default topic
conversation.ActiveTopic = new DefaultTopic();
handled = await conversation.ActiveTopic.StartTopic(context);
}
else
{
// we do have an active topic, so call it
handled = await conversation.ActiveTopic.ContinueTopic(context);
}
// if activeTopic's result is false and the activeTopic is NOT already the default topic
if (handled == false && !(conversation.ActiveTopic is DefaultTopic))
{
// USe DefaultTopic as the active topic
conversation.ActiveTopic = new DefaultTopic();
handled = await conversation.ActiveTopic.ResumeTopic(context);
}
}
}
}

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

@ -1,44 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Schema;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder
{
/// <summary>
/// Helper Bot Controller for ASP.NET Core
/// </summary>
public abstract class BotController : Controller
{
protected readonly BotFrameworkAdapter _adapter;
public BotController(BotFrameworkAdapter adapter)
{
this._adapter = adapter;
}
protected abstract Task OnReceiveActivity(IBotContext context);
[HttpPost]
public async Task<IActionResult> Post([FromBody]Activity activity)
{
try
{
await _adapter.ProcessActivity(this.Request.Headers["Authorization"].FirstOrDefault(), activity, OnReceiveActivity);
return this.Ok();
}
catch (UnauthorizedAccessException)
{
return this.Unauthorized();
}
catch (InvalidOperationException e)
{
return this.NotFound(e.Message);
}
}
}
}

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

@ -10,20 +10,16 @@ namespace AlarmBot.Models
/// <summary>
/// Object persisted as conversation state
/// </summary>
public class ConversationData : IStoreItem
public class ConversationData : StoreItem
{
public string eTag { get; set; }
public ITopic ActiveTopic { get; set; }
}
/// <summary>
/// object persisted as user state
/// </summary>
public class UserData : IStoreItem
public class UserData : StoreItem
{
public string eTag { get; set; }
public IList<Alarm> Alarms { get; set; }
}
}

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

@ -4,11 +4,10 @@
using AlarmBot.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.BotFramework;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Builder.Middleware;
using Microsoft.Bot.Builder.Storage;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Text.RegularExpressions;
@ -33,18 +32,15 @@ namespace AlarmBot
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_ => Configuration);
services.AddMvc();
// register adapater
services.AddSingleton<BotFrameworkAdapter>(serviceProvider =>
{
string applicationId = Configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value;
string applicationPassword = Configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppPasswordKey)?.Value;
services.AddBot<AlarmBot>(options =>
{
options.CredentialProvider = new ConfigurationCredentialProvider(Configuration);
// create bot hooked up to the activity adapater
return new BotFrameworkAdapter(applicationId, applicationPassword)
.Use(new UserState<UserData>(new MemoryStorage()))
.Use(new ConversationState<ConversationData>(new MemoryStorage()))
.Use(new RegExpRecognizerMiddleware()
var middleware = options.Middleware;
middleware.Add(new UserState<UserData>(new MemoryStorage()));
middleware.Add(new ConversationState<ConversationData>(new MemoryStorage()));
middleware.Add(new RegExpRecognizerMiddleware()
.AddIntent("showAlarms", new Regex("show alarms(.*)", RegexOptions.IgnoreCase))
.AddIntent("addAlarm", new Regex("add alarm(.*)", RegexOptions.IgnoreCase))
.AddIntent("deleteAlarm", new Regex("delete alarm(.*)", RegexOptions.IgnoreCase))
@ -64,8 +60,8 @@ namespace AlarmBot
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvc();
app.UseStaticFiles();
app.UseBotFramework();
}
}
}

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

@ -1,49 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using AlarmBot.Models;
using AlarmBot.Topics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Middleware;
using System.Threading.Tasks;
namespace AlarmBot.Controllers
{
[Route("api/[controller]")]
public class MessagesController : BotController
{
public MessagesController(BotFrameworkAdapter adapter) : base(adapter) { }
protected override async Task OnReceiveActivity(IBotContext botContext)
{
var context = new AlarmBotContext(botContext);
// --- Our receive handler simply inspects the persisted ITopic class and calls to it as appropriate ---
bool handled = false;
// if we don't have an active topic yet
if (context.ConversationState.ActiveTopic == null)
{
// use the default topic
context.ConversationState.ActiveTopic = new DefaultTopic();
handled = await context.ConversationState.ActiveTopic.StartTopic(context);
}
else
{
// we do have an active topic, so call it
handled = await context.ConversationState.ActiveTopic.ContinueTopic(context);
}
// if activeTopic's result is false and the activeTopic is NOT already the default topic
if (handled == false && !(context.ConversationState.ActiveTopic is DefaultTopic))
{
// USe DefaultTopic as the active topic
context.ConversationState.ActiveTopic = new DefaultTopic();
handled = await context.ConversationState.ActiveTopic.ResumeTopic(context);
}
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using AlarmBot.Models;
using AlarmBot.Topics;
using Microsoft.Bot;
using Microsoft.Bot.Builder;
using System.Threading.Tasks;
namespace AlarmBot
{
public class AlarmBot : IBot
{
public async Task OnReceiveActivity(IBotContext botContext)
{
var context = new AlarmBotContext(botContext);
// --- Our receive handler simply inspects the persisted ITopic class and calls to it as appropriate ---
bool handled = false;
// if we don't have an active topic yet
if (context.ConversationState.ActiveTopic == null)
{
// use the default topic
context.ConversationState.ActiveTopic = new DefaultTopic();
handled = await context.ConversationState.ActiveTopic.StartTopic(context);
}
else
{
// we do have an active topic, so call it
handled = await context.ConversationState.ActiveTopic.ContinueTopic(context);
}
// if activeTopic's result is false and the activeTopic is NOT already the default topic
if (handled == false && !(context.ConversationState.ActiveTopic is DefaultTopic))
{
// USe DefaultTopic as the active topic
context.ConversationState.ActiveTopic = new DefaultTopic();
handled = await context.ConversationState.ActiveTopic.ResumeTopic(context);
}
}
}
}

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

@ -8,6 +8,10 @@
<NoWarn>1701;1702;1705;1998</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1701;1702;1705;1998</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Microsoft.Recognizers.Text.DateTime" Version="1.0.0.36" />
@ -19,6 +23,7 @@
</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.Core\Microsoft.Bot.Builder.Core.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder\Microsoft.Bot.Builder.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Connector\Microsoft.Bot.Connector.csproj" />

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

@ -1,44 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Schema;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder
{
/// <summary>
/// Helper Bot Controller for ASP.NET Core
/// </summary>
public abstract class BotController : Controller
{
protected readonly BotFrameworkAdapter _adapter;
public BotController(BotFrameworkAdapter adapter)
{
this._adapter = adapter;
}
protected abstract Task OnReceiveActivity(IBotContext context);
[HttpPost]
public async Task<IActionResult> Post([FromBody]Activity activity)
{
try
{
await _adapter.ProcessActivity(this.Request.Headers["Authorization"].FirstOrDefault(), activity, OnReceiveActivity);
return this.Ok();
}
catch (UnauthorizedAccessException)
{
return this.Unauthorized();
}
catch (InvalidOperationException e)
{
return this.NotFound(e.Message);
}
}
}
}

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

@ -1,28 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder;
using System.Collections.Generic;
namespace AlarmBot.Models
{
/// <summary>
/// object persisted as conversation state
/// </summary>
public class ConversationData : IStoreItem
{
public string eTag { get; set; }
public ITopic ActiveTopic { get; set; }
}
/// <summary>
/// Object persisted as user state
/// </summary>
public class UserData : IStoreItem
{
public string eTag { get; set; }
public IList<Alarm> Alarms { get; set; }
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder;
using System.Collections.Generic;
namespace AlarmBot.Models
{
/// <summary>
/// object persisted as conversation state
/// </summary>
public class ConversationData : StoreItem
{
public ITopic ActiveTopic { get; set; }
}
/// <summary>
/// Object persisted as user state
/// </summary>
public class UserData : StoreItem
{
public IList<Alarm> Alarms { get; set; }
}
}

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

@ -1,72 +1,69 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using AlarmBot.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Middleware;
using Microsoft.Bot.Builder.Storage;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Text.RegularExpressions;
namespace AlarmBot
{
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_ => Configuration);
services.AddMvc();
// register adapater
services.AddSingleton<BotFrameworkAdapter>(serviceProvider =>
{
string applicationId = Configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value;
string applicationPassword = Configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppPasswordKey)?.Value;
// create bot hooked up to the activity adapater
return new BotFrameworkAdapter(applicationId, applicationPassword)
.Use(new UserState<UserData>(new MemoryStorage()))
.Use(new ConversationState<ConversationData>(new MemoryStorage()))
.Use(new RegExpRecognizerMiddleware()
.AddIntent("showAlarms", new Regex("show alarms(.*)", RegexOptions.IgnoreCase))
.AddIntent("addAlarm", new Regex("add alarm(.*)", RegexOptions.IgnoreCase))
.AddIntent("deleteAlarm", new Regex("delete alarm(.*)", RegexOptions.IgnoreCase))
.AddIntent("help", new Regex("help(.*)", RegexOptions.IgnoreCase))
.AddIntent("cancel", new Regex("cancel(.*)", RegexOptions.IgnoreCase))
.AddIntent("confirmYes", new Regex("(yes|yep|yessir|^y$)", RegexOptions.IgnoreCase))
.AddIntent("confirmNo", new Regex("(no|nope|^n$)", RegexOptions.IgnoreCase)));
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvc();
}
}
}
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using AlarmBot.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Middleware;
using Microsoft.Bot.Builder.Storage;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Text.RegularExpressions;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
namespace AlarmBot
{
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_ => Configuration);
services.AddBot<AlarmBot>(options =>
{
options.CredentialProvider = new SimpleCredentialProvider(Configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value, Configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppPasswordKey)?.Value);
var middleware = options.Middleware;
middleware.Add(new UserState<UserData>(new MemoryStorage()));
middleware.Add(new ConversationState<ConversationData>(new MemoryStorage()));
middleware.Add(new RegExpRecognizerMiddleware()
.AddIntent("showAlarms", new Regex("show alarms(.*)", RegexOptions.IgnoreCase))
.AddIntent("addAlarm", new Regex("add alarm(.*)", RegexOptions.IgnoreCase))
.AddIntent("deleteAlarm", new Regex("delete alarm(.*)", RegexOptions.IgnoreCase))
.AddIntent("help", new Regex("help(.*)", RegexOptions.IgnoreCase))
.AddIntent("cancel", new Regex("cancel(.*)", RegexOptions.IgnoreCase))
.AddIntent("confirmYes", new Regex("(yes|yep|yessir|^y$)", RegexOptions.IgnoreCase))
.AddIntent("confirmNo", new Regex("(no|nope|^n$)", RegexOptions.IgnoreCase)));
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseBotFramework();
}
}
}

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

@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Middleware;
using System.Threading.Tasks;
namespace Microsoft.Bot.Samples.Echo
{
public class EchoState : StoreItem
{
public string eTag { get; set; }
public int TurnNumber { get; set; }
}
public class EchoBot : IBot
{
private readonly IMyService _myService;
public EchoBot(IMyService myService)
{
_myService = myService;
}
public async Task OnReceiveActivity(IBotContext context)
{
var msgActivity = context.Request.AsMessageActivity();
if (msgActivity != null)
{
var conversationState = context.GetConversationState<EchoState>() ?? new EchoState();
conversationState.TurnNumber++;
// calculate something for us to return
int length = (msgActivity.Text ?? string.Empty).Length;
// simulate calling a dependent service that was injected
await _myService.DoSomethingAsync();
// return our reply to the user
context.Reply($"[{conversationState.TurnNumber}] You sent {msgActivity.Text} which was {length} characters");
}
var convUpdateActivity = context.Request.AsConversationUpdateActivity();
if (convUpdateActivity != null)
{
foreach (var newMember in convUpdateActivity.MembersAdded)
{
if (newMember.Id != convUpdateActivity.Recipient.Id)
{
context.Reply("Hello and welcome to the echo bot.");
}
}
}
}
}
}

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

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Microsoft.Bot.Samples.EchoBot</AssemblyName>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Core\Microsoft.Bot.Builder.Core.csproj" />
</ItemGroup>
</Project>

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

@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Threading.Tasks;
namespace Microsoft.Bot.Samples.Echo
{
public interface IMyService
{
Task DoSomethingAsync();
}
public sealed class MyService : IMyService
{
public Task DoSomethingAsync() => Task.Delay(500);
}
}

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

@ -1,17 +0,0 @@
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
namespace Microsoft.Bot.Samples.Connector.EchoBot
{
/// <summary>
/// Credential provider which uses <see cref="Microsoft.Extensions.Configuration.IConfiguration"/> to lookup appId and password.
/// </summary>
public sealed class ConfigurationCredentialProvider : SimpleCredentialProvider
{
public ConfigurationCredentialProvider(IConfiguration configuration)
{
this.AppId = configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value;
this.Password = configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppPasswordKey)?.Value;
}
}
}

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

@ -1,56 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
namespace Microsoft.Bot.Samples.Connector.EchoBot.Controllers
{
[Route("api/messages")]
public class MessagesController : Controller
{
private readonly SimpleCredentialProvider credentials;
public MessagesController(IConfiguration configuration)
{
this.credentials = new ConfigurationCredentialProvider(configuration);
}
[HttpPost]
public async Task<IActionResult> Post([FromBody]Activity activity)
{
// Validate Authorization Header. Should be a jwt token.
var authHeader = this.Request.Headers["Authorization"].SingleOrDefault();
try
{
await JwtTokenValidation.AssertValidActivity(activity, authHeader, this.credentials);
}
catch (UnauthorizedAccessException)
{
return this.Unauthorized();
}
// On message activity, reply with the same text
if (activity.Type == ActivityTypes.Message)
{
var reply = activity.CreateReply($"You said: {activity.Text}");
// Reply to Activity using Connector
var connector = new ConnectorClient(
new Uri(activity.ServiceUrl, UriKind.Absolute),
new MicrosoftAppCredentials(this.credentials.AppId, this.credentials.Password));
await connector.Conversations.ReplyToActivityAsync(reply);
}
return this.Ok();
}
}
}

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

@ -13,8 +13,11 @@
</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.Core\Microsoft.Bot.Builder.Core.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Connector\Microsoft.Bot.Connector.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Schema\Microsoft.Bot.Schema.csproj" />
<ProjectReference Include="..\EchoBot\EchoBot.csproj" />
</ItemGroup>
</Project>

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

@ -4,7 +4,7 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
namespace Connector.EchoBot
namespace Connector.Echo
{
public class Program
{

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

@ -3,11 +3,16 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder.BotFramework;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Builder.Middleware;
using Microsoft.Bot.Builder.Storage;
using Microsoft.Bot.Samples.Echo;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Connector.EchoBot
namespace Connector.Echo
{
public class Startup
{
@ -27,7 +32,14 @@ namespace Connector.EchoBot
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddBot<EchoBot>(options =>
{
options.CredentialProvider = new ConfigurationCredentialProvider(Configuration);
options.Middleware.Add(new ConversationState<EchoState>(new MemoryStorage()));
options.EnableProactiveMessages = true;
});
services.AddTransient<IMyService, MyService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -38,12 +50,9 @@ namespace Connector.EchoBot
app.UseDeveloperExceptionPage();
}
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc();
app.UseDefaultFiles()
.UseStaticFiles()
.UseBotFramework();
}
}
}

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

@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Integration.AspNet.WebApi;
using Microsoft.Bot.Builder.Middleware;
using Microsoft.Bot.Builder.Storage;
using Microsoft.Bot.Samples.Echo;
using System.Configuration;
using System.Web.Http;
namespace Microsoft.Bot.Samples.EchoBot_AspNet461
{
public class BotConfig
{
public static void Register(HttpConfiguration config)
{
config.MapBotFramework(botConfig =>
{
botConfig
.UseMicrosoftApplicationIdentity(ConfigurationManager.AppSettings["BotFramework.MicrosoftApplicationId"], ConfigurationManager.AppSettings["BotFramework.MicrosoftApplicationPassword"])
.EnableProactiveMessages()
.UseMiddleware(new ConversationState<EchoState>(new MemoryStorage()));
});
}
}
}

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

@ -1,3 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Samples.Echo;
using System;
using Unity;
@ -36,12 +40,8 @@ namespace Microsoft.Bot.Samples.EchoBot_AspNet461
/// </remarks>
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below.
// Make sure to add a Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your type's mappings here.
// container.RegisterType<IProductRepository, ProductRepository>();
container.RegisterType<IMyService, MyService>();
container.RegisterType<IBot, EchoBot>();
}
}
}

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

@ -1,48 +1,19 @@
using System.Configuration;
using System.Web.Http;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Middleware;
using Microsoft.Bot.Builder.Storage;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Unity;
namespace Microsoft.Bot.Samples.EchoBot_AspNet461
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Json settings
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Newtonsoft.Json.Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
};
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// services
UnityConfig.Container.RegisterSingleton<BotFrameworkAdapter>(
new Unity.Injection.InjectionConstructor(
ConfigurationManager.AppSettings[@"MicrosoftAppId"],
ConfigurationManager.AppSettings[@"MicrosoftAppPassword"])
)
.Resolve<BotFrameworkAdapter>()
.Use(new ConversationState<MyState>(new MemoryStorage()));
}
}
}
using System.Web.Http;
namespace Microsoft.Bot.Samples.EchoBot_AspNet461
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}

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

@ -1,45 +0,0 @@
// 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;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
namespace Microsoft.Bot.Builder
{
/// <summary>
/// Helper Bot Controller for ASP.NET
/// </summary>
public abstract class BotController : ApiController
{
protected readonly BotFrameworkAdapter _adapter;
public BotController(BotFrameworkAdapter adapter)
{
this._adapter = adapter;
}
protected abstract Task OnReceiveActivity(IBotContext context);
[HttpPost]
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
try
{
await _adapter.ProcessActivity(this.Request.Headers.Authorization?.Parameter, activity, OnReceiveActivity);
return this.Request.CreateResponse(HttpStatusCode.OK);
}
catch (UnauthorizedAccessException e)
{
return this.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, e.Message);
}
catch (InvalidOperationException e)
{
return this.Request.CreateErrorResponse(HttpStatusCode.NotFound, e.Message);
}
}
}
}

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

@ -1,50 +0,0 @@
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Middleware;
namespace Microsoft.Bot.Samples.EchoBot_AspNet461
{
public class MyState : StoreItem
{
public long TurnNumber { get; set; }
}
public class MessagesController : BotController
{
public MessagesController(BotFrameworkAdapter adapter) : base(adapter) { }
protected override Task OnReceiveActivity(IBotContext context)
{
var msgActivity = context.Request.AsMessageActivity();
if (msgActivity != null)
{
var myState = context.GetConversationState<MyState>();
myState.TurnNumber++;
// calculate something for us to return
int length = (msgActivity.Text ?? string.Empty).Length;
// return our reply to the user
context.Reply($"[{myState.TurnNumber}] You sent {msgActivity.Text} which was {length} characters");
return Task.CompletedTask;
}
var convUpdateActivity = context.Request.AsConversationUpdateActivity();
if (convUpdateActivity != null)
{
foreach (var newMember in convUpdateActivity.MembersAdded)
{
if (newMember.Id != convUpdateActivity.Recipient.Id)
{
context.Reply("Hello and welcome to the echo bot.");
}
}
return Task.CompletedTask;
}
return Task.CompletedTask;
}
}
}

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

@ -6,7 +6,11 @@ namespace Microsoft.Bot.Samples.EchoBot_AspNet461
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configure(config =>
{
BotConfig.Register(config);
WebApiConfig.Register(config);
});
}
}
}

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

@ -43,9 +43,6 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Autofac, Version=3.5.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Autofac.3.5.2\lib\net40\Autofac.dll</HintPath>
</Reference>
<Reference Include="Chronic, Version=0.3.2.0, Culture=neutral, PublicKeyToken=3bd1f1ef638b0d3c, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Chronic.Signed.0.3.2\lib\net40\Chronic.dll</HintPath>
</Reference>
@ -86,8 +83,8 @@
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
<Reference Include="System.Net.Http.Formatting, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.4\lib\net45\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
@ -103,11 +100,11 @@
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll</HintPath>
<Reference Include="System.Web.Http, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.4\lib\net45\System.Web.Http.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.WebHost, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll</HintPath>
<Reference Include="System.Web.Http.WebHost, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.4\lib\net45\System.Web.Http.WebHost.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Configuration" />
@ -150,11 +147,10 @@
</Content>
</ItemGroup>
<ItemGroup>
<Compile Include="App_Start\BotConfig.cs" />
<Compile Include="App_Start\UnityConfig.cs" />
<Compile Include="App_Start\UnityWebApiActivator.cs" />
<Compile Include="App_Start\WebApiConfig.cs" />
<Compile Include="BotController.cs" />
<Compile Include="Controllers\MessagesController.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
@ -173,6 +169,10 @@
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libraries\integration\Microsoft.Bot.Builder.Integration.AspNet.WebApi\Microsoft.Bot.Builder.Integration.AspNet.WebApi.csproj">
<Project>{bd0b82ef-1601-4e87-b78a-b43de7eb36b0}</Project>
<Name>Microsoft.Bot.Builder.Integration.AspNet.WebApi</Name>
</ProjectReference>
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Core\Microsoft.Bot.Builder.Core.csproj">
<Project>{F0C150E2-9B8A-444C-B70E-97AD918CB3D4}</Project>
<Name>Microsoft.Bot.Builder.Core</Name>
@ -189,7 +189,12 @@
<Project>{C1F54CDC-AD1D-45BB-8F7D-F49E411AFAF1}</Project>
<Name>Microsoft.Bot.Schema</Name>
</ProjectReference>
<ProjectReference Include="..\EchoBot\EchoBot.csproj">
<Project>{30b77905-0bab-44c1-a011-0245f220c30c}</Project>
<Name>EchoBot</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
@ -204,7 +209,7 @@
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>True</UseIIS>
<UseIIS>False</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>3979</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>

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

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301879
@ -6,9 +6,9 @@
<configuration>
<appSettings>
<!-- update these with your BotId, Microsoft App Id and your Microsoft App Password-->
<add key="BotId" value="YourBotId"/>
<add key="MicrosoftAppId" value=""/>
<add key="MicrosoftAppPassword" value=""/>
<add key="BotFramework.BotId" value="YourBotId" />
<add key="BotFramework.MicrosoftApplicationId" value="" />
<add key="BotFramework.MicrosoftApplicationPassword" value="" />
</appSettings>
<!--
For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367.
@ -19,273 +19,277 @@
</system.Web>
-->
<system.web>
<customErrors mode="Off"/>
<compilation debug="true" targetFramework="4.6.1"/>
<httpRuntime targetFramework="4.6"/>
<customErrors mode="Off" />
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6" />
</system.web>
<system.webServer>
<defaultDocument>
<files>
<clear/>
<add value="default.htm"/>
<clear />
<add value="default.htm" />
</files>
</defaultDocument>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
<remove name="OPTIONSVerbHandler"/>
<remove name="TRACEVerbHandler"/>
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>
</system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers></system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.Tokens" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.2.1.0" newVersion="5.2.1.0"/>
<assemblyIdentity name="Microsoft.IdentityModel.Tokens" publicKeyToken="31BF3856AD364E35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.1.0" newVersion="5.2.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection.Extensions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Reflection.Extensions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Threading" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.Extensions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
<assemblyIdentity name="System.Runtime.Extensions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Overlapped" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0"/>
<assemblyIdentity name="System.Threading.Overlapped" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Text.Encoding.Extensions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Text.Encoding.Extensions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Text.Encoding" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Text.Encoding" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Globalization" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Globalization" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.SecureString" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0"/>
<assemblyIdentity name="System.Security.SecureString" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Timer" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Threading.Timer" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.InteropServices.RuntimeInformation" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
<assemblyIdentity name="System.Runtime.InteropServices.RuntimeInformation" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Primitives" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Net.Primitives" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Sockets" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<assemblyIdentity name="System.Net.Sockets" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Collections" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Xml.ReaderWriter" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0"/>
<assemblyIdentity name="System.Xml.ReaderWriter" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.Debug" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Diagnostics.Debug" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Resources.ResourceManager" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Resources.ResourceManager" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
<assemblyIdentity name="System.Runtime" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Linq.Queryable" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Linq.Queryable" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.InteropServices" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
<assemblyIdentity name="System.Runtime.InteropServices" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
<assemblyIdentity name="System.IO" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Text.RegularExpressions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0"/>
<assemblyIdentity name="System.Text.RegularExpressions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.Compression" publicKeyToken="B77A5C561934E089" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<assemblyIdentity name="System.IO.Compression" publicKeyToken="B77A5C561934E089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.Contracts" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Diagnostics.Contracts" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.Numerics" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Runtime.Numerics" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ComponentModel.EventBasedAsync" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.ComponentModel.EventBasedAsync" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Collections.Concurrent" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Collections.Concurrent" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.Tracing" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<assemblyIdentity name="System.Diagnostics.Tracing" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Dynamic.Runtime" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Dynamic.Runtime" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection.Primitives" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Reflection.Primitives" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Principal" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Security.Principal" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ComponentModel" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.ComponentModel" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Linq" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
<assemblyIdentity name="System.Linq" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Cryptography.Algorithms" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
<assemblyIdentity name="System.Security.Cryptography.Algorithms" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Linq.Parallel" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Linq.Parallel" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.StackTrace" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0"/>
<assemblyIdentity name="System.Diagnostics.StackTrace" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Xml.XmlSerializer" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Xml.XmlSerializer" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<assemblyIdentity name="System.Net.Http" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
<assemblyIdentity name="System.Reflection" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.NetworkInformation" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
<assemblyIdentity name="System.Net.NetworkInformation" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Xml.XDocument" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Xml.XDocument" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.Serialization.Json" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Runtime.Serialization.Json" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ObjectModel" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.ObjectModel" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0"/>
<assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Linq.Expressions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0"/>
<assemblyIdentity name="System.Linq.Expressions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Parallel" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Threading.Tasks.Parallel" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.Serialization.Primitives" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<assemblyIdentity name="System.Runtime.Serialization.Primitives" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="CC7B13FFCD2DDD51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="CC7B13FFCD2DDD51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.Tools" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
<assemblyIdentity name="System.Diagnostics.Tools" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Requests" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0"/>
<assemblyIdentity name="System.Net.Requests" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.11.0" newVersion="4.0.11.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Data.Common" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0"/>
<assemblyIdentity name="System.Data.Common" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Globalization.Extensions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0"/>
<assemblyIdentity name="System.Globalization.Extensions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.Serialization.Xml" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.3.0" newVersion="4.1.3.0"/>
<assemblyIdentity name="System.Runtime.Serialization.Xml" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.3.0" newVersion="4.1.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0"/>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0"/>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0"/>
<assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0"/>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Unity.Abstractions" publicKeyToken="6d32ff45e0ccc69f" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-3.2.0.0" newVersion="3.2.0.0"/>
<assemblyIdentity name="Unity.Abstractions" publicKeyToken="6d32ff45e0ccc69f" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.2.0.0" newVersion="3.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-5.2.1.0" newVersion="5.2.1.0"/>
<assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.1.0" newVersion="5.2.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.4.0" newVersion="5.2.4.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>

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

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Autofac" version="3.5.2" targetFramework="net46" />
<package id="Chronic.Signed" version="0.3.2" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net46" />
<package id="Microsoft.AspNet.WebApi" version="5.2.4" targetFramework="net461" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.4" targetFramework="net461" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.4" targetFramework="net461" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.4" targetFramework="net461" />
<package id="Microsoft.Extensions.Configuration.Abstractions" version="2.0.0" targetFramework="net461" />
<package id="Microsoft.Extensions.Primitives" version="2.0.0" targetFramework="net461" />
<package id="Microsoft.IdentityModel.Logging" version="5.2.1" targetFramework="net461" />

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

@ -11,6 +11,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;1705; 1998</NoWarn>
<LangVersion>default</LangVersion>
</PropertyGroup>
<ItemGroup>
@ -21,6 +22,7 @@
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Core\Microsoft.Bot.Builder.Core.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder\Microsoft.Bot.Builder.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Schema\Microsoft.Bot.Schema.csproj" />
<ProjectReference Include="..\EchoBot\EchoBot.csproj" />
</ItemGroup>
</Project>

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

@ -1,31 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Middleware;
using Microsoft.Bot.Builder.Storage;
using System;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Schema;
namespace Microsoft.Bot.Samples.EchoBot
namespace Microsoft.Bot.Samples.Echo
{
class Program
{
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
public static void Main(string[] args)
{
Console.WriteLine("Welcome to the EchoBot.");
var adapter = new ConsoleAdapter();
await adapter.ProcessActivity(async (context) =>
var adapter = new ConsoleAdapter()
.Use(new ConversationState<EchoState>(new MemoryStorage()));
adapter.ProcessActivity(async (context) =>
{
if (context.Request.Type == ActivityTypes.Message)
{
context.Reply($"echo: {context.Request.AsMessageActivity().Text}");
}
});
var echoBot = new EchoBot(new MyService());
await echoBot.OnReceiveActivity(context);
}).Wait();
}
}
}

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

@ -13,7 +13,7 @@ namespace Microsoft.Bot.Builder.Azure.Tests
[TestClass]
[TestCategory("Storage")]
[TestCategory("Storage - Azure Tables")]
public class TableStorageTests : Storage_BaseTests, IStorageTests
public class TableStorageTests : Storage_BaseTests
{
private IStorage storage;
@ -52,12 +52,12 @@ namespace Microsoft.Bot.Builder.Azure.Tests
{
if (hasStorageEmulator.Value)
{
storage = new AzureTableStorage("UseDevelopmentStorage=true", TestContext.TestName + TestContext.GetHashCode().ToString("x"));
storage = new AzureTableStorage("UseDevelopmentStorage=true", TestContext.TestName.Replace("_","") + TestContext.GetHashCode().ToString("x"));
}
}
[TestCleanup]
public async Task TestCleanUp()
public async Task TableStorage_TestCleanUp()
{
if (storage != null)
{
@ -77,7 +77,7 @@ namespace Microsoft.Bot.Builder.Azure.Tests
// NOTE: THESE TESTS REQUIRE THAT THE AZURE STORAGE EMULATOR IS INSTALLED AND STARTED !!!!!!!!!!!!!!!!!
[TestMethod]
public async Task CreateObjectTest()
public async Task TableStorage_CreateObjectTest()
{
if (CheckStorageEmulator())
await base._createObjectTest(storage);
@ -85,7 +85,7 @@ namespace Microsoft.Bot.Builder.Azure.Tests
// NOTE: THESE TESTS REQUIRE THAT THE AZURE STORAGE EMULATOR IS INSTALLED AND STARTED !!!!!!!!!!!!!!!!!
[TestMethod]
public async Task ReadUnknownTest()
public async Task TableStorage_ReadUnknownTest()
{
if (CheckStorageEmulator())
await base._readUnknownTest(storage);
@ -93,7 +93,7 @@ namespace Microsoft.Bot.Builder.Azure.Tests
// NOTE: THESE TESTS REQUIRE THAT THE AZURE STORAGE EMULATOR IS INSTALLED AND STARTED !!!!!!!!!!!!!!!!!
[TestMethod]
public async Task UpdateObjectTest()
public async Task TableStorage_UpdateObjectTest()
{
if (CheckStorageEmulator())
await base._updateObjectTest(storage);
@ -101,7 +101,7 @@ namespace Microsoft.Bot.Builder.Azure.Tests
// NOTE: THESE TESTS REQUIRE THAT THE AZURE STORAGE EMULATOR IS INSTALLED AND STARTED !!!!!!!!!!!!!!!!!
[TestMethod]
public async Task DeleteObjectTest()
public async Task TableStorage_DeleteObjectTest()
{
if (CheckStorageEmulator())
await base._deleteObjectTest(storage);
@ -109,14 +109,14 @@ namespace Microsoft.Bot.Builder.Azure.Tests
// NOTE: THESE TESTS REQUIRE THAT THE AZURE STORAGE EMULATOR IS INSTALLED AND STARTED !!!!!!!!!!!!!!!!!
[TestMethod]
public async Task HandleCrazyKeys()
public async Task TableStorage_HandleCrazyKeys()
{
if (CheckStorageEmulator())
await base._handleCrazyKeys(storage);
}
[TestMethod]
public async Task TypedSerialization()
public async Task TableStorage_TypedSerialization()
{
if (CheckStorageEmulator())
await base._typedSerialization(this.storage);

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

@ -0,0 +1,219 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Cognitive.LUIS;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Bot.Builder.Tests;
namespace Microsoft.Bot.Builder.LUIS.Tests
{
[TestClass]
/*
* The LUIS application used in these unit tests is in TestData/TestLuistApp
*/
public class LuisRecognizerTests
{
private readonly string _luisAppId = TestUtilities.GetKey("LUISAPPID");
private readonly string _subscriptionKey = TestUtilities.GetKey("LUISAPPKEY");
private readonly string _luisUriBase = TestUtilities.GetKey("LUISURIBASE");
[TestMethod]
public async Task SingleIntent_SimplyEntity()
{
if (EnvironmentVariablesDefined())
{
Debug.WriteLine($"Missing Luis Environemnt variables - Skipping test");
return;
}
var luisRecognizer = GetLuisRecognizer(verbose: true);
var result = await luisRecognizer.Recognize("My name is Emad", CancellationToken.None);
Assert.IsNotNull(result);
Assert.AreEqual("My name is Emad", result.Text);
Assert.IsNotNull(result.Intents);
Assert.AreEqual(1, result.Intents.Count);
Assert.IsNotNull(result.Intents["SpecifyName"]);
Assert.IsTrue((double)result.Intents["SpecifyName"] > 0 && (double)result.Intents["SpecifyName"] <= 1);
Assert.IsNotNull(result.Entities);
Assert.IsNotNull(result.Entities["Name"]);
Assert.AreEqual("emad", (string)result.Entities["Name"].First);
Assert.IsNotNull(result.Entities["$instance"]);
Assert.IsNotNull(result.Entities["$instance"]["Name"]);
Assert.AreEqual(11, (int)result.Entities["$instance"]["Name"].First["startIndex"]);
Assert.AreEqual(14, (int)result.Entities["$instance"]["Name"].First["endIndex"]);
Assert.IsTrue((double)result.Entities["$instance"]["Name"].First["score"] > 0 && (double)result.Entities["$instance"]["Name"].First["score"] <= 1);
}
[TestMethod]
public async Task MultipleIntents_PrebuiltEntity()
{
if (EnvironmentVariablesDefined())
{
Debug.WriteLine($"Missing Luis Environemnt variables - Skipping test");
return;
}
var luisRecognizer = GetLuisRecognizer(verbose: true, luisOptions: new LuisRequest { Verbose = true });
var result = await luisRecognizer.Recognize("Please deliver February 2nd 2001", CancellationToken.None);
Assert.IsNotNull(result);
Assert.AreEqual("Please deliver February 2nd 2001", result.Text);
Assert.IsNotNull(result.Intents);
Assert.IsTrue(result.Intents.Count > 1);
Assert.IsNotNull(result.Intents["Delivery"]);
Assert.IsTrue((double)result.Intents["Delivery"] > 0 && (double)result.Intents["Delivery"] <= 1);
Assert.IsNotNull(result.Entities);
Assert.IsNotNull(result.Entities["builtin_number"]);
Assert.AreEqual(2001, (int)result.Entities["builtin_number"].First);
Assert.IsNotNull(result.Entities["builtin_datetimeV2_date"]);
Assert.AreEqual("2001-02-02", (string)result.Entities["builtin_datetimeV2_date"].First);
Assert.IsNotNull(result.Entities["$instance"]["builtin_number"]);
Assert.AreEqual(28, (int)result.Entities["$instance"]["builtin_number"].First["startIndex"]);
Assert.AreEqual(31, (int)result.Entities["$instance"]["builtin_number"].First["endIndex"]);
Assert.AreEqual("2001", (string)result.Entities["$instance"]["builtin_number"].First["text"]);
Assert.IsNotNull(result.Entities["$instance"]["builtin_datetimeV2_date"]);
Assert.AreEqual(15, (int)result.Entities["$instance"]["builtin_datetimeV2_date"].First["startIndex"]);
Assert.AreEqual(31, (int)result.Entities["$instance"]["builtin_datetimeV2_date"].First["endIndex"]);
Assert.AreEqual("february 2nd 2001", (string)result.Entities["$instance"]["builtin_datetimeV2_date"].First["text"]);
}
[TestMethod]
public async Task MultipleIntents_PrebuiltEntitiesWithMultiValues()
{
if (EnvironmentVariablesDefined())
{
Debug.WriteLine($"Missing Luis Environemnt variables - Skipping test");
return;
}
var luisRecognizer = GetLuisRecognizer(verbose: true, luisOptions: new LuisRequest { Verbose = true });
var result = await luisRecognizer.Recognize("Please deliver February 2nd 2001 in room 201", CancellationToken.None);
Assert.IsNotNull(result);
Assert.IsNotNull(result.Text);
Assert.AreEqual("Please deliver February 2nd 2001 in room 201", result.Text);
Assert.IsNotNull(result.Intents);
Assert.IsNotNull(result.Intents["Delivery"]);
Assert.IsNotNull(result.Entities);
Assert.IsNotNull(result.Entities["builtin_number"]);
Assert.AreEqual(2, result.Entities["builtin_number"].Count());
Assert.IsTrue(result.Entities["builtin_number"].Any(v => (int)v == 201));
Assert.IsTrue(result.Entities["builtin_number"].Any(v => (int)v == 2001));
Assert.IsNotNull(result.Entities["builtin_datetimeV2_date"]);
Assert.AreEqual("2001-02-02", (string)result.Entities["builtin_datetimeV2_date"].First);
}
[TestMethod]
public async Task MultipleIntents_ListEntityWithSingleValue()
{
if (EnvironmentVariablesDefined())
{
Debug.WriteLine($"Missing Luis Environemnt variables - Skipping test");
return;
}
var luisRecognizer = GetLuisRecognizer(verbose: true, luisOptions: new LuisRequest { Verbose = true });
var result = await luisRecognizer.Recognize("I want to travel on united", CancellationToken.None);
Assert.IsNotNull(result);
Assert.IsNotNull(result.Text);
Assert.AreEqual("I want to travel on united", result.Text);
Assert.IsNotNull(result.Intents);
Assert.IsNotNull(result.Intents["Travel"]);
Assert.IsNotNull(result.Entities);
Assert.IsNotNull(result.Entities["Airline"]);
Assert.AreEqual("United", result.Entities["Airline"][0][0]);
Assert.IsNotNull(result.Entities["$instance"]);
Assert.IsNotNull(result.Entities["$instance"]["Airline"]);
Assert.AreEqual(20, result.Entities["$instance"]["Airline"][0]["startIndex"]);
Assert.AreEqual(25, result.Entities["$instance"]["Airline"][0]["endIndex"]);
Assert.AreEqual("united", result.Entities["$instance"]["Airline"][0]["text"]);
}
[TestMethod]
public async Task MultipleIntents_ListEntityWithMultiValues()
{
if (EnvironmentVariablesDefined())
{
Debug.WriteLine($"Missing Luis Environemnt variables - Skipping test");
return;
}
var luisRecognizer = GetLuisRecognizer(verbose: true, luisOptions: new LuisRequest { Verbose = true });
var result = await luisRecognizer.Recognize("I want to travel on DL", CancellationToken.None);
Assert.IsNotNull(result);
Assert.IsNotNull(result.Text);
Assert.AreEqual("I want to travel on DL", result.Text);
Assert.IsNotNull(result.Intents);
Assert.IsNotNull(result.Intents["Travel"]);
Assert.IsNotNull(result.Entities);
Assert.IsNotNull(result.Entities["Airline"]);
Assert.AreEqual(2, result.Entities["Airline"][0].Count());
Assert.IsTrue(result.Entities["Airline"][0].Any(airline => (string)airline == "Delta"));
Assert.IsTrue(result.Entities["Airline"][0].Any(airline => (string)airline == "Virgin"));
Assert.IsNotNull(result.Entities["$instance"]);
Assert.IsNotNull(result.Entities["$instance"]["Airline"]);
Assert.AreEqual(20, result.Entities["$instance"]["Airline"][0]["startIndex"]);
Assert.AreEqual(21, result.Entities["$instance"]["Airline"][0]["endIndex"]);
Assert.AreEqual("dl", result.Entities["$instance"]["Airline"][0]["text"]);
}
[TestMethod]
public async Task MultipleIntens_CompositeEntity()
{
if (EnvironmentVariablesDefined())
{
Debug.WriteLine($"Missing Luis Environemnt variables - Skipping test");
return;
}
var luisRecognizer = GetLuisRecognizer(verbose: true, luisOptions: new LuisRequest { Verbose = true });
var result = await luisRecognizer.Recognize("Please deliver it to 98033 WA", CancellationToken.None);
Assert.IsNotNull(result);
Assert.IsNotNull(result.Text);
Assert.AreEqual("Please deliver it to 98033 WA", result.Text);
Assert.IsNotNull(result.Intents);
Assert.IsNotNull(result.Intents["Delivery"]);
Assert.IsNotNull(result.Entities);
Assert.IsNull(result.Entities["builtin_number"]);
Assert.IsNull(result.Entities["State"]);
Assert.IsNotNull(result.Entities["Address"]);
Assert.AreEqual(98033, result.Entities["Address"][0]["builtin_number"][0]);
Assert.AreEqual("wa", result.Entities["Address"][0]["State"][0]);
Assert.IsNotNull(result.Entities["$instance"]);
Assert.IsNull(result.Entities["$instance"]["builtin_number"]);
Assert.IsNull(result.Entities["$instance"]["State"]);
Assert.IsNotNull(result.Entities["$instance"]["Address"]);
Assert.AreEqual(21, result.Entities["$instance"]["Address"][0]["startIndex"]);
Assert.AreEqual(28, result.Entities["$instance"]["Address"][0]["endIndex"]);
Assert.IsTrue((double)result.Entities["$instance"]["Address"][0]["score"] >= 0 && (double)result.Entities["$instance"]["Address"][0]["score"] <= 1);
Assert.IsNotNull(result.Entities["Address"][0]["$instance"]);
Assert.IsNotNull(result.Entities["Address"][0]["$instance"]["builtin_number"]);
Assert.AreEqual(21, result.Entities["Address"][0]["$instance"]["builtin_number"][0]["startIndex"]);
Assert.AreEqual(25, result.Entities["Address"][0]["$instance"]["builtin_number"][0]["endIndex"]);
Assert.AreEqual("98033", result.Entities["Address"][0]["$instance"]["builtin_number"][0]["text"]);
Assert.IsNotNull(result.Entities["Address"][0]["$instance"]["State"]);
Assert.AreEqual(27, result.Entities["Address"][0]["$instance"]["State"][0]["startIndex"]);
Assert.AreEqual(28, result.Entities["Address"][0]["$instance"]["State"][0]["endIndex"]);
Assert.AreEqual("wa", result.Entities["Address"][0]["$instance"]["State"][0]["text"]);
Assert.IsTrue((double)result.Entities["Address"][0]["$instance"]["State"][0]["score"] >= 0 && (double)result.Entities["Address"][0]["$instance"]["State"][0]["score"] <= 1);
}
private bool EnvironmentVariablesDefined()
{
return _luisAppId == null || _subscriptionKey == null || _luisUriBase == null;
}
private IRecognizer GetLuisRecognizer(bool verbose = false, ILuisOptions luisOptions = null)
{
var luisRecognizerOptions = new LuisRecognizerOptions { Verbose = verbose };
var luisModel = new LuisModel(_luisAppId, _subscriptionKey, new Uri(_luisUriBase), LuisApiVersion.V2);
return new LuisRecognizer(luisModel, luisRecognizerOptions, luisOptions);
}
}
}

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

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="MSTest.TestAdapter" Version="1.2.0" />
<PackageReference Include="MSTest.TestFramework" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="TestData\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.LUIS\Microsoft.Bot.Builder.LUIS.csproj" />
<ProjectReference Include="..\Microsoft.Bot.Builder.Tests\Microsoft.Bot.Builder.Tests.csproj" />
</ItemGroup>
</Project>

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

@ -0,0 +1,489 @@
{
"luis_schema_version": "2.1.0",
"versionId": "0.1",
"name": "Contoso App",
"desc": "Default Intents for Azure Bot Service V2",
"culture": "en-us",
"intents": [
{
"name": "Cancel"
},
{
"name": "Delivery"
},
{
"name": "Greeting"
},
{
"name": "Help"
},
{
"name": "None"
},
{
"name": "SpecifyName"
},
{
"name": "Travel"
}
],
"entities": [
{
"name": "Name"
},
{
"name": "State"
},
{
"name": "City",
"children": [
"To",
"From"
]
}
],
"composites": [
{
"name": "Address",
"children": [
"number",
"State"
]
}
],
"closedLists": [
{
"name": "Airline",
"subLists": [
{
"canonicalForm": "Delta",
"list": [
"DL"
]
},
{
"canonicalForm": "Alaska",
"list": []
},
{
"canonicalForm": "United",
"list": []
},
{
"canonicalForm": "Virgin",
"list": [
"DL"
]
}
]
}
],
"bing_entities": [
"datetimeV2",
"money",
"number"
],
"model_features": [],
"regex_features": [],
"utterances": [
{
"text": "abort",
"intent": "Cancel",
"entities": []
},
{
"text": "cancel",
"intent": "Cancel",
"entities": []
},
{
"text": "delivery address is in 45654 ga",
"intent": "Delivery",
"entities": [
{
"entity": "Address",
"startPos": 23,
"endPos": 30
},
{
"entity": "State",
"startPos": 29,
"endPos": 30
}
]
},
{
"text": "disregard",
"intent": "Cancel",
"entities": []
},
{
"text": "do not do it",
"intent": "Cancel",
"entities": []
},
{
"text": "do not do that",
"intent": "Cancel",
"entities": []
},
{
"text": "don't",
"intent": "Cancel",
"entities": []
},
{
"text": "don't do it",
"intent": "Cancel",
"entities": []
},
{
"text": "don't do that",
"intent": "Cancel",
"entities": []
},
{
"text": "good afternoon",
"intent": "Greeting",
"entities": []
},
{
"text": "good evening",
"intent": "Greeting",
"entities": []
},
{
"text": "good morning",
"intent": "Greeting",
"entities": []
},
{
"text": "good night",
"intent": "Greeting",
"entities": []
},
{
"text": "he is yousef",
"intent": "SpecifyName",
"entities": [
{
"entity": "Name",
"startPos": 6,
"endPos": 11
}
]
},
{
"text": "hello",
"intent": "Greeting",
"entities": []
},
{
"text": "hello bot",
"intent": "Greeting",
"entities": []
},
{
"text": "help",
"intent": "Help",
"entities": []
},
{
"text": "help me",
"intent": "Help",
"entities": []
},
{
"text": "help me please",
"intent": "Help",
"entities": []
},
{
"text": "help please",
"intent": "Help",
"entities": []
},
{
"text": "hi",
"intent": "Greeting",
"entities": []
},
{
"text": "hi bot",
"intent": "Greeting",
"entities": []
},
{
"text": "his name is tom",
"intent": "SpecifyName",
"entities": [
{
"entity": "Name",
"startPos": 12,
"endPos": 14
}
]
},
{
"text": "hiya",
"intent": "Greeting",
"entities": []
},
{
"text": "how are you",
"intent": "Greeting",
"entities": []
},
{
"text": "how are you doing today?",
"intent": "Greeting",
"entities": []
},
{
"text": "how are you doing?",
"intent": "Greeting",
"entities": []
},
{
"text": "how are you today?",
"intent": "Greeting",
"entities": []
},
{
"text": "i am lili",
"intent": "SpecifyName",
"entities": [
{
"entity": "Name",
"startPos": 5,
"endPos": 8
}
]
},
{
"text": "i am stuck",
"intent": "Help",
"entities": []
},
{
"text": "i want this in 98052 wa",
"intent": "Delivery",
"entities": [
{
"entity": "Address",
"startPos": 15,
"endPos": 22
},
{
"entity": "State",
"startPos": 21,
"endPos": 22
}
]
},
{
"text": "i want to arrive at newyork",
"intent": "Travel",
"entities": [
{
"entity": "City::To",
"startPos": 20,
"endPos": 26
}
]
},
{
"text": "i want to fly out of seattle",
"intent": "Travel",
"entities": [
{
"entity": "City::From",
"startPos": 21,
"endPos": 27
}
]
},
{
"text": "i want to travel",
"intent": "Travel",
"entities": []
},
{
"text": "i want to travel from seattle to dallas",
"intent": "Travel",
"entities": [
{
"entity": "City::From",
"startPos": 22,
"endPos": 28
},
{
"entity": "City::To",
"startPos": 33,
"endPos": 38
}
]
},
{
"text": "i would like to cancel",
"intent": "Cancel",
"entities": []
},
{
"text": "i'll be leaving from cairo to paris",
"intent": "Travel",
"entities": [
{
"entity": "City::From",
"startPos": 21,
"endPos": 25
},
{
"entity": "City::To",
"startPos": 30,
"endPos": 34
}
]
},
{
"text": "i'm stuck",
"intent": "Help",
"entities": []
},
{
"text": "my name is emad",
"intent": "SpecifyName",
"entities": [
{
"entity": "Name",
"startPos": 11,
"endPos": 14
}
]
},
{
"text": "my water bottle is green.",
"intent": "None",
"entities": []
},
{
"text": "never mind",
"intent": "Cancel",
"entities": []
},
{
"text": "please cancel",
"intent": "Cancel",
"entities": []
},
{
"text": "please deliver to 98033 wa",
"intent": "Delivery",
"entities": [
{
"entity": "Address",
"startPos": 18,
"endPos": 25
},
{
"entity": "State",
"startPos": 24,
"endPos": 25
}
]
},
{
"text": "please disregard",
"intent": "Cancel",
"entities": []
},
{
"text": "please help me",
"intent": "Help",
"entities": []
},
{
"text": "please stop",
"intent": "Cancel",
"entities": []
},
{
"text": "stop",
"intent": "Cancel",
"entities": []
},
{
"text": "the address is 66666 fl",
"intent": "Delivery",
"entities": [
{
"entity": "Address",
"startPos": 15,
"endPos": 22
},
{
"entity": "State",
"startPos": 21,
"endPos": 22
}
]
},
{
"text": "there is a large deep dish pizza in your future.",
"intent": "None",
"entities": []
},
{
"text": "this is chris",
"intent": "SpecifyName",
"entities": [
{
"entity": "Name",
"startPos": 8,
"endPos": 12
}
]
},
{
"text": "this is requested in 55555 ny",
"intent": "Delivery",
"entities": [
{
"entity": "State",
"startPos": 27,
"endPos": 28
}
]
},
{
"text": "what can i say",
"intent": "Help",
"entities": []
},
{
"text": "what can you do",
"intent": "Help",
"entities": []
},
{
"text": "what can you help me with",
"intent": "Help",
"entities": []
},
{
"text": "what do i do now?",
"intent": "Help",
"entities": []
},
{
"text": "what do i do?",
"intent": "Help",
"entities": []
},
{
"text": "why doesn't this work ?",
"intent": "Help",
"entities": []
}
]
}

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

@ -9,6 +9,10 @@
<NoWarn>1701;1702;1705;1998</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1701;1702;1705;1998</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="Microsoft.Recognizers.Text" Version="1.0.0.36" />

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

@ -9,6 +9,10 @@
<NoWarn>1701;1702;1705;1998</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1701;1702;1705;1998</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="MSTest.TestAdapter" Version="1.2.0" />

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

@ -1,17 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.Middleware;
using Microsoft.Bot.Builder.Storage;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder.Tests
{
public class TestState : StoreItem
public class TestState : IStoreItem
{
public string eTag { get ; set; }
public string Value { get; set; }
}
public class TestPocoState
{
public string Value { get; set; }
}
@ -37,7 +42,7 @@ namespace Microsoft.Bot.Builder.Tests
}
[TestMethod]
public async Task State_RememberUserState()
public async Task State_RememberIStoreItemUserState()
{
var adapter = new TestAdapter()
.Use(new UserState<TestState>(new MemoryStorage()));
@ -64,7 +69,34 @@ namespace Microsoft.Bot.Builder.Tests
}
[TestMethod]
public async Task State_RememberConversationState()
public async Task State_RememberPocoUserState()
{
var adapter = new TestAdapter()
.Use(new UserState<TestPocoState>(new MemoryStorage()));
await new TestFlow(adapter,
async (context) =>
{
var userState = context.GetUserState<TestPocoState>();
Assert.IsNotNull(userState, "user state should exist");
switch (context.Request.AsMessageActivity().Text)
{
case "set value":
userState.Value = "test";
context.Reply("value saved");
break;
case "get value":
context.Reply(userState.Value);
break;
}
}
)
.Test("set value", "value saved")
.Test("get value", "test")
.StartTest();
}
[TestMethod]
public async Task State_RememberIStoreItemConversationState()
{
TestAdapter adapter = new TestAdapter()
.Use(new ConversationState<TestState>(new MemoryStorage()));
@ -90,6 +122,33 @@ namespace Microsoft.Bot.Builder.Tests
.StartTest();
}
[TestMethod]
public async Task State_RememberPocoConversationState()
{
TestAdapter adapter = new TestAdapter()
.Use(new ConversationState<TestPocoState>(new MemoryStorage()));
await new TestFlow(adapter,
async (context) =>
{
var conversationState = context.GetConversationState<TestPocoState>();
Assert.IsNotNull(conversationState, "state.conversation should exist");
switch (context.Request.AsMessageActivity().Text)
{
case "set value":
conversationState.Value = "test";
context.Reply("value saved");
break;
case "get value":
context.Reply(conversationState.Value);
break;
}
}
)
.Test("set value", "value saved")
.Test("get value", "test")
.StartTest();
}
[TestMethod]
public async Task State_CustomStateManagerTest()
{

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

@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@ -18,27 +19,42 @@ namespace Microsoft.Bot.Builder.Tests
protected async Task _createObjectTest(IStorage storage)
{
var storeItems = new StoreItems();
storeItems["create1"] = new TestItem() { Id = "1" };
dynamic newItem2 = new TestItem() { Id = "2" };
newItem2.dyno = "dynamicStuff";
storeItems["create2"] = newItem2;
dynamic storeItems = new StoreItems();
storeItems.createPoco = new PocoItem() { Id = "1" };
storeItems.createPocoStoreItem = new PocoStoreItem() { Id = "2" };
storeItems.createStoreItem = new StoreItem();
storeItems.createStoreItem.Id = "3" ;
storeItems.createStoreItem.dyno = "dynamicStuff";
await storage.Write(storeItems);
dynamic result = await storage.Read(new string[] { "create1", "create2" });
Assert.IsNotNull(result.create1, "create1 should not be null");
Assert.AreEqual(result.create1.Id, "1", "strong create1.id should be 1");
Assert.IsNotNull(result.create2, "create2 should not be null");
Assert.AreEqual(result.create2.Id, "2", "create2.id should be 2");
Assert.AreEqual(result.create2.dyno, "dynamicStuff", "create2.dyno should be dynoStuff");
dynamic result = await storage.Read(((StoreItems)storeItems).GetDynamicMemberNames().ToArray());
Assert.IsInstanceOfType(result.createPoco, typeof(PocoItem));
Assert.IsInstanceOfType(result.createPocoStoreItem, typeof(PocoStoreItem));
Assert.IsInstanceOfType(result.createStoreItem, typeof(StoreItem));
Assert.IsNotNull(result.createPoco, "createPoco should not be null");
Assert.AreEqual(result.createPoco.Id, "1", "createPoco.id should be 1");
Assert.IsNotNull(result.createPocoStoreItem, "createPocoStoreItem should not be null");
Assert.AreEqual(result.createPocoStoreItem.Id, "2", "createPocoStoreItem.id should be 2");
Assert.IsNotNull(result.createPocoStoreItem.eTag, "createPocoStoreItem.eTag should not be null");
Assert.IsNotNull(result.createStoreItem, "createStoreItem should not be null");
Assert.AreEqual(result.createStoreItem.Id, "3", "createStoreItem.id should be 3");
Assert.IsNotNull(result.createStoreItem.eTag, "CreateStoreItem.eTag should not be null");
Assert.AreEqual(result.createStoreItem.dyno, "dynamicStuff", "createStoreItem.dyno should be dynoStuff");
}
protected async Task _handleCrazyKeys(IStorage storage)
{
var storeItems = new StoreItems();
string key = "!@#$%^&*()~/\\><,.?';\"`~";
storeItems[key] = new TestItem() { Id = "1" };
storeItems[key] = new PocoStoreItem() { Id = "1" };
await storage.Write(storeItems);
@ -56,7 +72,8 @@ namespace Microsoft.Bot.Builder.Tests
{
string key = "typed";
var storeItems = new StoreItems();
dynamic testItem = new TestItem() { Id = "1" };
dynamic testItem = new StoreItem();
testItem.Id = "1";
testItem.x = new TypedObject() { Name = "test" };
storeItems[key] = testItem;
@ -71,61 +88,122 @@ namespace Microsoft.Bot.Builder.Tests
protected async Task _updateObjectTest(IStorage storage)
{
dynamic storeItems = new StoreItems();
storeItems.update = new TestItem() { Id = "1", Count = 1 };
storeItems.updatePocoItem = new PocoItem() { Id = "1", Count = 1 };
storeItems.updatePocoStoreItem = new PocoStoreItem() { Id = "1", Count = 1 };
storeItems.updateStoreItem = new StoreItem();
storeItems.updateStoreItem.Id = "3";
storeItems.updateStoreItem.Count = 1;
//first write should work
await storage.Write(storeItems);
dynamic result = await storage.Read("update");
Assert.IsTrue(!String.IsNullOrEmpty(result.update.eTag), "etag should be set");
Assert.AreEqual(result.update.Count, 1, "count should be 1");
dynamic result = await storage.Read(((StoreItems)storeItems).GetDynamicMemberNames().ToArray());
Assert.IsNotNull(result.updatePocoStoreItem.eTag, "updatePocoItem.eTag should not be null");
Assert.IsNotNull(result.updateStoreItem.eTag, "updateStoreItem.eTag should not be null");
// 2nd write should work, because we have new etag
result.update.Count++;
// 2nd write should work, because we have new etag, or no etag
result.updatePocoItem.Count++;
result.updatePocoStoreItem.Count++;
result.updateStoreItem.Count++;
await storage.Write(result);
dynamic result2 = await storage.Read("update");
Assert.IsTrue(!String.IsNullOrEmpty(result2.update.eTag), "etag should be set on second write too");
Assert.AreNotEqual(result.update.eTag, result2.update.eTag, "etag should be differnt on new write");
Assert.AreEqual(result2.update.Count, 2, "Count should be 2");
dynamic result2 = await storage.Read(((StoreItems)storeItems).GetDynamicMemberNames().ToArray());
Assert.IsNotNull(result2.updatePocoStoreItem.eTag, "updatePocoItem.eTag should not be null");
Assert.IsNotNull(result2.updateStoreItem.eTag, "updateStoreItem.eTag should not be null");
Assert.AreNotEqual(result.updatePocoStoreItem.eTag, result2.updatePocoStoreItem.eTag, "updatePocoItem.eTag should not be different");
Assert.AreNotEqual(result.updateStoreItem.eTag, result2.updateStoreItem.eTag, "updateStoreItem.eTag should not be different");
Assert.AreEqual(result2.updatePocoItem.Count, 2, "updatePocoItem.Count should be 2");
Assert.AreEqual(result2.updatePocoStoreItem.Count, 2, "updatePocoStoreItem.Count should be 2");
Assert.AreEqual(result2.updateStoreItem.Count, 2, "updateStoreItem.Count should be 2");
// write with old etag should fail
// write with old etag should succeed for updatePocoItem, but fail for the other 2
try
{
await storage.Write(result);
Assert.Fail("Should throw exception on write with old etag");
dynamic storeItemsUpdate = new StoreItems();
storeItemsUpdate.updatePocoItem = result.updatePocoItem;
storeItemsUpdate.updatePocoItem.Count++;
await storage.Write(storeItemsUpdate);
}
catch
{
Assert.Fail("Should not throw exception on write with pocoItem");
}
catch { }
dynamic result3 = await storage.Read("update");
Assert.AreEqual(result3.update.Count, 2, "count should still be be two");
try
{
dynamic storeItemsUpdate = new StoreItems();
storeItemsUpdate.updatePocoStoreItem = result.updatePocoStoreItem;
storeItemsUpdate.updatePocoStoreItem.Count++;
await storage.Write(storeItemsUpdate);
Assert.Fail("Should not throw exception on write with pocoStoreItem because of old etag");
}
catch
{
}
try
{
dynamic storeItemsUpdate = new StoreItems();
storeItemsUpdate.updateStoreItem = result.updateStoreItem;
storeItemsUpdate.updateStoreItem.Count++;
await storage.Write(storeItemsUpdate);
Assert.Fail("Should not throw exception on write with StoreItem because of old etag");
}
catch
{
}
dynamic result3 = await storage.Read(((StoreItems)storeItems).GetDynamicMemberNames().ToArray());
Assert.AreEqual(result3.updatePocoItem.Count, 3, "updatePocoItem.Count should be 3");
Assert.AreEqual(result3.updatePocoStoreItem.Count, 2, "updatePocoStoreItem.Count should be 2");
Assert.AreEqual(result3.updateStoreItem.Count, 2, "updateStoreItem.Count should be 2");
// write with wildcard etag should work
result3.update.Count = 100;
result3.update.eTag = "*";
result3.updatePocoItem.Count = 100;
result3.updatePocoStoreItem.Count = 100;
result3.updatePocoStoreItem.eTag = "*";
result3.updateStoreItem.Count = 100;
result3.updateStoreItem.eTag = "*";
await storage.Write(result3);
dynamic result4 = await storage.Read("update");
Assert.AreEqual(result4.update.Count, 100, "count should be 100");
dynamic result4 = await storage.Read(((StoreItems)storeItems).GetDynamicMemberNames().ToArray());
Assert.AreEqual(result3.updatePocoItem.Count, 100, "updatePocoItem.Count should be 100");
Assert.AreEqual(result3.updatePocoStoreItem.Count, 100, "updatePocoStoreItem.Count should be 100");
Assert.AreEqual(result3.updateStoreItem.Count, 100, "updateStoreItem.Count should be 100");
// write with empty etag should not work
result4.update.Count = 200;
result4.update.eTag = "";
try
{
await storage.Write(result4);
Assert.Fail("Should throw exception on write with empty etag");
dynamic storeItemsUpdate = new StoreItems();
storeItemsUpdate.updatePocoStoreItem = FlexObject.Clone(result4.updatePocoStoreItem);
storeItemsUpdate.updatePocoStoreItem.eTag = "";
await storage.Write(result);
Assert.Fail("Should not throw exception on write with pocoStoreItem because of empty etag");
}
catch
{
}
try
{
dynamic storeItemsUpdate = new StoreItems();
storeItemsUpdate.updateStoreItem = FlexObject.Clone(result4.updateStoreItem);
storeItemsUpdate.updateStoreItem.eTag = "";
await storage.Write(result);
Assert.Fail("Should not throw exception on write with storeItem because of empty etag");
}
catch
{
}
catch { }
dynamic result5 = await storage.Read("update");
Assert.AreEqual(result5.update.Count, 100, "count should be 100");
dynamic result5 = await storage.Read(((StoreItems)storeItems).GetDynamicMemberNames().ToArray());
Assert.AreEqual(result3.updatePocoItem.Count, 100, "updatePocoItem.Count should be 100");
Assert.AreEqual(result3.updatePocoStoreItem.Count, 100, "updatePocoStoreItem.Count should be 100");
Assert.AreEqual(result3.updateStoreItem.Count, 100, "updateStoreItem.Count should be 100");
}
protected async Task _deleteObjectTest(IStorage storage)
{
dynamic storeItems = new StoreItems();
storeItems.delete1 = new TestItem() { Id = "1", Count = 1 };
storeItems.delete1 = new PocoStoreItem() { Id = "1", Count = 1 };
//first write should work
await storage.Write(storeItems);

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

@ -12,7 +12,7 @@ namespace Microsoft.Bot.Builder.Tests
[TestClass]
[TestCategory("Storage")]
[TestCategory("Storage - File")]
public class Storage_FileTests : Storage_BaseTests, IStorageTests
public class Storage_FileTests : Storage_BaseTests
{
private IStorage storage;
public Storage_FileTests() { }
@ -29,37 +29,37 @@ namespace Microsoft.Bot.Builder.Tests
}
[TestMethod]
public async Task CreateObjectTest()
public async Task FileStorage_CreateObjectTest()
{
await base._createObjectTest(this.storage);
}
[TestMethod]
public async Task ReadUnknownTest()
public async Task FileStorage_ReadUnknownTest()
{
await base._readUnknownTest(this.storage);
}
[TestMethod]
public async Task UpdateObjectTest()
public async Task FileStorage_UpdateObjectTest()
{
await base._updateObjectTest(this.storage);
}
[TestMethod]
public async Task DeleteObjectTest()
public async Task FileStorage_DeleteObjectTest()
{
await base._deleteObjectTest(this.storage);
}
[TestMethod]
public async Task HandleCrazyKeys()
public async Task FileStorage_HandleCrazyKeys()
{
await base._handleCrazyKeys(this.storage);
}
[TestMethod]
public async Task TypedSerialization()
public async Task FileStorage_TypedSerialization()
{
await base._typedSerialization(this.storage);
}

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

@ -10,11 +10,11 @@ namespace Microsoft.Bot.Builder.Tests
[TestClass]
[TestCategory("Storage")]
[TestCategory("Storage - Memory")]
public class Storage_MemoryTests : Storage_BaseTests, IStorageTests
public class MemoryStorageTests : Storage_BaseTests
{
private IStorage storage;
public Storage_MemoryTests() { }
public MemoryStorageTests() { }
[TestInitialize]
public void initialize()
@ -23,59 +23,56 @@ namespace Microsoft.Bot.Builder.Tests
}
[TestMethod]
public async Task CreateObjectTest()
public async Task MemoryStorage_CreateObjectTest()
{
await base._createObjectTest(storage);
}
[TestMethod]
public async Task ReadUnknownTest()
public async Task MemoryStorage_ReadUnknownTest()
{
await base._readUnknownTest(storage);
}
[TestMethod]
public async Task UpdateObjectTest()
public async Task MemoryStorage_UpdateObjectTest()
{
await base._updateObjectTest(storage);
}
[TestMethod]
public async Task DeleteObjectTest()
public async Task MemoryStorage_DeleteObjectTest()
{
await base._deleteObjectTest(storage);
}
[TestMethod]
public async Task HandleCrazyKeys()
public async Task MemoryStorage_HandleCrazyKeys()
{
await base._handleCrazyKeys(storage);
}
[TestMethod]
public async Task TypedSerialization()
public async Task MemoryStorage_TypedSerialization()
{
await base._typedSerialization(this.storage);
}
}
public class TestItem : StoreItem
public class PocoItem
{
public string Id { get; set; }
public int Count { get; set; }
}
public interface IStorageTests
public class PocoStoreItem : IStoreItem
{
Task ReadUnknownTest();
public string eTag { get; set; }
Task CreateObjectTest();
public string Id { get; set; }
Task HandleCrazyKeys();
Task UpdateObjectTest();
Task DeleteObjectTest();
public int Count { get; set; }
}
}

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

@ -56,13 +56,14 @@ namespace Microsoft.Bot.Connector.Tests
}
[Fact]
public async void EmptyHeader_BotWithNoCredentials_ShouldValidate()
public async void EmptyHeader_BotWithNoCredentials_ShouldThrow()
{
var header = "";
var credentials = new SimpleCredentialProvider("", "");
var result = await JwtTokenValidation.ValidateAuthHeader(header, credentials, null, emptyClient);
Assert.True(result.IsAuthenticated);
await Assert.ThrowsAsync<ArgumentNullException>(
async () => await JwtTokenValidation.ValidateAuthHeader(header, credentials, null, emptyClient));
}
[Fact]
@ -108,7 +109,7 @@ namespace Microsoft.Bot.Connector.Tests
/// Tests with a valid Token and invalid service url; and ensures that Service url is NOT added to Trusted service url list.
/// </summary>
[Fact]
public async void Channel_MsaHeader_Invalid_ServiceUrlShouldBeTrusted()
public async void Channel_MsaHeader_Invalid_ServiceUrlShouldNotBeTrusted()
{
var header = "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImI0eXNPV0l0RDEzaVFmTExlQkZYOWxSUER0ayIsInR5cCI6IkpXVCIsIng1dCI6ImI0eXNPV0l0RDEzaVFmTExlQkZYOWxSUER0ayJ9.eyJzZXJ2aWNldXJsIjoiaHR0cHM6Ly9zbWJhLnRyYWZmaWNtYW5hZ2VyLm5ldC9hbWVyLWNsaWVudC1zcy5tc2cvIiwibmJmIjoxNTE5Njk3OTQ0LCJleHAiOjE1MTk3MDE1NDQsImlzcyI6Imh0dHBzOi8vYXBpLmJvdGZyYW1ld29yay5jb20iLCJhdWQiOiI3Zjc0NTEzZS02Zjk2LTRkYmMtYmU5ZC05YTgxZmVhMjJiODgifQ.wjApM-MBhEIHSRHJGmivfpyFg0-SrTFh6Xta2RrKlZT4urACPX7kdZAb6oGOeDIm0NU16BPcpEqtCm9nBPmwoKKRbLCQ4Q3DGcB_LY15VCYfiiAnaevNNcvq7j_Hu-oyTmKOqpjfzu8qMIsjySClf1qZFucUrqzccePtlb63DAVfv-nF3bp-sm-zFG7RBX32cCygBMvpVENBroAq3ANfUQCmixkExcGr5npV3dFihSE0H9ntLMGseBdW7dRe5xOXDIgCtcCJPid-A6Vz-DxWGabyy2mVXLwYYuDxP4L5aruGwJIl_Z2-_MjhrWVszoeCRoOlx9-LNtbdSYGWmXWSbg";
var credentials = new SimpleCredentialProvider("7f74513e-6f96-4dbc-be9d-9a81fea22b88", "");
@ -120,7 +121,43 @@ namespace Microsoft.Bot.Connector.Tests
credentials,
emptyClient));
Assert.False(MicrosoftAppCredentials.IsTrustedServiceUrl("https://smba.trafficmanager.net/amer-client-ss.msg/"));
Assert.False(MicrosoftAppCredentials.IsTrustedServiceUrl("https://webchat.botframework.com/"));
}
/// <summary>
/// Tests with no authentication header and makes sure the service URL is not added to the trusted list.
/// </summary>
[Fact]
public async void Channel_AuthenticationDisabled_ShouldBeAnonymous()
{
var header = "";
var credentials = new SimpleCredentialProvider();
var claimsPrincipal = await JwtTokenValidation.AuthenticateRequest(
new Activity { ServiceUrl = "https://webchat.botframework.com/" },
header,
credentials,
emptyClient);
Assert.Equal("anonymous", claimsPrincipal.AuthenticationType);
}
/// <summary>
/// Tests with no authentication header and makes sure the service URL is not added to the trusted list.
/// </summary>
[Fact]
public async void Channel_AuthenticationDisabled_ServiceUrlShouldNotBeTrusted()
{
var header = "";
var credentials = new SimpleCredentialProvider();
var claimsPrincipal = await JwtTokenValidation.AuthenticateRequest(
new Activity { ServiceUrl = "https://webchat.botframework.com/" },
header,
credentials,
emptyClient);
Assert.False(MicrosoftAppCredentials.IsTrustedServiceUrl("https://webchat.botframework.com/"));
}
}
}