Multiple forms in Microsoft bot framework - c#

I have two forms. I need to access both the forms based on the user Input.
The forms are as follows
internal static IDialog<JObject> BuildTravelForm()
{
travelstatus = 1;
leaveStatus = 0;
return Chain.From(() => FormDialog.FromForm(TravelForm.BuildForm))
.Do(async (context, order) =>
{
try
{
travelstatus = 0;
var completed = await order;
string source = (string)completed.GetValue("Question1");
string destination = (string)completed.GetValue("Question2");
await context.PostAsync("Your travel request is awaiting approval" + " " + "from" + " " + source + " " + "to" + " " + destination);
}
catch (Exception)
{
await context.PostAsync("Thank you");
}
});
}
The second one goes like this
internal static IDialog<JObject> BuildLeaveForm()
{
leaveStatus = 1;
travelstatus = 0;
return Chain.From(() => FormDialog.FromForm(LeaveForm.BuildForm))
.Do(async (context,order)=>
{
leaveStatus = 0;
var completed = await order;
string startDate = (string)completed.GetValue("Question1");
string endDate = (string)completed.GetValue("Question2");
await context.PostAsync("Your leave is applied" + " " + "from" + " " + startDate + " " + "to" + " " + endDate);
});
}
The controller method is as follows
public async Task<Activity> Post([FromBody]Activity activity)
{
try
{
if (activity.Type == ActivityTypes.Message)
{
if (leaveStatus == 1 && travelstatus==0)
{
//nested if to check intents to follow
await Conversation.SendAsync(activity, BuildLeaveForm);
}
else if(travelstatus == 1 && leaveStatus==0)
{
await Conversation.SendAsync(activity, BuildTravelForm);
}
else
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
StateClient stateClient = activity.GetStateClient();
string replyMessage = "";
Luis stluis = await GetEntityFromLUIS(activity.Text);
if (stluis.intents.Count() > 0)
{
Activity reply;
///await Conversation.SendAsync(activity, MakeGreetings);
using (var file = Assembly.GetExecutingAssembly().GetManifestResourceStream("Javis_V2.IntentLibrary.json"))
{
o2 = JObject.Parse(new StreamReader(file).ReadToEnd());
string luisIntent = stluis.intents[0].intent;
if (luisIntent == "LeaveManager")
{
await Conversation.SendAsync(activity, BuildLeaveForm);
}
else if(luisIntent=="TravelManager")
{
await Conversation.SendAsync(activity, BuildTravelForm);
}
else
{
leaveStatus = 0;
travelstatus = 0;
replyMessage = (string)o2.GetValue(luisIntent);
if(replyMessage=="")
{
replyMessage = "Sorry! Not getting you";
}
reply = activity.CreateReply(replyMessage);
await connector.Conversations.ReplyToActivityAsync(reply);
}
}
}
}
}
else
{
HandleSystemMessage(activity);
}
return null;
}
catch (Exception exp)
{
Debug.WriteLine(exp);
return null;
}
}
The problem is that when the first form is completed, and when the second form is triggered through luis intent, the first form pops up. I am looking for something without the use of Dialogs.
Any kind of help is appreciated.
Thanks in advance.

This line is the issue :
if (leaveStatus == 1 && travelstatus==0)
{
//nested if to check intents to follow
await Conversation.SendAsync(activity, BuildLeaveForm);
await connector.Conversations.ReplyToActivityAsync(activity.CreateReply("Thanks"));
}
else if(travelstatus == 1 && leaveStatus==0)
{
await Conversation.SendAsync(activity, BuildTravelForm);
await connector.Conversations.ReplyToActivityAsync(activity.CreateReply("Thanks"));
}
If you see on the above code, the BuildTravelForm or BuildLeaveForm can clearly generate an error and end it without calling the Chain operation Do. If everything executes ok, it will call Do otherwise it will simply skip it. So the best place to reset the status is after the await statement which is ensured to be called after the completion of the dialog.
I will do like this :
if (leaveStatus == 1 && travelstatus==0)
{
//nested if to check intents to follow
await Conversation.SendAsync(activity, BuildLeaveForm);
travelstatus =0; leaveStatus=0;
await connector.Conversations.ReplyToActivityAsync(activity.CreateReply("Thanks"));
}
else if(travelstatus == 1 && leaveStatus==0)
{
await Conversation.SendAsync(activity, BuildTravelForm);
travelstatus =0; leaveStatus=0;
await connector.Conversations.ReplyToActivityAsync(activity.CreateReply("Thanks"));
}
Do check if it works well.

