From 53d7210800b5fa06672160d41c7cd905e7db5735 Mon Sep 17 00:00:00 2001 From: Pablo Costantini Date: Mon, 9 Jan 2017 13:40:39 -0300 Subject: [PATCH] [CSharp-ContosoFlowers] Update to Microsoft.Bot.Builder v3.5.0 and add of Bing Location control --- .../ContosoFlowers.BotAssets.csproj | 32 +- .../ContosoLocationResourceManager.cs | 12 + .../Dialogs/AddressDialog.cs | 85 ---- .../Dialogs/CancelablePromptChoice.cs | 8 +- .../Dialogs/DialogFactory.cs | 7 + .../Dialogs/IDialogFactory.cs | 4 + .../Dialogs/SavedAddressDialog.cs | 31 +- .../Properties/Resources.Designer.cs | 9 + .../Properties/Resources.resx | 3 + .../ContosoFlowers.BotAssets/app.config | 20 +- .../ContosoFlowers.BotAssets/packages.config | 13 +- .../BingLocationService.cs | 23 - .../BingMaps/BingMapsService.cs | 53 -- .../BingMaps/DataContracts.cs | 454 ------------------ .../ContosoFlowers.Services.csproj | 8 +- .../ILocationService.cs | 10 - .../InMemoryBouquetRepository.cs | 1 + .../ContosoFlowers.Services/packages.config | 2 +- .../ContosoFlowers/ContosoFlowers.csproj | 40 +- .../ContosoFlowers/ContosoFlowersModule.cs | 25 +- .../Dialogs/FlowerCategoriesDialog.cs | 2 +- .../ContosoFlowers/Dialogs/RootDialog.cs | 23 +- .../ContosoFlowers/Dialogs/SettingsDialog.cs | 44 +- .../Dialogs/SettingsScorable.cs | 25 +- .../ContosoFlowers/Models/Order.cs | 14 +- .../ContosoFlowers/Properties/AssemblyInfo.cs | 6 +- .../ContosoFlowers/Web.config | 24 +- .../ContosoFlowers/packages.config | 19 +- CSharp/demo-ContosoFlowers/README.md | 23 +- 29 files changed, 264 insertions(+), 756 deletions(-) create mode 100644 CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/ContosoLocationResourceManager.cs delete mode 100644 CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/AddressDialog.cs delete mode 100644 CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingLocationService.cs delete mode 100644 CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingMaps/BingMapsService.cs delete mode 100644 CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingMaps/DataContracts.cs delete mode 100644 CSharp/demo-ContosoFlowers/ContosoFlowers.Services/ILocationService.cs diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/ContosoFlowers.BotAssets.csproj b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/ContosoFlowers.BotAssets.csproj index 51cdbe6bd3..e62bd7a48e 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/ContosoFlowers.BotAssets.csproj +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/ContosoFlowers.BotAssets.csproj @@ -31,38 +31,42 @@ 4 - - ..\packages\Autofac.4.0.0\lib\net451\Autofac.dll + + ..\packages\Autofac.4.2.1\lib\net45\Autofac.dll True ..\packages\Chronic.Signed.0.3.2\lib\net40\Chronic.dll True - - ..\packages\Microsoft.Bot.Builder.3.2.1\lib\net46\Microsoft.Bot.Builder.dll + + ..\packages\Microsoft.Bot.Builder.3.5.0\lib\net46\Microsoft.Bot.Builder.dll True - - ..\packages\Microsoft.Bot.Builder.3.2.1\lib\net46\Microsoft.Bot.Connector.dll + + ..\packages\Microsoft.Bot.Builder.Location.1.1.0\lib\net46\Microsoft.Bot.Builder.Location.dll True - - ..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.2.206221351\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll + + ..\packages\Microsoft.Bot.Builder.3.5.0\lib\net46\Microsoft.Bot.Connector.dll + True + + + ..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.3.308261200\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll True - ..\packages\Microsoft.Rest.ClientRuntime.2.3.2\lib\net45\Microsoft.Rest.ClientRuntime.dll + ..\packages\Microsoft.Rest.ClientRuntime.2.3.4\lib\net45\Microsoft.Rest.ClientRuntime.dll True - - ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll True - - ..\packages\System.IdentityModel.Tokens.Jwt.4.0.2.206221351\lib\net45\System.IdentityModel.Tokens.Jwt.dll + + ..\packages\System.IdentityModel.Tokens.Jwt.4.0.3.308261200\lib\net45\System.IdentityModel.Tokens.Jwt.dll True @@ -84,7 +88,7 @@ - + diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/ContosoLocationResourceManager.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/ContosoLocationResourceManager.cs new file mode 100644 index 0000000000..5000004b80 --- /dev/null +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/ContosoLocationResourceManager.cs @@ -0,0 +1,12 @@ +namespace ContosoFlowers.BotAssets +{ + using System; + using Microsoft.Bot.Builder.Location; + using Properties; + + [Serializable] + public class ContosoLocationResourceManager : LocationResourceManager + { + public override string ConfirmationAsk => Resources.Location_ConfirmationAsk; + } +} diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/AddressDialog.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/AddressDialog.cs deleted file mode 100644 index bee2d7ea6d..0000000000 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/AddressDialog.cs +++ /dev/null @@ -1,85 +0,0 @@ -namespace ContosoFlowers.BotAssets.Dialogs -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Extensions; - using Microsoft.Bot.Builder.Dialogs; - using Microsoft.Bot.Connector; - using Properties; - using Services; - - [Serializable] - public class AddressDialog : IDialog - { - private readonly string prompt; - private readonly ILocationService locationService; - - private string currentAddress; - - public AddressDialog(string prompt, ILocationService locationService) - { - this.prompt = prompt; - this.locationService = locationService; - } - - public async Task StartAsync(IDialogContext context) - { - await context.PostAsync(this.prompt); - context.Wait(this.MessageReceivedAsync); - } - - public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable result) - { - var message = await result; - - var addresses = await this.locationService.ParseAddressAsync(message.Text); - if (addresses.Count() == 0) - { - - await context.PostAsync(Resources.AddressDialog_EnterAddressAgain); - context.Wait(this.MessageReceivedAsync); - } - else if (addresses.Count() == 1) - { - this.currentAddress = addresses.First(); - PromptDialog.Choice(context, this.AfterAddressChoice, new[] { Resources.AddressDialog_Confirm, Resources.AddressDialog_Edit }, this.currentAddress); - } - else - { - var reply = context.MakeMessage(); - reply.AttachmentLayout = AttachmentLayoutTypes.Carousel; - - foreach (var address in addresses) - { - reply.AddHeroCard(Resources.AddressDialog_DidYouMean, address, new[] { new KeyValuePair(Resources.AddressDialog_UseThisAddress, address) }); - } - - await context.PostAsync(reply); - context.Wait(this.MessageReceivedAsync); - } - } - - private async Task AfterAddressChoice(IDialogContext context, IAwaitable result) - { - try - { - var choice = await result; - - if (choice == Resources.AddressDialog_Edit) - { - await this.StartAsync(context); - } - else - { - context.Done(this.currentAddress); - } - } - catch (TooManyAttemptsException) - { - throw; - } - } - } -} \ No newline at end of file diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/CancelablePromptChoice.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/CancelablePromptChoice.cs index 01e850c14d..9a083419f6 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/CancelablePromptChoice.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/CancelablePromptChoice.cs @@ -12,7 +12,7 @@ public class CancelablePromptChoice : PromptDialog.PromptChoice { private static IEnumerable cancelTerms = new[] { "Cancel", "Back", "B", "Abort" }; - protected new readonly CancelablePromptOptions promptOptions; + private new readonly CancelablePromptOptions promptOptions; public CancelablePromptChoice(CancelablePromptOptions promptOptions) : base(promptOptions) @@ -52,9 +52,9 @@ protected override bool TryParse(IMessageActivity message, out T result) return base.TryParse(message, out result); } - protected override IMessageActivity MakePrompt(IDialogContext context, string prompt, IList options = null) + protected override IMessageActivity MakePrompt(IDialogContext context, string prompt, IReadOnlyList options = null, IReadOnlyList descriptions = null) { - prompt += Environment.NewLine + (promptOptions.CancelPrompt ?? promptOptions.DefaultCancelPrompt); + prompt += Environment.NewLine + (this.promptOptions.CancelPrompt ?? this.promptOptions.DefaultCancelPrompt); return base.MakePrompt(context, prompt, options); } } @@ -62,7 +62,7 @@ protected override IMessageActivity MakePrompt(IDialogContext context, string pr [Serializable] public class CancelablePromptOptions : PromptOptions { - public CancelablePromptOptions(string prompt, string cancelPrompt = null, string retry = null, string tooManyAttempts = null, IList options = null, int attempts = 3, PromptStyler promptStyler = null) + public CancelablePromptOptions(string prompt, string cancelPrompt = null, string retry = null, string tooManyAttempts = null, IReadOnlyList options = null, int attempts = 3, PromptStyler promptStyler = null) : base(prompt, retry, tooManyAttempts, options, attempts, promptStyler) { this.DefaultCancelPrompt = Resources.CancelablePromptChoice_CancelText; diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/DialogFactory.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/DialogFactory.cs index 31293a1cb3..e67a9537be 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/DialogFactory.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/DialogFactory.cs @@ -1,5 +1,7 @@ namespace ContosoFlowers.BotAssets { + using System.Collections.Generic; + using System.Linq; using Autofac; using Microsoft.Bot.Builder.Internals.Fibers; @@ -21,5 +23,10 @@ public T Create(U parameter) { return this.Scope.Resolve(TypedParameter.From(parameter)); } + + public T Create(IDictionary parameters) + { + return this.Scope.Resolve(parameters.Select(kv => new NamedParameter(kv.Key, kv.Value))); + } } } \ No newline at end of file diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/IDialogFactory.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/IDialogFactory.cs index 2e51e07d67..d77d66785a 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/IDialogFactory.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/IDialogFactory.cs @@ -1,9 +1,13 @@ namespace ContosoFlowers.BotAssets { + using System.Collections.Generic; + public interface IDialogFactory { T Create(); T Create(U parameter); + + T Create(IDictionary parameters); } } \ No newline at end of file diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/SavedAddressDialog.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/SavedAddressDialog.cs index 7f3ae14acb..bc140033ac 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/SavedAddressDialog.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Dialogs/SavedAddressDialog.cs @@ -5,8 +5,9 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.Bot.Builder.Dialogs; + using Microsoft.Bot.Builder.Location; + using Microsoft.Bot.Connector; using Properties; - using Services; [Serializable] public class SavedAddressDialog : IDialog @@ -16,18 +17,16 @@ public class SavedAddressDialog : IDialog private readonly string prompt; private readonly string useSavedAddressPrompt; private readonly string saveAddressPrompt; - private readonly ILocationService locationService; private readonly IDialogFactory dialogFactory; private string currentAddress; public SavedAddressDialog( - string prompt, - string useSavedAddressPrompt, - string saveAddressPrompt, - IDictionary savedAddresses, + string prompt, + string useSavedAddressPrompt, + string saveAddressPrompt, + IDictionary savedAddresses, IEnumerable saveOptionNames, - ILocationService locationService, IDialogFactory dialogFactory) { this.savedAddresses = savedAddresses ?? new Dictionary(); @@ -35,7 +34,6 @@ public SavedAddressDialog( this.prompt = prompt; this.useSavedAddressPrompt = useSavedAddressPrompt; this.saveAddressPrompt = saveAddressPrompt; - this.locationService = locationService; this.dialogFactory = dialogFactory; } @@ -53,13 +51,22 @@ public async Task StartAsync(IDialogContext context) private void AddressPrompt(IDialogContext context) { - var addressDialog = this.dialogFactory.Create(this.prompt); - context.Call(addressDialog, this.AfterAddressPrompt); + // BotBuilder's LocationDialog + // Leverage DI to inject other parameters + var locationDialog = this.dialogFactory.Create( + new Dictionary() + { + { "prompt", this.prompt }, + { "channelId", context.Activity.ChannelId } + }); + + context.Call(locationDialog, this.AfterAddressPrompt); } - private async Task AfterAddressPrompt(IDialogContext context, IAwaitable result) + private async Task AfterAddressPrompt(IDialogContext context, IAwaitable result) { - this.currentAddress = await result; + var place = await result; + this.currentAddress = place.GetPostalAddress().FormattedAddress; PromptDialog.Choice(context, this.AfterSelectToSaveAddress, this.saveOptionNames.Concat(new[] { Resources.SavedAddressDialog_NotThisTime }), this.saveAddressPrompt); } diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Properties/Resources.Designer.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Properties/Resources.Designer.cs index 687aef85c8..35cef21608 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Properties/Resources.Designer.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Properties/Resources.Designer.cs @@ -114,6 +114,15 @@ internal static string CancelablePromptChoice_CancelText { } } + /// + /// Looks up a localized string similar to OK, you want to use {0}. Is that correct? Enter 'yes' or 'no'.. + /// + internal static string Location_ConfirmationAsk { + get { + return ResourceManager.GetString("Location_ConfirmationAsk", resourceCulture); + } + } + /// /// Looks up a localized string similar to Please select an item. /// diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Properties/Resources.resx b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Properties/Resources.resx index 8521906c9a..fd2a997c76 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Properties/Resources.resx +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/Properties/Resources.resx @@ -153,4 +153,7 @@ No, thanks! + + OK, you want to use {0}. Is that correct? Enter 'yes' or 'no'. + \ No newline at end of file diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/app.config b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/app.config index d88c013437..b18bd0d4c4 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/app.config +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/app.config @@ -4,11 +4,27 @@ - + - + + + + + + + + + + + + + + + + + diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/packages.config b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/packages.config index f0a195709e..d14fac0196 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/packages.config +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.BotAssets/packages.config @@ -1,12 +1,13 @@  - + - - - - - + + + + + + \ No newline at end of file diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingLocationService.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingLocationService.cs deleted file mode 100644 index e366e4b551..0000000000 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingLocationService.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace ContosoFlowers.Services -{ - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using ContosoFlowers.Services.BingMaps; - - public class BingLocationService : ILocationService - { - private readonly BingMapsService service; - - public BingLocationService(string bingMapsKey) - { - this.service = new BingMapsService(bingMapsKey); - } - - public async Task> ParseAddressAsync(string address) - { - var results = await this.service.GeoCode(address); - return results.Select(o => o.FormattedAddress); - } - } -} \ No newline at end of file diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingMaps/BingMapsService.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingMaps/BingMapsService.cs deleted file mode 100644 index 36f64b9d53..0000000000 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingMaps/BingMapsService.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace ContosoFlowers.Services.BingMaps -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Net; - using System.Text; - using System.Threading.Tasks; - using System.Web; - using Newtonsoft.Json; - - public class BingMapsService - { - private const string LocationServiceUriTemplate = "https://dev.virtualearth.net/REST/v1/Locations?key={0}&q={1}"; - - private readonly string apiKey; - - public BingMapsService(string apiKey) - { - if (string.IsNullOrWhiteSpace(apiKey)) - { - throw new ArgumentNullException("apiKey", "Bing Maps Key is required."); - } - - this.apiKey = apiKey; - } - - public async Task> GeoCode(string inputAddress) - { - Uri geocodeUri = new Uri(string.Format(LocationServiceUriTemplate, this.apiKey, HttpUtility.UrlEncode(inputAddress))); - var result = await GetResponse(geocodeUri); - - if (result.ResourceSets.Any()) - { - return result.ResourceSets[0].Resources - .Where(o => o.GetType() == typeof(Location)).Select(o => o as Location) - .Where(a => a.EntityType == "Address") - .Select(a => a.Address); - } - - return Enumerable.Empty
(); - } - - private static async Task GetResponse(Uri uri) - { - using (var client = new WebClient() { Encoding = Encoding.UTF8 }) - { - var json = await client.DownloadStringTaskAsync(uri); - return JsonConvert.DeserializeObject(json, new BingDataConverter()); - } - } - } -} diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingMaps/DataContracts.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingMaps/DataContracts.cs deleted file mode 100644 index 0c0b9807b7..0000000000 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/BingMaps/DataContracts.cs +++ /dev/null @@ -1,454 +0,0 @@ -namespace ContosoFlowers.Services.BingMaps -{ - using System; - using Newtonsoft.Json; - using Newtonsoft.Json.Linq; - - /// - /// https://msdn.microsoft.com/en-us/library/jj870778.aspx - /// - public class Address - { - public string AddressLine { get; set; } - - public string AdminDistrict { get; set; } - - public string AdminDistrict2 { get; set; } - - public string CountryRegion { get; set; } - - public string CountryRegionIso2 { get; set; } - - public string FormattedAddress { get; set; } - - public string Locality { get; set; } - - public string PostalCode { get; set; } - - public string Neighborhood { get; set; } - - public string Landmark { get; set; } - } - - public class BirdseyeMetadata : ImageryMetadata - { - public double Orientation { get; set; } - - public int TilesX { get; set; } - - public int TilesY { get; set; } - } - - public class BoundingBox - { - public double SouthLatitude { get; set; } - - public double WestLongitude { get; set; } - - public double NorthLatitude { get; set; } - - public double EastLongitude { get; set; } - } - - public class Detail - { - public int CompassDegrees { get; set; } - - public string ManeuverType { get; set; } - - public int[] StartPathIndices { get; set; } - - public int[] EndPathIndices { get; set; } - - public string RoadType { get; set; } - - public string[] LocationCodes { get; set; } - - public string[] Names { get; set; } - - public string Mode { get; set; } - - public RoadShield roadShieldRequestParameters { get; set; } - } - - public class Generalization - { - public int[] PathIndices { get; set; } - - public double LatLongTolerance { get; set; } - } - - public class Hint - { - public string HintType { get; set; } - - public string Text { get; set; } - } - - public class ImageryMetadata : Resource - { - public string ImageHeight { get; set; } - - public string ImageWidth { get; set; } - - public string ImageUrl { get; set; } - - public string[] ImageUrlSubdomains { get; set; } - - public string VintageEnd { get; set; } - - public string VintageStart { get; set; } - - public int ZoomMax { get; set; } - - public int ZoomMin { get; set; } - } - - public class Instruction - { - public string ManeuverType { get; set; } - - public string Text { get; set; } - } - - public class ItineraryItem - { - public ItineraryItem[] ChildItineraryItems { get; set; } - - public string CompassDirection { get; set; } - - public Detail[] Details { get; set; } - - public string Exit { get; set; } - - public Hint[] Hints { get; set; } - - public string IconType { get; set; } - - public Instruction Instruction { get; set; } - - public Point ManeuverPoint { get; set; } - - public string SideOfStreet { get; set; } - - public string[] Signs { get; set; } - - public string Time { get; set; } - - public string TollZone { get; set; } - - public string TowardsRoadName { get; set; } - - public TransitLine TransitLine { get; set; } - - public int TransitStopId { get; set; } - - public string TransitTerminus { get; set; } - - public double TravelDistance { get; set; } - - public double TravelDuration { get; set; } - - public string TravelMode { get; set; } - - public Warning[] Warning { get; set; } - } - - public class Line - { - public string Type { get; set; } - - public double[][] Coordinates { get; set; } - } - - public class Location : Resource - { - public string Name { get; set; } - - public Point Point { get; set; } - - public string EntityType { get; set; } - - public Address Address { get; set; } - - public string Confidence { get; set; } - - public string[] MatchCodes { get; set; } - - public Point[] GeocodePoints { get; set; } - - public QueryParseValue[] QueryParseValues { get; set; } - } - - public class QueryParseValue - { - public string Property { get; set; } - - public string Value { get; set; } - } - - public class PinInfo - { - public Pixel Anchor { get; set; } - - public Pixel BottomRightOffset { get; set; } - - public Pixel TopLeftOffset { get; set; } - - public Point Point { get; set; } - } - - public class Pixel - { - public string X { get; set; } - - public string Y { get; set; } - } - - public class Point : Shape - { - public string Type { get; set; } - - public double[] Coordinates { get; set; } - - public string CalculationMethod { get; set; } - - public string[] UsageTypes { get; set; } - } - - public class Resource - { - public double[] BoundingBox { get; set; } - - public string Type { get; set; } - } - - public class ResourceSet - { - public long EstimatedTotal { get; set; } - - public Resource[] Resources { get; set; } - } - - public class Response - { - public string Copyright { get; set; } - - public string BrandLogoUri { get; set; } - - public int StatusCode { get; set; } - - public string StatusDescription { get; set; } - - public string AuthenticationResultCode { get; set; } - - public string[] errorDetails { get; set; } - - public string TraceId { get; set; } - - public ResourceSet[] ResourceSets { get; set; } - } - - public class RoadShield - { - public int Bucket { get; set; } - - public Shield[] Shields { get; set; } - } - - public class Route : Resource - { - public string Id { get; set; } - - public string DistanceUnit { get; set; } - - public string DurationUnit { get; set; } - - public double TravelDistance { get; set; } - - public double TravelDuration { get; set; } - - public RouteLeg[] RouteLegs { get; set; } - - public RoutePath RoutePath { get; set; } - } - - public class RouteLeg - { - public double TravelDistance { get; set; } - - public double TravelDuration { get; set; } - - public Point ActualStart { get; set; } - - public Point ActualEnd { get; set; } - - public Location StartLocation { get; set; } - - public Location EndLocation { get; set; } - - public ItineraryItem[] ItineraryItems { get; set; } - } - - public class RoutePath - { - public Line Line { get; set; } - - public Generalization[] Generalizations { get; set; } - } - - public class Shape - { - public double[] BoundingBox { get; set; } - } - - public class Shield - { - public string[] Labels { get; set; } - - public int RoadShieldType { get; set; } - } - - public class StaticMapMetadata : ImageryMetadata - { - public Point MapCenter { get; set; } - - public PinInfo[] Pushpins { get; set; } - - public string Zoom { get; set; } - } - - public class TrafficIncident : Resource - { - public Point Point { get; set; } - - public string Congestion { get; set; } - - public string Description { get; set; } - - public string Detour { get; set; } - - public string Start { get; set; } - - public string End { get; set; } - - public long IncidentId { get; set; } - - public string Lane { get; set; } - - public string LastModified { get; set; } - - public bool RoadClosed { get; set; } - - public int Severity { get; set; } - - public Point ToPoint { get; set; } - - public string[] LocationCodes { get; set; } - - public int Type { get; set; } - - public bool Verified { get; set; } - } - - public class TransitLine - { - public string verboseName { get; set; } - - public string abbreviatedName { get; set; } - - public long AgencyId { get; set; } - - public string agencyName { get; set; } - - public long lineColor { get; set; } - - public long lineTextColor { get; set; } - - public string uri { get; set; } - - public string phoneNumber { get; set; } - - public string providerInfo { get; set; } - } - - public class Warning - { - public string WarningType { get; set; } - - public string Severity { get; set; } - - public string Text { get; set; } - } - - public class CompressedPointList : Resource - { - public string Value { get; set; } - } - - public class ElevationData : Resource - { - public int[] Elevations { get; set; } - - public int ZoomLevel { get; set; } - } - - public class SeaLevelData : Resource - { - public int[] Offsets { get; set; } - - public int ZoomLevel { get; set; } - } - - internal class BingDataConverter : JsonConverter - { - public override bool CanConvert(Type objectType) - { - return typeof(Resource).IsAssignableFrom(objectType); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var jObject = JObject.Load(reader); - var type = jObject["__type"].Value().Split(':')[0]; - - object target = null; - - switch (type) - { - case "Location": - target = new Location(); - break; - case "Route": - target = new Route(); - break; - case "TrafficIncident": - target = new TrafficIncident(); - break; - case "ImageryMetadata": - target = new ImageryMetadata(); - break; - case "ElevationData": - target = new ElevationData(); - break; - case "SeaLevelData": - target = new SeaLevelData(); - break; - case "CompressedPointList": - target = new CompressedPointList(); - break; - default: - throw new ArgumentException("Invalid source type"); - } - - serializer.Populate(jObject.CreateReader(), target); - - return target; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new NotImplementedException(); - } - } -} diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/ContosoFlowers.Services.csproj b/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/ContosoFlowers.Services.csproj index c55a16480e..31e01ce2af 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/ContosoFlowers.Services.csproj +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/ContosoFlowers.Services.csproj @@ -31,8 +31,8 @@ 4 - - ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll True @@ -47,12 +47,8 @@ - - - - diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/ILocationService.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/ILocationService.cs deleted file mode 100644 index ec17c41cf5..0000000000 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/ILocationService.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ContosoFlowers.Services -{ - using System.Collections.Generic; - using System.Threading.Tasks; - - public interface ILocationService - { - Task> ParseAddressAsync(string text); - } -} diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/InMemoryBouquetRepository.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/InMemoryBouquetRepository.cs index 4b91c60bb1..9cd60879c1 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/InMemoryBouquetRepository.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/InMemoryBouquetRepository.cs @@ -18,6 +18,7 @@ public InMemoryBouquetRepository() Name = $"Bouquet {i}\u2122", ImageUrl = $"https://placeholdit.imgix.net/~text?txtsize=48&txt={HttpUtility.UrlEncode("Bouquet " + i)}&w=640&h=330", Price = new Random(i).Next(10, 100) + .99, + // randomizing the flower category but ensuring at least 1 bouquet for each of it. FlowerCategory = (i <= 5) ? $"Flower {i}" : "Flower " + new Random(i).Next(1, 5) }); diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/packages.config b/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/packages.config index 92167d0838..90aba3007d 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/packages.config +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers.Services/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers/ContosoFlowers.csproj b/CSharp/demo-ContosoFlowers/ContosoFlowers/ContosoFlowers.csproj index 713c11dbc7..8df94e43fe 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers/ContosoFlowers.csproj +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers/ContosoFlowers.csproj @@ -43,41 +43,45 @@ 4 - - ..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll + + ..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll True - - ..\packages\Autofac.4.0.0\lib\net451\Autofac.dll + + ..\packages\Autofac.4.2.1\lib\net45\Autofac.dll True ..\packages\Autofac.Mvc5.4.0.0\lib\net451\Autofac.Integration.Mvc.dll True - - ..\packages\AutoMapper.5.1.1\lib\net45\AutoMapper.dll + + ..\packages\AutoMapper.5.2.0\lib\net45\AutoMapper.dll True ..\packages\Chronic.Signed.0.3.2\lib\net40\Chronic.dll True - - ..\packages\Microsoft.Bot.Builder.3.2.1\lib\net46\Microsoft.Bot.Builder.dll + + ..\packages\Microsoft.Bot.Builder.3.5.0\lib\net46\Microsoft.Bot.Builder.dll True - - ..\packages\Microsoft.Bot.Builder.3.2.1\lib\net46\Microsoft.Bot.Connector.dll + + ..\packages\Microsoft.Bot.Builder.Location.1.1.0\lib\net46\Microsoft.Bot.Builder.Location.dll + True + + + ..\packages\Microsoft.Bot.Builder.3.5.0\lib\net46\Microsoft.Bot.Connector.dll True - - ..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.2.206221351\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll + + ..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.3.308261200\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll True - ..\packages\Microsoft.Rest.ClientRuntime.2.3.2\lib\net45\Microsoft.Rest.ClientRuntime.dll + ..\packages\Microsoft.Rest.ClientRuntime.2.3.4\lib\net45\Microsoft.Rest.ClientRuntime.dll True @@ -85,16 +89,16 @@ True - ..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.1.0\lib\net40\Microsoft.WindowsAzure.Configuration.dll + ..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.2.3\lib\net40\Microsoft.WindowsAzure.Configuration.dll True - - ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll True - - ..\packages\System.IdentityModel.Tokens.Jwt.4.0.2.206221351\lib\net45\System.IdentityModel.Tokens.Jwt.dll + + ..\packages\System.IdentityModel.Tokens.Jwt.4.0.3.308261200\lib\net45\System.IdentityModel.Tokens.Jwt.dll True diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers/ContosoFlowersModule.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers/ContosoFlowersModule.cs index 4a13865909..f722e7c5e1 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers/ContosoFlowersModule.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers/ContosoFlowersModule.cs @@ -2,11 +2,14 @@ { using System.Configuration; using Autofac; + using BotAssets; using BotAssets.Dialogs; using Dialogs; using Microsoft.Bot.Builder.Dialogs; - using Microsoft.Bot.Builder.Dialogs.Internals; using Microsoft.Bot.Builder.Internals.Fibers; + using Microsoft.Bot.Builder.Location; + using Microsoft.Bot.Builder.Scorables; + using Microsoft.Bot.Connector; using Services.Models; public class ContosoFlowersModule : Module @@ -25,7 +28,7 @@ protected override void Load(ContainerBuilder builder) .InstancePerDependency(); builder.RegisterType() - .As>() + .As>() .InstancePerLifetimeScope(); builder.RegisterType() @@ -34,15 +37,21 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType() .InstancePerDependency(); - builder.RegisterType() - .InstancePerDependency(); - builder.RegisterType() .InstancePerDependency(); builder.RegisterType() .InstancePerDependency(); + // Location Dialog + // ctor signature: LocationDialog(string apiKey, string channelId, string prompt, LocationOptions options = LocationOptions.None, LocationRequiredFields requiredFields = LocationRequiredFields.None, LocationResourceManager resourceManager = null); + builder.RegisterType() + .WithParameter("apiKey", ConfigurationManager.AppSettings["MicrosoftBingMapsKey"]) + .WithParameter("options", LocationOptions.UseNativeControl | LocationOptions.ReverseGeocode) + .WithParameter("requiredFields", LocationRequiredFields.StreetAddress | LocationRequiredFields.Locality | LocationRequiredFields.Country) + .WithParameter("resourceManager", new ContosoLocationResourceManager()) + .InstancePerDependency(); + // Service dependencies builder.RegisterType() .Keyed(FiberModule.Key_DoNotSerialize) @@ -58,12 +67,6 @@ protected override void Load(ContainerBuilder builder) .Keyed>(FiberModule.Key_DoNotSerialize) .AsImplementedInterfaces() .SingleInstance(); - - builder.RegisterType() - .WithParameter("bingMapsKey", ConfigurationManager.AppSettings["MicrosoftBingMapsKey"]) - .Keyed(FiberModule.Key_DoNotSerialize) - .AsImplementedInterfaces() - .SingleInstance(); } } } \ No newline at end of file diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/FlowerCategoriesDialog.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/FlowerCategoriesDialog.cs index f10024a931..a3d7830f00 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/FlowerCategoriesDialog.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/FlowerCategoriesDialog.cs @@ -56,7 +56,7 @@ public override async Task ProcessMessageReceived(IDialogContext context, string else { await context.PostAsync(string.Format(CultureInfo.CurrentCulture, Resources.FlowerCategoriesDialog_InvalidOption, flowerCategoryName)); - await base.ShowProducts(context); + await this.ShowProducts(context); context.Wait(this.MessageReceivedAsync); } } diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/RootDialog.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/RootDialog.cs index 62484b53e5..e51cb70c58 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/RootDialog.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/RootDialog.cs @@ -10,6 +10,7 @@ using BotAssets.Extensions; using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Builder.FormFlow; + using Microsoft.Bot.Builder.Location; using Microsoft.Bot.Connector; using Models; using Properties; @@ -77,8 +78,17 @@ private async Task OnOptionSelected(IDialogContext context, IAwaitable(string.Format(CultureInfo.CurrentCulture, Resources.RootDialog_DeliveryAddress_Prompt, message.From.Name ?? "User")); - context.Call(addressDialog, this.AfterDeliveryAddress); + + // BotBuilder's LocationDialog + // Leverage DI to inject other parameters + var locationDialog = this.dialogFactory.Create( + new Dictionary() + { + { "prompt", string.Format(CultureInfo.CurrentCulture, Resources.RootDialog_DeliveryAddress_Prompt, message.From.Name ?? "User") }, + { "channelId", context.Activity.ChannelId } + }); + + context.Call(locationDialog, this.AfterDeliveryAddress); } else if (message.Text == Resources.RootDialog_Welcome_Support) { @@ -90,11 +100,13 @@ private async Task OnOptionSelected(IDialogContext context, IAwaitable result) + private async Task AfterDeliveryAddress(IDialogContext context, IAwaitable result) { try { - this.order.DeliveryAddress = await result; + var place = await result; + var formattedAddress = place.GetPostalAddress().FormattedAddress; + this.order.DeliveryAddress = formattedAddress; context.Call(this.dialogFactory.Create(), this.AfterFlowerCategorySelected); } @@ -337,7 +349,8 @@ private Attachment GetReceiptCard() var receiptCard = new ReceiptCard { Title = Resources.RootDialog_Receipt_Title, - Facts = new List { + Facts = new List + { new Fact(Resources.RootDialog_Receipt_OrderID, order.OrderID), new Fact(Resources.RootDialog_Receipt_PaymentMethod, creditCardOffuscated) }, diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/SettingsDialog.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/SettingsDialog.cs index 72cdb3a291..9c6d046f1b 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/SettingsDialog.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/SettingsDialog.cs @@ -9,6 +9,7 @@ using BotAssets.Extensions; using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Builder.Internals.Fibers; + using Microsoft.Bot.Builder.Location; using Microsoft.Bot.Connector; using Models; using Properties; @@ -121,8 +122,16 @@ private async Task OnAddressSelectedReceived(IDialogContext context, IAwaitable< { this.selectedAddressToUpdate = message.Text; - var addressDialog = this.dialogFactory.Create(Resources.SettingsDialog_BillingAddress_Prompt); - context.Call(addressDialog, this.ResumeAfterAddressEntered); + // BotBuilder's LocationDialog + // Leverage DI to inject other parameters + var locationDialog = this.dialogFactory.Create( + new Dictionary() + { + { "prompt", Resources.SettingsDialog_BillingAddress_Prompt }, + { "channelId", context.Activity.ChannelId } + }); + + context.Call(locationDialog, this.ResumeAfterAddressEntered); } else if (message.Text.Equals("B", StringComparison.InvariantCultureIgnoreCase) || message.Text.Equals("Back", StringComparison.InvariantCultureIgnoreCase)) { @@ -134,20 +143,31 @@ private async Task OnAddressSelectedReceived(IDialogContext context, IAwaitable< } } - private async Task ResumeAfterAddressEntered(IDialogContext context, IAwaitable result) + private async Task ResumeAfterAddressEntered(IDialogContext context, IAwaitable result) { - var address = await result; + string reply; - context.UserData.UpdateValue( - StringConstants.UserPreferencesKey, - userPreferences => - { - userPreferences.BillingAddresses = userPreferences.BillingAddresses ?? new Dictionary(); - userPreferences.BillingAddresses[this.selectedAddressToUpdate.ToLower()] = address; - }); + var place = await result; + if (place == null) + { + reply = "No address was selected, returning to settings menu."; + } + else + { + var formattedAddress = place.GetPostalAddress().FormattedAddress; - await context.PostAsync(Resources.SettingsDialog_Address_Entered); + context.UserData.UpdateValue( + StringConstants.UserPreferencesKey, + userPreferences => + { + userPreferences.BillingAddresses = userPreferences.BillingAddresses ?? new Dictionary(); + userPreferences.BillingAddresses[this.selectedAddressToUpdate.ToLower()] = formattedAddress; + }); + + reply = string.Format(CultureInfo.CurrentCulture, Resources.SettingsDialog_Address_Entered, this.selectedAddressToUpdate, formattedAddress); + } + await context.PostAsync(reply); await this.StartAsync(context); } diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/SettingsScorable.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/SettingsScorable.cs index 11480713e0..cc88292421 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/SettingsScorable.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers/Dialogs/SettingsScorable.cs @@ -6,9 +6,10 @@ using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Builder.Dialogs.Internals; using Microsoft.Bot.Builder.Internals.Fibers; + using Microsoft.Bot.Builder.Scorables; using Microsoft.Bot.Connector; - public class SettingsScorable : IScorable + public class SettingsScorable : IScorable { private readonly IDialogStack stack; private readonly IContosoFlowersDialogFactory dialogFactory; @@ -19,7 +20,7 @@ public SettingsScorable(IDialogStack stack, IContosoFlowersDialogFactory dialogF SetField.NotNull(out this.dialogFactory, nameof(dialogFactory), dialogFactory); } - public async Task PrepareAsync(Item item, CancellationToken token) + public async Task PrepareAsync(IActivity item, CancellationToken token) { var message = item as IMessageActivity; @@ -34,14 +35,19 @@ public async Task PrepareAsync(Item item, CancellationToken token) return null; } - public bool TryScore(object state, out double score) + public bool HasScore(IActivity item, object state) + { + return state != null; + } + + public double GetScore(IActivity item, object state) { bool matched = state != null; - score = matched ? 1.0 : double.NaN; - return matched; + var score = matched ? 1.0 : double.NaN; + return score; } - public async Task PostAsync(Item item, object state, CancellationToken token) + public async Task PostAsync(IActivity item, object state, CancellationToken token) { var message = item as IMessageActivity; @@ -52,7 +58,7 @@ public async Task PostAsync(Item item, object state, CancellationToken tok // wrap it with an additional dialog that will restart the wait for // messages from the user once the child dialog has finished var interruption = settingsDialog.Void(); - + // put the interrupting dialog on the stack this.stack.Call(interruption, null); @@ -60,5 +66,10 @@ public async Task PostAsync(Item item, object state, CancellationToken tok await this.stack.PollAsync(token); } } + + public Task DoneAsync(IActivity item, object state, CancellationToken token) + { + return Task.CompletedTask; + } } } diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers/Models/Order.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers/Models/Order.cs index 242bcc570d..4a0f5d41fe 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers/Models/Order.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers/Models/Order.cs @@ -17,25 +17,25 @@ public enum UseSaveInfoResponse public string OrderID { get; set; } - [Prompt()] + [Prompt] public string RecipientFirstName { get; set; } [Prompt(FieldCase = CaseNormalization.None)] public string RecipientLastName { get; set; } - [Prompt()] + [Prompt] [Pattern(RegexConstants.Phone)] public string RecipientPhoneNumber { get; set; } - [Prompt()] + [Prompt] [Pattern(@"^.{1,200}$")] public string Note { get; set; } - [Prompt()] + [Prompt] [Pattern(RegexConstants.Email)] public string SenderEmail { get; set; } - [Prompt()] + [Prompt] [Pattern(RegexConstants.Phone)] public string SenderPhoneNumber { get; set; } @@ -45,10 +45,10 @@ public enum UseSaveInfoResponse public bool AskToUseSavedSenderInfo { get; set; } - [Prompt()] + [Prompt] public UseSaveInfoResponse? UseSavedSenderInfo { get; set; } - [Prompt()] + [Prompt] public bool SaveSenderInfo { get; set; } public string DeliveryAddress { get; set; } diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers/Properties/AssemblyInfo.cs b/CSharp/demo-ContosoFlowers/ContosoFlowers/Properties/AssemblyInfo.cs index f2778ceb42..698efd6bf4 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers/Properties/AssemblyInfo.cs +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers/Properties/AssemblyInfo.cs @@ -1,6 +1,5 @@ -using System.Resources; -using System.Reflection; -using System.Runtime.CompilerServices; +using System.Reflection; +using System.Resources; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -35,4 +34,3 @@ [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: NeutralResourcesLanguage("en-US")] - diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers/Web.config b/CSharp/demo-ContosoFlowers/ContosoFlowers/Web.config index 622b6617ce..ca5c1d577e 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers/Web.config +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers/Web.config @@ -42,7 +42,7 @@ - + @@ -66,12 +66,32 @@ - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CSharp/demo-ContosoFlowers/ContosoFlowers/packages.config b/CSharp/demo-ContosoFlowers/ContosoFlowers/packages.config index 4bed45c99f..571f98494d 100644 --- a/CSharp/demo-ContosoFlowers/ContosoFlowers/packages.config +++ b/CSharp/demo-ContosoFlowers/ContosoFlowers/packages.config @@ -1,9 +1,9 @@  - - + + - + @@ -12,12 +12,13 @@ - - - + + + + - - - + + + \ No newline at end of file diff --git a/CSharp/demo-ContosoFlowers/README.md b/CSharp/demo-ContosoFlowers/README.md index 3efff9c55b..3ecbf3daff 100644 --- a/CSharp/demo-ContosoFlowers/README.md +++ b/CSharp/demo-ContosoFlowers/README.md @@ -13,12 +13,12 @@ You came across the Microsoft Bot Framework which support a great variety of cha The minimum prerequisites to run this sample are: * The latest update of Visual Studio 2015. You can download the community version [here](http://www.visualstudio.com) for free. -* The Bot Framework Emulator. To install the Bot Framework Emulator, download it from [here](https://aka.ms/bf-bc-emulator). Please refer to [this documentation article](https://docs.botframework.com/en-us/csharp/builder/sdkreference/gettingstarted.html#emulator) to know more about the Bot Framework Emulator. +* The Bot Framework Emulator. To install the Bot Framework Emulator, download it from [here](https://emulator.botframework.com/). Please refer to [this documentation article](https://github.com/microsoft/botframework-emulator/wiki/Getting-Started) to know more about the Bot Framework Emulator. #### Rich cards Many messaging channels provide the ability to attach richer objects. The Bot Framework has the ability to render rich cards as attachments. -The bot will render a Welcome message upon the first message using a [HeroCard](https://docs.botframework.com/en-us/csharp/builder/sdkreference/attachments.html#herocard) attachment within the [`RootDialog.WelcomeMessageAsync` method](ContosoFlowers/Dialogs/RootDialog.cs#L53-L71). +The bot will render a Welcome message upon the first message using a [HeroCard](https://docs.botframework.com/en-us/csharp/builder/sdkreference/attachments.html#herocard) attachment within the [`RootDialog.WelcomeMessageAsync` method](ContosoFlowers/Dialogs/RootDialog.cs#L54-L72). The sample also includes the [`HeroCardExtensions`](ContosoFlowers.BotAssets/Extensions/HeroCardExtensions.cs) class providing methods to ease the creation of rich cards. ````C# @@ -47,7 +47,7 @@ private async Task WelcomeMessageAsync(IDialogContext context) |![Rich Cards - Hero Card](images/richcards-herocard-emulator.png)|![Rich Cards - Hero Card](images/richcards-herocard-facebook.png)|![Rich Cards - Hero Card](images/richcards-herocard-skype.png)| Another example of rich card, is the [ReceiptCard](https://docs.botframework.com/en-us/csharp/builder/sdkreference/attachments.html#receiptcard) which renders differently depending on the messaging channel being supported. -The receipt card is created in the [`RootDialog.GetReceiptCard` method](ContosoFlowers/Dialogs/RootDialog.cs#L333-L356) and is rendered once the bot's user checkouts an order. +The receipt card is created in the [`RootDialog.GetReceiptCard` method](ContosoFlowers/Dialogs/RootDialog.cs#L345-L369) and is rendered once the bot's user checkouts an order. ````C# private Attachment GetReceiptCard() @@ -125,14 +125,17 @@ In this sample, the main flow is implemented in the [`RootDialog` class](Contoso #### Creating Reusable Components As seen in the two examples above, you can reuse your dialogs in different segments of the bot's flow, or even different bots, and extract them into a library. An example of this is the [ContosoFlowers.BotAssets project](ContosoFlowers.BotAssets) which includes several reusable dialogs and extension methods. -- Dialogs - - [AddressDialog](https://github.com/fuselabs/BotBuilder-samples/blob/master/ContosoFlowers/CSharp/ContosoFlowers.BotAssets/Dialogs/AddressDialog.cs) - - [PagedCarouselDialog](https://github.com/fuselabs/BotBuilder-samples/blob/master/ContosoFlowers/CSharp/ContosoFlowers.BotAssets/Dialogs/PagedCarouselDialog.cs) - - [PromptStringRegex](https://github.com/fuselabs/BotBuilder-samples/blob/master/ContosoFlowers/CSharp/ContosoFlowers.BotAssets/Dialogs/PromptStringRegex.cs) - - [SavedAddressDialog](https://github.com/fuselabs/BotBuilder-samples/blob/master/ContosoFlowers/CSharp/ContosoFlowers.BotAssets/Dialogs/SavedAddressDialog.cs) +- Contoso Flowers' Dialogs + - [PagedCarouselDialog](ContosoFlowers.BotAssets/Dialogs/PagedCarouselDialog.cs) + - [PromptStringRegex](ContosoFlowers.BotAssets/Dialogs/PromptStringRegex.cs) + - [SavedAddressDialog](ContosoFlowers.BotAssets/Dialogs/SavedAddressDialog.cs) - Extensions - - [HeroCardExtensions](https://github.com/fuselabs/BotBuilder-samples/blob/master/ContosoFlowers/CSharp/ContosoFlowers.BotAssets/Extensions/HeroCardExtensions.cs) - - [IBotDataBagExtensions](https://github.com/fuselabs/BotBuilder-samples/blob/master/ContosoFlowers/CSharp/ContosoFlowers.BotAssets/Extensions/IBotDataBagExtensions.cs) + - [HeroCardExtensions](ContosoFlowers.BotAssets/Extensions/HeroCardExtensions.cs) + - [IBotDataBagExtensions](ContosoFlowers.BotAssets/Extensions/IBotDataBagExtensions.cs) + +Additionally, the [Bing Location Control](https://github.com/Microsoft/BotBuilder-Location) is being used to resolve and validate the shipping and billing addresses, backed by Bing Maps REST services. +Take a look [here](ContosoFlowers/ContosoFlowersModule.cs#L46-L53) to see how to leverage DI to configure the control, and [here](ContosoFlowers/Dialogs/RootDialog.cs#L82-L91) to see how to use the DialogFactory to create an instance of the Control's Location Dialog. + #### Complex Forms Handling a guided conversation like ordering a bouquet of flowers for your loved one can require a lot of effort. In order to simplify building guided conversations the Bot Framework provides a powerful dialog building block known as [FormFlow](https://docs.botframework.com/en-us/csharp/builder/sdkreference/forms.html). A FormFlow dialog guides the user through filling in the form; a collection of fields that you want to fill in through a conversation with the user.