Merge branch 'master' into add/twilio-functional-tests

This commit is contained in:
Santiago Grangetto 2020-01-22 16:07:08 -03:00
Родитель 2ce2dd0a1b 8d8b2b594f
Коммит 9508da6912
360 изменённых файлов: 7141 добавлений и 2863 удалений

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

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- File name extension must be .runsettings --> <!-- File name extension must be .runsettings -->
<RunSettings> <RunSettings>
<RunConfiguration>
<MaxCpuCount>10</MaxCpuCount>
</RunConfiguration>
<DataCollectionRunSettings> <DataCollectionRunSettings>
<DataCollectors> <DataCollectors>
<DataCollector friendlyName="Code Coverage" uri="datacollector://Microsoft/CodeCoverage/2.0" assemblyQualifiedName="Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <DataCollector friendlyName="Code Coverage" uri="datacollector://Microsoft/CodeCoverage/2.0" assemblyQualifiedName="Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">

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

@ -6,12 +6,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{AD743B78-D61F-4FBF-B620-FA83CE599A50}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{AD743B78-D61F-4FBF-B620-FA83CE599A50}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Dialogs.Adaptive", "libraries\Microsoft.Bot.Builder.Dialogs.Adaptive\Microsoft.Bot.Builder.Dialogs.Adaptive.csproj", "{3CF175CF-1AF4-4109-96CB-221684DCED7D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Dialogs.Adaptive.Tests", "tests\Microsoft.Bot.Builder.Dialogs.Adaptive.Tests\Microsoft.Bot.Builder.Dialogs.Adaptive.Tests.csproj", "{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Azure.Tests", "tests\Microsoft.Bot.Builder.Azure.Tests\Microsoft.Bot.Builder.Azure.Tests.csproj", "{E325A0E2-716A-49E0-9767-5087CF05727C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Azure", "libraries\Microsoft.Bot.Builder.Azure\Microsoft.Bot.Builder.Azure.csproj", "{B2C5EED9-21B2-4763-AB92-C1995B76DA3A}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Azure", "libraries\Microsoft.Bot.Builder.Azure\Microsoft.Bot.Builder.Azure.csproj", "{B2C5EED9-21B2-4763-AB92-C1995B76DA3A}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.AI.QnA.Tests", "tests\Microsoft.Bot.Builder.AI.QnA.Tests\Microsoft.Bot.Builder.AI.QnA.Tests.csproj", "{9BDF7020-A19F-4C6C-B329-E4BFEFF6DE6B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.AI.QnA.Tests", "tests\Microsoft.Bot.Builder.AI.QnA.Tests\Microsoft.Bot.Builder.AI.QnA.Tests.csproj", "{9BDF7020-A19F-4C6C-B329-E4BFEFF6DE6B}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Azure.Tests", "tests\Microsoft.Bot.Builder.Azure.Tests\Microsoft.Bot.Builder.Azure.Tests.csproj", "{E325A0E2-716A-49E0-9767-5087CF05727C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Connector", "libraries\Microsoft.Bot.Connector\Microsoft.Bot.Connector.csproj", "{6462DA5D-27DC-4CD5-9467-5EFB998FD838}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Connector", "libraries\Microsoft.Bot.Connector\Microsoft.Bot.Connector.csproj", "{6462DA5D-27DC-4CD5-9467-5EFB998FD838}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Schema", "libraries\Microsoft.Bot.Schema\Microsoft.Bot.Schema.csproj", "{C1F54CDC-AD1D-45BB-8F7D-F49E411AFAF1}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Schema", "libraries\Microsoft.Bot.Schema\Microsoft.Bot.Schema.csproj", "{C1F54CDC-AD1D-45BB-8F7D-F49E411AFAF1}"
@ -76,10 +80,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.TestB
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Dialogs.Declarative", "libraries\Microsoft.Bot.Builder.Dialogs.Declarative\Microsoft.Bot.Builder.Dialogs.Declarative.csproj", "{1BC05915-044E-4776-8956-B44BBEFF2F84}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Dialogs.Declarative", "libraries\Microsoft.Bot.Builder.Dialogs.Declarative\Microsoft.Bot.Builder.Dialogs.Declarative.csproj", "{1BC05915-044E-4776-8956-B44BBEFF2F84}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Dialogs.Adaptive", "libraries\Microsoft.Bot.Builder.Dialogs.Adaptive\Microsoft.Bot.Builder.Dialogs.Adaptive.csproj", "{3CF175CF-1AF4-4109-96CB-221684DCED7D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Dialogs.Adaptive.Tests", "tests\Microsoft.Bot.Builder.Dialogs.Adaptive.Tests\Microsoft.Bot.Builder.Dialogs.Adaptive.Tests.csproj", "{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Expressions.Tests", "tests\Microsoft.Bot.Expressions.Tests\Microsoft.Bot.Expressions.Tests.csproj", "{AE3FC7F6-B212-4438-B1D7-C121BB4C15ED}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Expressions.Tests", "tests\Microsoft.Bot.Expressions.Tests\Microsoft.Bot.Expressions.Tests.csproj", "{AE3FC7F6-B212-4438-B1D7-C121BB4C15ED}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Expressions", "libraries\Microsoft.Bot.Expressions\Microsoft.Bot.Expressions.csproj", "{8DC1257B-7650-40EB-97A2-C1CBA306DA6A}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Expressions", "libraries\Microsoft.Bot.Expressions\Microsoft.Bot.Expressions.csproj", "{8DC1257B-7650-40EB-97A2-C1CBA306DA6A}"
@ -178,6 +178,30 @@ Global
Release-Windows|Any CPU = Release-Windows|Any CPU Release-Windows|Any CPU = Release-Windows|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Debug-Windows|Any CPU.Build.0 = Debug|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Release|Any CPU.Build.0 = Release|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Release-Windows|Any CPU.ActiveCfg = Release|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Release-Windows|Any CPU.Build.0 = Release|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Debug-Windows|Any CPU.Build.0 = Debug|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Release|Any CPU.Build.0 = Release|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Release-Windows|Any CPU.ActiveCfg = Release|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Release-Windows|Any CPU.Build.0 = Release|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Debug-Windows|Any CPU.Build.0 = Debug|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Release|Any CPU.Build.0 = Release|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Release-Windows|Any CPU.ActiveCfg = Release|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Release-Windows|Any CPU.Build.0 = Release|Any CPU
{B2C5EED9-21B2-4763-AB92-C1995B76DA3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B2C5EED9-21B2-4763-AB92-C1995B76DA3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2C5EED9-21B2-4763-AB92-C1995B76DA3A}.Debug|Any CPU.Build.0 = Debug|Any CPU {B2C5EED9-21B2-4763-AB92-C1995B76DA3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2C5EED9-21B2-4763-AB92-C1995B76DA3A}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU {B2C5EED9-21B2-4763-AB92-C1995B76DA3A}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU
@ -194,14 +218,6 @@ Global
{9BDF7020-A19F-4C6C-B329-E4BFEFF6DE6B}.Release|Any CPU.Build.0 = Release|Any CPU {9BDF7020-A19F-4C6C-B329-E4BFEFF6DE6B}.Release|Any CPU.Build.0 = Release|Any CPU
{9BDF7020-A19F-4C6C-B329-E4BFEFF6DE6B}.Release-Windows|Any CPU.ActiveCfg = Release|Any CPU {9BDF7020-A19F-4C6C-B329-E4BFEFF6DE6B}.Release-Windows|Any CPU.ActiveCfg = Release|Any CPU
{9BDF7020-A19F-4C6C-B329-E4BFEFF6DE6B}.Release-Windows|Any CPU.Build.0 = Release|Any CPU {9BDF7020-A19F-4C6C-B329-E4BFEFF6DE6B}.Release-Windows|Any CPU.Build.0 = Release|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Debug-Windows|Any CPU.Build.0 = Debug|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Release|Any CPU.Build.0 = Release|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Release-Windows|Any CPU.ActiveCfg = Release|Any CPU
{E325A0E2-716A-49E0-9767-5087CF05727C}.Release-Windows|Any CPU.Build.0 = Release|Any CPU
{6462DA5D-27DC-4CD5-9467-5EFB998FD838}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6462DA5D-27DC-4CD5-9467-5EFB998FD838}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6462DA5D-27DC-4CD5-9467-5EFB998FD838}.Debug|Any CPU.Build.0 = Debug|Any CPU {6462DA5D-27DC-4CD5-9467-5EFB998FD838}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6462DA5D-27DC-4CD5-9467-5EFB998FD838}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU {6462DA5D-27DC-4CD5-9467-5EFB998FD838}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU
@ -426,22 +442,6 @@ Global
{1BC05915-044E-4776-8956-B44BBEFF2F84}.Release|Any CPU.Build.0 = Release|Any CPU {1BC05915-044E-4776-8956-B44BBEFF2F84}.Release|Any CPU.Build.0 = Release|Any CPU
{1BC05915-044E-4776-8956-B44BBEFF2F84}.Release-Windows|Any CPU.ActiveCfg = Release|Any CPU {1BC05915-044E-4776-8956-B44BBEFF2F84}.Release-Windows|Any CPU.ActiveCfg = Release|Any CPU
{1BC05915-044E-4776-8956-B44BBEFF2F84}.Release-Windows|Any CPU.Build.0 = Release|Any CPU {1BC05915-044E-4776-8956-B44BBEFF2F84}.Release-Windows|Any CPU.Build.0 = Release|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Debug-Windows|Any CPU.Build.0 = Debug|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Release|Any CPU.Build.0 = Release|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Release-Windows|Any CPU.ActiveCfg = Release|Any CPU
{3CF175CF-1AF4-4109-96CB-221684DCED7D}.Release-Windows|Any CPU.Build.0 = Release|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Debug-Windows|Any CPU.Build.0 = Debug|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Release|Any CPU.Build.0 = Release|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Release-Windows|Any CPU.ActiveCfg = Release|Any CPU
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA}.Release-Windows|Any CPU.Build.0 = Release|Any CPU
{AE3FC7F6-B212-4438-B1D7-C121BB4C15ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AE3FC7F6-B212-4438-B1D7-C121BB4C15ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AE3FC7F6-B212-4438-B1D7-C121BB4C15ED}.Debug|Any CPU.Build.0 = Debug|Any CPU {AE3FC7F6-B212-4438-B1D7-C121BB4C15ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE3FC7F6-B212-4438-B1D7-C121BB4C15ED}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU {AE3FC7F6-B212-4438-B1D7-C121BB4C15ED}.Debug-Windows|Any CPU.ActiveCfg = Debug|Any CPU
@ -695,9 +695,11 @@ Global
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{3CF175CF-1AF4-4109-96CB-221684DCED7D} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{E325A0E2-716A-49E0-9767-5087CF05727C} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{B2C5EED9-21B2-4763-AB92-C1995B76DA3A} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A} {B2C5EED9-21B2-4763-AB92-C1995B76DA3A} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{9BDF7020-A19F-4C6C-B329-E4BFEFF6DE6B} = {AD743B78-D61F-4FBF-B620-FA83CE599A50} {9BDF7020-A19F-4C6C-B329-E4BFEFF6DE6B} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{E325A0E2-716A-49E0-9767-5087CF05727C} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{6462DA5D-27DC-4CD5-9467-5EFB998FD838} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A} {6462DA5D-27DC-4CD5-9467-5EFB998FD838} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{C1F54CDC-AD1D-45BB-8F7D-F49E411AFAF1} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A} {C1F54CDC-AD1D-45BB-8F7D-F49E411AFAF1} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{ADA8AB8B-2066-4193-B8F7-985669B23E00} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A} {ADA8AB8B-2066-4193-B8F7-985669B23E00} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
@ -729,8 +731,6 @@ Global
{E4E13301-9193-4106-B0E3-41276B478E7C} = {AD743B78-D61F-4FBF-B620-FA83CE599A50} {E4E13301-9193-4106-B0E3-41276B478E7C} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{76391566-9F22-4994-8B0F-02EFC0E9E228} = {AD743B78-D61F-4FBF-B620-FA83CE599A50} {76391566-9F22-4994-8B0F-02EFC0E9E228} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{1BC05915-044E-4776-8956-B44BBEFF2F84} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A} {1BC05915-044E-4776-8956-B44BBEFF2F84} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{3CF175CF-1AF4-4109-96CB-221684DCED7D} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{CA008713-655E-46DA-BBDF-1EF6B8CE7DCA} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{AE3FC7F6-B212-4438-B1D7-C121BB4C15ED} = {AD743B78-D61F-4FBF-B620-FA83CE599A50} {AE3FC7F6-B212-4438-B1D7-C121BB4C15ED} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{8DC1257B-7650-40EB-97A2-C1CBA306DA6A} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A} {8DC1257B-7650-40EB-97A2-C1CBA306DA6A} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{D5E70443-4BA2-42ED-992A-010268440B08} = {AD743B78-D61F-4FBF-B620-FA83CE599A50} {D5E70443-4BA2-42ED-992A-010268440B08} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}

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