Related

Allow an account access to only one mobile app and browser on website

I'm doing a task that allow an account access to only one mobile app and browser on website(When login on other mobile app or browser on website, this current mobile app or browser website will return to login page when call APi). My idea is creating Dictionary> on AddSingleton Class to save userName and Token.
The request call to API will check whether this account and token are existed on Dictionary> or not. Everything work on local (dev) but when i deploy on server,
Dictionary> clear (dispose) all value saved before automatically .
Anybody know why or have any idea for this issue. Thanks all.
Declare On Startup:
services.AddSingleton<DictionaryAccount, DictionaryAccount>();
Event When Call Api On Startup:
OnTokenValidated = AdditionalValidation
Fuction AdditionalValidation on startup:
public Task AdditionalValidation(TokenValidatedContext context)
{
bool check = true;
var securityToken = context.SecurityToken as JwtSecurityToken;
var claim = securityToken.Claims.SingleOrDefault(t => t.Type == "unique_name");
//1 - web ; 2 - mobile
var platform = securityToken.Claims.SingleOrDefault(t => t.Type == "platform");
try
{
if (TurnOff != 1)
{
if (platform.Value != null)
{
try
{
int type = int.Parse(platform.Value);
string email = securityToken.Claims.SingleOrDefault(t => t.Type == "Email").Value;
if(!string.IsNullOrEmpty(email) && !string.IsNullOrEmpty(securityToken.RawData))
{
using (var serviceScope = _app.ApplicationServices.CreateScope())
{
var _context = serviceScope.ServiceProvider.GetRequiredService<DictionaryAccount>();
check = _context.CheckValidSession(type, email, securityToken.RawData, _logger);
}
}
}
catch (Exception e)
{
_logger.LogError("Fail login startUp " + e.ToString());
context.Response.StatusCode = (int)HttpStatusCode.RequestedRangeNotSatisfiable;
context.Fail("Failed additional validation");
}
}
if (!check)
{
context.Response.StatusCode = (int)HttpStatusCode.RequestedRangeNotSatisfiable;
context.Fail("Failed additional validation");
}
}
}
catch(Exception e)
{
_logger.LogError("Fail login startUp " + e.ToString());
context.Response.StatusCode = (int)HttpStatusCode.RequestedRangeNotSatisfiable;
context.Fail("Failed additional validation");
}
return Task.CompletedTask;
}
Function CheckValidSession:
public bool CheckValidSession(int type, string email, string token, ILogger<AuthController> _logger)
{
string outConnection;
try
{
//1 - web ; 2 - mobile
_logger.LogWarning("login write log email: " +email);
_logger.LogWarning("login write log type: " +type);
_logger.LogWarning("login write log token: " + token);
_logger.LogWarning("login write log list" + string.Join(",", accountListWebsite.Select(x => x.Key).ToArray()));
var item = accountListWebsite.Select(x => x.Value).ToList();
for (int i = 0; i < item.Count; i++)
{
_logger.LogWarning("Token In list: " + string.Join(",", accountListWebsite.Select(x => x.Value).ToList()[0].ToArray()));
}
if (type == 1)
{
if (accountListWebsite[email].TryGetValue(token, out outConnection))
{
_logger.LogWarning("return true");
return true;
}
}
else if(type == 2)
{
if (accountListMobile[email].TryGetValue(token, out outConnection))
{
return true;
}
}
return false;
}
catch(Exception e)
{
_logger.LogWarning("Exception return false " + e.ToString(), e.Message);
bool check = false;
return check;
}
}
Function CreateDictionaryAccountWeb: -> called this function when login success
public bool CreateDictionaryAccountWeb(string email, string token, int count, ILogger<AuthController> logger)
{
_logger = logger;
Count = count;
bool result = true;
try
{
lock (accountListWebsite)
{
HashSet<string> emails;
if (!accountListWebsite.TryGetValue(email, out emails))
{
emails = new HashSet<string>();
accountListWebsite.Add(email, emails);
}
_logger.LogWarning("login write log " + string.Join(",", accountListWebsite.Select(x => x.Key).ToArray()));
lock (accountListWebsite)
{
if (emails != null && emails.Count >= 0) {
if (!emails.Any(x => x.Contains(token))) {
if (emails.Count >= count)
{
var temp = emails.First();
if (temp != token)
emails.Remove(temp);
}
_logger.LogWarning("login token " + token);
emails.Add(token);
}
}
else
{
emails.Add(token);
}
}
}
}
catch (Exception e)
{
_logger.LogError("Fail login" + e.ToString());
result = false;
}
return result;
}
My Log:

Xamarin forms Crash when user exit screen and come back after PUT process

My XF app crash when user try to open any screen after finishing update data in one specific screen, the others works well.
Only I got is :
"08-20 23:41:19.211 W/art (15347): JNI RegisterNativeMethods: attempt to register 0 native methods for android.runtime.JavaProxyThrowable".
No HokeyApp message received in my email and no extra information appears so I can solve the problem, just crash and close the app.
I tried to decrease the amount of requests to local database, tried to follow step by step the execution process so I could get any clue about causes.
Task act = Task.Run(async () => await App.DataService.UpdateItemAsync(CP, ToServer, "Contact_Party/EditContact_Party/" + CP.Id));
await act.ContinueWith(async (antecedent) =>
{
foreach (var sam in specialty)
{
if (CP.Id > 0)
{
sam.Cntct_SEQ = CP.Id;
}
else
{
sam.Tmp_Cntct_SEQ = CP.Cntct_SEQ;
}
if (sam.Id == 0)
{
if (sam.Cntct_Spec_SEQ == 0)
await App.DataService.CreateItemAsync(sam, ToServer, "Contact_Specialty/AddContact_Specialty");
else
{
await App.DataService.UpdateItemAsync(sam, ToServer, "Contact_Specialty/EditContact_Specialty/" + sam.Id);
}
}
else
{
await App.DataService.UpdateItemAsync(sam, ToServer, "Contact_Specialty/EditContact_Specialty/" + sam.Id);
}
}
}, TaskContinuationOptions.None);
Below is the other code or the final step in Update data...
public async Task<T> UpdateItemAsync<T>(T item, bool ToServer, string url) where T : BaseModel, new()
{
try
{
HttpResponseMessage hrm = new HttpResponseMessage();
if (!CrossConnectivity.Current.IsConnected)
ToServer = false;
if (ToServer)
{
RestURL = PrimaryRestURL;
RestURL += url;
var content = JsonConvert.SerializeObject(item);
content = content.Replace("null", " ");
try
{
hrm = await _client.PutAsync(RestURL, new StringContent(content, System.Text.Encoding.UTF8, "application/json"));
RestURL = PrimaryRestURL;
}
catch (Exception hre)
{
RestURL = PrimaryRestURL;
ContentPage page = new ContentPage();
string inner = "", source = "", trace = "", data = "";
if (hre.InnerException != null)
inner = hre.InnerException.Message;
data = hre.Data.ToString();
source = hre.Source;
trace = hre.StackTrace;
string msg = "RestURL: " + RestURL + "\n\n Data: " + data + "\n\n Message: " + hre.Message + "\n\n Source: " + source + "\n\n Trace: " + trace + "\n\n Inner Message: " + inner;
await page.DisplayAlert("Error", msg, "Ok");
}
if (hrm.StatusCode == System.Net.HttpStatusCode.OK || hrm.StatusCode == System.Net.HttpStatusCode.NoContent)
{
item.Updated = true;
await database.UpdateAsync(item);
DependencyService.Get<IMessage>().LongAlert("Completed");
}
else
{
item.Changed = true;
await database.UpdateAsync(item);
DependencyService.Get<IMessage>().LongAlert("Error connection to server");
}
}
else
{
item.Changed = true;
await database.UpdateAsync(item);
DependencyService.Get<IMessage>().LongAlert("Completed");
}
}
catch (Exception xc)
{
ContentPage page = new ContentPage();
string inner = "", source = "", trace = "", data = "";
if (xc.InnerException != null)
inner = xc.InnerException.Message;
data = xc.Data.ToString();
source = xc.Source;
trace = xc.StackTrace;
string msg = "RestURL: " + RestURL + "\n\n Data: " + data + "\n\n Message: " + xc.Message + "\n\n Source: " + source + "\n\n Trace: " + trace + "\n\n Inner Message: " + inner;
await page.DisplayAlert("Error", msg, "Ok");
}
return item;
}
Finally, I solved the issue, it was because I wanted to make the process of updating in a task so being continues with sub updates, after implementeing each update process alone it work ... the code that produced the issue is:
Task act = Task.Run(async () => await App.DataService.UpdateItemAsync(CP, ToServer, "Contact_Party/EditContact_Party/" + CP.Id));
await act.ContinueWith(async (antecedent) =>
{
foreach (var sam in specialty)
{
if (CP.Id > 0)
{
sam.Cntct_SEQ = CP.Id;
}
else
{
sam.Tmp_Cntct_SEQ = CP.Cntct_SEQ;
}
if (sam.Id == 0)
{
if (sam.Cntct_Spec_SEQ == 0)
await App.DataService.CreateItemAsync(sam, ToServer, "Contact_Specialty/AddContact_Specialty");
else
{
await App.DataService.UpdateItemAsync(sam, ToServer, "Contact_Specialty/EditContact_Specialty/" + sam.Id);
}
}
else
{
await App.DataService.UpdateItemAsync(sam, ToServer, "Contact_Specialty/EditContact_Specialty/" + sam.Id);
}
}
}, TaskContinuationOptions.None);

Execute Task.Run() in ASP.NET ActionResult without waiting for result

Below is the function where I am trying to execute a function in the background and then carry on without waiting for a result from it.
When debugging the task itself is executed but the actual function within it does not. The rest of the code then carries on like normal.
What could be the issue as there is no error produced after that to indicate otherwise?
This is on a page load.
public ActionResult ExceptionReport(int? id)
{
var ExceptionList = db.Invoices.Where(m => m.ExceptionFlag == true && m.GlobalInvoiceID == id);
if (ExceptionList.Count() == 0)
{
globalInvoice.Status = "Exception Verification";
db.Entry(globalInvoice).State = EntityState.Modified;
db.SaveChanges();
Task.Run(() => ExceptionFinalTests(globalInvoice)); //Function To run in the background
TempData["warning"] = "Verifying all exceptions fixed. A notification will be sent when the verifications are complete.";
return RedirectToAction("Index", "GlobalInvoices");
}
return View(ExceptionList);
}
private void ExceptionFinalTests(GlobalInvoice globalInvoice)
{
RunTests(globalInvoice, true);
decimal TotalPaymentAmount = db.Invoices.Where(m => m.GlobalInvoiceID == globalInvoice.Id).Sum(m => m.Invoice_Amount) ?? 0;
}
GlobalInvoicesController globalInvoicesController = new GlobalInvoicesController();
var ApproverList = globalInvoicesController.GetUserEmailsInRole(globalInvoice, "Reviewer");
globalInvoicesController.Dispose();
var exceptionExistCompulsoryTest = db.Invoices.Where(m => m.ExceptionFlag == true && m.GlobalInvoiceID == globalInvoice.Id);
if (exceptionExistCompulsoryTest.Count() > 0)
{
try
{
string baseUrl = ConfigurationManager.AppSettings["site"];
EmailExtension emailExtension = new EmailExtension();
foreach (var approver in ApproverList)
{
string approvalLink = baseUrl + "/Invoices/ExceptionReport/" + globalInvoice.Id;
StringBuilder mailbody = new StringBuilder();
mailbody.AppendFormat("Hi<br/>");
mailbody.AppendFormat("There are " + exceptionExistCompulsoryTest.Count() + " exceptions for invoice #" + globalInvoice.Id + "that need attention before proceeding. - <a href='" + approvalLink + "'>Click Here</a> <br/><br/>");
mailbody.AppendFormat("Exception Count: {0}<br/>", exceptionExistCompulsoryTest.Count());
mailbody.AppendFormat("Invoice Amount: {0}<br/>", TotalPaymentAmount.ToString("C"));
mailbody.AppendFormat("Reviewed By: {0} <br/>", "");
mailbody.AppendFormat("Approved By: {0} <br/>", "");
EmailVM emailVM = new EmailVM()
{
Subject = "Invoice - #" + globalInvoice.Id,
EmailAddress = approver,
Message = mailbody.ToString()
};
emailExtension.SendEmail(emailVM);
}
}
catch (Exception ex)
{
LogWriter.WriteLog(ex.Message);
LogWriter.WriteLog(ex.StackTrace);
}
}
}
private void RunTests(GlobalInvoice globalInvoice, bool retestFlag = false)
{
List<Invoice> invoices;
var vendorTests = globalInvoice.Vendor.VendorTests;
string[] testsToRun = vendorTests.Split(',');
if (retestFlag == true)
{
if (globalInvoice.Vendor.VendorHasHierarchy == true)
{
testsToRun = new string[] { "Account Number", "Hierarchy" };
}
else
{
testsToRun = new string[] { "Account Number" };
}
}
using (var context = new MyContext())
{
invoices = context.Invoices.Where(m => m.GlobalInvoiceID == globalInvoiceToTestID).ToList();
}
foreach (var test in testsToRun)
{
if (test == "Account Number")
{
LogWriter.WriteLog("Starting Account Number Check : Invoice Batch ID - " + globalInvoice.Id);
AccountNumberCheck(invoices, globalInvoice.VendorID);
LogWriter.WriteLog("Account Number Check Complete : Invoice Batch ID - " + globalInvoice.Id);
}
if (test == "Hierarchy")
{
LogWriter.WriteLog("Starting Hierarchy Check : Invoice Batch ID - " + globalInvoice.Id);
BillingHierarchyCheck(invoices);
LogWriter.WriteLog("Hierarchy Check Complete : Invoice Batch ID - " + globalInvoice.Id);
}
}
}

How can i use Inlinekeyboard in webhook method telegram Bot ? c#

I use c# and telegram.bot library.
When i use getUpdates method everything is ok but in webhook method not ok
in GetUpdates method when i write below code in OnCallbackQuery event everything is ok and bot get answers
private static void Bot_OnCallbackQuery(object sender,
Telegram.Bot.Args.CallbackQueryEventArgs e)
{
long b;
if (e.CallbackQuery != null && long.TryParse(e.CallbackQuery.Data, out b))//show Post
{
//PostContent
var post = dba.BlogPosts.Find(Convert.ToInt64(e.CallbackQuery.Data));
if (post != null)
{
string removedTag = Regex.Replace(post.Content, "<br>", Environment.NewLine);
removedTag = Regex.Replace(removedTag, "<.*?>", String.Empty);
// HtmlTagsRemover.CleanTagsExceptPbr(postContent.Content);
Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, removedTag, parseMode: ParseMode.Html);
}
}
else
{
if (e.CallbackQuery != null && e.CallbackQuery.Data.Contains("more_")) // user clicked on MoreButton
{
Post p = new Post();
var posts = p.BlogPostPaging(PostsList, 5, moreCount);
#region InlineKeyboard
var inlineButtons = posts.Select(title => new[]
{InlineKeyboardButton.WithCallbackData(title.Subject, title.BlogPostId.ToString())})
.ToArray();
InlinePostsKeyboard = new InlineKeyboardMarkup(inlineButtons);
#endregion
if (posts.Count>0)
{
Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, "page: " + moreCount, replyMarkup: InlinePostsKeyboard);// ShowMoreButton
Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, "see More...", replyMarkup: InlineBtnMoreKeyboard);// MoreButton
moreCount++;
}
else
{
Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id,
"End");
}
}
but when i want use above code in webhook method , bot does not work And no response is received from bot
#region QueryCallBack
var e = update;
long b;
if (e.CallbackQuery != null && long.TryParse(e.CallbackQuery.Data, out b))//show post
{
await Bot.AnswerCallbackQueryAsync(e.CallbackQuery.Id, "test1");
//post Content
var post = _blogPost.EfGetOneBlogPost(b);
if (post != null)
{
var removedTag = Regex.Replace(post.Content, "<br>", Environment.NewLine);
removedTag = Regex.Replace(removedTag, "<.*?>", string.Empty);
await Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, removedTag, parseMode: ParseMode.Html);
return Ok();
}
}
else
{
if (e.CallbackQuery != null && e.CallbackQuery.Data.Contains("more_")) // user clicked on MoreButton
{
TelegramPostsPaging p = new TelegramPostsPaging();
var posts = p.BlogPostPaging(PostsList, 5, moreCount);
#region InlineKeyboard
var inlineButtons = posts.Select(title => new[]{InlineKeyboardButton.WithCallbackData(title.Subject, title.BlogPostId.ToString())}).ToArray();
InlinePostsKeyboard = new InlineKeyboardMarkup(inlineButtons);
#endregion
if (posts.Count > 0)
{
await Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, "page: " + moreCount, replyMarkup: InlinePostsKeyboard);// show SeeMore Button
await Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, "see More...", replyMarkup: InlineBtnMoreKeyboard);// show SeeMore Button
moreCount++;
return Ok();
}
else
{
await Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id,
"End");
return Ok();
}
}
}
I don't know how to use CallBackQuery in webhook; but in update method i use in OnCallbackQuery event.
How are you getting the update in the webhook? Because the built-in serializer of ASP.NET does not correctly parse the update, you should instead take it as a string and then deserialize it using Newtonsoft.Json

error using IAsyncEnumerable<IReadOnlyCollection<IUser>> in discord bot

i have this code line
if (channel.GetUsersAsync().Contains(Program.kami.CurrentUser as IGuildUser))
do something;
it writes an exception which says IAsyncEnumerable> doesnt contain the definition of contains
and i dont know what to do
[Command("join", RunMode=RunMode.Async), Summary("joins voice channel")]
public async Task joinvoice([Remainder, Summary("The text to echo")] string searchP="")
{
IVoiceChannel channel = (CommandHandler.Last as IGuildUser).VoiceChannel;
if (channel == null)
{
await ReplyAsync("u have to be in a channel first");
return;
}
string choice = "";
VideoSearch SearchRisolts = new VideoSearch();
if (searchP != "")
{
if (searchP.Contains("https://"))
choice = searchP;
else
{
List<VideoInformation> video = SearchRisolts.SearchQuery(searchP, 1);
await ReplyAsync("* " + video[0].Title + "\n\n* " + video[1].Title + "\n\n* " + video[2].Title);
//choice = video[int.Parse() - 1].Url;
}
this.Context.Channel.GetMessagesAsync(1).First();
}
IAsyncEnumerable<IReadOnlyCollection<IUser>> x = channel.GetUsersAsync();
if ((await channel.GetUsersAsync()).Contains(Program.kami.CurrentUser as IGuildUser))
var audioClient = await channel.ConnectAsync();
await SendAsync(audioClient,choice);
}
You need to await a GetUserAsync operations
(await channel.GetUsersAsync()).Contains(....)
Be sure that your method is async.

Categories