I'm trying to get the data from an inline keyboard, I've searched a lot but unfortunately didn't get my answer and non of codes worked for me. Here's my code please help me
static void Main(string[] args){
InlineKeyboardButton[][] buttons =
new InlineKeyboardButton[][]{
new InlineKeyboardButton[]{newInlineKeyboardButton() { Text = "show Channel", CallbackData = "Data1" }},
new InlineKeyboardButton[]{new InlineKeyboardButton() { Text = "show Website", CallbackData = "Data2" }}};
inlineKeyboardMarkup = new InlineKeyboardMarkup() { InlineKeyboard = buttons };
Task.Run(() => RunBot());
Console.ReadLine();
} // End of main method
public static async Task RunBot(){
while (true){
var u = await bot.MakeRequestAsync(new GetUpdates() { Offset
= offset });
foreach (var update in u)
{
offset = update.UpdateId + 1;
var text = update.Message.Text;
// here I want to get the data like this, but it doesn't work
if (update.ChosenInlineResult != null){
Console.WriteLine("Chosen Inline Result: " +
update.ChosenInlineResult.ToString());
}
switch(text){
case "Something":{
var req = new SendMessage(update.Message.Chat.Id, "راهنما") { ReplyMarkup = inlineKeyboardMarkup };
await bot.MakeRequestAsync(req);
break;
}
}
}
}
}
you must replace this
if (update.ChosenInlineResult != null){
Console.WriteLine("Chosen Inline Result: " +
update.ChosenInlineResult.ToString());
}
with something like This :
if (update.CallbackQuery != null)
{
Console.WriteLine(val.CallbackQuery.Message+"-"+val.CallbackQuery.Data);
}
Related
This feels like a simple question and I feel like I am overthinking it. I am doing an AWS project that will compare face(s) on an image to a database (s3bucket) of other faces. So far, I have a lambda function for the comparefacerequest, a class library which invokes the function, and an UWP that inputs the image file and outputs a result. It has worked so far being based on boolean (true or false) functions, but now I want it to instead return what face(s) are recognized via an array. I struggling at implementing this.
Below is my lambda function. I have adjusted the task to be an Array instead of a bool and changed the return to be an array. At the bottom, I have created a global variable class with a testing array so I could attempt to reference the array elsewhere.
public class Function
{
//Function
public async Task<Array> FunctionHandler(string input, ILambdaContext context)
{
//number of matched faces
int matched = 0;
//Client setup
var rekognitionclient = new AmazonRekognitionClient();
var s3client = new AmazonS3Client();
//Create list of target images
ListObjectsRequest list = new ListObjectsRequest
{
BucketName = "bucket2"
};
ListObjectsResponse listre = await s3client.ListObjectsAsync(list);
//loop of list
foreach (Amazon.S3.Model.S3Object obj in listre.S3Objects)
{
//face request with input and obj.key images
var comparefacesrequest = new CompareFacesRequest
{
SourceImage = new Image
{
S3Object = new S3Objects
{
Bucket = "bucket1",
Name = input
}
},
TargetImage = new Image
{
S3Object = new S3Objects
{
Bucket = "bucket2",
Name = obj.Key
}
},
};
//compare with confidence of 95 (subject to change) to current target image
var detectresponse = await rekognitionclient.CompareFacesAsync(comparefacesrequest);
detectresponse.FaceMatches.ForEach(match =>
{
ComparedFace face = match.Face;
if (match.Similarity > 95)
{
//if face detected, raise matched
matched++;
for(int i = 0; i < Globaltest.testingarray.Length; i++)
{
if (Globaltest.testingarray[i] == "test")
{
Globaltest.testingarray[i] = obj.Key;
}
}
}
});
}
//Return true or false depending on if it is matched
if (matched > 0)
{
return Globaltest.testingarray;
}
return Globaltest.testingarray;
}
}
public static class Globaltest
{
public static string[] testingarray = { "test", "test", "test" };
}
Next, is my invoke request in my class library. It has so far been based on the lambda outputting a boolean result, but I thought, "hey, it is parsing the result, it should be fine, right"? I do convert the result to a string, as there is no GetArray, from what I know.
public async Task<bool> IsFace(string filePath, string fileName)
{
await UploadS3(filePath, fileName);
AmazonLambdaClient client = new AmazonLambdaClient(accessKey, secretKey, Amazon.RegionEndpoint.USWest2);
InvokeRequest ir = new InvokeRequest();
ir.InvocationType = InvocationType.RequestResponse;
ir.FunctionName = "ImageTesting";
ir.Payload = "\"" + fileName + "\"";
var result = await client.InvokeAsync(ir);
var strResponse = Encoding.ASCII.GetString(result.Payload.ToArray());
if (bool.TryParse(strResponse, out bool result2))
{
return result2;
}
return false;
}
Finally, here is the section of my UWP where I perform the function. I am referencing the lambda client via "using Lambdaclienttest" (name of lamda project, and this is its only instance I use the reference though). When I run my project, I do still get a face detected when it should, but the Globaltest.testingarray[0] is still equal to "test".
var Facedetector = new FaceDetector(Credentials.accesskey, Credentials.secretkey);
try
{
var result = await Facedetector.IsFace(filepath, filename);
if (result)
{
textBox1.Text = "There is a face detected";
textBox2.Text = Globaltest.testingarray[0];
}
else
{
textBox1.Text = "Try Again";
}
}
catch
{
textBox1.Text = "Please use a photo";
}
Does anyone have any suggestions?
I've got a method that returning back from CompletionService.GetDescriptionAsync(Document, CompletionItem) gives me the following description:
void SQL.GetSQLiteDB(string url) (+ 1 overload)
This is a method I made on a Xamarin project, here are both method signatures:
public static void GetSQLiteDB(string url);
public static string GetSQLiteDB(string url, string name);
What's the Roslyn way to get information on both?
Here's how I'm setting up completions:
async Task InitCodeCompletion()
{
host = MefHostServices.Create(MefHostServices.DefaultAssemblies);
workspace = new AdhocWorkspace(host);
Type[] types =
{
typeof(object),
typeof(System.Linq.Enumerable),
typeof(System.Collections.IEnumerable),
typeof(Console),
typeof(System.Reflection.Assembly),
typeof(List<>),
typeof(Type),
typeof(SQL)
};
imports = types.Select(x => x.Namespace).Distinct().ToImmutableArray();
assemblies = types.Select(x => x.Assembly).Distinct().ToImmutableArray();
references = assemblies.Select(t => MetadataReference.CreateFromFile(t.Location) as MetadataReference).ToImmutableArray();
compilationOptions = new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
usings: imports);
projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "Script", "Script", LanguageNames.CSharp, isSubmission: true)
.WithMetadataReferences(references).WithCompilationOptions(compilationOptions);
project = workspace.AddProject(projectInfo);
documentInfo = DocumentInfo.Create(DocumentId.CreateNewId(project.Id), "Script", sourceCodeKind: SourceCodeKind.Script,
loader: TextLoader.From(TextAndVersion.Create(SourceText.From(""), VersionStamp.Create())));
document = workspace.AddDocument(documentInfo);
var services = workspace.Services;
completionService = CompletionService.GetService(document);
}
async Task<CodeCompletionResults> GetCompletions(string code)
{
string codeModified = "using SQL = XamTestNET5.Services.SQLiteGeneratorService; " + Environment.NewLine;
codeModified += "using HtmlSvc = XamTestNET5.Services.HtmlRetrievalService;" + Environment.NewLine;
// ^^^ The above two lines set up some simple namespace aliases in my project, if you know how to put this in a separate project document and use it in code completion please let me know in comments as otherwise doing so gives me an exception that you can't have multiple syntax trees
codeModified += code;
var source = SourceText.From(codeModified);
document = document.WithText(source);
// cursor position is at the end
var position = source.Length;
var completions = await completionService.GetCompletionsAsync(document, position);
return new CodeCompletionResults() { InputCode = code, ModifiedCode = codeModified, Completions = completions };
}
Here's how I'm getting them now and putting them in a browser control:
private async void CSharpShellEnvironment_EntryCodeCompletionEntry(object sender, CSharpShellEnvironment.EntryEventArgs e)
{
if (e.Value != "")
{
CodeCompletionResults results = await GetCompletions(e.Value);
CompletionList list = results.Completions;
if (list != null)
{
if (list.Items != null)
{
StringBuilder sb = new StringBuilder();
foreach (var item in list.Items)
{
string spanText = (item.Span.Start != item.Span.End) ? results.ModifiedCode.Substring(item.Span.Start, item.Span.Length) : "";
bool recommended = spanText == "" ? true : item.DisplayText.StartsWith(spanText);
if (recommended)
{
string fText = item.DisplayText.Substring(spanText.Length);
string props = "";
foreach(var p in item.Properties)
{
props += $"<span data-key=\"{p.Key}\" data-value=\"{p.Value}\"></span>";
}
string tags = "";
foreach(var t in item.Tags)
{
tags += $"<span data-tag=\"{t}\"></span>";
}
string descStr = "";
if (item.Tags != null)
{
if (item.Tags.Where(x => x.ToLower() == "method").FirstOrDefault() != null && item.Tags.Where(x => x.ToLower() == "public").FirstOrDefault() != null)
{
var desc = await completionService.GetDescriptionAsync(document, item);
descStr += $"<span data-desc=\"{desc.Text}\">";
foreach(var part in desc.TaggedParts)
{
descStr += $"<span data-desc-part-tag=\"{part.Tag}\" data-desc-part-text=\"{part.Text}\"></span>";
}
descStr += "</span>";
}
}
sb.AppendLine($"<div class=\"codecompleteentry\" data-display-text=\"{item.DisplayText}\" data-span-text=\"{spanText}\" data-final-text=\"{fText}\">{props}{tags}{descStr}{fText}</div>");
}
}
string scriptInputClick = "Array.prototype.forEach.call(document.getElementsByClassName('codecompleteentry'), function(el) { el.addEventListener('click', function(elem) { var text = { MessageType: 'CodeCompletion', Parameters: JSON.stringify({ DataDisplayText: el.getAttribute('data-display-text'), DataSpanText: el.getAttribute('data-span-text'), DataFinalText: el.getAttribute('data-final-text') }), Message: el.innerText }; window.chrome.webview.postMessage(text); } ); });";
sb.AppendLine($"<script type=\"text/javascript\">{scriptInputClick}</script>");
env.EnterCodeCompletionResponse(sb.ToString());
}
else
{
env.EnterCodeCompletionResponse(strNoSuggestions);
}
}
else
{
env.EnterCodeCompletionResponse(strNoSuggestions);
}
}
else
{
env.EnterCodeCompletionResponse(strNoSuggestions);
}
}
It seems on the surface that CompletionSurface has everything you need, but it doesn't, you need to reference the Document's SemanticModel in order to get all of the signature overloads of a method when the user types ( on a method during code completion.
It wasn't very obvious to me until I started looking through the RoslynPad source, which I recommend doing for a practical example: https://github.com/aelij/RoslynPad
List<IEnumerable<ReferencedSymbol>> allMethodRefs = new List<IEnumerable<ReferencedSymbol>>();
async Task<CodeCompletionResults> GetCompletions(string code)
{
string codeModified = "using SQL = XamTestNET5.Services.SQLiteGeneratorService; " + Environment.NewLine;
codeModified += "using HtmlSvc = XamTestNET5.Services.HtmlRetrievalService;" + Environment.NewLine;
// ^^^ I put my namespace aliases in the same SyntaxTree for now,
// I'd like a better solution though.
codeModified += code;
var source = SourceText.From(codeModified);
document = document.WithText(source);
// cursor position is at the end
var position = source.Length;
var completions = await completionService.GetCompletionsAsync(document, position);
syntaxRoot = await document.GetSyntaxRootAsync();
semanticModel = await document.GetSemanticModelAsync();
var methods = syntaxRoot.DescendantNodes().OfType<InvocationExpressionSyntax>();
allMethodRefs = new List<IEnumerable<ReferencedSymbol>>();
if (methods != null)
{
if (methods.Count() > 0)
{
foreach(var m in methods)
{
var info = semanticModel.GetSymbolInfo(m);
if (info.Symbol != null)
{
allMethodRefs.Add(await SymbolFinder.FindReferencesAsync(info.Symbol, solution));
}
else
{
foreach(var symbol in info.CandidateSymbols)
{
allMethodRefs.Add(await SymbolFinder.FindReferencesAsync(symbol, solution));
}
}
}
}
}
return new CodeCompletionResults() { InputCode = code, ModifiedCode = codeModified, Completions = completions };
}
I'm new in Telegram bot programming with C#.
I created a simple bot but that doesn't work.
Console runs program completely, but bot shows me no response with any commands.
And I can't see the buttons in bot.
I know something is wrong but I don't know where.
Please help me, this is very force for me
What should I do?
This is my code:
using System;
using System.Linq;
using System.Threading.Tasks;
using NetTelegramBotApi;
using NetTelegramBotApi.Requests;
using NetTelegramBotApi.Types;
using System.Text;
using System.Collections.Generic;
namespace ConsoleApp1
{
class Program
{
private static string token = "<PRIVATE-KEY>"; //Telegram token
private static ReplyKeyboardMarkup mainMenu; //Declare a menu
private static ReplyKeyboardMarkup secondMenu;
static void Main(string[] args)
{
//Set Items as button for main menu
mainMenu = new ReplyKeyboardMarkup
{
Keyboard = new KeyboardButton[][]
{
new KeyboardButton[]
{
new KeyboardButton("Text 1"),
new KeyboardButton("Text 2"),
new KeyboardButton("Text 3")
},
new KeyboardButton[]
{
new KeyboardButton("Text 4"),
new KeyboardButton("Text 5"),
new KeyboardButton("Text 6")
}
}
};
//Set Items as button for second menu
secondMenu = new ReplyKeyboardMarkup
{
Keyboard = new KeyboardButton[][]
{
new KeyboardButton[]
{
new KeyboardButton("Second 1"),
new KeyboardButton("Second 2")
},
new KeyboardButton[]
{
new KeyboardButton("Back")
}
}
};
Task.Run(() => RunBot());
Console.ReadLine();
}
public static async Task RunBot()
{
var bot = new TelegramBot(token);
var me = await bot.MakeRequestAsync(new GetMe());
Console.WriteLine("User name is {0}", me.Username);
long offset = 0;
int whileCount = 0;
while (true)
{
Console.WriteLine("While is {0}", whileCount);
whileCount++;
//Check user creates a request
var updates = await bot.MakeRequestAsync(new GetUpdates() { Offset = offset });
Console.WriteLine("update count is {0}", updates.Count());
Console.WriteLine("------------------------------");
try
{
}
catch (Exception e)
{
foreach (var update in updates)
{
offset = update.UpdateId + 1; // Get offset of update
var text = update.Message.Text; //Get message from users
/*
* These lines check, that which button has been selected by user
* Do something for each button
*/
if (text == "/start")
{
var req = new SendMessage(update.Message.Chat.Id, "سلاااااام. این اولین ربات تلگرامی هست که ساختم. پیش به سوی موفقیت و پول زیاد ")
{ ReplyMarkup = mainMenu };
await bot.MakeRequestAsync(req); //Run req Command
continue; //Loop continues
}
else if (text != null && text.Contains("Text 1"))
{
var req = new SendMessage(update.Message.Chat.Id, "You clicked on Text 1")
{ ReplyMarkup = mainMenu }; //Send message to user
await bot.MakeRequestAsync(req); //Run req command
continue; //Loop continues
}
else if (text != null && text.Contains("Text 2"))
{
var req = new SendMessage(update.Message.Chat.Id, "You clicked on Text 2")
{ ReplyMarkup = mainMenu }; //Send message to user
await bot.MakeRequestAsync(req); //Run req command
continue; //Loop continues
}
else if (text != null && text.Contains("Text 3"))
{
var req = new SendMessage(update.Message.Chat.Id, "You clicked on Text 3")
{ ReplyMarkup = mainMenu };
await bot.MakeRequestAsync(req);
continue;
}
else if (text != null && text.Contains("Text 4"))
{
var req = new SendMessage(update.Message.Chat.Id, "You clicked on Text 4")
{ ReplyMarkup = mainMenu };
await bot.MakeRequestAsync(req);
continue;
}
else if (text != null && text.Contains("Text 5"))
{
var req = new SendMessage(update.Message.Chat.Id, "You clicked on Text 5")
{ ReplyMarkup = mainMenu };
await bot.MakeRequestAsync(req);
continue;
}
else if (text != null && text.Contains("Text 6"))
{
var req = new SendMessage(update.Message.Chat.Id, "You clicked on Text 6")
{ ReplyMarkup = secondMenu };
await bot.MakeRequestAsync(req);
continue;
}
else if (text != null && text.Contains("Second 1"))
{
var req = new SendMessage(update.Message.Chat.Id, "Please wait a moment")
{ ReplyMarkup = secondMenu};
await bot.MakeRequestAsync(req);
/*
* This using is for sending a video to a user
*/
using(var stream = System.IO.File.Open("D://Projects//Visual studio project//resources//test.mp4", System.IO.FileMode.Open))
{
var req2 = new SendVideo(update.Message.Chat.Id, new FileToSend(stream, "test.mp4"))
{ ReplyMarkup = secondMenu};
await bot.MakeRequestAsync(req2);
continue;
}
}
else if(text != null && text.Contains("Second 2"))
{
/**
* This using is for sending a photo to a user
*/
using (var stream = System.IO.File.Open("d://Photo//car.jpg", System.IO.FileMode.Open))
{
var req = new SendPhoto(update.Message.Chat.Id, new FileToSend(stream, "car.jpg"))
{ ReplyMarkup = secondMenu};
await bot.MakeRequestAsync(req);
continue;
}
}
else if(text != null && text.Contains("Back"))
{
var req = new SendMessage(update.Message.Chat.Id, "Back to main menu")
{ ReplyMarkup = mainMenu };
await bot.MakeRequestAsync(req);
continue;
}
else
{
var req = new SendMessage(update.Message.Chat.Id, "Undefined message!!!")
{ ReplyMarkup = mainMenu };
await bot.MakeRequestAsync(req);
continue;
}
}
}
}
}
}
}
I used NetTelegramBotApi package
Thanks a lot in advance
First cut the codes from catch clause and paste them into try.
initialize me and update variables like this:
var me = bot.MakeRequestAsync(new GetMe()).Result;
var updates = bot.MakeRequestAsync(new GetUpdates() { Offset = offset }).Result;
I am currently sending a file to be transcoded to my AWS lambda function. After I send the file, I send a notification to the SQS for some external aplication to start downloading the transcoded files.
The problem is, sometimes, the download of the files happen before the Lambda function completed.
How can I only send the notification to SQS after the Lambda completed.
I tried getting the Job.Status as follow, but not sure how to query it again if Status is not Complete.
Here is my code:
using (var eClient = new AmazonElasticTranscoderClient())
{
var response = await this.S3Client.GetObjectMetadataAsync(s3Event.Bucket.Name, s3Event.Object.Key);
var videoPresets = new List<Preset>();
var presetRequest = new ListPresetsRequest();
ListPresetsResponse presetResponse;
do
{
presetResponse = await eClient.ListPresetsAsync(presetRequest);
videoPresets.AddRange(presetResponse.Presets);
presetRequest.PageToken = presetResponse.NextPageToken;
} while (presetResponse.NextPageToken != null);
var pipelines = new List<Pipeline>();
var pipelineRequest = new ListPipelinesRequest();
ListPipelinesResponse pipelineResponse;
do
{
pipelineResponse = await eClient.ListPipelinesAsync(pipelineRequest);
pipelines.AddRange(pipelineResponse.Pipelines);
pipelineRequest.PageToken = pipelineResponse.NextPageToken;
} while (pipelineResponse.NextPageToken != null);
var pipeLine = s3Event.Bucket.Name.ToLower().Contains("test") ? pipelines.First(p => p.Name.ToLower().Contains("test")) : pipelines.First(p => !p.Name.ToLower().Contains("test"));
//HLS Stuff for Apple
var usablePreset = videoPresets.Where(p => p.Name.Contains("HLS") && !p.Name.Contains("HLS Video")).ToList();
var hlsPresets = new List<Preset>();
foreach (var preset in usablePreset)
{
var resolution = preset.Name.Replace("System preset: HLS ", "");
switch (resolution)
{
case "2M":
case "1M":
case "400k":
hlsPresets.Add(preset);
break;
}
}
var jobReq = new CreateJobRequest
{
PipelineId = pipeLine.Id,
Input = new JobInput() { Key = fileName, },
OutputKeyPrefix = outPutPrefix
//OutputKeyPrefix = "LambdaTest/" + playlistName + "/"
};
var outputs = new List<CreateJobOutput>();
var playlistHLS = new CreateJobPlaylist() { Name = "HLS_" + playlistName, Format = "HLSv3" };
foreach (var preset in hlsPresets)
{
var resolution = preset.Name.Replace("System preset: HLS ", "").Replace(".", "");
var newName = resolution + "_" + playlistName;
var output = new CreateJobOutput() { Key = newName, PresetId = preset.Id, SegmentDuration = "10" };
outputs.Add(output);
playlistHLS.OutputKeys.Add(newName);
}
jobReq.Playlists.Add(playlistHLS);
jobReq.Outputs = outputs;
//var temp = JsonConvert.SerializeObject(jobReq);
var reply = eClient.CreateJobAsync(jobReq);
var transcodingCompleted = reply.Result.Job.Status == "Complete" ? true : false;
do {
//somehow need to query status again
} while (!transcodingCompleted);
if (transcodingCompleted)
await SendAsync(jobReq.OutputKeyPrefix, pipeLine.OutputBucket);
}
The part I am interested in:
var reply = eClient.CreateJobAsync(jobReq);
var transcodingCompleted = reply.Result.Job.Status == "Complete" ? true : false;
do {
//somehow need to query status again
} while (!transcodingCompleted);
if (transcodingCompleted)
await SendAsync(jobReq.OutputKeyPrefix, pipeLine.OutputBucket);
I'm new to MS BOT Framework.
I changed MS github MultiDialogsBot.sln , I added a HotelsQuery property to init Form's Field value at HotelsDialog.cs,
public class HotelsDialog : IDialog<object>
{
public HotelsQuery _HotelsQuery { get; set; }
public HotelsDialog()
{
_HotelsQuery = new HotelsQuery{
Destination = "Taiwan",
CheckIn = new DateTime(2017,10,29),
Nights = 3
};
}
public async Task StartAsync(IDialogContext context)
{
await context.PostAsync("Welcome to the Hotels finder!");
var hotelsFormDialog = FormDialog.FromForm(this.BuildHotelsForm, FormOptions.PromptInStart);
context.Call(hotelsFormDialog, this.ResumeAfterHotelsFormDialog);
}
public IForm<HotelsQuery> BuildHotelsForm()
{
OnCompletionAsyncDelegate<HotelsQuery> processHotelsSearch = async (context, state) =>
{
await context.PostAsync($"Ok. Searching for Hotels in {state.Destination} from {state.CheckIn.ToString("MM/dd")} to {state.CheckIn.AddDays(state.Nights).ToString("MM/dd")}...");
};
var destField = new FieldReflector<HotelsQuery>(nameof(HotelsQuery.Destination))
.SetActive((state) =>
{
//depend on _HotelsQuery's values
bool isActive = string.IsNullOrWhiteSpace(_HotelsQuery.Destination);
if (!isActive) state.Destination = _HotelsQuery.Destination;
return isActive;
});
var checkInField = new FieldReflector<HotelsQuery>(nameof(HotelsQuery.CheckIn))
.SetActive((state) =>
{
//depend on _HotelsQuery's values
bool isActive = _HotelsQuery.CheckIn == DateTime.MinValue;
if (!isActive) state.CheckIn = _HotelsQuery.CheckIn;
return isActive;
});
var nightsField = new FieldReflector<HotelsQuery>(nameof(HotelsQuery.Nights))
.SetActive((state) =>
{
//depend on _HotelsQuery's values
bool isActive = _HotelsQuery.Nights == 0;
if (!isActive) state.Nights = _HotelsQuery.Nights;
return isActive;
});
var form = new FormBuilder<HotelsQuery>()
.Field(destField)
.Message("Looking for hotels in {Destination}...")
.Field(checkInField)
.Message("Check in {CheckIn}...")
.Field(nightsField)
.Message("Nights : {Nights}...")
.Confirm("Is this your selection?\n {*}", state =>
{
//clean all fields for showing fields in confirmation
_HotelsQuery.Destination = string.Empty;
_HotelsQuery.CheckIn = DateTime.MinValue;
_HotelsQuery.Nights = 0;
return true;
}, new List<string>())
.Message("Thanks you ...")
.OnCompletion(processHotelsSearch)
.Build();
return form;
}
public async Task ResumeAfterHotelsFormDialog(IDialogContext context, IAwaitable<HotelsQuery> result)
{
try
{
var searchQuery = await result;
var hotels = await this.GetHotelsAsync(searchQuery);
await context.PostAsync($"I found in total {hotels.Count()} hotels for your dates:");
var resultMessage = context.MakeMessage();
resultMessage.AttachmentLayout = AttachmentLayoutTypes.Carousel;
resultMessage.Attachments = new List<Attachment>();
foreach (var hotel in hotels)
{
HeroCard heroCard = new HeroCard()
{
Title = hotel.Name,
Subtitle = $"{hotel.Rating} starts. {hotel.NumberOfReviews} reviews. From ${hotel.PriceStarting} per night.",
Images = new List<CardImage>()
{
new CardImage() { Url = hotel.Image }
},
Buttons = new List<CardAction>()
{
new CardAction()
{
Title = "More details",
Type = ActionTypes.OpenUrl,
Value = $"https://www.bing.com/search?q=hotels+in+" + HttpUtility.UrlEncode(hotel.Location)
}
}
};
resultMessage.Attachments.Add(heroCard.ToAttachment());
}
await context.PostAsync(resultMessage);
}
catch (FormCanceledException ex)
{
string reply;
if (ex.InnerException == null)
{
reply = "You have canceled the operation. Quitting from the HotelsDialog";
}
else
{
reply = $"Oops! Something went wrong :( Technical Details: {ex.InnerException.Message}";
}
await context.PostAsync(reply);
}
finally
{
context.Done<object>(null);
}
}
private async Task<IEnumerable<Hotel>> GetHotelsAsync(HotelsQuery searchQuery)
{
var hotels = new List<Hotel>();
// Filling the hotels results manually just for demo purposes
for (int i = 1; i <= 5; i++)
{
var random = new Random(i);
Hotel hotel = new Hotel()
{
Name = $"{searchQuery.Destination} Hotel {i}",
Location = searchQuery.Destination,
Rating = random.Next(1, 5),
NumberOfReviews = random.Next(0, 5000),
PriceStarting = random.Next(80, 450),
Image = $"https://placeholdit.imgix.net/~text?txtsize=35&txt=Hotel+{i}&w=500&h=260"
};
hotels.Add(hotel);
}
hotels.Sort((h1, h2) => h1.PriceStarting.CompareTo(h2.PriceStarting));
return hotels;
}
}
I have trouble after the confirmation shows. When a user answers yes, BOT will ask CheckIn's prompt.
Why does it not go to the OnCompletion event?
Thanks for your help.
You are clearing out the values in the .Confirm
Try something like this:
var form = new FormBuilder<HotelsQuery>()
.Field(destField)
.Message("Looking for hotels in {Destination}...")
.Field(checkInField)
.Message("Check in {CheckIn}...")
.Field(nightsField)
.Message("Nights : {Nights}...")
.Confirm("Is this your selection?\n {*}", state =>
{
if (_HotelsQuery.Destination == string.Empty ||
_HotelsQuery.CheckIn == DateTime.MinValue ||
_HotelsQuery.Nights == 0)
return false;
return true;
}, new List<string>())
.Message("Thanks you ...")
.OnCompletion(processHotelsSearch)
.Build();