@ -1,7 +1,6 @@
# ![Bot Framework for dotnet](./doc/media/BotFrameworkDotnet_header.png) # ![Bot Framework for dotnet](./doc/media/BotFrameworkDotnet_header.png)
### [Click here to find out what's new with Bot Framework](https://github.com/Microsoft/botframework/blob/master/whats-new.md#whats-new) ### [Click here to find out what's new with Bot Framework](https://docs.microsoft.com/en-us/azure/bot-service/what-is-new?view=azure-bot-service-4.0)
# Bot Framework SDK v4 for .NET # Bot Framework SDK v4 for .NET
This repository contains code for the .NET version of the [Microsoft Bot Framework SDK](https://github.com/Microsoft/botbuilder). The Bot Framework SDK v4 enable developers to model conversation and build sophisticated bot applications using .NET. This repository contains code for the .NET version of the [Microsoft Bot Framework SDK](https://github.com/Microsoft/botbuilder). The Bot Framework SDK v4 enable developers to model conversation and build sophisticated bot applications using .NET.

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

@ -16,7 +16,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU' "> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU' ">
<DocumentationFile>bin\$(Configuration)\netstandard2.0\Microsoft.Bot.Builder.Adapters.Facebook.xml</DocumentationFile> <DocumentationFile>bin\$(Configuration)\$(TargetFramework)\Microsoft.Bot.Builder.Adapters.Facebook.xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors /> <WarningsAsErrors />
</PropertyGroup> </PropertyGroup>
@ -29,7 +29,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" /> <PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" />
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" /> <PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" />
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" /> <PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" >
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

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

@ -18,7 +18,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DocumentationFile>bin\$(Configuration)\netstandard2.0\Microsoft.Bot.Builder.Adapters.Slack.xml</DocumentationFile> <DocumentationFile>bin\$(Configuration)\$(TargetFramework)\Microsoft.Bot.Builder.Adapters.Slack.xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors /> <WarningsAsErrors />
</PropertyGroup> </PropertyGroup>
@ -31,7 +31,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="SlackAPI" Version="1.1.2" /> <PackageReference Include="SlackAPI" Version="1.1.2" />
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" /> <PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" >
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" /> <PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" />
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" /> <PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" />
</ItemGroup> </ItemGroup>

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

@ -22,7 +22,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU' "> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU' ">
<DocumentationFile>bin\$(Configuration)\netstandard2.0\Microsoft.Bot.Builder.Adapters.Twilio.xml</DocumentationFile> <DocumentationFile>bin\$(Configuration)\$(TargetFramework)\Microsoft.Bot.Builder.Adapters.Twilio.xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors /> <WarningsAsErrors />
</PropertyGroup> </PropertyGroup>
@ -36,7 +36,9 @@
<PackageReference Include="Twilio" Version="5.33.1" /> <PackageReference Include="Twilio" Version="5.33.1" />
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" /> <PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" />
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" /> <PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" />
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" /> <PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" >
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

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

@ -18,7 +18,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU' "> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU' ">
<DocumentationFile>bin\$(Configuration)\netstandard2.0\Microsoft.Bot.Builder.Adapters.Webex.xml</DocumentationFile> <DocumentationFile>bin\$(Configuration)\$(TargetFramework)\Microsoft.Bot.Builder.Adapters.Webex.xml</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors /> <WarningsAsErrors />
</PropertyGroup> </PropertyGroup>
@ -32,7 +32,9 @@
<PackageReference Include="Thrzn41.WebexTeams" Version="1.6.2" /> <PackageReference Include="Thrzn41.WebexTeams" Version="1.6.2" />
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" /> <PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" />
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" /> <PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" />
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" /> <PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" >
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

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

@ -48,7 +48,6 @@ namespace Microsoft.Bot.Builder.AI.Luis
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="LuisRecognizer"/> class. /// Initializes a new instance of the <see cref="LuisRecognizer"/> class.
/// </summary> /// </summary>
/// <param name="application">The LUIS application to use to recognize text.</param>
/// <param name="recognizerOptions"> The LUIS recognizer version options.</param> /// <param name="recognizerOptions"> The LUIS recognizer version options.</param>
/// <param name="clientHandler">(Optional) Custom handler for LUIS API calls to allow mocking.</param> /// <param name="clientHandler">(Optional) Custom handler for LUIS API calls to allow mocking.</param>
public LuisRecognizer(LuisRecognizerOptions recognizerOptions, HttpClientHandler clientHandler = null) public LuisRecognizer(LuisRecognizerOptions recognizerOptions, HttpClientHandler clientHandler = null)

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

@ -34,7 +34,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AsyncUsageAnalyzers" Version="1.0.0-alpha003" PrivateAssets="all" /> <PackageReference Include="AsyncUsageAnalyzers" Version="1.0.0-alpha003" PrivateAssets="all" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" /> <PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" >
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Azure.CognitiveServices.Language.LUIS.Runtime" Version="2.1.0" /> <PackageReference Include="Microsoft.Azure.CognitiveServices.Language.LUIS.Runtime" Version="2.1.0" />
<PackageReference Include="Microsoft.Bot.Schema" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" /> <PackageReference Include="Microsoft.Bot.Schema" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" />
<PackageReference Include="Microsoft.Bot.Schema" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" /> <PackageReference Include="Microsoft.Bot.Schema" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" />

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

@ -38,7 +38,9 @@
<PackageReference Include="Microsoft.Bot.Configuration" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" /> <PackageReference Include="Microsoft.Bot.Configuration" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" />
<PackageReference Include="Microsoft.Bot.Builder.Dialogs" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" /> <PackageReference Include="Microsoft.Bot.Builder.Dialogs" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" />
<PackageReference Include="Microsoft.Bot.Builder.Dialogs" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" /> <PackageReference Include="Microsoft.Bot.Builder.Dialogs" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" />
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" /> <PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" >
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

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

@ -29,7 +29,9 @@
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.8.1" /> <PackageReference Include="Microsoft.ApplicationInsights" Version="2.8.1" />
<PackageReference Include="Microsoft.Bot.Builder" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" /> <PackageReference Include="Microsoft.Bot.Builder" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" />
<PackageReference Include="Microsoft.Bot.Builder" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" /> <PackageReference Include="Microsoft.Bot.Builder" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" />
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" /> <PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" >
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

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

@ -51,7 +51,9 @@
<PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="2.1.2" /> <PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="2.1.2" />
<PackageReference Include="Microsoft.Azure.Storage.Blob" Version="9.4.2" /> <PackageReference Include="Microsoft.Azure.Storage.Blob" Version="9.4.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" /> <PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" >
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.1" /> <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.1" />
<PackageReference Include="Microsoft.Bot.Builder" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" /> <PackageReference Include="Microsoft.Bot.Builder" Condition=" '$(IsBuildServer)' == '' " Version="4.8.0-local" />
<PackageReference Include="Microsoft.Bot.Builder" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" /> <PackageReference Include="Microsoft.Bot.Builder" Condition=" '$(IsBuildServer)' != '' " Version="$(ReleasePackageVersion)" />

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

@ -49,8 +49,10 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
return await OnActionScopeResultAsync(dc, actionScopeResult, cancellationToken).ConfigureAwait(false); return await OnActionScopeResultAsync(dc, actionScopeResult, cancellationToken).ConfigureAwait(false);
} }
var dcState = dc.GetState();
// When we are resumed, we increment our offset into the actions and being the next action // When we are resumed, we increment our offset into the actions and being the next action
var nextOffset = dc.GetState().GetIntValue(OFFSETKEY, 0) + 1; var nextOffset = dcState.GetIntValue(OFFSETKEY, 0) + 1;
if (nextOffset < this.Actions.Count) if (nextOffset < this.Actions.Count)
{ {
return await this.BeginActionAsync(dc, nextOffset, cancellationToken: cancellationToken).ConfigureAwait(false); return await this.BeginActionAsync(dc, nextOffset, cancellationToken: cancellationToken).ConfigureAwait(false);
@ -135,7 +137,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
protected virtual async Task<DialogTurnResult> BeginActionAsync(DialogContext dc, int offset, CancellationToken cancellationToken = default) protected virtual async Task<DialogTurnResult> BeginActionAsync(DialogContext dc, int offset, CancellationToken cancellationToken = default)
{ {
// get the action for the offset // get the action for the offset
dc.GetState().SetValue(OFFSETKEY, offset); var dcState = dc.GetState();
dcState.SetValue(OFFSETKEY, offset);
var actionId = this.Actions[offset].Id; var actionId = this.Actions[offset].Id;
// begin Action dialog // begin Action dialog

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

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using Microsoft.Bot.Builder.Dialogs.Declarative;
using Microsoft.Bot.Expressions; using Microsoft.Bot.Expressions;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -16,12 +17,13 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
public abstract class BaseInvokeDialog : Dialog, IDialogDependencies public abstract class BaseInvokeDialog : Dialog, IDialogDependencies
{ {
// Expression for dialogId to call (allowing dynamic expression) // Expression for dialogId to call (allowing dynamic expression)
private string dialogIdToCall; public BaseInvokeDialog(string dialogIdToCall = null, object bindingOptions = null)
public BaseInvokeDialog(string dialogIdToCall = null, IDictionary<string, string> bindingOptions = null)
: base() : base()
{ {
this.dialogIdToCall = dialogIdToCall; if (dialogIdToCall != null)
{
this.Dialog = dialogIdToCall;
}
if (bindingOptions != null) if (bindingOptions != null)
{ {
@ -36,7 +38,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Configurable options for the dialog. /// Configurable options for the dialog.
/// </value> /// </value>
[JsonProperty("options")] [JsonProperty("options")]
public object Options { get; set; } = new JObject(); public ObjectExpression<object> Options { get; set; } = new ObjectExpression<object>();
/// <summary> /// <summary>
/// Gets or sets the dialog to call. /// Gets or sets the dialog to call.
@ -45,7 +47,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// The dialog to call. /// The dialog to call.
/// </value> /// </value>
[JsonProperty("dialog")] [JsonProperty("dialog")]
public Dialog Dialog { get; set; } public DialogExpression Dialog { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to have the new dialog should process the activity. /// Gets or sets a value indicating whether to have the new dialog should process the activity.
@ -53,13 +55,13 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// <value>The default for this will be true, which means the new dialog should not look the activity. You can set this to false to dispatch the activity to the new dialog.</value> /// <value>The default for this will be true, which means the new dialog should not look the activity. You can set this to false to dispatch the activity to the new dialog.</value>
[DefaultValue(true)] [DefaultValue(true)]
[JsonProperty("activityProcessed")] [JsonProperty("activityProcessed")]
public bool ActivityProcessed { get; set; } = true; public BoolExpression ActivityProcessed { get; set; } = true;
public virtual IEnumerable<Dialog> GetDependencies() public virtual IEnumerable<Dialog> GetDependencies()
{ {
if (Dialog != null) if (Dialog?.Value != null)
{ {
yield return Dialog; yield return Dialog.Value;
} }
yield break; yield break;
@ -67,30 +69,36 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
protected override string OnComputeId() protected override string OnComputeId()
{ {
return $"{this.GetType().Name}[{Dialog?.Id ?? this.dialogIdToCall}]"; return $"{this.GetType().Name}[{Dialog?.ToString()}]";
} }
protected Dialog ResolveDialog(DialogContext dc) protected Dialog ResolveDialog(DialogContext dc)
{ {
if (this.Dialog != null) if (this.Dialog?.Value != null)
{ {
return this.Dialog; return this.Dialog.Value;
} }
var dialogId = this.dialogIdToCall ?? throw new Exception($"{this.GetType().Name} requires a dialog to be called."); var dcState = dc.GetState();
return dc.FindDialog(dialogId) ?? throw new Exception($"{dialogId} not found.");
// NOTE: we call TryEvaluate instead of TryGetValue because we want the result of the expression as a string so we can
// look up the string using external FindDialog().
var (dialogId, _) = this.Dialog.Expression.TryEvaluate<string>(dcState);
return dc.FindDialog(dialogId ?? throw new Exception($"{this.Dialog.ToString()} not found."));
} }
protected object BindOptions(DialogContext dc, object options) protected object BindOptions(DialogContext dc, object options)
{ {
var dcState = dc.GetState();
// binding options are static definition of options with overlay of passed in options); // binding options are static definition of options with overlay of passed in options);
var bindingOptions = (JObject)ObjectPath.Merge(Options, options ?? new JObject()); var bindingOptions = (JObject)ObjectPath.Merge(this.Options.GetValue(dcState), options ?? new JObject());
var boundOptions = new JObject(); var boundOptions = new JObject();
foreach (var binding in bindingOptions) foreach (var binding in bindingOptions)
{ {
// evalute the value // evalute the value
var (result, error) = new ExpressionEngine().Parse(binding.Value.ToString()).TryEvaluate(dc.GetState()); var (value, error) = new ValueExpression(binding.Value).TryGetValue(dcState);
if (error != null) if (error != null)
{ {
@ -98,7 +106,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
} }
// and store in options as the result // and store in options as the result
boundOptions[binding.Key] = JToken.FromObject(result); ObjectPath.SetPathValue(boundOptions, binding.Key, value);
} }
return boundOptions; return boundOptions;

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

@ -19,10 +19,8 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.BeginDialog"; public const string DeclarativeType = "Microsoft.BeginDialog";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public BeginDialog(string dialogIdToCall = null, IDictionary<string, string> options = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public BeginDialog(string dialogIdToCall = null, object options = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base(dialogIdToCall, options) : base(dialogIdToCall, options)
{ {
this.RegisterSourceLocation(callerPath, callerLine); this.RegisterSourceLocation(callerPath, callerLine);
@ -38,11 +36,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the property path to store the dialog result in. /// Gets or sets the property path to store the dialog result in.
@ -51,7 +45,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// The property path to store the dialog result in. /// The property path to store the dialog result in.
/// </value> /// </value>
[JsonProperty("resultProperty")] [JsonProperty("resultProperty")]
public string ResultProperty { get; set; } public StringExpression ResultProperty { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -60,7 +54,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -71,7 +67,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
var boundOptions = BindOptions(dc, options); var boundOptions = BindOptions(dc, options);
// set the activity processed state (default is true) // set the activity processed state (default is true)
dc.GetState().SetValue(TurnPath.ACTIVITYPROCESSED, this.ActivityProcessed); dcState.SetValue(TurnPath.ACTIVITYPROCESSED, this.ActivityProcessed);
// start dialog with bound options passed in as the options // start dialog with bound options passed in as the options
return await dc.BeginDialogAsync(dialog.Id, options: boundOptions, cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.BeginDialogAsync(dialog.Id, options: boundOptions, cancellationToken: cancellationToken).ConfigureAwait(false);
@ -79,9 +75,11 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
public override async Task<DialogTurnResult> ResumeDialogAsync(DialogContext dc, DialogReason reason, object result = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> ResumeDialogAsync(DialogContext dc, DialogReason reason, object result = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
var dcState = dc.GetState();
if (this.ResultProperty != null) if (this.ResultProperty != null)
{ {
dc.GetState().SetValue(this.ResultProperty, result); dcState.SetValue(this.ResultProperty.GetValue(dcState), result);
} }
// By default just end the current dialog and return result to parent. // By default just end the current dialog and return result to parent.

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

@ -18,8 +18,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.BreakLoop"; public const string DeclarativeType = "Microsoft.BreakLoop";
private Expression disabled;
public BreakLoop([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public BreakLoop([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{ {
this.RegisterSourceLocation(callerPath, callerLine); this.RegisterSourceLocation(callerPath, callerLine);
@ -35,11 +33,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -48,7 +42,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }

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

@ -18,8 +18,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.CancelAllDialogs"; public const string DeclarativeType = "Microsoft.CancelAllDialogs";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public CancelAllDialogs([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public CancelAllDialogs([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
@ -37,11 +35,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets event name. /// Gets or sets event name.
@ -50,7 +44,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Event name. /// Event name.
/// </value> /// </value>
[JsonProperty("eventName")] [JsonProperty("eventName")]
public string EventName { get; set; } public StringExpression EventName { get; set; }
/// <summary> /// <summary>
/// Gets or sets value expression for EventValue. /// Gets or sets value expression for EventValue.
@ -59,7 +53,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Value expression for EventValue. /// Value expression for EventValue.
/// </value> /// </value>
[JsonProperty("eventValue")] [JsonProperty("eventValue")]
public string EventValue { get; set; } public StringExpression EventValue { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -68,24 +62,20 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
object eventValue = null;
if (this.EventValue != null)
{
eventValue = new ExpressionEngine().Parse(this.EventValue).TryEvaluate(dc.GetState());
}
if (dc.Parent == null) if (dc.Parent == null)
{ {
return await dc.CancelAllDialogsAsync(true, EventName, eventValue, cancellationToken).ConfigureAwait(false); return await dc.CancelAllDialogsAsync(true, EventName.GetValue(dcState), this.EventValue.GetValue(dcState), cancellationToken).ConfigureAwait(false);
} }
else else
{ {
var turnResult = await dc.Parent.CancelAllDialogsAsync(true, EventName, eventValue, cancellationToken).ConfigureAwait(false); var turnResult = await dc.Parent.CancelAllDialogsAsync(true, EventName.GetValue(dcState), this.EventValue.GetValue(dcState), cancellationToken).ConfigureAwait(false);
turnResult.ParentEnded = true; turnResult.ParentEnded = true;
return turnResult; return turnResult;
} }

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

@ -15,7 +15,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
public class CodeAction : Dialog public class CodeAction : Dialog
{ {
private readonly CodeActionHandler codeHandler; private readonly CodeActionHandler codeHandler;
private Expression disabled;
public CodeAction(CodeActionHandler codeHandler, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public CodeAction(CodeActionHandler codeHandler, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
@ -34,11 +33,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -47,7 +42,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }

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

@ -18,8 +18,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.ContinueLoop"; public const string DeclarativeType = "Microsoft.ContinueLoop";
private Expression disabled;
public ContinueLoop([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public ContinueLoop([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{ {
this.RegisterSourceLocation(callerPath, callerLine); this.RegisterSourceLocation(callerPath, callerLine);
@ -35,11 +33,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -48,7 +42,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }

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

@ -18,8 +18,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.DebugBreak"; public const string DeclarativeType = "Microsoft.DebugBreak";
private Expression disabled;
public DebugBreak([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public DebugBreak([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{ {
this.RegisterSourceLocation(callerPath, callerLine); this.RegisterSourceLocation(callerPath, callerLine);
@ -35,11 +33,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -48,7 +42,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }

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

@ -20,9 +20,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.DeleteActivity"; public const string DeclarativeType = "Microsoft.DeleteActivity";
private Expression activityId;
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public DeleteActivity([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public DeleteActivity([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{ {
@ -39,22 +36,14 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the expression which resolves to the activityId to update. /// Gets or sets the expression which resolves to the activityId to update.
/// </summary> /// </summary>
/// <value>Expression to activityId.</value> /// <value>Expression to activityId.</value>
[JsonProperty("activityId")] [JsonProperty("activityId")]
public string ActivityId public StringExpression ActivityId { get; set; }
{
get { return activityId.ToString(); }
set { activityId = new ExpressionEngine().Parse(value); }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -63,12 +52,14 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
var (result, error) = new ExpressionEngine().Parse(this.ActivityId).TryEvaluate(dc.GetState()); var (result, error) = this.ActivityId.TryGetValue(dcState);
if (error != null) if (error != null)
{ {
throw new ArgumentException(error); throw new ArgumentException(error);

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

@ -20,8 +20,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.DeleteProperties"; public const string DeclarativeType = "Microsoft.DeleteProperties";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public DeleteProperties([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public DeleteProperties([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
@ -39,11 +37,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets properties to remove. /// Gets or sets properties to remove.
@ -55,7 +49,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Collection of property paths to remove. /// Collection of property paths to remove.
/// </value> /// </value>
[JsonProperty("properties")] [JsonProperty("properties")]
public List<string> Properties { get; set; } = new List<string>(); public List<StringExpression> Properties { get; set; } = new List<StringExpression>();
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -64,7 +58,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -76,7 +72,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
{ {
foreach (var property in this.Properties) foreach (var property in this.Properties)
{ {
dc.GetState().RemoveValue(property); dcState.RemoveValue(property.GetValue(dcState));
} }
} }

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

@ -18,8 +18,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.DeleteProperty"; public const string DeclarativeType = "Microsoft.DeleteProperty";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public DeleteProperty([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public DeleteProperty([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
@ -47,11 +45,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets property path to remove. /// Gets or sets property path to remove.
@ -63,7 +57,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Property path to remove. /// Property path to remove.
/// </value> /// </value>
[JsonProperty("property")] [JsonProperty("property")]
public string Property { get; set; } public StringExpression Property { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -72,7 +66,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -80,7 +76,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
// Ensure planning context // Ensure planning context
if (dc is SequenceContext planning) if (dc is SequenceContext planning)
{ {
dc.GetState().RemoveValue(Property); dcState.RemoveValue(Property.GetValue(dcState));
return await dc.EndDialogAsync(); return await dc.EndDialogAsync();
} }
else else

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

@ -20,8 +20,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.EditActions"; public const string DeclarativeType = "Microsoft.EditActions";
private Expression disabled;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="EditActions"/> class. /// Initializes a new instance of the <see cref="EditActions"/> class.
/// </summary> /// </summary>
@ -44,11 +42,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the actions to be applied to the active action. /// Gets or sets the actions to be applied to the active action.
@ -66,7 +60,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// The type of change to appy to the active actions. /// The type of change to appy to the active actions.
/// </value> /// </value>
[JsonProperty("changeType")] [JsonProperty("changeType")]
public ActionChangeType ChangeType { get; set; } public EnumExpression<ActionChangeType> ChangeType { get; set; } = new EnumExpression<ActionChangeType>();
public virtual IEnumerable<Dialog> GetDependencies() public virtual IEnumerable<Dialog> GetDependencies()
{ {
@ -75,7 +69,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -91,7 +87,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
var changes = new ActionChangeList() var changes = new ActionChangeList()
{ {
ChangeType = ChangeType, ChangeType = ChangeType.GetValue(dcState),
Actions = planActions.ToList() Actions = planActions.ToList()
}; };

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

@ -22,11 +22,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.EditArray"; public const string DeclarativeType = "Microsoft.EditArray";
private Expression value;
private Expression itemsProperty;
private Expression resultProperty;
private Expression disabled;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="EditArray"/> class. /// Initializes a new instance of the <see cref="EditArray"/> class.
/// </summary> /// </summary>
@ -34,10 +29,10 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// <param name="arrayProperty">array property (optional).</param> /// <param name="arrayProperty">array property (optional).</param>
/// <param name="value">value to insert.</param> /// <param name="value">value to insert.</param>
/// <param name="resultProperty">output property to put Pop/Take into.</param> /// <param name="resultProperty">output property to put Pop/Take into.</param>
public EditArray(ArrayChangeType changeType, string arrayProperty = null, string value = null, string resultProperty = null) public EditArray(ArrayChangeType changeType, string arrayProperty = null, object value = null, string resultProperty = null)
: base() : base()
{ {
this.ChangeType = changeType; this.ChangeType = new EnumExpression<ArrayChangeType>(changeType);
if (!string.IsNullOrEmpty(arrayProperty)) if (!string.IsNullOrEmpty(arrayProperty))
{ {
@ -49,11 +44,19 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
case ArrayChangeType.Clear: case ArrayChangeType.Clear:
case ArrayChangeType.Pop: case ArrayChangeType.Pop:
case ArrayChangeType.Take: case ArrayChangeType.Take:
if (ResultProperty != null)
{
this.ResultProperty = resultProperty; this.ResultProperty = resultProperty;
}
break; break;
case ArrayChangeType.Push: case ArrayChangeType.Push:
case ArrayChangeType.Remove: case ArrayChangeType.Remove:
this.Value = value; if (value != null)
{
this.Value = new ValueExpression(value);
}
break; break;
} }
} }
@ -101,7 +104,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Type of change being applied. /// Type of change being applied.
/// </value> /// </value>
[JsonProperty("changeType")] [JsonProperty("changeType")]
public ArrayChangeType ChangeType { get; set; } public EnumExpression<ArrayChangeType> ChangeType { get; set; } = new EnumExpression<ArrayChangeType>(default(ArrayChangeType));
/// <summary> /// <summary>
/// Gets or sets an optional expression which if is true will disable this action. /// Gets or sets an optional expression which if is true will disable this action.
@ -113,11 +116,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets property path expression to the collection of items. /// Gets or sets property path expression to the collection of items.
@ -126,11 +125,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Property path expression to the collection of items. /// Property path expression to the collection of items.
/// </value> /// </value>
[JsonProperty("itemsProperty")] [JsonProperty("itemsProperty")]
public string ItemsProperty public StringExpression ItemsProperty { get; set; }
{
get { return itemsProperty?.ToString(); }
set { this.itemsProperty = (value != null) ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the path expression to store the result of the action. /// Gets or sets the path expression to store the result of the action.
@ -139,11 +134,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// The path expression to store the result of the action. /// The path expression to store the result of the action.
/// </value> /// </value>
[JsonProperty("resultProperty")] [JsonProperty("resultProperty")]
public string ResultProperty public StringExpression ResultProperty { get; set; }
{
get { return resultProperty?.ToString(); }
set { this.resultProperty = (value != null) ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the expression of the value to put onto the array. /// Gets or sets the expression of the value to put onto the array.
@ -152,11 +143,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// The expression of the value to put onto the array. /// The expression of the value to put onto the array.
/// </value> /// </value>
[JsonProperty("value")] [JsonProperty("value")]
public string Value public ValueExpression Value { get; set; } = new ValueExpression();
{
get { return value?.ToString(); }
set { this.value = (value != null) ? new ExpressionEngine().Parse(value) : null; }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -165,22 +152,24 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState))
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
if (string.IsNullOrEmpty(ItemsProperty)) if (ItemsProperty == null)
{ {
throw new Exception($"EditArray: \"{ChangeType}\" operation couldn't be performed because the arrayProperty wasn't specified."); throw new Exception($"EditArray: \"{ChangeType}\" operation couldn't be performed because the arrayProperty wasn't specified.");
} }
var array = dc.GetState().GetValue<JArray>(this.ItemsProperty, () => new JArray()); var array = dcState.GetValue<JArray>(this.ItemsProperty.GetValue(dcState), () => new JArray());
object item = null; object item = null;
object result = null; object result = null;
switch (ChangeType) switch (ChangeType.GetValue(dcState))
{ {
case ArrayChangeType.Pop: case ArrayChangeType.Pop:
item = array[array.Count - 1]; item = array[array.Count - 1];
@ -189,7 +178,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
break; break;
case ArrayChangeType.Push: case ArrayChangeType.Push:
EnsureValue(); EnsureValue();
var (itemResult, error) = this.value.TryEvaluate(dc.GetState()); var (itemResult, error) = this.Value.TryGetValue(dcState);
if (error == null && itemResult != null) if (error == null && itemResult != null)
{ {
array.Add(itemResult); array.Add(itemResult);
@ -208,7 +197,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
break; break;
case ArrayChangeType.Remove: case ArrayChangeType.Remove:
EnsureValue(); EnsureValue();
(itemResult, error) = this.value.TryEvaluate(dc.GetState()); (itemResult, error) = this.Value.TryGetValue(dcState);
if (error == null && itemResult != null) if (error == null && itemResult != null)
{ {
result = false; result = false;
@ -230,11 +219,11 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
break; break;
} }
dc.GetState().SetValue(this.ItemsProperty, array); dcState.SetValue(this.ItemsProperty.GetValue(dcState), array);
if (ResultProperty != null) if (ResultProperty != null)
{ {
dc.GetState().SetValue(this.ResultProperty, result); dcState.SetValue(this.ResultProperty.GetValue(dcState), result);
} }
return await dc.EndDialogAsync(result); return await dc.EndDialogAsync(result);

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

@ -18,17 +18,23 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.EmitEvent"; public const string DeclarativeType = "Microsoft.EmitEvent";
private Expression eventValue;
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public EmitEvent(string eventName = null, string eventValue = null, bool bubble = false, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public EmitEvent(string eventName = null, object eventValue = null, bool bubble = false, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
{ {
this.RegisterSourceLocation(callerPath, callerLine); this.RegisterSourceLocation(callerPath, callerLine);
if (eventName != null)
{
this.EventName = eventName; this.EventName = eventName;
this.EventValue = eventValue; }
this.BubbleEvent = bubble;
if (eventValue != null)
{
this.EventValue = new ValueExpression(eventValue);
}
this.BubbleEvent = new BoolExpression(bubble);
} }
/// <summary> /// <summary>
@ -41,11 +47,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the name of the event to emit. /// Gets or sets the name of the event to emit.
@ -54,7 +56,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// The name of the event to emit. /// The name of the event to emit.
/// </value> /// </value>
[JsonProperty("eventName")] [JsonProperty("eventName")]
public string EventName { get; set; } public StringExpression EventName { get; set; }
/// <summary> /// <summary>
/// Gets or sets the memory property path to use to get the value to send as part of the event. /// Gets or sets the memory property path to use to get the value to send as part of the event.
@ -63,11 +65,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// The memory property path to use to get the value to send as part of the event. /// The memory property path to use to get the value to send as part of the event.
/// </value> /// </value>
[JsonProperty("eventValue")] [JsonProperty("eventValue")]
public string EventValue public ValueExpression EventValue { get; set; }
{
get { return eventValue?.ToString(); }
set { this.eventValue = (value != null) ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the event should bubble to parents or not. /// Gets or sets a value indicating whether the event should bubble to parents or not.
@ -76,7 +74,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A value indicating whether gets or sets whether the event should bubble to parents or not. /// A value indicating whether gets or sets whether the event should bubble to parents or not.
/// </value> /// </value>
[JsonProperty("bubbleEvent")] [JsonProperty("bubbleEvent")]
public bool BubbleEvent { get; set; } public BoolExpression BubbleEvent { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -85,27 +83,31 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
var handled = false; bool handled;
if (eventValue != null) var eventName = EventName?.GetValue(dcState);
var bubbleEvent = BubbleEvent.GetValue(dcState);
if (EventValue != null)
{ {
var (value, valueError) = this.eventValue.TryEvaluate(dc.GetState()); var (value, valueError) = this.EventValue.TryGetValue(dcState);
if (valueError == null) if (valueError == null)
{ {
handled = await dc.EmitEventAsync(EventName, value, BubbleEvent, false, cancellationToken).ConfigureAwait(false); handled = await dc.EmitEventAsync(eventName, value, bubbleEvent, false, cancellationToken).ConfigureAwait(false);
} }
else else
{ {
throw new Exception($"Expression evaluation resulted in an error. Expression: {eventValue.ToString()}. Error: {valueError}"); throw new Exception($"Expression evaluation resulted in an error. Expression: {EventValue.ToString()}. Error: {valueError}");
} }
} }
else else
{ {
handled = await dc.EmitEventAsync(EventName, EventValue, BubbleEvent, false, cancellationToken).ConfigureAwait(false); handled = await dc.EmitEventAsync(eventName, EventValue, bubbleEvent, false, cancellationToken).ConfigureAwait(false);
} }
return await dc.EndDialogAsync(handled, cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(handled, cancellationToken).ConfigureAwait(false);
@ -113,7 +115,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
protected override string OnComputeId() protected override string OnComputeId()
{ {
return $"{this.GetType().Name}[{EventName ?? string.Empty}]"; return $"{this.GetType().Name}[{EventName.ToString() ?? string.Empty}]";
} }
} }
} }

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

@ -18,18 +18,15 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.EndDialog"; public const string DeclarativeType = "Microsoft.EndDialog";
private Expression value;
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public EndDialog(string value = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public EndDialog(object value = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
{ {
this.RegisterSourceLocation(callerPath, callerLine); this.RegisterSourceLocation(callerPath, callerLine);
if (!string.IsNullOrEmpty(value)) if (value != null)
{ {
this.Value = value; this.Value = new ValueExpression(value);
} }
} }
@ -43,11 +40,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets a value expression for the result to be returned to the caller. /// Gets or sets a value expression for the result to be returned to the caller.
@ -56,11 +49,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A value expression for the result to be returned to the caller. /// A value expression for the result to be returned to the caller.
/// </value> /// </value>
[JsonProperty("value")] [JsonProperty("value")]
public string Value public ValueExpression Value { get; set; }
{
get { return value?.ToString(); }
set { this.value = (value != null) ? new ExpressionEngine().Parse(value) : null; }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -69,14 +58,16 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
if (this.Value != null) if (this.Value != null)
{ {
var (result, error) = this.value.TryEvaluate(dc.GetState()); var (result, error) = this.Value.TryGetValue(dcState);
return await EndParentDialogAsync(dc, result, cancellationToken).ConfigureAwait(false); return await EndParentDialogAsync(dc, result, cancellationToken).ConfigureAwait(false);
} }
@ -104,7 +95,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
protected override string OnComputeId() protected override string OnComputeId()
{ {
return $"{this.GetType().Name}({this.Value ?? string.Empty})"; return $"{this.GetType().Name}({this.Value?.ToString() ?? string.Empty})";
} }
} }
} }

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

@ -18,8 +18,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.EndTurn"; public const string DeclarativeType = "Microsoft.EndTurn";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public EndTurn([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public EndTurn([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
@ -38,11 +36,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
public override Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -51,7 +45,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return dc.EndDialogAsync(cancellationToken: cancellationToken); return dc.EndDialogAsync(cancellationToken: cancellationToken);
} }

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

@ -23,8 +23,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
private const string INDEX = "dialog.foreach.index"; private const string INDEX = "dialog.foreach.index";
private const string VALUE = "dialog.foreach.value"; private const string VALUE = "dialog.foreach.value";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public Foreach([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) public Foreach([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
: base() : base()
@ -42,11 +40,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets property path expression to the collection of items. /// Gets or sets property path expression to the collection of items.
@ -55,7 +49,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Property path expression to the collection of items. /// Property path expression to the collection of items.
/// </value> /// </value>
[JsonProperty("itemsProperty")] [JsonProperty("itemsProperty")]
public string ItemsProperty { get; set; } public StringExpression ItemsProperty { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -64,12 +58,14 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
dc.GetState().SetValue(INDEX, -1); dcState.SetValue(INDEX, -1);
return await this.NextItemAsync(dc, cancellationToken).ConfigureAwait(false); return await this.NextItemAsync(dc, cancellationToken).ConfigureAwait(false);
} }
@ -91,17 +87,16 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
protected virtual async Task<DialogTurnResult> NextItemAsync(DialogContext dc, CancellationToken cancellationToken = default) protected virtual async Task<DialogTurnResult> NextItemAsync(DialogContext dc, CancellationToken cancellationToken = default)
{ {
// Get list information // Get list information
var itemsProperty = new ExpressionEngine().Parse(this.ItemsProperty); var dcState = dc.GetState();
var (itemList, error) = itemsProperty.TryEvaluate(dc.GetState()); var list = dcState.GetValue<JArray>(this.ItemsProperty.GetValue(dcState));
var list = JArray.FromObject(itemList); var index = dcState.GetIntValue(INDEX);
var index = dc.GetState().GetIntValue(INDEX);
// Next item // Next item
if (++index < list.Count) if (++index < list.Count)
{ {
// Persist index and value // Persist index and value
dc.GetState().SetValue(VALUE, list[index]); dcState.SetValue(VALUE, list[index]);
dc.GetState().SetValue(INDEX, index); dcState.SetValue(INDEX, index);
// Start loop // Start loop
return await this.BeginActionAsync(dc, 0, cancellationToken).ConfigureAwait(false); return await this.BeginActionAsync(dc, 0, cancellationToken).ConfigureAwait(false);

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

@ -25,8 +25,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
private const string FOREACHPAGE = "dialog.foreach.page"; private const string FOREACHPAGE = "dialog.foreach.page";
private const string FOREACHPAGEINDEX = "dialog.foreach.pageindex"; private const string FOREACHPAGEINDEX = "dialog.foreach.pageindex";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public ForeachPage([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) public ForeachPage([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
: base() : base()
@ -44,18 +42,14 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
// Expression used to compute the list that should be enumerated. // Expression used to compute the list that should be enumerated.
[JsonProperty("itemsProperty")] [JsonProperty("itemsProperty")]
public string ItemsProperty { get; set; } public StringExpression ItemsProperty { get; set; }
[JsonProperty("pageSize")] [JsonProperty("pageSize")]
public int PageSize { get; set; } = 10; public IntExpression PageSize { get; set; } = 10;
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -64,7 +58,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -94,20 +90,20 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
private async Task<DialogTurnResult> NextPageAsync(DialogContext dc, CancellationToken cancellationToken) private async Task<DialogTurnResult> NextPageAsync(DialogContext dc, CancellationToken cancellationToken)
{ {
Expression itemsProperty = new ExpressionEngine().Parse(this.ItemsProperty); var dcState = dc.GetState();
int pageIndex = dc.GetState().GetIntValue(FOREACHPAGEINDEX, 0); int pageIndex = dcState.GetIntValue(FOREACHPAGEINDEX, 0);
int pageSize = this.PageSize; int pageSize = this.PageSize.GetValue(dcState);
int itemOffset = pageSize * pageIndex; int itemOffset = pageSize * pageIndex;
var (items, error) = itemsProperty.TryEvaluate(dc.GetState()); var itemsProperty = this.ItemsProperty.GetValue(dcState);
if (error == null) if (dcState.TryGetValue<object>(itemsProperty, out object items))
{ {
var page = this.GetPage(items, itemOffset, pageSize); var page = this.GetPage(items, itemOffset, pageSize);
if (page.Any()) if (page.Any())
{ {
dc.GetState().SetValue(FOREACHPAGE, page); dcState.SetValue(FOREACHPAGE, page);
dc.GetState().SetValue(FOREACHPAGEINDEX, ++pageIndex); dcState.SetValue(FOREACHPAGEINDEX, ++pageIndex);
return await this.BeginActionAsync(dc, 0, cancellationToken).ConfigureAwait(false); return await this.BeginActionAsync(dc, 0, cancellationToken).ConfigureAwait(false);
} }
} }

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

@ -18,9 +18,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.GetActivityMembers"; public const string DeclarativeType = "Microsoft.GetActivityMembers";
private Expression activityId;
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public GetActivityMembers([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public GetActivityMembers([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
@ -38,11 +35,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets property path to put the value in. /// Gets or sets property path to put the value in.
@ -51,7 +44,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Property path to put the value in. /// Property path to put the value in.
/// </value> /// </value>
[JsonProperty("property")] [JsonProperty("property")]
public string Property { get; set; } public StringExpression Property { get; set; }
/// <summary> /// <summary>
/// Gets or sets the expression to get the value to put into property path. /// Gets or sets the expression to get the value to put into property path.
@ -60,11 +53,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// The expression to get the value to put into property path. If this is missing, then the current turn Activity.id will be used. /// The expression to get the value to put into property path. If this is missing, then the current turn Activity.id will be used.
/// </value> /// </value>
[JsonProperty("activityId")] [JsonProperty("activityId")]
public string ActivityId public StringExpression ActivityId { get; set; }
{
get { return activityId?.ToString(); }
set { this.activityId = (value != null) ? new ExpressionEngine().Parse(value) : null; }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -73,7 +62,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -85,9 +76,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
} }
string id = dc.Context.Activity.Id; string id = dc.Context.Activity.Id;
if (this.activityId != null) if (this.ActivityId != null)
{ {
var (value, valueError) = this.activityId.TryEvaluate(dc.GetState()); var (value, valueError) = this.ActivityId.TryGetValue(dcState);
if (valueError != null) if (valueError != null)
{ {
throw new Exception($"Expression evaluation resulted in an error. Expression: {this.ActivityId}. Error: {valueError}"); throw new Exception($"Expression evaluation resulted in an error. Expression: {this.ActivityId}. Error: {valueError}");
@ -98,14 +89,14 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
var result = await bfAdapter.GetActivityMembersAsync(dc.Context, id, cancellationToken).ConfigureAwait(false); var result = await bfAdapter.GetActivityMembersAsync(dc.Context, id, cancellationToken).ConfigureAwait(false);
dc.GetState().SetValue(this.Property, result); dcState.SetValue(this.Property.GetValue(dcState), result);
return await dc.EndDialogAsync(result, cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(result, cancellationToken: cancellationToken).ConfigureAwait(false);
} }
protected override string OnComputeId() protected override string OnComputeId()
{ {
return $"{this.GetType().Name}[{this.ActivityId ?? string.Empty},{this.Property ?? string.Empty}]"; return $"{this.GetType().Name}[{this.ActivityId?.ToString() ?? string.Empty},{this.Property ?? string.Empty}]";
} }
} }
} }

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

@ -18,8 +18,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.GetConversationMembers"; public const string DeclarativeType = "Microsoft.GetConversationMembers";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public GetConversationMembers([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public GetConversationMembers([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
@ -37,11 +35,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets property path to put the value in. /// Gets or sets property path to put the value in.
@ -50,7 +44,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Property path to put the value in. /// Property path to put the value in.
/// </value> /// </value>
[JsonProperty("property")] [JsonProperty("property")]
public string Property { get; set; } public StringExpression Property { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -59,7 +53,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -74,7 +70,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
if (this.Property != null) if (this.Property != null)
{ {
dc.GetState().SetValue(this.Property, result); dcState.SetValue(this.Property.GetValue(dcState), result);
} }
return await dc.EndDialogAsync(result, cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(result, cancellationToken: cancellationToken).ConfigureAwait(false);

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

@ -18,8 +18,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.GotoAction"; public const string DeclarativeType = "Microsoft.GotoAction";
private Expression disabled;
public GotoAction(string actionId = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public GotoAction(string actionId = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{ {
this.RegisterSourceLocation(callerPath, callerLine); this.RegisterSourceLocation(callerPath, callerLine);
@ -30,7 +28,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Gets or sets the action Id to goto. /// Gets or sets the action Id to goto.
/// </summary> /// </summary>
/// <value>The action Id.</value> /// <value>The action Id.</value>
public string ActionId { get; set; } public StringExpression ActionId { get; set; }
/// <summary> /// <summary>
/// Gets or sets an optional expression which if is true will disable this action. /// Gets or sets an optional expression which if is true will disable this action.
@ -42,11 +40,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -55,7 +49,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -64,7 +60,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
var actionScopeResult = new ActionScopeResult() var actionScopeResult = new ActionScopeResult()
{ {
ActionScopeCommand = ActionScopeCommands.GotoAction, ActionScopeCommand = ActionScopeCommands.GotoAction,
ActionId = this.ActionId ?? throw new ArgumentNullException(nameof(ActionId)) ActionId = this.ActionId?.GetValue(dcState) ?? throw new ArgumentNullException(nameof(ActionId))
}; };
return await dc.EndDialogAsync(result: actionScopeResult, cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(result: actionScopeResult, cancellationToken: cancellationToken).ConfigureAwait(false);

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

@ -10,9 +10,7 @@ using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Templates;
using Microsoft.Bot.Builder.TraceExtensions; using Microsoft.Bot.Builder.TraceExtensions;
using Microsoft.Bot.Expressions;
using Microsoft.Bot.Schema; using Microsoft.Bot.Schema;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Converters;
@ -28,15 +26,13 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.HttpRequest"; public const string DeclarativeType = "Microsoft.HttpRequest";
private Expression disabled; public HttpRequest(HttpMethod method, string url, Dictionary<string, StringExpression> headers = null, object body = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
public HttpRequest(HttpMethod method, string url, string inputProperty, Dictionary<string, string> headers = null, JObject body = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{ {
this.RegisterSourceLocation(callerPath, callerLine); this.RegisterSourceLocation(callerPath, callerLine);
this.Method = method; this.Method = method;
this.Url = url ?? throw new ArgumentNullException(nameof(url)); this.Url = url ?? throw new ArgumentNullException(nameof(url));
this.Headers = headers; this.Headers = headers;
this.Body = body; this.Body = JToken.FromObject(body);
} }
[JsonConstructor] [JsonConstructor]
@ -111,27 +107,51 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary>
/// Gets or sets the HttpMethod to use.
/// </summary>
/// <value>
/// HttpMethod.
/// </value>
[JsonConverter(typeof(StringEnumConverter))] [JsonConverter(typeof(StringEnumConverter))]
[JsonProperty("method")] [JsonProperty("method")]
public HttpMethod Method { get; set; } public HttpMethod Method { get; set; }
/// <summary>
/// Gets or sets the Url.
/// </summary>
/// <value>url.</value>
[JsonProperty("url")] [JsonProperty("url")]
public string Url { get; set; } public StringExpression Url { get; set; }
/// <summary>
/// Gets or sets headers.
/// </summary>
/// <value>
/// Headers.
/// </value>
[JsonProperty("headers")] [JsonProperty("headers")]
public Dictionary<string, string> Headers { get; set; } public Dictionary<string, StringExpression> Headers { get; set; }
/// <summary>
/// Gets or sets body payload.
/// </summary>
/// <value>
/// Body payload.
/// </value>
[JsonProperty("body")] [JsonProperty("body")]
public JToken Body { get; set; } public ValueExpression Body { get; set; }
/// <summary>
/// Gets or sets the ResponseType.
/// </summary>
/// <value>
/// The ResponseType.
/// </value>
[JsonProperty("responseType")] [JsonProperty("responseType")]
public ResponseTypes ResponseType { get; set; } = ResponseTypes.Json; public EnumExpression<ResponseTypes> ResponseType { get; set; } = ResponseTypes.Json;
/// <summary> /// <summary>
/// Gets or sets the property expression to store the HTTP response in. /// Gets or sets the property expression to store the HTTP response in.
@ -145,7 +165,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// The property expression to store the HTTP response in. /// The property expression to store the HTTP response in.
/// </value> /// </value>
[JsonProperty("resultProperty")] [JsonProperty("resultProperty")]
public string ResultProperty { get; set; } public StringExpression ResultProperty { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -154,7 +174,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -167,13 +189,22 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
JToken instanceBody = null; JToken instanceBody = null;
if (this.Body != null) if (this.Body != null)
{ {
instanceBody = (JToken)this.Body.DeepClone(); var (body, err) = this.Body.TryGetValue(dcState);
if (err != null)
{
throw new ArgumentException(err);
} }
var instanceHeaders = Headers == null ? null : new Dictionary<string, string>(Headers); instanceBody = (JToken)JToken.FromObject(body).DeepClone();
var instanceUrl = this.Url; }
instanceUrl = await new TextTemplate(this.Url).BindToData(dc.Context, dc.GetState()).ConfigureAwait(false); var instanceHeaders = Headers == null ? null : Headers.ToDictionary(kv => kv.Key, kv => kv.Value.GetValue(dcState));
var (instanceUrl, instanceUrlError) = this.Url.TryGetValue(dcState);
if (instanceUrlError != null)
{
throw new ArgumentException(instanceUrlError);
}
// Bind each string token to the data in state // Bind each string token to the data in state
if (instanceBody != null) if (instanceBody != null)
@ -186,9 +217,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
{ {
foreach (var unit in instanceHeaders) foreach (var unit in instanceHeaders)
{ {
client.DefaultRequestHeaders.Add( client.DefaultRequestHeaders.TryAddWithoutValidation(unit.Key, unit.Value);
await new TextTemplate(unit.Key).BindToData(dc.Context, dc.GetState()),
await new TextTemplate(unit.Value).BindToData(dc.Context, dc.GetState()));
} }
} }
@ -266,7 +295,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
object content = (object)await response.Content.ReadAsStringAsync(); object content = (object)await response.Content.ReadAsStringAsync();
switch (this.ResponseType) switch (this.ResponseType.GetValue(dcState))
{ {
case ResponseTypes.Activity: case ResponseTypes.Activity:
var activity = JsonConvert.DeserializeObject<Activity>((string)content); var activity = JsonConvert.DeserializeObject<Activity>((string)content);
@ -306,7 +335,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
if (this.ResultProperty != null) if (this.ResultProperty != null)
{ {
dc.GetState().SetValue(this.ResultProperty, requestResult); dcState.SetValue(this.ResultProperty.GetValue(dcState), requestResult);
} }
// return the actionResult as the result of this operation // return the actionResult as the result of this operation
@ -320,6 +349,8 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
private async Task ReplaceJTokenRecursively(DialogContext dc, JToken token) private async Task ReplaceJTokenRecursively(DialogContext dc, JToken token)
{ {
var dcState = dc.GetState();
switch (token.Type) switch (token.Type)
{ {
case JTokenType.Object: case JTokenType.Object:
@ -331,7 +362,8 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
break; break;
case JTokenType.Array: case JTokenType.Array:
foreach (var child in token.Children()) // NOTE: ToList() is required because JToken.Replace will break the enumeration.
foreach (var child in token.Children().ToList())
{ {
await ReplaceJTokenRecursively(dc, child); await ReplaceJTokenRecursively(dc, child);
} }
@ -348,17 +380,10 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
var text = token.ToString(); var text = token.ToString();
// if it is a "{bindingpath}" then run through expression engine and treat as a value // if it is a "{bindingpath}" then run through expression engine and treat as a value
if (text.StartsWith("{") && text.EndsWith("}")) var (result, error) = new ValueExpression(text).TryGetValue(dcState);
if (error == null)
{ {
text = text.Trim('{', '}'); token.Replace(JToken.FromObject(result));
var (val, error) = new ExpressionEngine().Parse(text).TryEvaluate(dc.GetState());
token.Replace(new JValue(val));
}
else
{
// use text template binding to bind in place to a string
var temp = await new TextTemplate(text).BindToData(dc.Context, dc.GetState());
token.Replace(new JValue(temp));
} }
} }

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

@ -20,9 +20,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.IfCondition"; public const string DeclarativeType = "Microsoft.IfCondition";
private Expression condition;
private Expression disabled;
private ActionScope trueScope; private ActionScope trueScope;
private ActionScope falseScope; private ActionScope falseScope;
@ -43,11 +40,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// The memory expression. /// The memory expression.
/// </value> /// </value>
[JsonProperty("condition")] [JsonProperty("condition")]
public string Condition public BoolExpression Condition { get; set; } = false;
{
get { return condition?.ToString(); }
set { condition = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets an optional expression which if is true will disable this action. /// Gets or sets an optional expression which if is true will disable this action.
@ -59,11 +52,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
[JsonProperty("actions")] [JsonProperty("actions")]
public List<Dialog> Actions { get; set; } = new List<Dialog>(); public List<Dialog> Actions { get; set; } = new List<Dialog>();
@ -110,7 +99,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -118,9 +109,8 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
// Ensure planning context // Ensure planning context
if (dc is SequenceContext planning) if (dc is SequenceContext planning)
{ {
var (value, error) = condition.TryEvaluate(dc.GetState()); var (conditionResult, error) = this.Condition.TryGetValue(dcState);
var conditionResult = error == null && value != null && (bool)value; if (error == null && conditionResult == true && TrueScope.Actions.Any())
if (conditionResult == true && TrueScope.Actions.Any())
{ {
// replace dialog with If True Action Scope // replace dialog with If True Action Scope
return await dc.ReplaceDialogAsync(this.TrueScope.Id, cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.ReplaceDialogAsync(this.TrueScope.Id, cancellationToken: cancellationToken).ConfigureAwait(false);

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

@ -19,8 +19,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.InitProperty"; public const string DeclarativeType = "Microsoft.InitProperty";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public InitProperty([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public InitProperty([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
@ -38,11 +36,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets property path to initialize. /// Gets or sets property path to initialize.
@ -51,7 +45,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Property path to initialize. /// Property path to initialize.
/// </value> /// </value>
[JsonProperty("property")] [JsonProperty("property")]
public string Property { get; set; } public StringExpression Property { get; set; }
/// <summary> /// <summary>
/// Gets or sets type, either Array or Object. /// Gets or sets type, either Array or Object.
@ -69,7 +63,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -77,13 +73,15 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
// Ensure planning context // Ensure planning context
if (dc is SequenceContext planning) if (dc is SequenceContext planning)
{ {
var state = dcState;
switch (Type.ToLower()) switch (Type.ToLower())
{ {
case "array": case "array":
dc.GetState().SetValue(this.Property, new JArray()); state.SetValue(this.Property.GetValue(state), new JArray());
break; break;
case "object": case "object":
dc.GetState().SetValue(this.Property, new JObject()); state.SetValue(this.Property.GetValue(state), new JObject());
break; break;
} }

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

@ -21,8 +21,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.LogAction"; public const string DeclarativeType = "Microsoft.LogAction";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public LogAction(string text = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public LogAction(string text = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{ {
@ -43,11 +41,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets lG expression to log. /// Gets or sets lG expression to log.
@ -65,14 +59,14 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Whether a TraceActivity will be sent in addition to console log. /// Whether a TraceActivity will be sent in addition to console log.
/// </value> /// </value>
[JsonProperty("traceActivity")] [JsonProperty("traceActivity")]
public bool TraceActivity { get; set; } = false; public BoolExpression TraceActivity { get; set; } = false;
/// <summary> /// <summary>
/// Gets or sets a label to use when describing a trace activity. /// Gets or sets a label to use when describing a trace activity.
/// </summary> /// </summary>
/// <value>The label to use. (default is the id of the action).</value> /// <value>The label to use. (default is the id of the action).</value>
[JsonProperty] [JsonProperty]
public string Label { get; set; } public StringExpression Label { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -81,18 +75,20 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
var text = await Text.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false); var text = await Text.BindToData(dc.Context, dcState).ConfigureAwait(false);
System.Diagnostics.Trace.TraceInformation(text); System.Diagnostics.Trace.TraceInformation(text);
if (this.TraceActivity) if (this.TraceActivity.GetValue(dcState))
{ {
var traceActivity = Activity.CreateTraceActivity(name: "Log", valueType: "Text", value: text, label: this.Label ?? dc.Parent?.ActiveDialog?.Id); var traceActivity = Activity.CreateTraceActivity(name: "Log", valueType: "Text", value: text, label: this.Label?.GetValue(dcState) ?? dc.Parent?.ActiveDialog?.Id);
await dc.Context.SendActivityAsync(traceActivity, cancellationToken).ConfigureAwait(false); await dc.Context.SendActivityAsync(traceActivity, cancellationToken).ConfigureAwait(false);
} }

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

@ -6,7 +6,7 @@ using Newtonsoft.Json;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
{ {
/// <summary> /// <summary>
/// Property Assignment. /// Property Assignment (used in SetProperty and SetProperties actions).
/// </summary> /// </summary>
public class PropertyAssignment public class PropertyAssignment
{ {
@ -15,13 +15,13 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// </summary> /// </summary>
/// <value>A property path expression.</value> /// <value>A property path expression.</value>
[JsonProperty("property")] [JsonProperty("property")]
public string Property { get; set; } public StringExpression Property { get; set; }
/// <summary> /// <summary>
/// Gets or sets the value to set. /// Gets or sets the value to set.
/// </summary> /// </summary>
/// <value>Value expression.</value> /// <value>Value expression.</value>
[JsonProperty("value")] [JsonProperty("value")]
public string Value { get; set; } public ValueExpression Value { get; set; }
} }
} }

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

@ -19,8 +19,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.RepeatDialog"; public const string DeclarativeType = "Microsoft.RepeatDialog";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public RepeatDialog([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public RepeatDialog([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
@ -38,11 +36,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -51,7 +45,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -61,17 +57,17 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
var targetDialogId = dc.Parent.ActiveDialog.Id; var targetDialogId = dc.Parent.ActiveDialog.Id;
var repeatedIds = dc.GetState().GetValue<List<string>>(TurnPath.REPEATEDIDS, () => new List<string>()); var repeatedIds = dcState.GetValue<List<string>>(TurnPath.REPEATEDIDS, () => new List<string>());
if (repeatedIds.Contains(targetDialogId)) if (repeatedIds.Contains(targetDialogId))
{ {
throw new ArgumentException($"Recursive loop detected, {targetDialogId} cannot be repeated twice in one turn."); throw new ArgumentException($"Recursive loop detected, {targetDialogId} cannot be repeated twice in one turn.");
} }
repeatedIds.Add(targetDialogId); repeatedIds.Add(targetDialogId);
dc.GetState().SetValue(TurnPath.REPEATEDIDS, repeatedIds); dcState.SetValue(TurnPath.REPEATEDIDS, repeatedIds);
// set the activity processed state (default is true) // set the activity processed state (default is true)
dc.GetState().SetValue(TurnPath.ACTIVITYPROCESSED, this.ActivityProcessed); dcState.SetValue(TurnPath.ACTIVITYPROCESSED, this.ActivityProcessed);
var turnResult = await dc.Parent.ReplaceDialogAsync(dc.Parent.ActiveDialog.Id, boundOptions, cancellationToken).ConfigureAwait(false); var turnResult = await dc.Parent.ReplaceDialogAsync(dc.Parent.ActiveDialog.Id, boundOptions, cancellationToken).ConfigureAwait(false);
turnResult.ParentEnded = true; turnResult.ParentEnded = true;

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

@ -19,10 +19,8 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.ReplaceDialog"; public const string DeclarativeType = "Microsoft.ReplaceDialog";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public ReplaceDialog(string dialogIdToCall = null, IDictionary<string, string> options = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public ReplaceDialog(string dialogIdToCall = null, object options = null, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base(dialogIdToCall, options) : base(dialogIdToCall, options)
{ {
this.RegisterSourceLocation(callerPath, callerLine); this.RegisterSourceLocation(callerPath, callerLine);
@ -38,11 +36,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -51,7 +45,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -62,7 +58,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
var boundOptions = BindOptions(dc, options); var boundOptions = BindOptions(dc, options);
// set the activity processed state (default is true) // set the activity processed state (default is true)
dc.GetState().SetValue(TurnPath.ACTIVITYPROCESSED, this.ActivityProcessed); dcState.SetValue(TurnPath.ACTIVITYPROCESSED, this.ActivityProcessed);
// replace dialog with bound options passed in as the options // replace dialog with bound options passed in as the options
return await dc.ReplaceDialogAsync(dialog.Id, options: boundOptions, cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.ReplaceDialogAsync(dialog.Id, options: boundOptions, cancellationToken: cancellationToken).ConfigureAwait(false);

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

@ -21,8 +21,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.SendActivity"; public const string DeclarativeType = "Microsoft.SendActivity";
private Expression disabled;
public SendActivity(Activity activity, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public SendActivity(Activity activity, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{ {
this.RegisterSourceLocation(callerPath, callerLine); this.RegisterSourceLocation(callerPath, callerLine);
@ -46,11 +44,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets template for the activity. /// Gets or sets template for the activity.
@ -68,12 +62,14 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
var activity = await Activity.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false); var activity = await Activity.BindToData(dc.Context, dcState).ConfigureAwait(false);
ResourceResponse response = null; ResourceResponse response = null;
if (activity.Type != "message" if (activity.Type != "message"
|| !string.IsNullOrEmpty(activity.Text) || !string.IsNullOrEmpty(activity.Text)

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

@ -20,8 +20,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.SetProperties"; public const string DeclarativeType = "Microsoft.SetProperties";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public SetProperties([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public SetProperties([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
@ -39,11 +37,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets additional property assignments. /// Gets or sets additional property assignments.
@ -61,21 +55,22 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
foreach (var propValue in this.Assignments) foreach (var propValue in this.Assignments)
{ {
var valexp = new ExpressionEngine().Parse(propValue.Value); var (value, valueError) = propValue.Value.TryGetValue(dcState);
var (value, valueError) = valexp.TryEvaluate(dc.GetState());
if (valueError != null) if (valueError != null)
{ {
throw new Exception($"Expression evaluation resulted in an error. Expression: {valexp.ToString()}. Error: {valueError}"); throw new Exception($"Expression evaluation resulted in an error. Expression: {propValue.Value.ToString()}. Error: {valueError}");
} }
dc.GetState().SetValue(propValue.Property, value); dcState.SetValue(propValue.Property.GetValue(dcState), value);
} }
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);

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

@ -5,6 +5,7 @@ using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs.Declarative;
using Microsoft.Bot.Expressions; using Microsoft.Bot.Expressions;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -18,9 +19,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.SetProperty"; public const string DeclarativeType = "Microsoft.SetProperty";
private Expression value;
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public SetProperty([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public SetProperty([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
: base() : base()
@ -38,11 +36,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets property path to put the value in. /// Gets or sets property path to put the value in.
@ -51,7 +45,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Property path to put the value in. /// Property path to put the value in.
/// </value> /// </value>
[JsonProperty("property")] [JsonProperty("property")]
public string Property { get; set; } public StringExpression Property { get; set; }
/// <summary> /// <summary>
/// Gets or sets the expression to get the value to put into property path. /// Gets or sets the expression to get the value to put into property path.
@ -60,11 +54,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// The expression to get the value to put into property path. /// The expression to get the value to put into property path.
/// </value> /// </value>
[JsonProperty("value")] [JsonProperty("value")]
public string Value public ValueExpression Value { get; set; }
{
get { return value?.ToString(); }
set { this.value = (value != null) ? new ExpressionEngine().Parse(value) : null; }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -73,21 +63,28 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState))
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
// SetProperty evaluates the "Value" expression and returns it as the result of the dialog // SetProperty evaluates the "Value" expression and returns it as the result of the dialog
var (value, valueError) = this.value.TryEvaluate(dc.GetState()); object value = null;
if (this.Value != null)
{
var (val, valueError) = this.Value.TryGetValue(dcState);
if (valueError != null) if (valueError != null)
{ {
throw new Exception($"Expression evaluation resulted in an error. Expression: {this.Value.ToString()}. Error: {valueError}"); throw new Exception($"Expression evaluation resulted in an error. Expression: {this.Value.ToString()}. Error: {valueError}");
} }
dc.GetState().SetValue(this.Property, value); value = val;
}
dc.GetState().SetValue(DialogPath.Retries, 0); dcState.SetValue(this.Property.GetValue(dcState), value);
dcState.SetValue(DialogPath.Retries, 0);
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }

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

@ -20,9 +20,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.SignOutUser"; public const string DeclarativeType = "Microsoft.SignOutUser";
private Expression userId;
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public SignOutUser([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public SignOutUser([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{ {
@ -39,29 +36,21 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the expression which resolves to the activityId to update. /// Gets or sets the expression which resolves to the activityId to update.
/// </summary> /// </summary>
/// <value>Expression to userId. If there is no expression, then the current user.id will be used.</value> /// <value>Expression to userId. If there is no expression, then the current user.id will be used.</value>
[JsonProperty("userId")] [JsonProperty("userId")]
public string UserId public StringExpression UserId { get; set; }
{
get { return userId?.ToString(); }
set { this.userId = (value != null) ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the name of the OAuth connection. /// Gets or sets the name of the OAuth connection.
/// </summary> /// </summary>
/// <value>The name of the OAuth connection.</value> /// <value>The name of the OAuth connection.</value>
[JsonProperty("connectionName")] [JsonProperty("connectionName")]
public string ConnectionName { get; set; } public StringExpression ConnectionName { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -70,24 +59,22 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
string userId = null; string userId = this.UserId?.GetValue(dcState);
var (result, error) = new ExpressionEngine().Parse(this.UserId).TryEvaluate(dc.GetState());
if (result != null)
{
userId = result as string;
}
if (!(dc.Context.Adapter is IUserTokenProvider adapter)) if (!(dc.Context.Adapter is IUserTokenProvider adapter))
{ {
throw new InvalidOperationException("SignoutUser(): not supported by the current adapter"); throw new InvalidOperationException("SignoutUser(): not supported by the current adapter");
} }
await adapter.SignOutUserAsync(dc.Context, this.ConnectionName, (string)userId, cancellationToken).ConfigureAwait(false); var connectionName = this.ConnectionName?.GetValue(dcState);
await adapter.SignOutUserAsync(dc.Context, connectionName, (string)userId, cancellationToken).ConfigureAwait(false);
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }

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

@ -22,8 +22,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
private Dictionary<string, Expression> caseExpressions = null; private Dictionary<string, Expression> caseExpressions = null;
private Expression condition;
private Expression disabled;
private ActionScope defaultScope; private ActionScope defaultScope;
[JsonConstructor] [JsonConstructor]
@ -34,17 +32,13 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
} }
/// <summary> /// <summary>
/// Gets or sets condition expression against memory Example: "user.age > 18". /// Gets or sets value expression against memory Example: "user.age".
/// </summary> /// </summary>
/// <value> /// <value>
/// Condition expression against memory Example: "user.age > 18". /// Value Expression against memory. This value expression will be combined with value expression in case statements to make a bool expression.
/// </value> /// </value>
[JsonProperty("condition")] [JsonProperty("condition")]
public string Condition public ValueExpression Condition { get; set; }
{
get { return condition?.ToString(); }
set { condition = (value != null) ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets an optional expression which if is true will disable this action. /// Gets or sets an optional expression which if is true will disable this action.
@ -56,11 +50,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets default case. /// Gets or sets default case.
@ -113,7 +103,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -127,13 +119,13 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
{ {
this.caseExpressions = new Dictionary<string, Expression>(); this.caseExpressions = new Dictionary<string, Expression>();
foreach (var c in this.Cases) foreach (var cse in this.Cases)
{ {
// Values for cases are always coerced to string // Values for cases are always coerced to string
var caseCondition = Expression.EqualsExpression(this.condition, c.CreateValueExpression()); var caseCondition = Expression.EqualsExpression(this.Condition.ToExpression(), cse.CreateValueExpression());
// Map of expression to actions // Map of expression to actions
this.caseExpressions[c.Value] = caseCondition; this.caseExpressions[cse.Value] = caseCondition;
} }
} }
} }
@ -142,7 +134,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
foreach (var caseScope in this.Cases) foreach (var caseScope in this.Cases)
{ {
var (value, error) = this.caseExpressions[caseScope.Value].TryEvaluate(dc.GetState()); var (value, error) = this.caseExpressions[caseScope.Value].TryEvaluate(dcState);
if (error != null) if (error != null)
{ {

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

@ -19,8 +19,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.TraceActivity"; public const string DeclarativeType = "Microsoft.TraceActivity";
private Expression disabled;
[JsonConstructor] [JsonConstructor]
public TraceActivity([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public TraceActivity([CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{ {
@ -37,11 +35,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets name of the trace activity. /// Gets or sets name of the trace activity.
@ -50,7 +44,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Name of the trace activity. /// Name of the trace activity.
/// </value> /// </value>
[JsonProperty("name")] [JsonProperty("name")]
public string Name { get; set; } public StringExpression Name { get; set; }
/// <summary> /// <summary>
/// Gets or sets value type of the trace activity. /// Gets or sets value type of the trace activity.
@ -59,7 +53,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Value type of the trace activity. /// Value type of the trace activity.
/// </value> /// </value>
[JsonProperty("valueType")] [JsonProperty("valueType")]
public string ValueType { get; set; } public StringExpression ValueType { get; set; }
/// <summary> /// <summary>
/// Gets or sets value expression to send as the value. /// Gets or sets value expression to send as the value.
@ -68,14 +62,14 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Property binding to memory to send as the value. /// Property binding to memory to send as the value.
/// </value> /// </value>
[JsonProperty("value")] [JsonProperty("value")]
public string Value { get; set; } public ValueExpression Value { get; set; }
/// <summary> /// <summary>
/// Gets or sets a label to use when describing a trace activity. /// Gets or sets a label to use when describing a trace activity.
/// </summary> /// </summary>
/// <value>The label to use. (default will use Name or parent dialog.id).</value> /// <value>The label to use. (default will use Name or parent dialog.id).</value>
[JsonProperty] [JsonProperty]
public string Label { get; set; } public StringExpression Label { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -84,22 +78,34 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
object value = null; object value = null;
if (!string.IsNullOrEmpty(this.Value)) if (this.Value != null)
{ {
value = dc.GetState().GetValue<object>(this.Value); var (val, valError) = this.Value.TryGetValue(dcState);
if (valError != null)
{
throw new Exception(valError);
}
value = val;
} }
else else
{ {
value = dc.GetState().GetMemorySnapshot(); value = dcState.GetMemorySnapshot();
} }
var traceActivity = Activity.CreateTraceActivity(this.Name ?? "Trace", valueType: this.ValueType ?? "State", value: value, label: this.Label ?? this.Name ?? dc.Parent?.ActiveDialog?.Id); var name = this.Name?.GetValue(dcState);
var valueType = this.ValueType?.GetValue(dcState);
var label = this.Label?.GetValue(dcState);
var traceActivity = Activity.CreateTraceActivity(name ?? "Trace", valueType: valueType ?? "State", value: value, label: label ?? name ?? dc.Parent?.ActiveDialog?.Id);
await dc.Context.SendActivityAsync(traceActivity, cancellationToken).ConfigureAwait(false); await dc.Context.SendActivityAsync(traceActivity, cancellationToken).ConfigureAwait(false);
return await dc.EndDialogAsync(traceActivity, cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(traceActivity, cancellationToken: cancellationToken).ConfigureAwait(false);
} }

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

@ -20,9 +20,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.UpdateActivity"; public const string DeclarativeType = "Microsoft.UpdateActivity";
private Expression activityId;
private Expression disabled;
public UpdateActivity(Activity activity, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0) public UpdateActivity(Activity activity, [CallerFilePath] string callerPath = "", [CallerLineNumber] int callerLine = 0)
{ {
this.RegisterSourceLocation(callerPath, callerLine); this.RegisterSourceLocation(callerPath, callerLine);
@ -46,11 +43,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// A boolean expression. /// A boolean expression.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets template for the activity. /// Gets or sets template for the activity.
@ -66,11 +59,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// </summary> /// </summary>
/// <value>Expression to activityId.</value> /// <value>Expression to activityId.</value>
[JsonProperty("activityId")] [JsonProperty("activityId")]
public string ActivityId public StringExpression ActivityId { get; set; }
{
get { return activityId.ToString(); }
set { activityId = new ExpressionEngine().Parse(value); }
}
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -79,13 +68,15 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
var activity = await Activity.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false); var activity = await Activity.BindToData(dc.Context, dcState).ConfigureAwait(false);
var (result, error) = activityId.TryEvaluate(dc.GetState()); var (result, error) = this.ActivityId.TryGetValue(dcState);
if (error != null) if (error != null)
{ {
throw new ArgumentException(error); throw new ArgumentException(error);

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

@ -5,6 +5,7 @@ using System.Collections.Generic;
using Microsoft.Bot.Builder.AI.Luis; using Microsoft.Bot.Builder.AI.Luis;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Actions; using Microsoft.Bot.Builder.Dialogs.Adaptive.Actions;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Conditions; using Microsoft.Bot.Builder.Dialogs.Adaptive.Conditions;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Converters;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Generators; using Microsoft.Bot.Builder.Dialogs.Adaptive.Generators;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Input; using Microsoft.Bot.Builder.Dialogs.Adaptive.Input;
using Microsoft.Bot.Builder.Dialogs.Adaptive.QnA; using Microsoft.Bot.Builder.Dialogs.Adaptive.QnA;
@ -14,6 +15,7 @@ using Microsoft.Bot.Builder.Dialogs.Adaptive.Selectors;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Testing; using Microsoft.Bot.Builder.Dialogs.Adaptive.Testing;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Testing.Actions; using Microsoft.Bot.Builder.Dialogs.Adaptive.Testing.Actions;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Testing.TestActions; using Microsoft.Bot.Builder.Dialogs.Adaptive.Testing.TestActions;
using Microsoft.Bot.Builder.Dialogs.Choices;
using Microsoft.Bot.Builder.Dialogs.Debugging; using Microsoft.Bot.Builder.Dialogs.Debugging;
using Microsoft.Bot.Builder.Dialogs.Declarative; using Microsoft.Bot.Builder.Dialogs.Declarative;
using Microsoft.Bot.Builder.Dialogs.Declarative.Converters; using Microsoft.Bot.Builder.Dialogs.Declarative.Converters;
@ -21,6 +23,7 @@ using Microsoft.Bot.Builder.Dialogs.Declarative.Loaders;
using Microsoft.Bot.Builder.Dialogs.Declarative.Resolvers; using Microsoft.Bot.Builder.Dialogs.Declarative.Resolvers;
using Microsoft.Bot.Builder.Dialogs.Declarative.Types; using Microsoft.Bot.Builder.Dialogs.Declarative.Types;
using Newtonsoft.Json; using Newtonsoft.Json;
using static Microsoft.Bot.Builder.Dialogs.Adaptive.Actions.EditArray;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{ {
@ -167,8 +170,28 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
yield return new InterfaceConverter<TestAction>(refResolver, sourceMap, paths); yield return new InterfaceConverter<TestAction>(refResolver, sourceMap, paths);
yield return new InterfaceConverter<EntityRecognizer>(refResolver, sourceMap, paths); yield return new InterfaceConverter<EntityRecognizer>(refResolver, sourceMap, paths);
yield return new InterfaceConverter<ITriggerSelector>(refResolver, sourceMap, paths); yield return new InterfaceConverter<ITriggerSelector>(refResolver, sourceMap, paths);
yield return new ExpressionPropertyConverter<ChoiceSet>();
yield return new ExpressionPropertyConverter<ExpressionProperty<List<string>>>(); yield return new IntExpressionConverter();
yield return new NumberExpressionConverter();
yield return new StringExpressionConverter();
yield return new ValueExpressionConverter();
yield return new BoolExpressionConverter();
yield return new DialogExpressionConverter(refResolver, sourceMap, paths);
yield return new ObjectExpressionConverter<ChoiceSet>();
yield return new ObjectExpressionConverter<ChoiceFactoryOptions>();
yield return new ObjectExpressionConverter<FindChoicesOptions>();
yield return new ArrayExpressionConverter<string>();
yield return new ArrayExpressionConverter<Choice>();
yield return new EnumExpressionConverter<ActionChangeType>();
yield return new EnumExpressionConverter<ArrayChangeType>();
yield return new EnumExpressionConverter<AttachmentOutputFormat>();
yield return new EnumExpressionConverter<ListStyle>();
yield return new EnumExpressionConverter<ChoiceOutputFormat>();
yield return new ChoiceSetConverter();
yield return new ActivityTemplateConverter(); yield return new ActivityTemplateConverter();
yield return new JObjectConverter(refResolver); yield return new JObjectConverter(refResolver);
} }

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

@ -153,31 +153,33 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
EnsureDependenciesInstalled(); EnsureDependenciesInstalled();
if (!dc.GetState().ContainsKey(DialogPath.EventCounter)) var dcState = dc.GetState();
if (!dcState.ContainsKey(DialogPath.EventCounter))
{ {
dc.GetState().SetValue(DialogPath.EventCounter, 0u); dcState.SetValue(DialogPath.EventCounter, 0u);
} }
if (dialogSchema != null && !dc.GetState().ContainsKey(DialogPath.RequiredProperties)) if (dialogSchema != null && !dcState.ContainsKey(DialogPath.RequiredProperties))
{ {
// RequiredProperties control what properties must be filled in. // RequiredProperties control what properties must be filled in.
// Initialize if not present from schema. // Initialize if not present from schema.
dc.GetState().SetValue(DialogPath.RequiredProperties, dialogSchema.Required()); dcState.SetValue(DialogPath.RequiredProperties, dialogSchema.Required());
} }
if (needsTracker) if (needsTracker)
{ {
if (!dc.GetState().ContainsKey(ConditionTracker)) if (!dcState.ContainsKey(ConditionTracker))
{ {
var parser = Selector.Parser; var parser = Selector.Parser;
foreach (var trigger in Triggers) foreach (var trigger in Triggers)
{ {
if (trigger.RunOnce) if (trigger.RunOnce && trigger.Condition != null)
{ {
var paths = dc.GetState().TrackPaths(parser.Parse(trigger.Condition).References()); var paths = dcState.TrackPaths(trigger.Condition.ToExpression().References());
var triggerPath = $"{ConditionTracker}.{trigger.Id}."; var triggerPath = $"{ConditionTracker}.{trigger.Id}.";
dc.GetState().SetValue(triggerPath + "paths", paths); dcState.SetValue(triggerPath + "paths", paths);
dc.GetState().SetValue(triggerPath + "lastRun", 0u); dcState.SetValue(triggerPath + "lastRun", 0u);
} }
} }
} }
@ -303,14 +305,16 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
protected virtual async Task<bool> ProcessEventAsync(SequenceContext sequenceContext, DialogEvent dialogEvent, bool preBubble, CancellationToken cancellationToken = default(CancellationToken)) protected virtual async Task<bool> ProcessEventAsync(SequenceContext sequenceContext, DialogEvent dialogEvent, bool preBubble, CancellationToken cancellationToken = default(CancellationToken))
{ {
var dcState = sequenceContext.GetState();
// Save into turn // Save into turn
sequenceContext.GetState().SetValue(TurnPath.DIALOGEVENT, dialogEvent); dcState.SetValue(TurnPath.DIALOGEVENT, dialogEvent);
EnsureDependenciesInstalled(); EnsureDependenciesInstalled();
// Count of events processed // Count of events processed
var count = sequenceContext.GetState().GetValue<uint>(DialogPath.EventCounter); var count = dcState.GetValue<uint>(DialogPath.EventCounter);
sequenceContext.GetState().SetValue(DialogPath.EventCounter, ++count); dcState.SetValue(DialogPath.EventCounter, ++count);
// Look for triggered evt // Look for triggered evt
var handled = await QueueFirstMatchAsync(sequenceContext, dialogEvent, preBubble, cancellationToken).ConfigureAwait(false); var handled = await QueueFirstMatchAsync(sequenceContext, dialogEvent, preBubble, cancellationToken).ConfigureAwait(false);
@ -326,7 +330,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
switch (dialogEvent.Name) switch (dialogEvent.Name)
{ {
case AdaptiveEvents.BeginDialog: case AdaptiveEvents.BeginDialog:
if (sequenceContext.GetState().GetBoolValue(TurnPath.ACTIVITYPROCESSED) == false) if (dcState.GetBoolValue(TurnPath.ACTIVITYPROCESSED) == false)
{ {
// Emit leading ActivityReceived event // Emit leading ActivityReceived event
var activityReceivedEvent = new DialogEvent() var activityReceivedEvent = new DialogEvent()
@ -355,7 +359,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
await ProcessEventAsync(sequenceContext, dialogEvent: recognizeUtteranceEvent, preBubble: true, cancellationToken: cancellationToken).ConfigureAwait(false); await ProcessEventAsync(sequenceContext, dialogEvent: recognizeUtteranceEvent, preBubble: true, cancellationToken: cancellationToken).ConfigureAwait(false);
// Emit leading RecognizedIntent event // Emit leading RecognizedIntent event
var recognized = sequenceContext.GetState().GetValue<RecognizerResult>(TurnPath.RECOGNIZED); var recognized = dcState.GetValue<RecognizerResult>(TurnPath.RECOGNIZED);
var recognizedIntentEvent = new DialogEvent var recognizedIntentEvent = new DialogEvent
{ {
Name = AdaptiveEvents.RecognizedIntent, Name = AdaptiveEvents.RecognizedIntent,
@ -372,7 +376,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
// process the users uterrance when its continued. // process the users uterrance when its continued.
if (handled) if (handled)
{ {
sequenceContext.GetState().SetValue(TurnPath.INTERRUPTED, true); dcState.SetValue(TurnPath.INTERRUPTED, true);
} }
break; break;
@ -384,12 +388,12 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
// Recognize utterance // Recognize utterance
var recognized = await OnRecognize(sequenceContext, cancellationToken).ConfigureAwait(false); var recognized = await OnRecognize(sequenceContext, cancellationToken).ConfigureAwait(false);
sequenceContext.GetState().SetValue(TurnPath.RECOGNIZED, recognized); dcState.SetValue(TurnPath.RECOGNIZED, recognized);
var (name, score) = recognized.GetTopScoringIntent(); var (name, score) = recognized.GetTopScoringIntent();
sequenceContext.GetState().SetValue(TurnPath.TOPINTENT, name); dcState.SetValue(TurnPath.TOPINTENT, name);
sequenceContext.GetState().SetValue(DialogPath.LastIntent, name); dcState.SetValue(DialogPath.LastIntent, name);
sequenceContext.GetState().SetValue(TurnPath.TOPSCORE, score); dcState.SetValue(TurnPath.TOPSCORE, score);
if (Recognizer != null) if (Recognizer != null)
{ {
@ -407,7 +411,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
switch (dialogEvent.Name) switch (dialogEvent.Name)
{ {
case AdaptiveEvents.BeginDialog: case AdaptiveEvents.BeginDialog:
if (sequenceContext.GetState().GetBoolValue(TurnPath.ACTIVITYPROCESSED) == false) if (dcState.GetBoolValue(TurnPath.ACTIVITYPROCESSED) == false)
{ {
var activityReceivedEvent = new DialogEvent var activityReceivedEvent = new DialogEvent
{ {
@ -450,7 +454,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
// process the users uterrance when its continued. // process the users uterrance when its continued.
if (handled) if (handled)
{ {
sequenceContext.GetState().SetValue(TurnPath.INTERRUPTED, true); dcState.SetValue(TurnPath.INTERRUPTED, true);
} }
break; break;
@ -555,6 +559,8 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
// Is the current dialog still on the stack? // Is the current dialog still on the stack?
if (sequenceContext.ActiveDialog != null) if (sequenceContext.ActiveDialog != null)
{ {
var dcState = sequenceContext.GetState();
// Completed actions so continue processing entity queues // Completed actions so continue processing entity queues
var handled = await ProcessQueuesAsync(sequenceContext, cancellationToken).ConfigureAwait(false); var handled = await ProcessQueuesAsync(sequenceContext, cancellationToken).ConfigureAwait(false);
@ -566,7 +572,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
else if (ShouldEnd(sequenceContext)) else if (ShouldEnd(sequenceContext))
{ {
RestoreParentGenerator(sequenceContext.Context); RestoreParentGenerator(sequenceContext.Context);
sequenceContext.GetState().TryGetValue<object>(DefaultResultProperty, out var result); dcState.TryGetValue<object>(DefaultResultProperty, out var result);
return await sequenceContext.EndDialogAsync(result, cancellationToken).ConfigureAwait(false); return await sequenceContext.EndDialogAsync(result, cancellationToken).ConfigureAwait(false);
} }
@ -620,6 +626,8 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
// In order ClearProperties, AssignEntity, ChooseProperties, ChooseEntity, EndOfActions. // In order ClearProperties, AssignEntity, ChooseProperties, ChooseEntity, EndOfActions.
private async Task<bool> ProcessQueuesAsync(SequenceContext sequenceContext, CancellationToken cancellationToken) private async Task<bool> ProcessQueuesAsync(SequenceContext sequenceContext, CancellationToken cancellationToken)
{ {
var dcState = sequenceContext.GetState();
DialogEvent evt; DialogEvent evt;
var queues = EntityEvents.Read(sequenceContext); var queues = EntityEvents.Read(sequenceContext);
var changed = false; var changed = false;
@ -642,7 +650,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
entity = new object[] { entity }; entity = new object[] { entity };
} }
sequenceContext.GetState().SetValue($"{TurnPath.RECOGNIZED}.entities.{val.Entity.Name}", entity); dcState.SetValue($"{TurnPath.RECOGNIZED}.entities.{val.Entity.Name}", entity);
changed = true; changed = true;
} }
else if (queues.ChooseProperties.Any()) else if (queues.ChooseProperties.Any())
@ -663,7 +671,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
queues.Write(sequenceContext); queues.Write(sequenceContext);
} }
sequenceContext.GetState().SetValue(DialogPath.LastEvent, evt.Name); dcState.SetValue(DialogPath.LastEvent, evt.Name);
var handled = await this.ProcessEventAsync(sequenceContext, dialogEvent: evt, preBubble: true, cancellationToken: cancellationToken).ConfigureAwait(false); var handled = await this.ProcessEventAsync(sequenceContext, dialogEvent: evt, preBubble: true, cancellationToken: cancellationToken).ConfigureAwait(false);
if (!handled) if (!handled)
{ {
@ -690,7 +698,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{ {
var evt = selection.First(); var evt = selection.First();
await sequenceContext.DebuggerStepAsync(evt, dialogEvent, cancellationToken).ConfigureAwait(false); await sequenceContext.DebuggerStepAsync(evt, dialogEvent, cancellationToken).ConfigureAwait(false);
Trace.TraceInformation($"Executing Dialog: {Id} Rule[{selection}]: {evt.GetType().Name}: {evt.GetExpression(new ExpressionEngine())}"); Trace.TraceInformation($"Executing Dialog: {Id} Rule[{evt.Id}]: {evt.GetType().Name}: {evt.GetExpression(new ExpressionEngine())}");
var changes = await evt.ExecuteAsync(sequenceContext).ConfigureAwait(false); var changes = await evt.ExecuteAsync(sequenceContext).ConfigureAwait(false);
if (changes != null && changes.Any()) if (changes != null && changes.Any())
@ -711,7 +719,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{ {
installedDependencies = true; installedDependencies = true;
var id = 0u; var id = 0;
foreach (var trigger in Triggers) foreach (var trigger in Triggers)
{ {
if (trigger is IDialogDependencies depends) if (trigger is IDialogDependencies depends)
@ -730,7 +738,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
if (trigger.Priority == null) if (trigger.Priority == null)
{ {
// Constant expression defined from order // Constant expression defined from order
trigger.Priority = id.ToString(); trigger.Priority = id;
} }
if (trigger.Id == null) if (trigger.Id == null)
@ -812,17 +820,19 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
// Merge new queues into existing queues of ambiguity events // Merge new queues into existing queues of ambiguity events
private void ProcessEntities(SequenceContext context) private void ProcessEntities(SequenceContext context)
{ {
var dcState = context.GetState();
if (dialogSchema != null) if (dialogSchema != null)
{ {
if (context.GetState().TryGetValue<string>(DialogPath.LastEvent, out var lastEvent)) if (dcState.TryGetValue<string>(DialogPath.LastEvent, out var lastEvent))
{ {
context.GetState().RemoveValue(DialogPath.LastEvent); dcState.RemoveValue(DialogPath.LastEvent);
} }
var queues = EntityEvents.Read(context); var queues = EntityEvents.Read(context);
var entities = NormalizeEntities(context); var entities = NormalizeEntities(context);
var utterance = context.Context.Activity?.AsMessageActivity()?.Text; var utterance = context.Context.Activity?.AsMessageActivity()?.Text;
if (!context.GetState().TryGetValue<string[]>(DialogPath.ExpectedProperties, out var expected)) if (!dcState.TryGetValue<string[]>(DialogPath.ExpectedProperties, out var expected))
{ {
expected = new string[0]; expected = new string[0];
} }
@ -833,9 +843,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
var unrecognized = SplitUtterance(utterance, recognized); var unrecognized = SplitUtterance(utterance, recognized);
// TODO: Is this actually useful information? // TODO: Is this actually useful information?
context.GetState().SetValue(TurnPath.UNRECOGNIZEDTEXT, unrecognized); dcState.SetValue(TurnPath.UNRECOGNIZEDTEXT, unrecognized);
context.GetState().SetValue(TurnPath.RECOGNIZEDENTITIES, recognized); dcState.SetValue(TurnPath.RECOGNIZEDENTITIES, recognized);
var turn = context.GetState().GetValue<uint>(DialogPath.EventCounter); var turn = dcState.GetValue<uint>(DialogPath.EventCounter);
CombineOldEntityToProperties(queues, turn); CombineOldEntityToProperties(queues, turn);
queues.Write(context); queues.Write(context);
} }
@ -873,11 +883,12 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
// Combine entity values and $instance meta-data // Combine entity values and $instance meta-data
private Dictionary<string, List<EntityInfo>> NormalizeEntities(SequenceContext context) private Dictionary<string, List<EntityInfo>> NormalizeEntities(SequenceContext context)
{ {
var dcState = context.GetState();
var entityToInfo = new Dictionary<string, List<EntityInfo>>(); var entityToInfo = new Dictionary<string, List<EntityInfo>>();
var text = context.GetState().GetValue<string>(TurnPath.RECOGNIZED + ".text"); var text = dcState.GetValue<string>(TurnPath.RECOGNIZED + ".text");
if (context.GetState().TryGetValue<dynamic>(TurnPath.RECOGNIZED + ".entities", out var entities)) if (dcState.TryGetValue<dynamic>(TurnPath.RECOGNIZED + ".entities", out var entities))
{ {
var turn = context.GetState().GetValue<uint>(DialogPath.EventCounter); var turn = dcState.GetValue<uint>(DialogPath.EventCounter);
var metaData = entities["$instance"]; var metaData = entities["$instance"];
foreach (var entry in entities) foreach (var entry in entities)
{ {
@ -1070,6 +1081,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
private List<EntityInfo> AddToQueues(SequenceContext context, Dictionary<string, List<EntityInfo>> entities, string[] expected, EntityEvents queues, string lastEvent) private List<EntityInfo> AddToQueues(SequenceContext context, Dictionary<string, List<EntityInfo>> entities, string[] expected, EntityEvents queues, string lastEvent)
{ {
var dcState = context.GetState();
var candidates = (from candidate in RemoveOverlappingPerProperty(Candidates(entities, expected)) var candidates = (from candidate in RemoveOverlappingPerProperty(Candidates(entities, expected))
orderby candidate.IsExpected descending orderby candidate.IsExpected descending
select candidate).ToList(); select candidate).ToList();
@ -1103,7 +1115,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{ {
// Resolve choice and add to queues // Resolve choice and add to queues
queues.ChooseProperties.Dequeue(); queues.ChooseProperties.Dequeue();
context.GetState().SetValue(DialogPath.ExpectedProperties, new List<string> { choice.Property }); dcState.SetValue(DialogPath.ExpectedProperties, new List<string> { choice.Property });
choice.IsExpected = true; choice.IsExpected = true;
AddMappingToQueue(choice, queues); AddMappingToQueue(choice, queues);
mapped = true; mapped = true;

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

@ -22,13 +22,10 @@ namespace Microsoft.Bot.Builder.Dialogs
{ {
private const string DIALOGS = "_dialogs"; private const string DIALOGS = "_dialogs";
private const string LASTACCESS = "_lastAccess"; private const string LASTACCESS = "_lastAccess";
private DialogSet dialogSet;
private string rootDialogId; private string rootDialogId;
public DialogManager(Dialog rootDialog = null) public DialogManager(Dialog rootDialog = null)
{ {
this.dialogSet = new DialogSet();
if (rootDialog != null) if (rootDialog != null)
{ {
this.RootDialog = rootDialog; this.RootDialog = rootDialog;
@ -63,7 +60,7 @@ namespace Microsoft.Bot.Builder.Dialogs
{ {
if (this.rootDialogId != null) if (this.rootDialogId != null)
{ {
return this.dialogSet.Find(this.rootDialogId); return this.Dialogs.Find(this.rootDialogId);
} }
return null; return null;
@ -71,11 +68,11 @@ namespace Microsoft.Bot.Builder.Dialogs
set set
{ {
this.dialogSet = new DialogSet(); this.Dialogs = new DialogSet();
if (value != null) if (value != null)
{ {
this.rootDialogId = value.Id; this.rootDialogId = value.Id;
this.dialogSet.Add(value); this.Dialogs.Add(value);
} }
else else
{ {
@ -84,6 +81,13 @@ namespace Microsoft.Bot.Builder.Dialogs
} }
} }
/// <summary>
/// Gets or sets global dialogs that you want to have be callable.
/// </summary>
/// <value>Dialogs set.</value>
[JsonIgnore]
public DialogSet Dialogs { get; set; } = new DialogSet();
/// <summary> /// <summary>
/// Gets or sets the DialogStateManagerConfiguration. /// Gets or sets the DialogStateManagerConfiguration.
/// </summary> /// </summary>
@ -141,7 +145,7 @@ namespace Microsoft.Bot.Builder.Dialogs
DialogState dialogState = await dialogsProperty.GetAsync(context, () => new DialogState(), cancellationToken: cancellationToken).ConfigureAwait(false); DialogState dialogState = await dialogsProperty.GetAsync(context, () => new DialogState(), cancellationToken: cancellationToken).ConfigureAwait(false);
// Create DialogContext // Create DialogContext
var dc = new DialogContext(this.dialogSet, context, dialogState); var dc = new DialogContext(this.Dialogs, context, dialogState);
// set DSM configuration // set DSM configuration
dc.SetStateConfiguration(this.StateConfiguration ?? DialogStateManager.CreateStandardConfiguration(conversationState, userState)); dc.SetStateConfiguration(this.StateConfiguration ?? DialogStateManager.CreateStandardConfiguration(conversationState, userState));

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

@ -46,7 +46,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
/// <returns>Event queues.</returns> /// <returns>Event queues.</returns>
public static EntityEvents Read(SequenceContext context) public static EntityEvents Read(SequenceContext context)
{ {
if (!context.GetState().TryGetValue<EntityEvents>(Events, out var queues)) var dcState = context.GetState();
if (!dcState.TryGetValue<EntityEvents>(Events, out var queues))
{ {
queues = new EntityEvents(); queues = new EntityEvents();
} }

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

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. // Licensed under the MIT License.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -16,8 +17,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Ask for an open-ended response. /// Ask for an open-ended response.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This sends an activity and then terminates with <see cref="DialogTurnStatus.CompleteAndWait"/> in order to allow the parent /// This sends an activity and then terminates the turn with <see cref="DialogTurnStatus.CompleteAndWait"/>.
/// adaptive dialog to handle the user utterance. /// The next activity from the user will then be handled by the parent adaptive dialog.
///
/// It also builds in a model of the properties that are expected in response through <see cref="DialogPath.ExpectedProperties"/>. /// It also builds in a model of the properties that are expected in response through <see cref="DialogPath.ExpectedProperties"/>.
/// <see cref="DialogPath.Retries"/> is updated as the same question is asked multiple times. /// <see cref="DialogPath.Retries"/> is updated as the same question is asked multiple times.
/// </remarks> /// </remarks>
@ -29,7 +31,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
[JsonConstructor] [JsonConstructor]
public Ask( public Ask(
string text = null, string text = null,
ExpressionProperty<List<string>> expectedProperties = null, ArrayExpression<string> expectedProperties = null,
[CallerFilePath] string callerPath = "", [CallerFilePath] string callerPath = "",
[CallerLineNumber] int callerLine = 0) [CallerLineNumber] int callerLine = 0)
: base(text, callerPath, callerLine) : base(text, callerPath, callerLine)
@ -45,24 +47,26 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
/// Properties expected to be filled by response. /// Properties expected to be filled by response.
/// </value> /// </value>
[JsonProperty("expectedProperties")] [JsonProperty("expectedProperties")]
public ExpressionProperty<List<string>> ExpectedProperties { get; set; } public ArrayExpression<string> ExpectedProperties { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default)
{ {
var dcState = dc.GetState();
//get number of retries from memory //get number of retries from memory
if (!dc.GetState().TryGetValue(DialogPath.Retries, out int retries)) if (!dcState.TryGetValue(DialogPath.Retries, out int retries))
{ {
retries = 0; retries = 0;
} }
dc.GetState().TryGetValue(TurnPath.DIALOGEVENT, out DialogEvent trigger); dcState.TryGetValue(TurnPath.DIALOGEVENT, out DialogEvent trigger);
var expected = ExpectedProperties?.GetValue(dc.GetState()); var expected = this.ExpectedProperties?.GetValue(dcState);
if (expected != null if (expected != null
&& dc.GetState().TryGetValue(DialogPath.ExpectedProperties, out List<string> lastExpectedProperties) && dcState.TryGetValue(DialogPath.ExpectedProperties, out List<string> lastExpectedProperties)
&& !expected.Any(prop => !lastExpectedProperties.Contains(prop)) && !expected.Any(prop => !lastExpectedProperties.Contains(prop))
&& !lastExpectedProperties.Any(prop => !expected.Contains(prop)) && !lastExpectedProperties.Any(prop => !expected.Contains(prop))
&& dc.GetState().TryGetValue(DialogPath.LastTriggerEvent, out DialogEvent lastTrigger) && dcState.TryGetValue(DialogPath.LastTriggerEvent, out DialogEvent lastTrigger)
&& lastTrigger.Name.Equals(trigger.Name)) && lastTrigger.Name.Equals(trigger.Name))
{ {
retries++; retries++;
@ -72,9 +76,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Actions
retries = 0; retries = 0;
} }
dc.GetState().SetValue(DialogPath.Retries, retries); dcState.SetValue(DialogPath.Retries, retries);
dc.GetState().SetValue(DialogPath.LastTriggerEvent, trigger); dcState.SetValue(DialogPath.LastTriggerEvent, trigger);
dc.GetState().SetValue(DialogPath.ExpectedProperties, expected); dcState.SetValue(DialogPath.ExpectedProperties, expected);
var result = await base.BeginDialogAsync(dc, options, cancellationToken).ConfigureAwait(false); var result = await base.BeginDialogAsync(dc, options, cancellationToken).ConfigureAwait(false);
result.Status = DialogTurnStatus.CompleteAndWait; result.Status = DialogTurnStatus.CompleteAndWait;
return result; return result;

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

@ -38,11 +38,12 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
} }
[JsonProperty("outputFormat")] [JsonProperty("outputFormat")]
public AttachmentOutputFormat OutputFormat { get; set; } = AttachmentOutputFormat.First; public EnumExpression<AttachmentOutputFormat> OutputFormat { get; set; } = AttachmentOutputFormat.First;
protected override Task<InputState> OnRecognizeInput(DialogContext dc) protected override Task<InputState> OnRecognizeInput(DialogContext dc)
{ {
var input = dc.GetState().GetValue<List<Attachment>>(VALUE_PROPERTY); var dcState = dc.GetState();
var input = dcState.GetValue<List<Attachment>>(VALUE_PROPERTY);
var first = input.Count > 0 ? input[0] : null; var first = input.Count > 0 ? input[0] : null;
if (first == null || (string.IsNullOrEmpty(first.ContentUrl) && first.Content == null)) if (first == null || (string.IsNullOrEmpty(first.ContentUrl) && first.Content == null))
@ -50,13 +51,13 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
return Task.FromResult(InputState.Unrecognized); return Task.FromResult(InputState.Unrecognized);
} }
switch (this.OutputFormat) switch (this.OutputFormat.GetValue(dcState))
{ {
case AttachmentOutputFormat.All: case AttachmentOutputFormat.All:
dc.GetState().SetValue(VALUE_PROPERTY, input); dcState.SetValue(VALUE_PROPERTY, input);
break; break;
case AttachmentOutputFormat.First: case AttachmentOutputFormat.First:
dc.GetState().SetValue(VALUE_PROPERTY, first); dcState.SetValue(VALUE_PROPERTY, first);
break; break;
} }

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

@ -61,7 +61,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// Value Expression or List of choices (string or Choice objects) to present to user. /// Value Expression or List of choices (string or Choice objects) to present to user.
/// </value> /// </value>
[JsonProperty("choices")] [JsonProperty("choices")]
public ChoiceSet Choices { get; set; } public ObjectExpression<ChoiceSet> Choices { get; set; }
/// <summary> /// <summary>
/// Gets or sets listStyle to use to render the choices. /// Gets or sets listStyle to use to render the choices.
@ -70,7 +70,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// ListStyle to use to render the choices. /// ListStyle to use to render the choices.
/// </value> /// </value>
[JsonProperty("style")] [JsonProperty("style")]
public ListStyle Style { get; set; } = ListStyle.Auto; public EnumExpression<ListStyle> Style { get; set; } = ListStyle.Auto;
/// <summary> /// <summary>
/// Gets or sets defaultLocale. /// Gets or sets defaultLocale.
@ -79,7 +79,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// DefaultLocale. /// DefaultLocale.
/// </value> /// </value>
[JsonProperty("defaultLocale")] [JsonProperty("defaultLocale")]
public string DefaultLocale { get; set; } = null; public StringExpression DefaultLocale { get; set; }
/// <summary> /// <summary>
/// Gets or sets control the format of the response (value or the index of the choice). /// Gets or sets control the format of the response (value or the index of the choice).
@ -88,7 +88,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// Control the format of the response (value or the index of the choice). /// Control the format of the response (value or the index of the choice).
/// </value> /// </value>
[JsonProperty("outputFormat")] [JsonProperty("outputFormat")]
public ChoiceOutputFormat OutputFormat { get; set; } = ChoiceOutputFormat.Value; public EnumExpression<ChoiceOutputFormat> OutputFormat { get; set; } = ChoiceOutputFormat.Value;
/// <summary> /// <summary>
/// Gets or sets choiceOptions controls display options for customizing language. /// Gets or sets choiceOptions controls display options for customizing language.
@ -97,7 +97,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// ChoiceOptions controls display options for customizing language. /// ChoiceOptions controls display options for customizing language.
/// </value> /// </value>
[JsonProperty("choiceOptions")] [JsonProperty("choiceOptions")]
public ChoiceFactoryOptions ChoiceOptions { get; set; } = null; public ObjectExpression<ChoiceFactoryOptions> ChoiceOptions { get; set; }
/// <summary> /// <summary>
/// Gets or sets customize how to use the choices to recognize the response from the user. /// Gets or sets customize how to use the choices to recognize the response from the user.
@ -106,7 +106,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// Customize how to use the choices to recognize the response from the user. /// Customize how to use the choices to recognize the response from the user.
/// </value> /// </value>
[JsonProperty("recognizerOptions")] [JsonProperty("recognizerOptions")]
public FindChoicesOptions RecognizerOptions { get; set; } = null; public ObjectExpression<FindChoicesOptions> RecognizerOptions { get; set; } = null;
public override Task<DialogTurnResult> ResumeDialogAsync(DialogContext dc, DialogReason reason, object result = null, CancellationToken cancellationToken = default(CancellationToken)) public override Task<DialogTurnResult> ResumeDialogAsync(DialogContext dc, DialogReason reason, object result = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -125,12 +125,18 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
var op = options as ChoiceInputOptions; var op = options as ChoiceInputOptions;
if (op == null || op.Choices == null || op.Choices.Count == 0) if (op == null || op.Choices == null || op.Choices.Count == 0)
{ {
var dcState = dc.GetState();
if (op == null) if (op == null)
{ {
op = new ChoiceInputOptions(); op = new ChoiceInputOptions();
} }
var choices = this.Choices.GetValue(dc.GetState()); var (choices, error) = this.Choices.TryGetValue(dcState);
if (error != null)
{
throw new Exception(error);
}
op.Choices = choices; op.Choices = choices;
} }
@ -139,15 +145,17 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
protected override Task<InputState> OnRecognizeInput(DialogContext dc) protected override Task<InputState> OnRecognizeInput(DialogContext dc)
{ {
var input = dc.GetState().GetValue<object>(VALUE_PROPERTY); var dcState = dc.GetState();
var options = dc.GetState().GetValue<ChoiceInputOptions>(ThisPath.OPTIONS);
var input = dcState.GetValue<object>(VALUE_PROPERTY);
var options = dcState.GetValue<ChoiceInputOptions>(ThisPath.OPTIONS);
var choices = options.Choices; var choices = options.Choices;
var result = new PromptRecognizerResult<FoundChoice>(); var result = new PromptRecognizerResult<FoundChoice>();
if (dc.Context.Activity.Type == ActivityTypes.Message) if (dc.Context.Activity.Type == ActivityTypes.Message)
{ {
var opt = this.RecognizerOptions ?? new FindChoicesOptions(); var opt = this.RecognizerOptions?.GetValue(dcState) ?? new FindChoicesOptions();
opt.Locale = GetCulture(dc); opt.Locale = GetCulture(dc);
var results = ChoiceRecognizers.RecognizeChoices(input.ToString(), choices, opt); var results = ChoiceRecognizers.RecognizeChoices(input.ToString(), choices, opt);
if (results == null || results.Count == 0) if (results == null || results.Count == 0)
@ -156,14 +164,14 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
} }
var foundChoice = results[0].Resolution; var foundChoice = results[0].Resolution;
switch (this.OutputFormat) switch (this.OutputFormat.GetValue(dcState))
{ {
case ChoiceOutputFormat.Value: case ChoiceOutputFormat.Value:
default: default:
dc.GetState().SetValue(VALUE_PROPERTY, foundChoice.Value); dcState.SetValue(VALUE_PROPERTY, foundChoice.Value);
break; break;
case ChoiceOutputFormat.Index: case ChoiceOutputFormat.Index:
dc.GetState().SetValue(VALUE_PROPERTY, foundChoice.Index); dcState.SetValue(VALUE_PROPERTY, foundChoice.Index);
break; break;
} }
} }
@ -173,27 +181,34 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
protected override async Task<IActivity> OnRenderPrompt(DialogContext dc, InputState state) protected override async Task<IActivity> OnRenderPrompt(DialogContext dc, InputState state)
{ {
var dcState = dc.GetState();
var locale = GetCulture(dc); var locale = GetCulture(dc);
var prompt = await base.OnRenderPrompt(dc, state); var prompt = await base.OnRenderPrompt(dc, state);
var channelId = dc.Context.Activity.ChannelId; var channelId = dc.Context.Activity.ChannelId;
var choicePrompt = new ChoicePrompt(this.Id); var choicePrompt = new ChoicePrompt(this.Id);
var choiceOptions = this.ChoiceOptions ?? ChoiceInput.DefaultChoiceOptions[locale]; var choiceOptions = this.ChoiceOptions?.GetValue(dcState) ?? ChoiceInput.DefaultChoiceOptions[locale];
var choices = this.Choices.GetValue(dc.GetState()); var (choices, error) = this.Choices.TryGetValue(dcState);
if (error != null)
{
throw new Exception(error);
}
return this.AppendChoices(prompt.AsMessageActivity(), channelId, choices, this.Style, choiceOptions); return this.AppendChoices(prompt.AsMessageActivity(), channelId, choices, this.Style.GetValue(dcState), choiceOptions);
} }
private string GetCulture(DialogContext dc) private string GetCulture(DialogContext dc)
{ {
var dcState = dc.GetState();
if (!string.IsNullOrWhiteSpace(dc.Context.Activity.Locale)) if (!string.IsNullOrWhiteSpace(dc.Context.Activity.Locale))
{ {
return dc.Context.Activity.Locale; return dc.Context.Activity.Locale;
} }
if (!string.IsNullOrWhiteSpace(this.DefaultLocale)) if (this.DefaultLocale != null)
{ {
return this.DefaultLocale; return this.DefaultLocale.GetValue(dcState);
} }
return English; return English;

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

@ -1,69 +1,60 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs.Choices; using Microsoft.Bot.Builder.Dialogs.Choices;
using Microsoft.Bot.Builder.Dialogs.Declarative;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
{ {
/// <summary> /// <summary>
/// Defines Choices Property as either collection of Choices, array of strings or string which is an expression to one of thoses. /// Defines ChoiceSet collection.
/// </summary> /// </summary>
public class ChoiceSet : ExpressionProperty<List<Choice>> [JsonConverter(typeof(ChoiceSetConverter))]
public class ChoiceSet : List<Choice>
{ {
public ChoiceSet() public ChoiceSet()
{ {
} }
public ChoiceSet(string expression) public ChoiceSet(IEnumerable<Choice> choices)
: base(expression)
{
}
public ChoiceSet(List<Choice> choices)
: base(choices) : base(choices)
{ {
} }
public ChoiceSet(object choices) public ChoiceSet(object obj)
: base(choices)
{
}
protected override List<Choice> ConvertObject(object result)
{ {
// support string[] => choice[] // support string[] => choice[]
if (result is IEnumerable<string> strings) if (obj is IEnumerable<string> strings)
{ {
return strings.Select(s => new Choice(s)).ToList(); foreach (var str in strings)
{
this.Add(new Choice(str));
}
} }
// support JArray to => choice // support JArray to => choice
if (result is JArray array) if (obj is JArray array)
{ {
var choices = new List<Choice>();
if (array.HasValues) if (array.HasValues)
{ {
foreach (var element in array) foreach (var element in array)
{ {
if (element is JValue jval) if (element is JValue jval)
{ {
choices.Add(new Choice(element.ToString())); this.Add(new Choice(element.ToString()));
} }
else if (element is JObject jobj) else if (element is JObject jobj)
{ {
choices.Add(jobj.ToObject<Choice>()); this.Add(jobj.ToObject<Choice>());
}
}
} }
} }
} }
return choices; public static implicit operator ChoiceSet(bool value) => new ChoiceSet(value);
}
return JArray.FromObject(result).ToObject<List<Choice>>(); public static implicit operator ChoiceSet(string value) => new ChoiceSet(value);
}
public static implicit operator ChoiceSet(JToken value) => new ChoiceSet(value);
} }
} }

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

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs.Choices; using Microsoft.Bot.Builder.Dialogs.Choices;
using Microsoft.Bot.Builder.Dialogs.Declarative;
using Microsoft.Bot.Expressions; using Microsoft.Bot.Expressions;
using Microsoft.Bot.Schema; using Microsoft.Bot.Schema;
using Microsoft.Recognizers.Text.Choice; using Microsoft.Recognizers.Text.Choice;
@ -40,23 +41,24 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
} }
[JsonProperty("defaultLocale")] [JsonProperty("defaultLocale")]
public string DefaultLocale { get; set; } = null; public StringExpression DefaultLocale { get; set; }
[JsonProperty("style")] [JsonProperty("style")]
public ListStyle Style { get; set; } = ListStyle.Auto; public EnumExpression<ListStyle> Style { get; set; } = ListStyle.Auto;
[JsonProperty("choiceOptions")] [JsonProperty("choiceOptions")]
public ChoiceFactoryOptions ChoiceOptions { get; set; } = null; public ObjectExpression<ChoiceFactoryOptions> ChoiceOptions { get; set; }
[JsonProperty("confirmChoices")] [JsonProperty("confirmChoices")]
public List<Choice> ConfirmChoices { get; set; } = null; public ArrayExpression<Choice> ConfirmChoices { get; set; }
[JsonProperty("outputFormat")] [JsonProperty("outputFormat")]
public string OutputFormat { get; set; } public StringExpression OutputFormat { get; set; }
protected override Task<InputState> OnRecognizeInput(DialogContext dc) protected override Task<InputState> OnRecognizeInput(DialogContext dc)
{ {
var input = dc.GetState().GetValue<object>(VALUE_PROPERTY); var dcState = dc.GetState();
var input = dcState.GetValue<object>(VALUE_PROPERTY);
if (dc.Context.Activity.Type == ActivityTypes.Message) if (dc.Context.Activity.Type == ActivityTypes.Message)
{ {
// Recognize utterance // Recognize utterance
@ -67,18 +69,17 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
var first = results[0]; var first = results[0];
if (bool.TryParse(first.Resolution["value"].ToString(), out var value)) if (bool.TryParse(first.Resolution["value"].ToString(), out var value))
{ {
dc.GetState().SetValue(VALUE_PROPERTY, value); dcState.SetValue(VALUE_PROPERTY, value);
if (!string.IsNullOrEmpty(OutputFormat)) if (OutputFormat != null)
{ {
var outputExpression = new ExpressionEngine().Parse(OutputFormat); var (outputValue, error) = OutputFormat.TryGetValue(dcState);
var (outputValue, error) = outputExpression.TryEvaluate(dc.GetState());
if (error == null) if (error == null)
{ {
dc.GetState().SetValue(VALUE_PROPERTY, outputValue); dcState.SetValue(VALUE_PROPERTY, outputValue);
} }
else else
{ {
throw new Exception($"OutputFormat Expression evaluation resulted in an error. Expression: {outputExpression.ToString()}. Error: {error}"); throw new Exception($"OutputFormat Expression evaluation resulted in an error. Expression: {OutputFormat.ToString()}. Error: {error}");
} }
} }
@ -93,18 +94,18 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
{ {
// First check whether the prompt was sent to the user with numbers - if it was we should recognize numbers // First check whether the prompt was sent to the user with numbers - if it was we should recognize numbers
var defaults = ChoiceDefaults[culture]; var defaults = ChoiceDefaults[culture];
var choiceOptions = ChoiceOptions ?? defaults.Item3; var choiceOptions = ChoiceOptions?.GetValue(dcState) ?? defaults.Item3;
// This logic reflects the fact that IncludeNumbers is nullable and True is the default set in Inline style // This logic reflects the fact that IncludeNumbers is nullable and True is the default set in Inline style
if (!choiceOptions.IncludeNumbers.HasValue || choiceOptions.IncludeNumbers.Value) if (!choiceOptions.IncludeNumbers.HasValue || choiceOptions.IncludeNumbers.Value)
{ {
// The text may be a number in which case we will interpret that as a choice. // The text may be a number in which case we will interpret that as a choice.
var confirmChoices = ConfirmChoices ?? new List<Choice>() { defaults.Item1, defaults.Item2 }; var confirmChoices = ConfirmChoices?.GetValue(dcState) ?? new List<Choice>() { defaults.Item1, defaults.Item2 };
var secondAttemptResults = ChoiceRecognizers.RecognizeChoices(input.ToString(), confirmChoices); var secondAttemptResults = ChoiceRecognizers.RecognizeChoices(input.ToString(), confirmChoices);
if (secondAttemptResults.Count > 0) if (secondAttemptResults.Count > 0)
{ {
input = secondAttemptResults[0].Resolution.Index == 0; input = secondAttemptResults[0].Resolution.Index == 0;
dc.GetState().SetValue(VALUE_PROPERTY, input); dcState.SetValue(VALUE_PROPERTY, input);
} }
else else
{ {
@ -120,15 +121,16 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
protected override async Task<IActivity> OnRenderPrompt(DialogContext dc, InputState state) protected override async Task<IActivity> OnRenderPrompt(DialogContext dc, InputState state)
{ {
// Format prompt to send // Format prompt to send
var dcState = dc.GetState();
var channelId = dc.Context.Activity.ChannelId; var channelId = dc.Context.Activity.ChannelId;
var culture = GetCulture(dc); var culture = GetCulture(dc);
var defaults = ChoiceDefaults[culture]; var defaults = ChoiceDefaults[culture];
var choiceOptions = ChoiceOptions ?? defaults.Item3; var choiceOptions = ChoiceOptions?.GetValue(dcState) ?? defaults.Item3;
var confirmChoices = ConfirmChoices ?? new List<Choice>() { defaults.Item1, defaults.Item2 }; var confirmChoices = ConfirmChoices?.GetValue(dcState) ?? new List<Choice>() { defaults.Item1, defaults.Item2 };
var prompt = await base.OnRenderPrompt(dc, state); var prompt = await base.OnRenderPrompt(dc, state);
var (style, error) = this.Style.TryGetValue(dcState);
return this.AppendChoices(prompt.AsMessageActivity(), channelId, confirmChoices, this.Style, choiceOptions); return this.AppendChoices(prompt.AsMessageActivity(), channelId, confirmChoices, style, choiceOptions);
} }
private string GetCulture(DialogContext dc) private string GetCulture(DialogContext dc)
@ -138,9 +140,10 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
return dc.Context.Activity.Locale; return dc.Context.Activity.Locale;
} }
if (!string.IsNullOrEmpty(this.DefaultLocale)) if (this.DefaultLocale != null)
{ {
return this.DefaultLocale; var dcState = dc.GetState();
return this.DefaultLocale.GetValue(dcState);
} }
return English; return English;

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

@ -23,17 +23,18 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
} }
[JsonProperty("defaultLocale")] [JsonProperty("defaultLocale")]
public string DefaultLocale { get; set; } = null; public StringExpression DefaultLocale { get; set; } = null;
[JsonProperty("outputFormat")] [JsonProperty("outputFormat")]
public string OutputFormat { get; set; } public StringExpression OutputFormat { get; set; }
protected override Task<InputState> OnRecognizeInput(DialogContext dc) protected override Task<InputState> OnRecognizeInput(DialogContext dc)
{ {
var input = dc.GetState().GetValue<object>(VALUE_PROPERTY); var dcState = dc.GetState();
var input = dcState.GetValue<object>(VALUE_PROPERTY);
var culture = GetCulture(dc); var culture = GetCulture(dc);
var results = DateTimeRecognizer.RecognizeDateTime(input.ToString(), culture); var refTime = dc.Context.Activity.LocalTimestamp?.LocalDateTime;
var results = DateTimeRecognizer.RecognizeDateTime(input.ToString(), culture, refTime: refTime);
if (results.Count > 0) if (results.Count > 0)
{ {
// Return list of resolutions from first match // Return list of resolutions from first match
@ -44,18 +45,18 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
result.Add(ReadResolution(value)); result.Add(ReadResolution(value));
} }
dc.GetState().SetValue(VALUE_PROPERTY, result); dcState.SetValue(VALUE_PROPERTY, result);
if (!string.IsNullOrEmpty(OutputFormat))
if (OutputFormat != null)
{ {
var outputExpression = new ExpressionEngine().Parse(OutputFormat); var (outputValue, error) = this.OutputFormat.TryGetValue(dcState);
var (outputValue, error) = outputExpression.TryEvaluate(dc.GetState());
if (error == null) if (error == null)
{ {
dc.GetState().SetValue(VALUE_PROPERTY, outputValue); dcState.SetValue(VALUE_PROPERTY, outputValue);
} }
else else
{ {
throw new Exception($"OutputFormat Expression evaluation resulted in an error. Expression: {outputExpression.ToString()}. Error: {error}"); throw new Exception($"OutputFormat Expression evaluation resulted in an error. Expression: {this.OutputFormat}. Error: {error}");
} }
} }
} }
@ -101,9 +102,10 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
return dc.Context.Activity.Locale; return dc.Context.Activity.Locale;
} }
if (!string.IsNullOrEmpty(this.DefaultLocale)) if (this.DefaultLocale != null)
{ {
return this.DefaultLocale; var dcState = dc.GetState();
return this.DefaultLocale.GetValue(dcState);
} }
return English; return English;

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

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -21,9 +22,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
protected const string VALUE_PROPERTY = "this.value"; protected const string VALUE_PROPERTY = "this.value";
#pragma warning restore SA1310 // Field should not contain underscore. #pragma warning restore SA1310 // Field should not contain underscore.
private Expression allowInterruptions;
private Expression disabled;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the input should always prompt the user regardless of there being a value or not. /// Gets or sets a value indicating whether the input should always prompt the user regardless of there being a value or not.
/// </summary> /// </summary>
@ -31,7 +29,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// A value indicating whether the input should always prompt the user regardless of there being a value or not. /// A value indicating whether the input should always prompt the user regardless of there being a value or not.
/// </value> /// </value>
[JsonProperty("alwaysPrompt")] [JsonProperty("alwaysPrompt")]
public bool AlwaysPrompt { get; set; } = false; public BoolExpression AlwaysPrompt { get; set; }
/// <summary> /// <summary>
/// Gets or sets intteruption policy. /// Gets or sets intteruption policy.
@ -40,14 +38,10 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// "true". /// "true".
/// </example> /// </example>
/// <value> /// <value>
/// Intteruption policy. /// Intteruption policy. Default is True.
/// </value> /// </value>
[JsonProperty("allowInterruptions")] [JsonProperty("allowInterruptions")]
public string AllowInterruptions public BoolExpression AllowInterruptions { get; set; }
{
get { return allowInterruptions?.ToString(); }
set { allowInterruptions = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets an optional expression which if is true will disable this action. /// Gets or sets an optional expression which if is true will disable this action.
@ -56,23 +50,19 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// "user.age > 18". /// "user.age > 18".
/// </example> /// </example>
/// <value> /// <value>
/// A boolean expression. /// A boolean expression. Default is false.
/// </value> /// </value>
[JsonProperty("disabled")] [JsonProperty("disabled")]
public string Disabled public BoolExpression Disabled { get; set; }
{
get { return disabled?.ToString(); }
set { disabled = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the value expression which the input will be bound to. /// Gets or sets the memory property path which the value will be bound to.
/// </summary> /// </summary>
/// <value> /// <value>
/// The value expression which the input will be bound to. /// The property path to the value that the input dialog will be bound to.
/// </value> /// </value>
[JsonProperty("property")] [JsonProperty("property")]
public string Property { get; set; } public StringExpression Property { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value expression which can be used to intialize the input prompt. /// Gets or sets a value expression which can be used to intialize the input prompt.
@ -85,7 +75,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// A value expression which can be used to intialize the input prompt. /// A value expression which can be used to intialize the input prompt.
/// </value> /// </value>
[JsonProperty("value")] [JsonProperty("value")]
public string Value { get; set; } public ValueExpression Value { get; set; }
/// <summary> /// <summary>
/// Gets or sets the activity to send to the user. /// Gets or sets the activity to send to the user.
@ -133,13 +123,13 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
public List<string> Validations { get; set; } = new List<string>(); public List<string> Validations { get; set; } = new List<string>();
/// <summary> /// <summary>
/// Gets or sets maximum number of times to ask the user for this value before the dilog gives up. /// Gets or sets maximum number of times to ask the user for this value before the dialog gives up.
/// </summary> /// </summary>
/// <value> /// <value>
/// Maximum number of times to ask the user for this value before the dilog gives up. /// Maximum number of times to ask the user for this value before the dilog gives up.
/// </value> /// </value>
[JsonProperty("maxTurnCount")] [JsonProperty("maxTurnCount")]
public int? MaxTurnCount { get; set; } public IntExpression MaxTurnCount { get; set; }
/// <summary> /// <summary>
/// Gets or sets the default value for the input dialog when MaxTurnCount is exceeded. /// Gets or sets the default value for the input dialog when MaxTurnCount is exceeded.
@ -148,7 +138,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// The default value for the input dialog when MaxTurnCount is exceeded. /// The default value for the input dialog when MaxTurnCount is exceeded.
/// </value> /// </value>
[JsonProperty("defaultValue")] [JsonProperty("defaultValue")]
public string DefaultValue { get; set; } public ValueExpression DefaultValue { get; set; }
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options, CancellationToken cancellationToken = default(CancellationToken)) public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options, CancellationToken cancellationToken = default(CancellationToken))
{ {
@ -162,28 +152,33 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.disabled != null && (bool?)this.disabled.TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState) == true)
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
var op = OnInitializeOptions(dc, options); var op = OnInitializeOptions(dc, options);
dc.GetState().SetValue(ThisPath.OPTIONS, op); dcState.SetValue(ThisPath.OPTIONS, op);
dc.GetState().SetValue(TURN_COUNT_PROPERTY, 0); dcState.SetValue(TURN_COUNT_PROPERTY, 0);
var alwaysPrompt = this.AlwaysPrompt?.GetValue(dcState) ?? false;
// If AlwaysPrompt is set to true, then clear Property value for turn 0. // If AlwaysPrompt is set to true, then clear Property value for turn 0.
if (!string.IsNullOrEmpty(this.Property) && this.AlwaysPrompt) var property = this.Property?.GetValue(dcState);
if (property != null && alwaysPrompt)
{ {
dc.GetState().SetValue(this.Property, null); dcState.SetValue(property, null);
} }
var state = this.AlwaysPrompt ? InputState.Missing : await this.RecognizeInput(dc, 0); var state = alwaysPrompt ? InputState.Missing : await this.RecognizeInput(dc, 0);
if (state == InputState.Valid) if (state == InputState.Valid)
{ {
var input = dc.GetState().GetValue<object>(VALUE_PROPERTY); var input = dcState.GetValue<object>(VALUE_PROPERTY);
// set property // set property
dc.GetState().SetValue(this.Property, input); dcState.SetValue(property, input);
// return as result too // return as result too
return await dc.EndDialogAsync(input); return await dc.EndDialogAsync(input);
@ -193,7 +188,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
// turnCount should increase here, because you want when nextTurn comes in // turnCount should increase here, because you want when nextTurn comes in
// We will set the turn count to 1 so the input will not pick from "dialog.value" // We will set the turn count to 1 so the input will not pick from "dialog.value"
// and instead go with "turn.activity.text" // and instead go with "turn.activity.text"
dc.GetState().SetValue(TURN_COUNT_PROPERTY, 1); dcState.SetValue(TURN_COUNT_PROPERTY, 1);
return await this.PromptUser(dc, state); return await this.PromptUser(dc, state);
} }
} }
@ -206,43 +201,45 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
return Dialog.EndOfTurn; return Dialog.EndOfTurn;
} }
var interrupted = dc.GetState().GetValue<bool>(TurnPath.INTERRUPTED, () => false); var dcState = dc.GetState();
var turnCount = dc.GetState().GetValue<int>(TURN_COUNT_PROPERTY, () => 0);
var interrupted = dcState.GetValue<bool>(TurnPath.INTERRUPTED, () => false);
var turnCount = dcState.GetValue<int>(TURN_COUNT_PROPERTY, () => 0);
// Perform base recognition // Perform base recognition
var state = await this.RecognizeInput(dc, interrupted ? 0 : turnCount); var state = await this.RecognizeInput(dc, interrupted ? 0 : turnCount);
if (state == InputState.Valid) if (state == InputState.Valid)
{ {
var input = dc.GetState().GetValue<object>(VALUE_PROPERTY); var input = dcState.GetValue<object>(VALUE_PROPERTY);
// set output property // set output property
if (!string.IsNullOrEmpty(this.Property)) if (this.Property != null)
{ {
dc.GetState().SetValue(this.Property, input); dcState.SetValue(this.Property.GetValue(dcState), input);
} }
return await dc.EndDialogAsync(input).ConfigureAwait(false); return await dc.EndDialogAsync(input).ConfigureAwait(false);
} }
else if (this.MaxTurnCount == null || turnCount < this.MaxTurnCount) else if (this.MaxTurnCount == null || turnCount < this.MaxTurnCount.GetValue(dcState))
{ {
// increase the turnCount as last step // increase the turnCount as last step
dc.GetState().SetValue(TURN_COUNT_PROPERTY, turnCount + 1); dcState.SetValue(TURN_COUNT_PROPERTY, turnCount + 1);
return await this.PromptUser(dc, state).ConfigureAwait(false); return await this.PromptUser(dc, state).ConfigureAwait(false);
} }
else else
{ {
if (this.DefaultValue != null) if (this.DefaultValue != null)
{ {
var (value, error) = new ExpressionEngine().Parse(this.DefaultValue).TryEvaluate(dc.GetState()); var (value, error) = this.DefaultValue.TryGetValue(dcState);
if (this.DefaultValueResponse != null) if (this.DefaultValueResponse != null)
{ {
var response = await this.DefaultValueResponse.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false); var response = await this.DefaultValueResponse.BindToData(dc.Context, dcState).ConfigureAwait(false);
await dc.Context.SendActivityAsync(response).ConfigureAwait(false); await dc.Context.SendActivityAsync(response).ConfigureAwait(false);
} }
// set output property // set output property
dc.GetState().SetValue(this.Property, value); dcState.SetValue(this.Property.GetValue(dcState), value);
return await dc.EndDialogAsync(value).ConfigureAwait(false); return await dc.EndDialogAsync(value).ConfigureAwait(false);
} }
@ -262,15 +259,17 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
{ {
if (e.Name == DialogEvents.ActivityReceived && dc.Context.Activity.Type == ActivityTypes.Message) if (e.Name == DialogEvents.ActivityReceived && dc.Context.Activity.Type == ActivityTypes.Message)
{ {
var dcState = dc.GetState();
// Ask parent to perform recognition // Ask parent to perform recognition
await dc.Parent.EmitEventAsync(AdaptiveEvents.RecognizeUtterance, value: dc.Context.Activity, bubble: false, cancellationToken: cancellationToken).ConfigureAwait(false); await dc.Parent.EmitEventAsync(AdaptiveEvents.RecognizeUtterance, value: dc.Context.Activity, bubble: false, cancellationToken: cancellationToken).ConfigureAwait(false);
// Should we allow interruptions // Should we allow interruptions
var canInterrupt = true; var canInterrupt = true;
if (allowInterruptions != null) if (this.AllowInterruptions != null)
{ {
var (value, error) = allowInterruptions.TryEvaluate(dc.GetState()); var (allowInterruptions, error) = this.AllowInterruptions.TryGetValue(dcState);
canInterrupt = error == null && value != null && (bool)value; canInterrupt = error == null && allowInterruptions;
} }
// Stop bubbling if interruptions ar NOT allowed // Stop bubbling if interruptions ar NOT allowed
@ -349,16 +348,18 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
protected virtual async Task<IActivity> OnRenderPrompt(DialogContext dc, InputState state) protected virtual async Task<IActivity> OnRenderPrompt(DialogContext dc, InputState state)
{ {
var dcState = dc.GetState();
switch (state) switch (state)
{ {
case InputState.Unrecognized: case InputState.Unrecognized:
if (this.UnrecognizedPrompt != null) if (this.UnrecognizedPrompt != null)
{ {
return await this.UnrecognizedPrompt.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false); return await this.UnrecognizedPrompt.BindToData(dc.Context, dcState).ConfigureAwait(false);
} }
else if (this.InvalidPrompt != null) else if (this.InvalidPrompt != null)
{ {
return await this.InvalidPrompt.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false); return await this.InvalidPrompt.BindToData(dc.Context, dcState).ConfigureAwait(false);
} }
break; break;
@ -366,37 +367,40 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
case InputState.Invalid: case InputState.Invalid:
if (this.InvalidPrompt != null) if (this.InvalidPrompt != null)
{ {
return await this.InvalidPrompt.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false); return await this.InvalidPrompt.BindToData(dc.Context, dcState).ConfigureAwait(false);
} }
else if (this.UnrecognizedPrompt != null) else if (this.UnrecognizedPrompt != null)
{ {
return await this.UnrecognizedPrompt.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false); return await this.UnrecognizedPrompt.BindToData(dc.Context, dcState).ConfigureAwait(false);
} }
break; break;
} }
return await this.Prompt.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false); return await this.Prompt.BindToData(dc.Context, dcState).ConfigureAwait(false);
} }
private async Task<InputState> RecognizeInput(DialogContext dc, int turnCount) private async Task<InputState> RecognizeInput(DialogContext dc, int turnCount)
{ {
dynamic input = null; dynamic input = null;
var dcState = dc.GetState();
// Use Property expression for input first // Use Property expression for input first
if (!string.IsNullOrEmpty(this.Property)) if (this.Property != null)
{ {
dc.GetState().TryGetValue(this.Property, out input); var property = this.Property.GetValue(dcState);
dcState.TryGetValue(property, out input);
// Clear property to avoid it being stuck on the next turn. It will get written // Clear property to avoid it being stuck on the next turn. It will get written
// back if the value passes validations. // back if the value passes validations.
dc.GetState().SetValue(this.Property, null); dcState.SetValue(property, null);
} }
// Use Value expression for input second // Use Value expression for input second
if (input == null && !string.IsNullOrEmpty(this.Value)) if (input == null && this.Value != null)
{ {
var (value, valueError) = new ExpressionEngine().Parse(this.Value).TryEvaluate(dc.GetState()); var (value, valueError) = this.Value.TryGetValue(dcState);
if (valueError != null) if (valueError != null)
{ {
throw new Exception($"In InputDialog, this.Value expression evaluation resulted in an error. Expression: {this.Value}. Error: {valueError}"); throw new Exception($"In InputDialog, this.Value expression evaluation resulted in an error. Expression: {this.Value}. Error: {valueError}");
@ -406,7 +410,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
} }
// Fallback to using activity // Fallback to using activity
bool activityProcessed = dc.GetState().GetBoolValue(TurnPath.ACTIVITYPROCESSED); bool activityProcessed = dcState.GetBoolValue(TurnPath.ACTIVITYPROCESSED);
if (!activityProcessed && input == null && turnCount > 0) if (!activityProcessed && input == null && turnCount > 0)
{ {
if (this.GetType().Name == nameof(AttachmentInput)) if (this.GetType().Name == nameof(AttachmentInput))
@ -420,7 +424,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
} }
// Update "this.value" and perform additional recognition and validations // Update "this.value" and perform additional recognition and validations
dc.GetState().SetValue(VALUE_PROPERTY, input); dcState.SetValue(VALUE_PROPERTY, input);
if (input != null) if (input != null)
{ {
var state = await this.OnRecognizeInput(dc).ConfigureAwait(false); var state = await this.OnRecognizeInput(dc).ConfigureAwait(false);
@ -428,15 +432,15 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
{ {
foreach (var validation in this.Validations) foreach (var validation in this.Validations)
{ {
var exp = new ExpressionEngine().Parse(validation); var exp = new ExpressionEngine().Parse(validation.TrimStart('='));
var (value, error) = exp.TryEvaluate(dc.GetState()); var (value, error) = exp.TryEvaluate(dcState);
if (value == null || (value is bool && (bool)value == false)) if (value == null || (value is bool && (bool)value == false))
{ {
return InputState.Invalid; return InputState.Invalid;
} }
} }
dc.GetState().SetValue(TurnPath.ACTIVITYPROCESSED, true); dcState.SetValue(TurnPath.ACTIVITYPROCESSED, true);
return InputState.Valid; return InputState.Valid;
} }
else else

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

@ -23,14 +23,15 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
} }
[JsonProperty("defaultLocale")] [JsonProperty("defaultLocale")]
public string DefaultLocale { get; set; } = null; public StringExpression DefaultLocale { get; set; } = null;
[JsonProperty("outputFormat")] [JsonProperty("outputFormat")]
public string OutputFormat { get; set; } public NumberExpression OutputFormat { get; set; }
protected override Task<InputState> OnRecognizeInput(DialogContext dc) protected override Task<InputState> OnRecognizeInput(DialogContext dc)
{ {
var input = dc.GetState().GetValue<object>(VALUE_PROPERTY); var dcState = dc.GetState();
var input = dcState.GetValue<object>(VALUE_PROPERTY);
var culture = GetCulture(dc); var culture = GetCulture(dc);
var results = NumberRecognizer.RecognizeNumber(input.ToString(), culture); var results = NumberRecognizer.RecognizeNumber(input.ToString(), culture);
@ -60,19 +61,18 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
return Task.FromResult(InputState.Unrecognized); return Task.FromResult(InputState.Unrecognized);
} }
dc.GetState().SetValue(VALUE_PROPERTY, input); dcState.SetValue(VALUE_PROPERTY, input);
if (!string.IsNullOrEmpty(OutputFormat)) if (OutputFormat != null)
{ {
var outputExpression = new ExpressionEngine().Parse(OutputFormat); var (outputValue, error) = this.OutputFormat.TryGetValue(dcState);
var (outputValue, error) = outputExpression.TryEvaluate(dc.GetState());
if (error == null) if (error == null)
{ {
dc.GetState().SetValue(VALUE_PROPERTY, outputValue); dcState.SetValue(VALUE_PROPERTY, outputValue);
} }
else else
{ {
throw new Exception($"In TextInput, OutputFormat Expression evaluation resulted in an error. Expression: {outputExpression.ToString()}. Error: {error}"); throw new Exception($"In TextInput, OutputFormat Expression evaluation resulted in an error. Expression: {this.OutputFormat}. Error: {error}");
} }
} }
@ -86,9 +86,11 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
return dc.Context.Activity.Locale; return dc.Context.Activity.Locale;
} }
if (!string.IsNullOrEmpty(this.DefaultLocale)) if (this.DefaultLocale != null)
{ {
return this.DefaultLocale; var dcState = dc.GetState();
return this.DefaultLocale.GetValue(dcState);
} }
return English; return English;

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

@ -34,21 +34,21 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// </summary> /// </summary>
/// <value>The name of the OAuth connection.</value> /// <value>The name of the OAuth connection.</value>
[JsonProperty("connectionName")] [JsonProperty("connectionName")]
public string ConnectionName { get; set; } public StringExpression ConnectionName { get; set; }
/// <summary> /// <summary>
/// Gets or sets the title of the sign-in card. /// Gets or sets the title of the sign-in card.
/// </summary> /// </summary>
/// <value>The title of the sign-in card.</value> /// <value>The title of the sign-in card.</value>
[JsonProperty("title")] [JsonProperty("title")]
public string Title { get; set; } public StringExpression Title { get; set; }
/// <summary> /// <summary>
/// Gets or sets any additional text to include in the sign-in card. /// Gets or sets any additional text to include in the sign-in card.
/// </summary> /// </summary>
/// <value>Any additional text to include in the sign-in card.</value> /// <value>Any additional text to include in the sign-in card.</value>
[JsonProperty("text")] [JsonProperty("text")]
public string Text { get; set; } public StringExpression Text { get; set; }
/// <summary> /// <summary>
/// Gets or sets the number of milliseconds the prompt waits for the user to authenticate. /// Gets or sets the number of milliseconds the prompt waits for the user to authenticate.
@ -56,7 +56,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// </summary> /// </summary>
/// <value>The number of milliseconds the prompt waits for the user to authenticate.</value> /// <value>The number of milliseconds the prompt waits for the user to authenticate.</value>
[JsonProperty("timeout")] [JsonProperty("timeout")]
public int Timeout { get; set; } = 900000; public IntExpression Timeout { get; set; } = 900000;
/// <summary> /// <summary>
/// Called when a prompt dialog is pushed onto the dialog stack and is being activated. /// Called when a prompt dialog is pushed onto the dialog stack and is being activated.
@ -80,7 +80,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
throw new ArgumentException($"{nameof(options)} cannot be a cancellation token"); throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
} }
if (this.Disabled != null && (bool)new ExpressionEngine().Parse(this.Disabled).TryEvaluate(dc.GetState()).value == true) var dcState = dc.GetState();
if (this.Disabled != null && this.Disabled.GetValue(dcState))
{ {
return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
} }
@ -105,13 +107,15 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
} }
var op = OnInitializeOptions(dc, options); var op = OnInitializeOptions(dc, options);
dc.GetState().SetValue(ThisPath.OPTIONS, op); dcState.SetValue(ThisPath.OPTIONS, op);
dc.GetState().SetValue(TURN_COUNT_PROPERTY, 0); dcState.SetValue(TURN_COUNT_PROPERTY, 0);
// If AlwaysPrompt is set to true, then clear Property value for turn 0. // If AlwaysPrompt is set to true, then clear Property value for turn 0.
if (!string.IsNullOrEmpty(this.Property) && this.AlwaysPrompt) var (alwaysPrompt, _) = this.AlwaysPrompt.TryGetValue(dcState);
if (this.Property != null && alwaysPrompt)
{ {
dc.GetState().SetValue(this.Property, null); dcState.SetValue(this.Property.GetValue(dcState), null);
} }
// Initialize state // Initialize state
@ -122,7 +126,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
{ AttemptCountKey, 0 }, { AttemptCountKey, 0 },
}; };
state[PersistedExpires] = DateTime.Now.AddMilliseconds(Timeout); state[PersistedExpires] = DateTime.Now.AddMilliseconds(Timeout.GetValue(dcState));
// Attempt to get the users token // Attempt to get the users token
if (!(dc.Context.Adapter is IUserTokenProvider adapter)) if (!(dc.Context.Adapter is IUserTokenProvider adapter))
@ -130,12 +134,12 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
throw new InvalidOperationException("OAuthPrompt.Recognize(): not supported by the current adapter"); throw new InvalidOperationException("OAuthPrompt.Recognize(): not supported by the current adapter");
} }
var output = await adapter.GetUserTokenAsync(dc.Context, ConnectionName, null, cancellationToken).ConfigureAwait(false); var output = await adapter.GetUserTokenAsync(dc.Context, ConnectionName.GetValue(dcState), null, cancellationToken).ConfigureAwait(false);
if (output != null) if (output != null)
{ {
if (this.Property != null) if (this.Property != null)
{ {
dc.GetState().SetValue(this.Property, output); dcState.SetValue(this.Property.GetValue(dcState), output);
} }
// Return token // Return token
@ -143,10 +147,10 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
} }
else else
{ {
dc.GetState().SetValue(TURN_COUNT_PROPERTY, 1); dcState.SetValue(TURN_COUNT_PROPERTY, 1);
// Prompt user to login // Prompt user to login
await SendOAuthCardAsync(dc.Context, opt?.Prompt, cancellationToken).ConfigureAwait(false); await SendOAuthCardAsync(dc, opt?.Prompt, cancellationToken).ConfigureAwait(false);
return Dialog.EndOfTurn; return Dialog.EndOfTurn;
} }
} }
@ -169,11 +173,12 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
throw new ArgumentNullException(nameof(dc)); throw new ArgumentNullException(nameof(dc));
} }
var interrupted = dc.GetState().GetValue<bool>(TurnPath.INTERRUPTED, () => false); var dcState = dc.GetState();
var turnCount = dc.GetState().GetValue<int>(TURN_COUNT_PROPERTY, () => 0); var interrupted = dcState.GetValue<bool>(TurnPath.INTERRUPTED, () => false);
var turnCount = dcState.GetValue<int>(TURN_COUNT_PROPERTY, () => 0);
// Recognize token // Recognize token
var recognized = await RecognizeTokenAsync(dc.Context, cancellationToken).ConfigureAwait(false); var recognized = await RecognizeTokenAsync(dc, cancellationToken).ConfigureAwait(false);
// Check for timeout // Check for timeout
var state = dc.ActiveDialog.State; var state = dc.ActiveDialog.State;
@ -185,7 +190,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
{ {
if (this.Property != null) if (this.Property != null)
{ {
dc.GetState().SetValue(this.Property, null); dcState.SetValue(this.Property.GetValue(dcState), null);
} }
// if the token fetch request times out, complete the prompt with no result. // if the token fetch request times out, complete the prompt with no result.
@ -212,33 +217,33 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
{ {
if (this.Property != null) if (this.Property != null)
{ {
dc.GetState().SetValue(this.Property, recognized.Value); dcState.SetValue(this.Property.GetValue(dcState), recognized.Value);
} }
return await dc.EndDialogAsync(recognized.Value, cancellationToken).ConfigureAwait(false); return await dc.EndDialogAsync(recognized.Value, cancellationToken).ConfigureAwait(false);
} }
else if (this.MaxTurnCount == null || turnCount < this.MaxTurnCount) else if (this.MaxTurnCount == null || turnCount < this.MaxTurnCount.GetValue(dcState))
{ {
// increase the turnCount as last step // increase the turnCount as last step
dc.GetState().SetValue(TURN_COUNT_PROPERTY, turnCount + 1); dcState.SetValue(TURN_COUNT_PROPERTY, turnCount + 1);
var prompt = await this.OnRenderPrompt(dc, inputState).ConfigureAwait(false); var prompt = await this.OnRenderPrompt(dc, inputState).ConfigureAwait(false);
await dc.Context.SendActivityAsync(prompt).ConfigureAwait(false); await dc.Context.SendActivityAsync(prompt).ConfigureAwait(false);
await SendOAuthCardAsync(dc.Context, promptOptions?.Prompt, cancellationToken).ConfigureAwait(false); await SendOAuthCardAsync(dc, promptOptions?.Prompt, cancellationToken).ConfigureAwait(false);
return Dialog.EndOfTurn; return Dialog.EndOfTurn;
} }
else else
{ {
if (this.DefaultValue != null) if (this.DefaultValue != null)
{ {
var (value, error) = new ExpressionEngine().Parse(this.DefaultValue).TryEvaluate(dc.GetState()); var (value, _) = this.DefaultValue.TryGetValue(dcState);
if (this.DefaultValueResponse != null) if (this.DefaultValueResponse != null)
{ {
var response = await this.DefaultValueResponse.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false); var response = await this.DefaultValueResponse.BindToData(dc.Context, dcState).ConfigureAwait(false);
await dc.Context.SendActivityAsync(response).ConfigureAwait(false); await dc.Context.SendActivityAsync(response).ConfigureAwait(false);
} }
// set output property // set output property
dc.GetState().SetValue(this.Property, value); dcState.SetValue(this.Property.GetValue(dcState), value);
return await dc.EndDialogAsync(value).ConfigureAwait(false); return await dc.EndDialogAsync(value).ConfigureAwait(false);
} }
} }
@ -250,38 +255,41 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
/// <summary> /// <summary>
/// Attempts to get the user's token. /// Attempts to get the user's token.
/// </summary> /// </summary>
/// <param name="turnContext">Context for the current turn of conversation with the user.</param> /// <param name="dc">DialogContext for the current turn of conversation with the user.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects /// <param name="cancellationToken">A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.</param> /// or threads to receive notice of cancellation.</param>
/// <returns>A task that represents the work queued to execute.</returns> /// <returns>A task that represents the work queued to execute.</returns>
/// <remarks>If the task is successful and user already has a token or the user successfully signs in, /// <remarks>If the task is successful and user already has a token or the user successfully signs in,
/// the result contains the user's token.</remarks> /// the result contains the user's token.</remarks>
public async Task<TokenResponse> GetUserTokenAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken)) public async Task<TokenResponse> GetUserTokenAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
{ {
if (!(turnContext.Adapter is IUserTokenProvider adapter)) if (!(dc.Context.Adapter is IUserTokenProvider adapter))
{ {
throw new InvalidOperationException("OAuthPrompt.GetUserToken(): not supported by the current adapter"); throw new InvalidOperationException("OAuthPrompt.GetUserToken(): not supported by the current adapter");
} }
return await adapter.GetUserTokenAsync(turnContext, ConnectionName, null, cancellationToken).ConfigureAwait(false); var dcState = dc.GetState();
return await adapter.GetUserTokenAsync(dc.Context, ConnectionName.GetValue(dcState), null, cancellationToken).ConfigureAwait(false);
} }
/// <summary> /// <summary>
/// Signs out the user. /// Signs out the user.
/// </summary> /// </summary>
/// <param name="turnContext">Context for the current turn of conversation with the user.</param> /// <param name="dc">DialogContext for the current turn of conversation with the user.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects /// <param name="cancellationToken">A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.</param> /// or threads to receive notice of cancellation.</param>
/// <returns>A task that represents the work queued to execute.</returns> /// <returns>A task that represents the work queued to execute.</returns>
public async Task SignOutUserAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken)) public async Task SignOutUserAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
{ {
if (!(turnContext.Adapter is IUserTokenProvider adapter)) if (!(dc.Context.Adapter is IUserTokenProvider adapter))
{ {
throw new InvalidOperationException("OAuthPrompt.SignOutUser(): not supported by the current adapter"); throw new InvalidOperationException("OAuthPrompt.SignOutUser(): not supported by the current adapter");
} }
var dcState = dc.GetState();
// Sign out user // Sign out user
await adapter.SignOutUserAsync(turnContext, ConnectionName, turnContext.Activity?.From?.Id, cancellationToken).ConfigureAwait(false); await adapter.SignOutUserAsync(dc.Context, ConnectionName.GetValue(dcState), dc.Context.Activity?.From?.Id, cancellationToken).ConfigureAwait(false);
} }
protected override Task<InputState> OnRecognizeInput(DialogContext dc) protected override Task<InputState> OnRecognizeInput(DialogContext dc)
@ -289,15 +297,17 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
throw new NotImplementedException(); throw new NotImplementedException();
} }
private async Task SendOAuthCardAsync(ITurnContext turnContext, IMessageActivity prompt, CancellationToken cancellationToken = default(CancellationToken)) private async Task SendOAuthCardAsync(DialogContext dc, IMessageActivity prompt, CancellationToken cancellationToken = default(CancellationToken))
{ {
BotAssert.ContextNotNull(turnContext); var turnContext = dc.Context;
if (!(turnContext.Adapter is IUserTokenProvider adapter)) if (!(turnContext.Adapter is IUserTokenProvider adapter))
{ {
throw new InvalidOperationException("OAuthPrompt.Prompt(): not supported by the current adapter"); throw new InvalidOperationException("OAuthPrompt.Prompt(): not supported by the current adapter");
} }
var dcState = dc.GetState();
// Ensure prompt initialized // Ensure prompt initialized
if (prompt == null) if (prompt == null)
{ {
@ -314,18 +324,18 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
{ {
if (!prompt.Attachments.Any(a => a.Content is SigninCard)) if (!prompt.Attachments.Any(a => a.Content is SigninCard))
{ {
var link = await adapter.GetOauthSignInLinkAsync(turnContext, ConnectionName, cancellationToken).ConfigureAwait(false); var link = await adapter.GetOauthSignInLinkAsync(turnContext, ConnectionName?.GetValue(dcState), cancellationToken).ConfigureAwait(false);
prompt.Attachments.Add(new Attachment prompt.Attachments.Add(new Attachment
{ {
ContentType = SigninCard.ContentType, ContentType = SigninCard.ContentType,
Content = new SigninCard Content = new SigninCard
{ {
Text = Text, Text = Text?.GetValue(dcState),
Buttons = new[] Buttons = new[]
{ {
new CardAction new CardAction
{ {
Title = Title, Title = Title?.GetValue(dcState),
Value = link, Value = link,
Type = ActionTypes.Signin, Type = ActionTypes.Signin,
}, },
@ -341,14 +351,14 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
ContentType = OAuthCard.ContentType, ContentType = OAuthCard.ContentType,
Content = new OAuthCard Content = new OAuthCard
{ {
Text = Text, Text = Text?.GetValue(dcState),
ConnectionName = ConnectionName, ConnectionName = ConnectionName?.GetValue(dcState),
Buttons = new[] Buttons = new[]
{ {
new CardAction new CardAction
{ {
Title = Title, Title = Title?.GetValue(dcState),
Text = Text, Text = Text?.GetValue(dcState),
Type = ActionTypes.Signin, Type = ActionTypes.Signin,
}, },
}, },
@ -365,22 +375,24 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
await turnContext.SendActivityAsync(prompt, cancellationToken).ConfigureAwait(false); await turnContext.SendActivityAsync(prompt, cancellationToken).ConfigureAwait(false);
} }
private async Task<PromptRecognizerResult<TokenResponse>> RecognizeTokenAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken)) private async Task<PromptRecognizerResult<TokenResponse>> RecognizeTokenAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
{ {
var dcState = dc.GetState();
var result = new PromptRecognizerResult<TokenResponse>(); var result = new PromptRecognizerResult<TokenResponse>();
if (IsTokenResponseEvent(turnContext)) if (IsTokenResponseEvent(dc.Context))
{ {
var tokenResponseObject = turnContext.Activity.Value as JObject; var tokenResponseObject = dc.Context.Activity.Value as JObject;
var token = tokenResponseObject?.ToObject<TokenResponse>(); var token = tokenResponseObject?.ToObject<TokenResponse>();
result.Succeeded = true; result.Succeeded = true;
result.Value = token; result.Value = token;
} }
else if (IsTeamsVerificationInvoke(turnContext)) else if (IsTeamsVerificationInvoke(dc.Context))
{ {
var magicCodeObject = turnContext.Activity.Value as JObject; var magicCodeObject = dc.Context.Activity.Value as JObject;
var magicCode = magicCodeObject.GetValue("state")?.ToString(); var magicCode = magicCodeObject.GetValue("state")?.ToString();
if (!(turnContext.Adapter is IUserTokenProvider adapter)) if (!(dc.Context.Adapter is IUserTokenProvider adapter))
{ {
throw new InvalidOperationException("OAuthPrompt.Recognize(): not supported by the current adapter"); throw new InvalidOperationException("OAuthPrompt.Recognize(): not supported by the current adapter");
} }
@ -394,36 +406,36 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
// progress) retry in that case. // progress) retry in that case.
try try
{ {
var token = await adapter.GetUserTokenAsync(turnContext, ConnectionName, magicCode, cancellationToken).ConfigureAwait(false); var token = await adapter.GetUserTokenAsync(dc.Context, ConnectionName.GetValue(dcState), magicCode, cancellationToken).ConfigureAwait(false);
if (token != null) if (token != null)
{ {
result.Succeeded = true; result.Succeeded = true;
result.Value = token; result.Value = token;
await turnContext.SendActivityAsync(new Activity { Type = ActivityTypesEx.InvokeResponse }, cancellationToken).ConfigureAwait(false); await dc.Context.SendActivityAsync(new Activity { Type = ActivityTypesEx.InvokeResponse }, cancellationToken).ConfigureAwait(false);
} }
else else
{ {
await turnContext.SendActivityAsync(new Activity { Type = ActivityTypesEx.InvokeResponse, Value = new InvokeResponse { Status = 404 } }, cancellationToken).ConfigureAwait(false); await dc.Context.SendActivityAsync(new Activity { Type = ActivityTypesEx.InvokeResponse, Value = new InvokeResponse { Status = 404 } }, cancellationToken).ConfigureAwait(false);
} }
} }
catch catch
{ {
await turnContext.SendActivityAsync(new Activity { Type = ActivityTypesEx.InvokeResponse, Value = new InvokeResponse { Status = 500 } }, cancellationToken).ConfigureAwait(false); await dc.Context.SendActivityAsync(new Activity { Type = ActivityTypesEx.InvokeResponse, Value = new InvokeResponse { Status = 500 } }, cancellationToken).ConfigureAwait(false);
} }
} }
else if (turnContext.Activity.Type == ActivityTypes.Message) else if (dc.Context.Activity.Type == ActivityTypes.Message)
{ {
var matched = _magicCodeRegex.Match(turnContext.Activity.Text); var matched = _magicCodeRegex.Match(dc.Context.Activity.Text);
if (matched.Success) if (matched.Success)
{ {
if (!(turnContext.Adapter is IUserTokenProvider adapter)) if (!(dc.Context.Adapter is IUserTokenProvider adapter))
{ {
throw new InvalidOperationException("OAuthPrompt.Recognize(): not supported by the current adapter"); throw new InvalidOperationException("OAuthPrompt.Recognize(): not supported by the current adapter");
} }
var token = await adapter.GetUserTokenAsync(turnContext, ConnectionName, matched.Value, cancellationToken).ConfigureAwait(false); var token = await adapter.GetUserTokenAsync(dc.Context, ConnectionName.GetValue(dcState), matched.Value, cancellationToken).ConfigureAwait(false);
if (token != null) if (token != null)
{ {
result.Succeeded = true; result.Succeeded = true;

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

@ -23,27 +23,28 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
} }
[JsonProperty("outputFormat")] [JsonProperty("outputFormat")]
public string OutputFormat { get; set; } public StringExpression OutputFormat { get; set; }
protected override Task<InputState> OnRecognizeInput(DialogContext dc) protected override Task<InputState> OnRecognizeInput(DialogContext dc)
{ {
var input = dc.GetState().GetValue<string>(VALUE_PROPERTY); var dcState = dc.GetState();
if (!string.IsNullOrEmpty(OutputFormat)) var input = dcState.GetValue<string>(VALUE_PROPERTY);
if (this.OutputFormat != null)
{ {
var outputExpression = new ExpressionEngine().Parse(OutputFormat); var (outputValue, error) = this.OutputFormat.TryGetValue(dcState);
var (outputValue, error) = outputExpression.TryEvaluate(dc.GetState());
if (error == null) if (error == null)
{ {
input = outputValue.ToString(); input = outputValue.ToString();
} }
else else
{ {
throw new Exception($"In TextInput, OutputFormat Expression evaluation resulted in an error. Expression: {outputExpression.ToString()}. Error: {error}"); throw new Exception($"In TextInput, OutputFormat Expression evaluation resulted in an error. Expression: {OutputFormat.ToString()}. Error: {error}");
} }
} }
dc.GetState().SetValue(VALUE_PROPERTY, input); dcState.SetValue(VALUE_PROPERTY, input);
return input.Length > 0 ? Task.FromResult(InputState.Valid) : Task.FromResult(InputState.Unrecognized); return input.Length > 0 ? Task.FromResult(InputState.Valid) : Task.FromResult(InputState.Unrecognized);
} }
} }

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

@ -2,6 +2,7 @@
// Licensed under the MIT License. // Licensed under the MIT License.
using System; using System;
using System.Collections.Generic;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Generators; using Microsoft.Bot.Builder.Dialogs.Adaptive.Generators;
using Microsoft.Bot.Builder.Dialogs.Declarative; using Microsoft.Bot.Builder.Dialogs.Declarative;
using Microsoft.Bot.Builder.Dialogs.Declarative.Resources; using Microsoft.Bot.Builder.Dialogs.Declarative.Resources;
@ -10,6 +11,8 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{ {
public static class LGAdapterExtensions public static class LGAdapterExtensions
{ {
private static Dictionary<ResourceExplorer, LanguageGeneratorManager> languageGeneratorManagers = new Dictionary<ResourceExplorer, LanguageGeneratorManager>();
/// <summary> /// <summary>
/// Register default LG file as language generation. /// Register default LG file as language generation.
/// </summary> /// </summary>
@ -54,9 +57,19 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive
public static BotAdapter UseLanguageGeneration(this BotAdapter botAdapter, ResourceExplorer resourceExplorer, ILanguageGenerator languageGenerator) public static BotAdapter UseLanguageGeneration(this BotAdapter botAdapter, ResourceExplorer resourceExplorer, ILanguageGenerator languageGenerator)
{ {
DeclarativeTypeLoader.AddComponent(new LanguageGenerationComponentRegistration()); DeclarativeTypeLoader.AddComponent(new LanguageGenerationComponentRegistration());
botAdapter.Use(new RegisterClassMiddleware<LanguageGeneratorManager>(new LanguageGeneratorManager(resourceExplorer ?? throw new ArgumentNullException(nameof(resourceExplorer)))));
lock (languageGeneratorManagers)
{
if (!languageGeneratorManagers.TryGetValue(resourceExplorer ?? throw new ArgumentNullException(nameof(resourceExplorer)), out var lgm))
{
lgm = new LanguageGeneratorManager(resourceExplorer);
languageGeneratorManagers[resourceExplorer] = lgm;
}
botAdapter.Use(new RegisterClassMiddleware<LanguageGeneratorManager>(lgm));
botAdapter.Use(new RegisterClassMiddleware<ILanguageGenerator>(languageGenerator ?? throw new ArgumentNullException(nameof(languageGenerator)))); botAdapter.Use(new RegisterClassMiddleware<ILanguageGenerator>(languageGenerator ?? throw new ArgumentNullException(nameof(languageGenerator))));
return botAdapter; return botAdapter;
} }
} }
}
} }

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

@ -383,13 +383,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Memory
public bool TryGetValue(string key, out object value) public bool TryGetValue(string key, out object value)
{ {
value = default; return this.TryGetValue<object>(key, out value);
if (this.TryGetValue<object>(key, out var result))
{
value = result;
}
return true;
} }
public void Add(KeyValuePair<string, object> item) public void Add(KeyValuePair<string, object> item)
@ -461,6 +455,8 @@ namespace Microsoft.Bot.Builder.Dialogs.Memory
public bool AnyPathChanged(uint counter, IEnumerable<string> paths) public bool AnyPathChanged(uint counter, IEnumerable<string> paths)
{ {
var found = false; var found = false;
if (paths != null)
{
foreach (var path in paths) foreach (var path in paths)
{ {
if (GetValue<uint>(PathTracker + "." + path) > counter) if (GetValue<uint>(PathTracker + "." + path) > counter)
@ -469,6 +465,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Memory
break; break;
} }
} }
}
return found; return found;
} }

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

@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections;
using System.Collections.Generic;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Converters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{
/// <summary>
/// ArrayExpression - represents a property which is either a value of array of T or a string expression to bind to a array of T.
/// </summary>
/// <typeparam name="T">type of object in the array.</typeparam>
/// <remarks>String values are always interpreted as an expression, whether it has '=' prefix or not.</remarks>
public class ArrayExpression<T> : ExpressionProperty<List<T>>
{
/// <summary>
/// Initializes a new instance of the <see cref="ArrayExpression{T}"/> class.
/// </summary>
public ArrayExpression()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ArrayExpression{T}"/> class.
/// </summary>
/// <param name="value">collection of (T).</param>
public ArrayExpression(List<T> value)
: base(value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ArrayExpression{T}"/> class.
/// </summary>
/// <param name="expression">expression which evaluates to array.</param>
public ArrayExpression(string expression)
: base(expression)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ArrayExpression{T}"/> class.
/// </summary>
/// <param name="value">JToken which is either a collection of (T) or expression which evalutes to array.</param>
public ArrayExpression(JToken value)
: base(value)
{
}
public static implicit operator ArrayExpression<T>(List<T> value) => new ArrayExpression<T>(value);
public static implicit operator ArrayExpression<T>(string value) => new ArrayExpression<T>(value);
public static implicit operator ArrayExpression<T>(JToken value) => new ArrayExpression<T>(value);
}
}

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

@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Dialogs.Adaptive.Converters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{
/// <summary>
/// BoolExpression - represents a property which is either a boolean or a string expression which resolves to a boolean.
/// </summary>
/// <remarks>String values are always interpreted as an expression, whether it has '=' prefix or not.</remarks>
[JsonConverter(typeof(BoolExpressionConverter))]
public class BoolExpression : ExpressionProperty<bool>
{
/// <summary>
/// Initializes a new instance of the <see cref="BoolExpression"/> class.
/// </summary>
public BoolExpression()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BoolExpression"/> class.
/// </summary>
/// <param name="value">bool value.</param>
public BoolExpression(bool value)
: base(value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BoolExpression"/> class.
/// </summary>
/// <param name="expression">expression to resolve to bool.</param>
public BoolExpression(string expression)
: base(expression)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BoolExpression"/> class.
/// </summary>
/// <param name="value">expression or value to resolve to bool.</param>
public BoolExpression(JToken value)
: base(value)
{
}
public static implicit operator BoolExpression(bool value) => new BoolExpression(value);
public static implicit operator BoolExpression(string value) => new BoolExpression(value);
public static implicit operator BoolExpression(JToken value) => new BoolExpression(value);
}
}

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

@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections;
using System.Data.SqlTypes;
using Microsoft.Bot.Expressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Converters
{
/// <summary>
/// Converter which allows json to be expression to object or static object.
/// </summary>
/// <typeparam name="T">The type of the items of the array.</typeparam>
public class ArrayExpressionConverter<T> : JsonConverter<ArrayExpression<T>>
{
public override bool CanRead => true;
public override ArrayExpression<T> ReadJson(JsonReader reader, Type objectType, ArrayExpression<T> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.ValueType == typeof(string))
{
return new ArrayExpression<T>((string)reader.Value);
}
else
{
return new ArrayExpression<T>(JToken.Load(reader));
}
}
public override void WriteJson(JsonWriter writer, ArrayExpression<T> value, JsonSerializer serializer)
{
if (value.Expression != null)
{
serializer.Serialize(writer, value.ToString());
}
else
{
serializer.Serialize(writer, value.Value);
}
}
}
}

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

@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Data.SqlTypes;
using Microsoft.Bot.Expressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Converters
{
/// <summary>
/// Converter which allows json to be expression to object or static object.
/// </summary>
public class BoolExpressionConverter : JsonConverter<BoolExpression>
{
public BoolExpressionConverter()
{
}
public override bool CanRead => true;
public override BoolExpression ReadJson(JsonReader reader, Type objectType, BoolExpression existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.ValueType == typeof(string))
{
return new BoolExpression((string)reader.Value);
}
else
{
return new BoolExpression(JToken.Load(reader));
}
}
public override void WriteJson(JsonWriter writer, BoolExpression value, JsonSerializer serializer)
{
if (value.Expression != null)
{
serializer.Serialize(writer, value.ToString());
}
else
{
serializer.Serialize(writer, value.Value);
}
}
}
}

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

@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Input
{
/// <summary>
/// Converter for ChoiceSet - allows string or array initializers.
/// </summary>
public class ChoiceSetConverter : JsonConverter<ChoiceSet>
{
public override ChoiceSet ReadJson(JsonReader reader, Type objectType, ChoiceSet existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.ValueType == typeof(string))
{
return new ChoiceSet((string)reader.Value);
}
else
{
return new ChoiceSet(JArray.Load(reader));
}
}
public override void WriteJson(JsonWriter writer, ChoiceSet choiceSet, JsonSerializer serializer)
{
writer.WriteStartArray();
foreach (var choice in choiceSet)
{
JObject.FromObject(choice).WriteTo(writer);
}
writer.WriteEndArray();
}
}
}

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

@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.IO;
using Microsoft.Bot.Builder.Dialogs.Debugging;
using Microsoft.Bot.Builder.Dialogs.Declarative.Converters;
using Microsoft.Bot.Builder.Dialogs.Declarative.Resolvers;
using Microsoft.Bot.Expressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Converters
{
/// <summary>
/// Converter which allows json to be expression to object or static object.
/// </summary>
public class DialogExpressionConverter : JsonConverter<DialogExpression>
{
private readonly InterfaceConverter<Dialog> converter;
public DialogExpressionConverter(IRefResolver refResolver, ISourceMap sourceMap, Stack<string> paths)
{
this.converter = new InterfaceConverter<Dialog>(refResolver, sourceMap, paths);
}
public override bool CanRead => true;
public override DialogExpression ReadJson(JsonReader reader, Type objectType, DialogExpression existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.ValueType == typeof(string))
{
var id = (string)reader.Value;
if (id.StartsWith("="))
{
return new DialogExpression(id);
}
try
{
return new DialogExpression((Dialog)this.converter.ReadJson(new JsonTextReader(new StringReader($"\"{id}\"")), objectType, existingValue, serializer));
}
catch (Exception)
{
return new DialogExpression($"='{id}'");
}
}
return new DialogExpression((Dialog)this.converter.ReadJson(reader, objectType, existingValue, serializer));
}
public override void WriteJson(JsonWriter writer, DialogExpression value, JsonSerializer serializer)
{
if (value.Expression != null)
{
serializer.Serialize(writer, value.ToString());
}
else
{
serializer.Serialize(writer, value.Value);
}
}
}
}

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

@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Data.SqlTypes;
using Microsoft.Bot.Expressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Converters
{
/// <summary>
/// Converter which allows json to be expression to object or static object.
/// </summary>
/// <typeparam name="T">The enum type to construct.</typeparam>
public class EnumExpressionConverter<T> : JsonConverter<EnumExpression<T>>
where T : struct
{
public EnumExpressionConverter()
{
}
public override bool CanRead => true;
public override EnumExpression<T> ReadJson(JsonReader reader, Type objectType, EnumExpression<T> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.ValueType == typeof(string))
{
return new EnumExpression<T>((string)reader.Value);
}
else
{
return new EnumExpression<T>(JToken.Load(reader));
}
}
public override void WriteJson(JsonWriter writer, EnumExpression<T> value, JsonSerializer serializer)
{
if (value.Expression != null)
{
serializer.Serialize(writer, value.ToString());
}
else
{
serializer.Serialize(writer, value.Value);
}
}
}
}

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

@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Data.SqlTypes;
using Microsoft.Bot.Expressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Converters
{
/// <summary>
/// Converter which allows json to be expression to object or static object.
/// </summary>
/// <typeparam name="T">The property type to construct.</typeparam>
public class ExpressionPropertyConverter<T> : JsonConverter<ExpressionProperty<T>>
{
public override bool CanRead => true;
public override ExpressionProperty<T> ReadJson(JsonReader reader, Type objectType, ExpressionProperty<T> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.ValueType == typeof(string))
{
return new ExpressionProperty<T>((string)reader.Value);
}
else
{
return new ExpressionProperty<T>(JToken.Load(reader));
}
}
public override void WriteJson(JsonWriter writer, ExpressionProperty<T> value, JsonSerializer serializer)
{
if (value.Expression != null)
{
serializer.Serialize(writer, value.ToString());
}
else
{
serializer.Serialize(writer, value.Value);
}
}
}
}

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

@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Converters
{
/// <summary>
/// Converter which allows json to be expression to object or static object.
/// </summary>
public class IntExpressionConverter : JsonConverter<IntExpression>
{
public IntExpressionConverter()
{
}
public override bool CanRead => true;
public override IntExpression ReadJson(JsonReader reader, Type objectType, IntExpression existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.ValueType == typeof(string))
{
return new IntExpression((string)reader.Value);
}
else
{
return new IntExpression(JToken.Load(reader));
}
}
public override void WriteJson(JsonWriter writer, IntExpression value, JsonSerializer serializer)
{
if (value.Expression != null)
{
serializer.Serialize(writer, value.ToString());
}
else
{
serializer.Serialize(writer, value.Value);
}
}
}
}

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

@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Data.SqlTypes;
using Microsoft.Bot.Expressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Converters
{
/// <summary>
/// Converter which allows json to be expression to object or static object.
/// </summary>
public class NumberExpressionConverter : JsonConverter<NumberExpression>
{
public NumberExpressionConverter()
{
}
public override bool CanRead => true;
public override NumberExpression ReadJson(JsonReader reader, Type objectType, NumberExpression existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.ValueType == typeof(string))
{
return new NumberExpression((string)reader.Value);
}
else
{
return new NumberExpression(JToken.Load(reader));
}
}
public override void WriteJson(JsonWriter writer, NumberExpression value, JsonSerializer serializer)
{
if (value.Expression != null)
{
serializer.Serialize(writer, value.ToString());
}
else
{
serializer.Serialize(writer, value.Value);
}
}
}
}

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

@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Data.SqlTypes;
using Microsoft.Bot.Expressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Converters
{
/// <summary>
/// Converter which allows json to be expression to object or static object.
/// </summary>
/// <typeparam name="T">The property type to construct.</typeparam>
public class ObjectExpressionConverter<T> : JsonConverter<ObjectExpression<T>>
{
public override bool CanRead => true;
public override ObjectExpression<T> ReadJson(JsonReader reader, Type objectType, ObjectExpression<T> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.ValueType == typeof(string))
{
return new ObjectExpression<T>((string)reader.Value);
}
else
{
return new ObjectExpression<T>(JToken.Load(reader));
}
}
public override void WriteJson(JsonWriter writer, ObjectExpression<T> value, JsonSerializer serializer)
{
if (value.Expression != null)
{
serializer.Serialize(writer, value.ToString());
}
else
{
serializer.Serialize(writer, value.Value);
}
}
}
}

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

@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Data.SqlTypes;
using Microsoft.Bot.Expressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Converters
{
/// <summary>
/// Converter which allows json to be expression to object or static object.
/// </summary>
public class StringExpressionConverter : JsonConverter<StringExpression>
{
public StringExpressionConverter()
{
}
public override StringExpression ReadJson(JsonReader reader, Type objectType, StringExpression existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.ValueType == typeof(string))
{
return new StringExpression((string)reader.Value);
}
else
{
return new StringExpression(JToken.Load(reader));
}
}
public override void WriteJson(JsonWriter writer, StringExpression value, JsonSerializer serializer)
{
if (value.Expression != null)
{
serializer.Serialize(writer, value.ToString());
}
else
{
serializer.Serialize(writer, value.Value);
}
}
}
}

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

@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Converters
{
/// <summary>
/// Converter which allows json to be expression to object or static object.
/// </summary>
public class ValueExpressionConverter : JsonConverter<ValueExpression>
{
public ValueExpressionConverter()
{
}
public override bool CanRead => true;
public override ValueExpression ReadJson(JsonReader reader, Type objectType, ValueExpression existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.ValueType == typeof(string))
{
return new ValueExpression((string)reader.Value);
}
else
{
return new ValueExpression(JToken.Load(reader));
}
}
public override void WriteJson(JsonWriter writer, ValueExpression value, JsonSerializer serializer)
{
if (value.Expression != null)
{
serializer.Serialize(writer, value.ToString());
}
else
{
serializer.Serialize(writer, value.Value);
}
}
}
}

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

@ -0,0 +1,72 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Dialogs.Adaptive.Converters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{
/// <summary>
/// DialogExpression - represents a property which is either a Dialog or a string expression for a dialogId.
/// </summary>
/// <remarks>String values are always interpreted as a string with interpolation, unless it has '=' prefix or not. The result is interpreted as a resource Id or dialogId.</remarks>
public class DialogExpression : ObjectExpression<Dialog>
{
/// <summary>
/// Initializes a new instance of the <see cref="DialogExpression"/> class.
/// </summary>
public DialogExpression()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DialogExpression"/> class.
/// </summary>
/// <param name="value">dialog value.</param>
public DialogExpression(Dialog value)
: base(value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DialogExpression"/> class.
/// </summary>
/// <param name="dialogIdOrExpression">dialogId or expression to dialogId.</param>
public DialogExpression(string dialogIdOrExpression)
: base(dialogIdOrExpression)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DialogExpression"/> class.
/// </summary>
/// <param name="value">JToken which is either dialog or dialogId.</param>
public DialogExpression(JToken value)
: base(value)
{
}
public static implicit operator DialogExpression(Dialog value) => new DialogExpression(value);
public static implicit operator DialogExpression(string dialogIdOrExpression) => new DialogExpression(dialogIdOrExpression);
public static implicit operator DialogExpression(JToken value) => new DialogExpression(value);
public override void SetValue(object value)
{
if (value is string str)
{
if (!str.StartsWith("="))
{
// Resource Id's will be resolved to actual dialog value
// if it's not a = then we want to convert to a constant string expressions to represent a
// external dialog id resolved by dc.FindDialog()
value = $"='{str}'";
}
}
base.SetValue(value);
}
}
}

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

@ -0,0 +1,74 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Converters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{
/// <summary>
/// EnumExpression - represents a property which is either a enum(T) or a string expression which resolves to a enum(T).
/// </summary>
/// <typeparam name="T">type of enum.</typeparam>
/// <remarks>String values are always interpreted as an enum, unless it has '=' prefix in which case it is evaluated as a expression.</remarks>
public class EnumExpression<T> : ExpressionProperty<T>
where T : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="EnumExpression{T}"/> class.
/// </summary>
public EnumExpression()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EnumExpression{T}"/> class.
/// </summary>
/// <param name="value">value of T.</param>
public EnumExpression(T value)
: base(value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EnumExpression{T}"/> class.
/// </summary>
/// <param name="expression">expression to resolve to an enum.</param>
public EnumExpression(string expression)
: base(expression)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EnumExpression{T}"/> class.
/// </summary>
/// <param name="value">jtoken value to resolve to an enum.</param>
public EnumExpression(JToken value)
: base(value)
{
}
public static implicit operator EnumExpression<T>(T value) => new EnumExpression<T>(value);
public static implicit operator EnumExpression<T>(string enumOrExpression) => new EnumExpression<T>(enumOrExpression);
public static implicit operator EnumExpression<T>(JToken value) => new EnumExpression<T>(value);
public override void SetValue(object value)
{
if (value is string stringOrExpression)
{
// if the expression is the enum value, then use that as the value, else it is an expression.
if (Enum.TryParse<T>(stringOrExpression.TrimStart('='), ignoreCase: true, out T val))
{
this.Value = val;
return;
}
}
base.SetValue(value);
}
}
}

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

@ -0,0 +1,136 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections;
using System.Text;
using Microsoft.Bot.Builder.LanguageGeneration;
using Microsoft.Bot.Expressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{
/// <summary>
/// Base class which defines a Expression or value for a property.
/// </summary>
/// <typeparam name="T">type of object the expression should evaluate to.</typeparam>
public class ExpressionProperty<T>
{
public ExpressionProperty()
{
}
public ExpressionProperty(object value)
{
SetValue(value);
}
public T Value { get; set; } = default(T);
public Expression Expression { get; set; }
public new string ToString()
{
if (this.Expression != null)
{
return $"={this.Expression}";
}
return this.Value?.ToString();
}
/// <summary>
/// This will return the existing expression or ConstantExpression(Value) if the value is non-complex type.
/// </summary>
/// <returns>expression.</returns>
public Expression ToExpression()
{
if (this.Expression != null)
{
return this.Expression;
}
if (this.Value is string || this.Value.IsNumber() || this.Value.IsInteger() || this.Value is bool || this.Value.GetType().IsEnum)
{
return new ExpressionEngine().Parse(this.Value.ToString());
}
// return expression for json object
return new ExpressionEngine().Parse($"json({JsonConvert.SerializeObject(this.Value)})");
}
/// <summary>
/// Get the value.
/// </summary>
/// <param name="data">data to use for expression binding.</param>
/// <returns>value or default(T) if not found.</returns>
public virtual T GetValue(object data)
{
return this.TryGetValue(data).Value;
}
/// <summary>
/// try to Get the value.
/// </summary>
/// <param name="data">data to use for expression binding.</param>
/// <returns>value.</returns>
public virtual (T Value, string Error) TryGetValue(object data)
{
if (Expression != null)
{
return Expression.TryEvaluate<T>(data);
}
return (Value, null);
}
/// <summary>
/// Set the value.
/// </summary>
/// <param name="value">value to set.</param>
public virtual void SetValue(object value)
{
this.Value = default(T);
this.Expression = null;
if (value == null)
{
this.Value = default(T);
this.Expression = null;
return;
}
if (value is string stringOrExpression)
{
Expression = new ExpressionEngine().Parse(stringOrExpression.TrimStart('='));
return;
}
this.Value = ConvertObject(value);
}
/// <summary>
/// Convert raw object to desired value type.
/// </summary>
/// <remarks>
/// This method is called whenever an object is fected via expression or is deserialized from raw text.
/// </remarks>
/// <param name="result">result to convert to object of type T.</param>
/// <returns>object of type T.</returns>
protected virtual T ConvertObject(object result)
{
if (result is T)
{
return (T)result;
}
if (result == null)
{
return default(T);
}
return JToken.FromObject(result).ToObject<T>();
}
}
}

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

@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Dialogs.Adaptive.Converters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{
/// <summary>
/// IntExpression - represents a property which is either an Integer or a string expression which resolves to a Integer.
/// </summary>
/// <remarks>String values are always interpreted as an expression, whether it has '=' prefix or not.</remarks>
[JsonConverter(typeof(IntExpressionConverter))]
public class IntExpression : ExpressionProperty<int>
{
/// <summary>
/// Initializes a new instance of the <see cref="IntExpression"/> class.
/// </summary>
public IntExpression()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IntExpression"/> class.
/// </summary>
/// <param name="value">value to return.</param>
public IntExpression(int value)
: base(value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IntExpression"/> class.
/// </summary>
/// <param name="expression">string expression to resolve to an int.</param>
public IntExpression(string expression)
: base(expression)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="IntExpression"/> class.
/// </summary>
/// <param name="value">JToken to resolve to an int.</param>
public IntExpression(JToken value)
: base(value)
{
}
public static implicit operator IntExpression(int value) => new IntExpression(value);
public static implicit operator IntExpression(string value) => new IntExpression(value);
public static implicit operator IntExpression(JToken value) => new IntExpression(value);
}
}

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

@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Dialogs.Adaptive.Converters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{
/// <summary>
/// NumberExpression - represents a property which is either a float or a string expression which resolves to a float.
/// </summary>
/// <remarks>String values are always interpreted as an expression, whether it has '=' prefix or not.</remarks>
[JsonConverter(typeof(NumberExpressionConverter))]
public class NumberExpression : ExpressionProperty<float>
{
/// <summary>
/// Initializes a new instance of the <see cref="NumberExpression"/> class.
/// </summary>
public NumberExpression()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="NumberExpression"/> class.
/// </summary>
/// <param name="value">value to use.</param>
public NumberExpression(float value)
: base(value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="NumberExpression"/> class.
/// </summary>
/// <param name="expression">string to interpret as expression or number.</param>
public NumberExpression(string expression)
: base(expression)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="NumberExpression"/> class.
/// </summary>
/// <param name="value">jtoken to interpret as expression or number.</param>
public NumberExpression(JToken value)
: base(value)
{
}
public static implicit operator NumberExpression(float value) => new NumberExpression(value);
public static implicit operator NumberExpression(string value) => new NumberExpression(value);
public static implicit operator NumberExpression(JToken value) => new NumberExpression(value);
}
}

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

@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Dialogs.Adaptive.Converters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{
/// <summary>
/// ObjectExpression(T) - represents a property which is either an object of type T or a string expression which resolves to a object of type T.
/// </summary>
/// <typeparam name="T">the type of object.</typeparam>
/// <remarks>String values are always interpreted as an expression, whether it has '=' prefix or not.</remarks>
public class ObjectExpression<T> : ExpressionProperty<T>
{
public ObjectExpression()
{
}
public ObjectExpression(T value)
: base(value)
{
}
public ObjectExpression(string expressionOrString)
: base(expressionOrString)
{
}
public ObjectExpression(JToken value)
: base(value)
{
}
public static implicit operator ObjectExpression<T>(T value) => new ObjectExpression<T>(value);
public static implicit operator ObjectExpression<T>(string value) => new ObjectExpression<T>(value);
public static implicit operator ObjectExpression<T>(JToken value) => new ObjectExpression<T>(value);
}
}

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

@ -0,0 +1,96 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Dialogs.Adaptive.Converters;
using Microsoft.Bot.Builder.LanguageGeneration;
using Microsoft.Bot.Expressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{
/// <summary>
/// StringExpression - represents a property which is either a string value or a string expression.
/// </summary>
/// <remarks>
/// If the value is
/// * a string with '=' prefix then the string is treated as an expression to resolve to a string.
/// * a string without '=' then value is treated as string with string interpolation.
/// * You can escape the '=' prefix by putting a backslash.
/// Examples:
/// prop = "Hello @{user.name}" => "Hello Joe"
/// prop = "=length(user.name)" => "3"
/// prop = "=user.name" => "Joe"
/// prop = "\=user" => "=user".
/// </remarks>
[JsonConverter(typeof(StringExpressionConverter))]
public class StringExpression : ExpressionProperty<string>
{
private LGFile lg = new LGFile();
/// <summary>
/// Initializes a new instance of the <see cref="StringExpression"/> class.
/// </summary>
public StringExpression()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="StringExpression"/> class.
/// </summary>
/// <param name="valueOrExpression">string to interpret as string or expression to a string.</param>
public StringExpression(string valueOrExpression)
: base(valueOrExpression)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="StringExpression"/> class.
/// </summary>
/// <param name="value">value to interpret as a string or expression to a string.</param>
public StringExpression(JToken value)
: base(value)
{
}
public static implicit operator StringExpression(string valueOrExpression) => new StringExpression(valueOrExpression);
public static implicit operator StringExpression(JToken value) => new StringExpression(value);
public override (string Value, string Error) TryGetValue(object data)
{
if (this.Value != null)
{
// interpolated string
return (lg.Evaluate(this.Value, data).ToString(), null);
}
return base.TryGetValue(data);
}
public override void SetValue(object value)
{
var stringOrExpression = (value as string) ?? (value as JValue)?.Value as string;
if (stringOrExpression != null)
{
// if it starts with = it always is an expression
if (stringOrExpression.StartsWith("="))
{
Expression = new ExpressionEngine().Parse(stringOrExpression.TrimStart('='));
return;
}
else if (stringOrExpression.StartsWith("\\="))
{
// then trim off the escape char for equals (\=foo) should simply be the string (=foo), and not an expression (but it could still be stringTemplate)
stringOrExpression = stringOrExpression.TrimStart('\\');
}
this.Value = stringOrExpression;
return;
}
base.SetValue(value);
}
}
}

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

@ -0,0 +1,89 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Bot.Builder.Dialogs.Adaptive.Converters;
using Microsoft.Bot.Builder.LanguageGeneration;
using Microsoft.Bot.Expressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.Dialogs.Adaptive
{
/// <summary>
/// ValueExpression - represents a property which is an object of any kind or a string expression.
/// </summary>
/// <remarks>
/// If the value is
/// * a string with '=' prefix then the string is treated as an expression to resolve to a string.
/// * a string without '=' then value is treated as string with string interpolation.
/// * any other type, then it is of that type (int, bool, object, etc.)
/// You can escape the '=' prefix by putting a backslash.
/// Examples:
/// prop = true ==> true
/// prop = "Hello @{user.name}" => "Hello Joe"
/// prop = "=length(user.name)" => 3
/// prop = "=user.age" => 45.
/// prop = "\=user.age" => "=user.age".
/// </remarks>
[JsonConverter(typeof(ValueExpressionConverter))]
public class ValueExpression : ExpressionProperty<object>
{
private LGFile lg = new LGFile();
/// <summary>
/// Initializes a new instance of the <see cref="ValueExpression"/> class.
/// </summary>
public ValueExpression()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ValueExpression"/> class.
/// </summary>
/// <param name="value">value to interpret as object or string expression.</param>
public ValueExpression(object value)
: base(value)
{
}
public static implicit operator ValueExpression(string valueOrExpression) => new ValueExpression(valueOrExpression);
public static implicit operator ValueExpression(JToken value) => new ValueExpression(value);
public override (object Value, string Error) TryGetValue(object data)
{
if (this.Value != null && this.Value is string val)
{
// value is a string (not an expression) should be interpreted as string, which means interperlated
return (lg.Evaluate(val, data).ToString(), null);
}
return base.TryGetValue(data);
}
public override void SetValue(object value)
{
var stringOrExpression = (value as string) ?? (value as JValue)?.Value as string;
if (stringOrExpression != null)
{
// if it starts with = it always is an expression
if (stringOrExpression.StartsWith("="))
{
Expression = new ExpressionEngine().Parse(stringOrExpression.TrimStart('='));
return;
}
else if (stringOrExpression.StartsWith("\\="))
{
// then trim off the escape char for equals (\=foo) should simply be the string (=foo), and not an expression (but it could still be stringTemplate)
stringOrExpression = stringOrExpression.TrimStart('\\');
}
this.Value = stringOrExpression;
return;
}
base.SetValue(value);
}
}
}

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

@ -2,6 +2,8 @@
// Licensed under the MIT License. // Licensed under the MIT License.
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Bot.Builder.Dialogs.Adaptive;
using Microsoft.Bot.Builder.Dialogs.Adaptive.Converters;
using Microsoft.Bot.Builder.Dialogs.Adaptive.QnA; using Microsoft.Bot.Builder.Dialogs.Adaptive.QnA;
using Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers; using Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers;
using Microsoft.Bot.Builder.Dialogs.Debugging; using Microsoft.Bot.Builder.Dialogs.Debugging;
@ -24,6 +26,8 @@ namespace Microsoft.Bot.Builder.AI.QnA
public override IEnumerable<JsonConverter> GetConverters(ISourceMap sourceMap, IRefResolver refResolver, Stack<string> paths) public override IEnumerable<JsonConverter> GetConverters(ISourceMap sourceMap, IRefResolver refResolver, Stack<string> paths)
{ {
yield return new ArrayExpressionConverter<Metadata>();
yield break; yield break;
} }
} }

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

@ -14,10 +14,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
[JsonProperty("$kind")] [JsonProperty("$kind")]
public const string DeclarativeType = "Microsoft.QnAMakerDialog"; public const string DeclarativeType = "Microsoft.QnAMakerDialog";
private Expression knowledgebaseIdExpression;
private Expression endpointkeyExpression;
private Expression hostnameExpression;
[JsonConstructor] [JsonConstructor]
public QnAMakerDialog2([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) public QnAMakerDialog2([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
: base(sourceFilePath, sourceLineNumber) : base(sourceFilePath, sourceLineNumber)
@ -31,11 +27,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
/// The knowledgebase Id. /// The knowledgebase Id.
/// </value> /// </value>
[JsonProperty("knowledgeBaseId")] [JsonProperty("knowledgeBaseId")]
public string KnowledgeBaseId public StringExpression KnowledgeBaseId { get; set; }
{
get { return knowledgebaseIdExpression?.ToString(); }
set { knowledgebaseIdExpression = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the Hostname for your QnA Maker service. /// Gets or sets the Hostname for your QnA Maker service.
@ -44,11 +36,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
/// The host name of the QnA Maker knowledgebase. /// The host name of the QnA Maker knowledgebase.
/// </value> /// </value>
[JsonProperty("hostname")] [JsonProperty("hostname")]
public string HostName public StringExpression HostName { get; set; }
{
get { return hostnameExpression?.ToString(); }
set { hostnameExpression = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the Endpoint key for the QnA Maker KB. /// Gets or sets the Endpoint key for the QnA Maker KB.
@ -57,11 +45,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
/// The endpoint key for the QnA service. /// The endpoint key for the QnA service.
/// </value> /// </value>
[JsonProperty("endpointKey")] [JsonProperty("endpointKey")]
public string EndpointKey public StringExpression EndpointKey { get; set; }
{
get { return endpointkeyExpression?.ToString(); }
set { endpointkeyExpression = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the Threshold score to filter results. /// Gets or sets the Threshold score to filter results.
@ -70,7 +54,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
/// The threshold for the results. /// The threshold for the results.
/// </value> /// </value>
[JsonProperty("threshold")] [JsonProperty("threshold")]
public float Threshold { get; set; } = DefaultThreshold; public NumberExpression Threshold { get; set; } = DefaultThreshold;
/// <summary> /// <summary>
/// Gets or sets the number of results you want. /// Gets or sets the number of results you want.
@ -79,7 +63,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
/// The number of results you want. /// The number of results you want.
/// </value> /// </value>
[JsonProperty("top")] [JsonProperty("top")]
public int Top { get; set; } = DefaultTopN; public IntExpression Top { get; set; } = DefaultTopN;
/// <summary> /// <summary>
/// Gets or sets the template for Default answer to return when none found in KB. /// Gets or sets the template for Default answer to return when none found in KB.
@ -97,7 +81,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
/// Title for active learning suggestions card. /// Title for active learning suggestions card.
/// </value> /// </value>
[JsonProperty("activeLearningCardTitle")] [JsonProperty("activeLearningCardTitle")]
public string ActiveLearningCardTitle { get; set; } public StringExpression ActiveLearningCardTitle { get; set; }
/// <summary> /// <summary>
/// Gets or sets the Text for no match option. /// Gets or sets the Text for no match option.
@ -106,7 +90,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
/// The Text for no match option. /// The Text for no match option.
/// </value> /// </value>
[JsonProperty("cardNoMatchText")] [JsonProperty("cardNoMatchText")]
public string CardNoMatchText { get; set; } public StringExpression CardNoMatchText { get; set; }
/// <summary> /// <summary>
/// Gets or sets the template for Custom response when no match option was selected. /// Gets or sets the template for Custom response when no match option was selected.
@ -124,7 +108,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
/// The metadata strict filters. /// The metadata strict filters.
/// </value> /// </value>
[JsonProperty("strictFilters")] [JsonProperty("strictFilters")]
public Metadata[] StrictFilters { get; set; } public ArrayExpression<Metadata> StrictFilters { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether gets or sets environment of knowledgebase to be called. /// Gets or sets a value indicating whether gets or sets environment of knowledgebase to be called.
@ -142,10 +126,12 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
/// Ranker Types. /// Ranker Types.
/// </value> /// </value>
[JsonProperty("rankerType")] [JsonProperty("rankerType")]
public string RankerType { get; set; } = RankerTypes.DefaultRankerType; public StringExpression RankerType { get; set; } = new StringExpression(RankerTypes.DefaultRankerType);
protected async override Task<IQnAMakerClient> GetQnAMakerClientAsync(DialogContext dc) protected async override Task<IQnAMakerClient> GetQnAMakerClientAsync(DialogContext dc)
{ {
var dcState = dc.GetState();
var qnaClient = dc.Context.TurnState.Get<IQnAMakerClient>(); var qnaClient = dc.Context.TurnState.Get<IQnAMakerClient>();
if (qnaClient != null) if (qnaClient != null)
{ {
@ -153,9 +139,9 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
return qnaClient; return qnaClient;
} }
var (epKey, error) = this.endpointkeyExpression.TryEvaluate(dc.GetState()); var (epKey, error) = this.EndpointKey.TryGetValue(dcState);
var (hn, error2) = this.hostnameExpression.TryEvaluate(dc.GetState()); var (hn, error2) = this.HostName.TryGetValue(dcState);
var (kbId, error3) = this.knowledgebaseIdExpression.TryEvaluate(dc.GetState()); var (kbId, error3) = this.KnowledgeBaseId.TryGetValue(dcState);
var endpoint = new QnAMakerEndpoint var endpoint = new QnAMakerEndpoint
{ {
@ -169,26 +155,29 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA
protected override Task<QnAMakerOptions> GetQnAMakerOptionsAsync(DialogContext dc) protected override Task<QnAMakerOptions> GetQnAMakerOptionsAsync(DialogContext dc)
{ {
var dcState = dc.GetState();
return Task.FromResult(new QnAMakerOptions return Task.FromResult(new QnAMakerOptions
{ {
ScoreThreshold = this.Threshold, ScoreThreshold = this.Threshold.GetValue(dcState),
StrictFilters = this.StrictFilters, StrictFilters = this.StrictFilters?.GetValue(dcState)?.ToArray(),
Top = this.Top, Top = this.Top.GetValue(dcState),
QnAId = 0, QnAId = 0,
RankerType = this.RankerType, RankerType = this.RankerType.GetValue(dcState),
IsTest = this.IsTest IsTest = this.IsTest
}); });
} }
protected async override Task<QnADialogResponseOptions> GetQnAResponseOptionsAsync(DialogContext dc) protected async override Task<QnADialogResponseOptions> GetQnAResponseOptionsAsync(DialogContext dc)
{ {
var noAnswer = (this.NoAnswer != null) ? await this.NoAnswer.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false) : null; var dcState = dc.GetState();
var cardNoMatchResponse = (this.CardNoMatchResponse != null) ? await this.CardNoMatchResponse.BindToData(dc.Context, dc.GetState()).ConfigureAwait(false) : null; var noAnswer = (this.NoAnswer != null) ? await this.NoAnswer.BindToData(dc.Context, dcState).ConfigureAwait(false) : null;
var cardNoMatchResponse = (this.CardNoMatchResponse != null) ? await this.CardNoMatchResponse.BindToData(dc.Context, dcState).ConfigureAwait(false) : null;
var responseOptions = new QnADialogResponseOptions var responseOptions = new QnADialogResponseOptions
{ {
ActiveLearningCardTitle = this.ActiveLearningCardTitle, ActiveLearningCardTitle = this.ActiveLearningCardTitle.GetValue(dcState),
CardNoMatchText = this.CardNoMatchText, CardNoMatchText = this.CardNoMatchText.GetValue(dcState),
NoAnswer = noAnswer, NoAnswer = noAnswer,
CardNoMatchResponse = cardNoMatchResponse, CardNoMatchResponse = cardNoMatchResponse,
}; };

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

@ -6,13 +6,9 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Bot.Builder.AI.QnA; using Microsoft.Bot.Builder.AI.QnA;
using Microsoft.Bot.Expressions;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -30,10 +26,6 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers
private const string IntentPrefix = "intent="; private const string IntentPrefix = "intent=";
private Expression knowledgebaseIdExpression;
private Expression endpointkeyExpression;
private Expression hostnameExpression;
public QnAMakerRecognizer() public QnAMakerRecognizer()
{ {
} }
@ -45,11 +37,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers
/// The knowledgebase Id. /// The knowledgebase Id.
/// </value> /// </value>
[JsonProperty("knowledgeBaseId")] [JsonProperty("knowledgeBaseId")]
public string KnowledgeBaseId public StringExpression KnowledgeBaseId { get; set; }
{
get { return knowledgebaseIdExpression?.ToString(); }
set { knowledgebaseIdExpression = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the Hostname for your QnA Maker service. /// Gets or sets the Hostname for your QnA Maker service.
@ -58,11 +46,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers
/// The host name of the QnA Maker knowledgebase. /// The host name of the QnA Maker knowledgebase.
/// </value> /// </value>
[JsonProperty("hostname")] [JsonProperty("hostname")]
public string HostName public StringExpression HostName { get; set; }
{
get { return hostnameExpression?.ToString(); }
set { hostnameExpression = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the Endpoint key for the QnA Maker KB. /// Gets or sets the Endpoint key for the QnA Maker KB.
@ -71,11 +55,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers
/// The endpoint key for the QnA service. /// The endpoint key for the QnA service.
/// </value> /// </value>
[JsonProperty("endpointKey")] [JsonProperty("endpointKey")]
public string EndpointKey public StringExpression EndpointKey { get; set; }
{
get { return endpointkeyExpression?.ToString(); }
set { endpointkeyExpression = value != null ? new ExpressionEngine().Parse(value) : null; }
}
/// <summary> /// <summary>
/// Gets or sets the number of results you want. /// Gets or sets the number of results you want.
@ -85,7 +65,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers
/// </value> /// </value>
[DefaultValue(3)] [DefaultValue(3)]
[JsonProperty("top")] [JsonProperty("top")]
public int Top { get; set; } = 3; public IntExpression Top { get; set; } = 3;
/// <summary> /// <summary>
/// Gets or sets the threshold score to filter results. /// Gets or sets the threshold score to filter results.
@ -95,7 +75,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers
/// </value> /// </value>
[DefaultValue(0.3F)] [DefaultValue(0.3F)]
[JsonProperty("threshold")] [JsonProperty("threshold")]
public float Threshold { get; set; } = 0.3F; public NumberExpression Threshold { get; set; } = 0.3F;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether gets or sets environment of knowledgebase to be called. /// Gets or sets a value indicating whether gets or sets environment of knowledgebase to be called.
@ -113,13 +93,15 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers
/// The desired RankerType. /// The desired RankerType.
/// </value> /// </value>
[JsonProperty("rankerType")] [JsonProperty("rankerType")]
public string RankerType { get; set; } = RankerTypes.DefaultRankerType; public StringExpression RankerType { get; set; } = RankerTypes.DefaultRankerType;
[JsonIgnore] [JsonIgnore]
public HttpClient HttpClient { get; set; } public HttpClient HttpClient { get; set; }
public override async Task<RecognizerResult> RecognizeAsync(DialogContext dialogContext, string text, string locale, CancellationToken cancellationToken) public override async Task<RecognizerResult> RecognizeAsync(DialogContext dialogContext, string text, string locale, CancellationToken cancellationToken)
{ {
var dcState = dialogContext.GetState();
// Identify matched intents // Identify matched intents
var utterance = text ?? string.Empty; var utterance = text ?? string.Empty;
@ -135,7 +117,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers
}; };
// if there is $qna.metadata set add to filters // if there is $qna.metadata set add to filters
var externalMetadata = dialogContext.GetState().GetValue<Metadata[]>("$qna.metadata"); var externalMetadata = dcState.GetValue<Metadata[]>("$qna.metadata");
if (externalMetadata != null) if (externalMetadata != null)
{ {
filters.AddRange(externalMetadata); filters.AddRange(externalMetadata);
@ -147,12 +129,12 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers
dialogContext.Context, dialogContext.Context,
new QnAMakerOptions new QnAMakerOptions
{ {
Context = dialogContext.GetState().GetValue<QnARequestContext>("$qna.context"), Context = dcState.GetValue<QnARequestContext>("$qna.context"),
ScoreThreshold = this.Threshold, ScoreThreshold = this.Threshold.TryGetValue(dcState).Value,
StrictFilters = filters.ToArray(), StrictFilters = filters.ToArray(),
Top = this.Top, Top = this.Top.TryGetValue(dcState).Value,
QnAId = 0, QnAId = 0,
RankerType = this.RankerType, RankerType = this.RankerType.TryGetValue(dcState).Value,
IsTest = this.IsTest IsTest = this.IsTest
}, },
null).ConfigureAwait(false); null).ConfigureAwait(false);
@ -204,9 +186,11 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.QnA.Recognizers
return Task.FromResult(qnaClient); return Task.FromResult(qnaClient);
} }
var (epKey, error) = this.endpointkeyExpression.TryEvaluate(dc.GetState()); var dcState = dc.GetState();
var (hn, error2) = this.hostnameExpression.TryEvaluate(dc.GetState());
var (kbId, error3) = this.knowledgebaseIdExpression.TryEvaluate(dc.GetState()); var (epKey, error) = this.EndpointKey.TryGetValue(dcState);
var (hn, error2) = this.HostName.TryGetValue(dcState);
var (kbId, error3) = this.KnowledgeBaseId.TryGetValue(dcState);
var endpoint = new QnAMakerEndpoint var endpoint = new QnAMakerEndpoint
{ {

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

@ -50,7 +50,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Recognizers
set set
{ {
this.pattern = value; this.pattern = value;
this.regex = new Regex(pattern, RegexOptions.Compiled); this.regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
} }
} }

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

@ -7,6 +7,7 @@ using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Bot.Builder.TraceExtensions;
using Microsoft.Bot.Schema; using Microsoft.Bot.Schema;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -50,7 +51,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Recognizers
// Identify matched intents // Identify matched intents
text = text ?? string.Empty; text = text ?? string.Empty;
var result = new RecognizerResult() var recognizerResult = new RecognizerResult()
{ {
Text = text, Text = text,
Intents = new Dictionary<string, IntentScore>(), Intents = new Dictionary<string, IntentScore>(),
@ -74,9 +75,13 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Recognizers
{ {
// TODO length weighted match and multiple intents // TODO length weighted match and multiple intents
var intentKey = intentPattern.Intent.Replace(" ", "_"); var intentKey = intentPattern.Intent.Replace(" ", "_");
if (!result.Intents.ContainsKey(intentKey)) if (!recognizerResult.Intents.ContainsKey(intentKey))
{ {
result.Intents.Add(intentKey, new IntentScore() { Score = 1.0 }); recognizerResult.Intents.Add(intentKey, new IntentScore()
{
Score = 1.0,
Properties = new Dictionary<string, object>() { { "pattern", intentPattern.Pattern } }
});
} }
// Check for named capture groups // Check for named capture groups
@ -115,16 +120,16 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Recognizers
} }
// map entityPool of Entity objects => RecognizerResult entity format // map entityPool of Entity objects => RecognizerResult entity format
result.Entities = new JObject(); recognizerResult.Entities = new JObject();
foreach (var entityResult in entityPool) foreach (var entityResult in entityPool)
{ {
// add value // add value
JToken values; JToken values;
if (!result.Entities.TryGetValue(entityResult.Type, StringComparison.OrdinalIgnoreCase, out values)) if (!recognizerResult.Entities.TryGetValue(entityResult.Type, StringComparison.OrdinalIgnoreCase, out values))
{ {
values = new JArray(); values = new JArray();
result.Entities[entityResult.Type] = values; recognizerResult.Entities[entityResult.Type] = values;
} }
// The Entity type names are not consistent, map everything to camelcase so we can process them cleaner. // The Entity type names are not consistent, map everything to camelcase so we can process them cleaner.
@ -133,10 +138,10 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Recognizers
// get/create $instance // get/create $instance
JToken instanceRoot; JToken instanceRoot;
if (!result.Entities.TryGetValue("$instance", StringComparison.OrdinalIgnoreCase, out instanceRoot)) if (!recognizerResult.Entities.TryGetValue("$instance", StringComparison.OrdinalIgnoreCase, out instanceRoot))
{ {
instanceRoot = new JObject(); instanceRoot = new JObject();
result.Entities["$instance"] = instanceRoot; recognizerResult.Entities["$instance"] = instanceRoot;
} }
// add instanceData // add instanceData
@ -158,12 +163,14 @@ namespace Microsoft.Bot.Builder.Dialogs.Adaptive.Recognizers
} }
// if no match return None intent // if no match return None intent
if (!result.Intents.Keys.Any()) if (!recognizerResult.Intents.Keys.Any())
{ {
result.Intents.Add("None", new IntentScore() { Score = 1.0 }); recognizerResult.Intents.Add("None", new IntentScore() { Score = 1.0 });
} }
return result; await dialogContext.Context.TraceActivityAsync(nameof(RegexRecognizer), JObject.FromObject(recognizerResult), "RecognizerResult", "Regex RecognizerResult", cancellationToken).ConfigureAwait(false);
return recognizerResult;
} }
} }
} }

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

@ -12,6 +12,7 @@
}, },
"disabled": { "disabled": {
"$role": "expression", "$role": "expression",
"type": [ "boolean", "string"],
"title": "Disabled", "title": "Disabled",
"description": "Optional condition which if true will disable this action.", "description": "Optional condition which if true will disable this action.",
"examples": [ "examples": [
@ -20,6 +21,8 @@
}, },
"dialog": { "dialog": {
"$kind": "Microsoft.IDialog", "$kind": "Microsoft.IDialog",
"$role": "expression",
"type": ["string", "object"],
"title": "Dialog name", "title": "Dialog name",
"description": "Name of the dialog to call.", "description": "Name of the dialog to call.",
"examples": [ "examples": [
@ -27,7 +30,8 @@
] ]
}, },
"options": { "options": {
"type": "object", "$role": "expression",
"type": [ "string", "object" ],
"title": "Options", "title": "Options",
"description": "One or more options that are passed to the dialog that is called.", "description": "One or more options that are passed to the dialog that is called.",
"additionalProperties": { "additionalProperties": {
@ -36,13 +40,15 @@
} }
}, },
"activityProcessed": { "activityProcessed": {
"type": "boolean", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Activity Processed", "title": "Activity Processed",
"description": "When set to false, the dialog that is called can process the current activity.", "description": "When set to false, the dialog that is called can process the current activity.",
"default": true "default": true
}, },
"resultProperty": { "resultProperty": {
"$role": "expression", "$role": "expression",
"type": "string",
"title": "Property", "title": "Property",
"description": "Property to store any value returned by the dialog that is called.", "description": "Property to store any value returned by the dialog that is called.",
"examples": [ "examples": [

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

@ -13,6 +13,7 @@
}, },
"disabled": { "disabled": {
"$role": "expression", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Disabled", "title": "Disabled",
"description": "Optional condition which if true will disable this action.", "description": "Optional condition which if true will disable this action.",
"examples": [ "examples": [

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

@ -12,6 +12,7 @@
}, },
"disabled": { "disabled": {
"$role": "expression", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Disabled", "title": "Disabled",
"description": "Optional condition which if true will disable this action.", "description": "Optional condition which if true will disable this action.",
"examples": [ "examples": [
@ -19,12 +20,14 @@
] ]
}, },
"eventName": { "eventName": {
"$role": "expression",
"type": "string",
"title": "Event name", "title": "Event name",
"description": "Name of the event to emit.", "description": "Name of the event to emit."
"type": "string"
}, },
"eventValue": { "eventValue": {
"type": "object", "$role": "expression",
"type": [ "object", "array", "number", "integer", "boolean", "string" ],
"title": "Event value", "title": "Event value",
"description": "Value to emit with the event (optional).", "description": "Value to emit with the event (optional).",
"additionalProperties": true "additionalProperties": true

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

@ -13,6 +13,7 @@
}, },
"disabled": { "disabled": {
"$role": "expression", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Disabled", "title": "Disabled",
"description": "Optional condition which if true will disable this action.", "description": "Optional condition which if true will disable this action.",
"examples": [ "examples": [

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

@ -12,6 +12,7 @@
}, },
"disabled": { "disabled": {
"$role": "expression", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Disabled", "title": "Disabled",
"description": "Optional condition which if true will disable this action.", "description": "Optional condition which if true will disable this action.",
"examples": [ "examples": [

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

@ -16,14 +16,16 @@
}, },
"activityId": { "activityId": {
"$role": "expression", "$role": "expression",
"type": "string",
"title": "ActivityId", "title": "ActivityId",
"description": "expression to an activityId to delete", "description": "expression to an activityId to delete",
"examples": [ "examples": [
"$lastActivity" "=$lastActivity"
] ]
}, },
"disabled": { "disabled": {
"$role": "expression", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Disabled", "title": "Disabled",
"description": "Optional condition which if true will disable this action.", "description": "Optional condition which if true will disable this action.",
"examples": [ "examples": [

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

@ -15,6 +15,7 @@
}, },
"disabled": { "disabled": {
"$role": "expression", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Disabled", "title": "Disabled",
"description": "Optional condition which if true will disable this action.", "description": "Optional condition which if true will disable this action.",
"examples": [ "examples": [
@ -27,6 +28,7 @@
"description": "Properties to delete.", "description": "Properties to delete.",
"items": { "items": {
"$role": "expression", "$role": "expression",
"type": "string",
"title": "Property", "title": "Property",
"description": "Property to delete." "description": "Property to delete."
} }

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

@ -15,6 +15,7 @@
}, },
"disabled": { "disabled": {
"$role": "expression", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Disabled", "title": "Disabled",
"description": "Optional condition which if true will disable this action.", "description": "Optional condition which if true will disable this action.",
"examples": [ "examples": [
@ -23,6 +24,7 @@
}, },
"property": { "property": {
"$role": "expression", "$role": "expression",
"type": "string",
"title": "Property", "title": "Property",
"description": "Property to delete." "description": "Property to delete."
} }

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

@ -16,6 +16,7 @@
}, },
"disabled": { "disabled": {
"$role": "expression", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Disabled", "title": "Disabled",
"description": "Optional condition which if true will disable this action.", "description": "Optional condition which if true will disable this action.",
"examples": [ "examples": [
@ -23,6 +24,7 @@
] ]
}, },
"changeType": { "changeType": {
"$role": "expression",
"type": "string", "type": "string",
"title": "Type of change", "title": "Type of change",
"description": "Type of change to apply to the current actions.", "description": "Type of change to apply to the current actions.",

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

@ -15,6 +15,7 @@
"description": "Optional id for the dialog" "description": "Optional id for the dialog"
}, },
"changeType": { "changeType": {
"$role": "expression",
"type": "string", "type": "string",
"title": "Type of change", "title": "Type of change",
"description": "Type of change to the array in memory.", "description": "Type of change to the array in memory.",
@ -28,6 +29,7 @@
}, },
"disabled": { "disabled": {
"$role": "expression", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Disabled", "title": "Disabled",
"description": "Optional condition which if true will disable this action.", "description": "Optional condition which if true will disable this action.",
"examples": [ "examples": [
@ -36,16 +38,19 @@
}, },
"itemsProperty": { "itemsProperty": {
"$role": "expression", "$role": "expression",
"type": "string",
"title": "Items property", "title": "Items property",
"description": "Property that holds the array to update." "description": "Property that holds the array to update."
}, },
"resultProperty": { "resultProperty": {
"$role": "expression", "$role": "expression",
"type": "string",
"title": "Result Property", "title": "Result Property",
"description": "Property to store the result of this action." "description": "Property to store the result of this action."
}, },
"value": { "value": {
"$role": "expression", "$role": "expression",
"type": [ "object", "array", "number", "integer", "boolean", "string" ],
"title": "Value", "title": "Value",
"description": "New value or expression.", "description": "New value or expression.",
"examples": [ "examples": [

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

@ -15,6 +15,7 @@
}, },
"disabled": { "disabled": {
"$role": "expression", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Disabled", "title": "Disabled",
"description": "Optional condition which if true will disable this action.", "description": "Optional condition which if true will disable this action.",
"examples": [ "examples": [
@ -22,10 +23,10 @@
] ]
}, },
"eventName": { "eventName": {
"$role": "expression",
"type": "string",
"title": "Event name", "title": "Event name",
"description": "Name of the event to emit.", "description": "Name of the event to emit.",
"anyOf": [
{
"enum": [ "enum": [
"beginDialog", "beginDialog",
"resumeDialog", "resumeDialog",
@ -41,18 +42,15 @@
"actionsResumed" "actionsResumed"
] ]
}, },
{
"type": "string"
}
]
},
"eventValue": { "eventValue": {
"$role": "expression", "$role": "expression",
"type": [ "object", "array", "number", "integer", "boolean", "string" ],
"title": "Event value", "title": "Event value",
"description": "Value to emit with the event (optional)." "description": "Value to emit with the event (optional)."
}, },
"bubbleEvent": { "bubbleEvent": {
"type": "boolean", "$role": "expression",
"type": [ "boolean", "string" ],
"title": "Bubble event", "title": "Bubble event",
"description": "If true this event is passed on to parent dialogs.", "description": "If true this event is passed on to parent dialogs.",
"default": false "default": false

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше