Merge branch 'master' into tomlm/moreprompts
This commit is contained in:
Коммит
053e96f94e
|
@ -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/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче