Disabling button from async function in Blazor - validation

I have following EditForm model on my page:
<EditForm Model="#projectParameters" OnValidSubmit="#SubmitProject">
<MatButton Raised="true" Type="submit" Disabled="#saveButtonDisabled">#saveButtonName</MatButton>
</EditForm>
Then the following functions:
private async Task SubmitProject()
{
DisableSave();
if (pageType == "Create")
{
await CreateProject();
}
else if (pageType == "Create")
{
await EditProject();
}
}
and
void DisableSave()
{
saveButtonDisabled = true;
saveButtonName = "Saving...";
StateHasChanged();
}
SubmitProject & DisableSave are properly called, but the saveButtonName & disabled never actually show as completed when CreateProject is working. What am I missing?

Flush changes with await Task.Delay(1);:
private async Task SubmitProject()
{
await DisableSave();
...
Then
async Task DisableSave()
{
saveButtonDisabled = true;
saveButtonName = "Saving...";
await Task.Delay(1); //flush changes
StateHasChanged(); // not needed
}

Related

How to cancel skill's Dialog from Virtual Assistant while using MS Bot Framework V4

We are using bot-framework version 4.x
"botbuilder": "4.11.0",
"botbuilder-ai": "4.11.0",
"botbuilder-applicationinsights": "4.11.0",
"botbuilder-azure": "4.11.0",
"botbuilder-dialogs": "4.11.0",
"botbuilder-lg": "4.11.0",
"botbuilder-testing": "4.11.0",
"botframework-config": "4.11.0",
"botframework-connector": "4.11.0"
Case
We need to start a Dialog in Virtual Assistant and cancel any ongoing Skill dialog (If any)
Example
LiveChat - part of Virtual Assistant
CreateIncidentDialog - part of skill
Suppose we are in the middle of CreateIncidentDialog and the user wants to start LiveChat. We are supposed to start LiveChat and cancel current CreateIncidentDialog.
Sample Code
MainDialog.ts in Virtual Assistant
If current Dialog is a part of skill, we are starting a dialog with activity.type as EVENT for skill.
switch (gIntent) {
case 'Escalate': {
// Checking if current Dialog is a part of Skill
if (isSkill) {
const activity: Activity = innerDc.context.activity;
if ((activity.value === null || activity.value === undefined)) {
activity.value = { userState: userProfile };
};
activity.type = ActivityTypes.Event;
activity.name = "liveChat";
const skillDialogArgs: BeginSkillDialogOptions = {
activity: activity as Activity
};
await innerDc.beginDialog(EvaConfig.LUIS_DEFAULT_INTENT, skillDialogArgs);
} else {
await innerDc.cancelAllDialogs();
}
// code for starting LiveChat goes here
// .....
// .....
// .....
}
MainDialog.ts in Skill
If activity.type is EVENT and name is 'liveChat', cancel dialogs.
protected async onContinueDialog(innerDc: DialogContext): Promise<DialogTurnResult> {
try {
let activity = innerDc.context.activity;
if (innerDc.context.activity.type === ActivityTypes.Message) {
// .....
// .....
// .....
} else if (activity.type === ActivityTypes.Event) {
const ev = activity;
if (ev.name !== undefined && ev.name.trim().length > 0) {
switch (ev.name) {
case 'liveChat': {
await innerDc.cancelAllDialogs(true);
return await innerDc.endDialog();
}
}
}
}
return await super.onContinueDialog(innerDc);
} catch (e) {
console.log(`Error onContinueDialog ---> ${e} `);
return await this.hanldeException(innerDc);
}
}
Issue
The above code is not able to cancel the skill's dialog correctly. If we try to start a new dialog after the cancellation of skill dialog, it again sends an activity with activity.type as EVENT to routeStep method of MainDilaog.ts in Skill. Please find the sample code below for the same.
routeStep method of MainDialog.ts in Skill
protected async routeStep(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {
console.log('skill routeStep');
if (activity.type === ActivityTypes.Message && activity.text !== undefined && activity.text.trim().length > 0) {
// .....
// .....
// .....
} else if (activity.type === ActivityTypes.Event) {
const ev = activity;
if (ev.name !== undefined && ev.name.trim().length > 0) {
switch (ev.name) {
case 'SampleAction': {
// .....
// .....
// .....
}
}
} else {
// If we try to start a new dialog, control comes here
await stepContext.context.sendActivity({
type: ActivityTypes.Trace,
text: 'An event with no name was received but not processed.'
});
}
}
} else {
await this.responder.replyWith(stepContext.context, MainResponses.responseIds.dontHavePermissionServiceNow);
await this.complete(stepContext);
}
return await stepContext.next();
}
Step to Reproduce
Step 1. Start a Dialog in Skill
Step 2. End the Dialog in the Skill and start a Dialog in VA
Step 3. Start a new Dialog
Thanks.
Edward

Virtual assistant created using Typscript- running in Bot Framework Emulator is not responding

I am trying to develop virtual assistant using typescript . i have followed this below document
https://microsoft.github.io/botframework-solutions/tutorials/typescript/create-assistant/1_intro/
When i run npm start and test it in Botframework emulator , the bot is not responding any message.
But the Bot is opening with new user greeting adaptive card message
I have tried to edit the adaptive greeting card following this document page
https://microsoft.github.io/botframework-solutions/tutorials/typescript/customize-assistant/2_edit_your_greeting/
but eventhough the bot is not replying any message
`[11:53:22]Emulator listening on http://localhost:49963`
[11:53:22]ngrok listening on https://b2915c2d.ngrok.io
[11:53:22]ngrok traffic inspector:http://127.0.0.1:4040
[11:53:22]Will bypass ngrok for local addresses
[11:53:23]<- messageapplication/vnd.microsoft.card.adaptive
[11:53:23]POST200conversations.replyToActivity
[11:53:23]POST200directline.conversationUpdate
[11:53:23]POST200directline.conversationUpdate
expected and actual results: it should ask what is your name once connected and start conversing
================================================================================mainDialog.ts
import {
BotFrameworkAdapter,
BotTelemetryClient,
RecognizerResult,
StatePropertyAccessor } from 'botbuilder';
import { LuisRecognizer, LuisRecognizerTelemetryClient, QnAMakerResult, QnAMakerTelemetryClient } from 'botbuilder-ai';
import {
DialogContext,
DialogTurnResult,
DialogTurnStatus } from 'botbuilder-dialogs';
import {
ISkillManifest,
SkillContext,
SkillDialog,
SkillRouter } from 'botbuilder-skills';
import {
ICognitiveModelSet,
InterruptionAction,
RouterDialog,
TokenEvents } from 'botbuilder-solutions';
import { TokenStatus } from 'botframework-connector';
import {
Activity,
ActivityTypes } from 'botframework-schema';
import i18next from 'i18next';
import { IOnboardingState } from '../models/onboardingState';
import { CancelResponses } from '../responses/cancelResponses';
import { MainResponses } from '../responses/mainResponses';
import { BotServices } from '../services/botServices';
import { IBotSettings } from '../services/botSettings';
import { CancelDialog } from './cancelDialog';
import { EscalateDialog } from './escalateDialog';
import { OnboardingDialog } from './onboardingDialog';
enum Events {
timeZoneEvent = 'va.timeZone',
locationEvent = 'va.location'
}
export class MainDialog extends RouterDialog {
// Fields
private readonly luisServiceGeneral: string = 'general';
private readonly luisServiceFaq: string = 'faq';
private readonly luisServiceChitchat: string = 'chitchat';
private readonly settings: Partial<IBotSettings>;
private readonly services: BotServices;
private readonly skillContextAccessor: StatePropertyAccessor<SkillContext>;
private readonly onboardingAccessor: StatePropertyAccessor<IOnboardingState>;
private readonly responder: MainResponses = new MainResponses();
// Constructor
public constructor(
settings: Partial<IBotSettings>,
services: BotServices,
onboardingDialog: OnboardingDialog,
escalateDialog: EscalateDialog,
cancelDialog: CancelDialog,
skillDialogs: SkillDialog[],
skillContextAccessor: StatePropertyAccessor<SkillContext>,
onboardingAccessor: StatePropertyAccessor<IOnboardingState>,
telemetryClient: BotTelemetryClient
) {
super(MainDialog.name, telemetryClient);
this.settings = settings;
this.services = services;
this.onboardingAccessor = onboardingAccessor;
this.skillContextAccessor = skillContextAccessor;
this.telemetryClient = telemetryClient;
this.addDialog(onboardingDialog);
this.addDialog(escalateDialog);
this.addDialog(cancelDialog);
skillDialogs.forEach((skillDialog: SkillDialog): void => {
this.addDialog(skillDialog);
});
}
protected async onStart(dc: DialogContext): Promise<void> {
const view: MainResponses = new MainResponses();
const onboardingState: IOnboardingState|undefined = await this.onboardingAccessor.get(dc.context);
if (onboardingState === undefined || onboardingState.name === undefined || onboardingState.name === '') {
await view.replyWith(dc.context, MainResponses.responseIds.newUserGreeting);
} else {
await view.replyWith(dc.context, MainResponses.responseIds.returningUserGreeting);
}
}
protected async route(dc: DialogContext): Promise<void> {
// Get cognitive models for locale
const locale: string = i18next.language.substring(0, 2);
const cognitiveModels: ICognitiveModelSet | undefined = this.services.cognitiveModelSets.get(locale);
if (cognitiveModels === undefined) {
throw new Error('There is no value in cognitiveModels');
}
// Check dispatch result
const dispatchResult: RecognizerResult = await cognitiveModels.dispatchService.recognize(dc.context);
const intent: string = LuisRecognizer.topIntent(dispatchResult);
if (this.settings.skills === undefined) {
throw new Error('There is no skills in settings value');
}
// Identify if the dispatch intent matches any Action within a Skill if so, we pass to the appropriate SkillDialog to hand-off
const identifiedSkill: ISkillManifest | undefined = SkillRouter.isSkill(this.settings.skills, intent);
if (identifiedSkill !== undefined) {
// We have identified a skill so initialize the skill connection with the target skill
const result: DialogTurnResult = await dc.beginDialog(identifiedSkill.id);
if (result.status === DialogTurnStatus.complete) {
await this.complete(dc);
}
} else if (intent === 'l_general') {
// If dispatch result is general luis model
const luisService: LuisRecognizerTelemetryClient | undefined = cognitiveModels.luisServices.get(this.luisServiceGeneral);
if (luisService === undefined) {
throw new Error('The specified LUIS Model could not be found in your Bot Services configuration.');
} else {
const result: RecognizerResult = await luisService.recognize(dc.context);
if (result !== undefined) {
const generalIntent: string = LuisRecognizer.topIntent(result);
// switch on general intents
switch (generalIntent) {
case 'Escalate': {
// start escalate dialog
await dc.beginDialog(EscalateDialog.name);
break;
}
case 'None':
default: {
// No intent was identified, send confused message
await this.responder.replyWith(dc.context, MainResponses.responseIds.confused);
}
}
}
}
} else if (intent === 'q_faq') {
const qnaService: QnAMakerTelemetryClient | undefined = cognitiveModels.qnaServices.get(this.luisServiceFaq);
if (qnaService === undefined) {
throw new Error('The specified QnA Maker Service could not be found in your Bot Services configuration.');
} else {
const answers: QnAMakerResult[] = await qnaService.getAnswers(dc.context);
if (answers !== undefined && answers.length > 0) {
await dc.context.sendActivity(answers[0].answer, answers[0].answer);
} else {
await this.responder.replyWith(dc.context, MainResponses.responseIds.confused);
}
}
} else if (intent === 'q_chitchat') {
const qnaService: QnAMakerTelemetryClient | undefined = cognitiveModels.qnaServices.get(this.luisServiceChitchat);
if (qnaService === undefined) {
throw new Error('The specified QnA Maker Service could not be found in your Bot Services configuration.');
} else {
const answers: QnAMakerResult[] = await qnaService.getAnswers(dc.context);
if (answers !== undefined && answers.length > 0) {
await dc.context.sendActivity(answers[0].answer, answers[0].answer);
} else {
await this.responder.replyWith(dc.context, MainResponses.responseIds.confused);
}
}
} else {
// If dispatch intent does not map to configured models, send 'confused' response.
await this.responder.replyWith(dc.context, MainResponses.responseIds.confused);
}
}
protected async onEvent(dc: DialogContext): Promise<void> {
// Check if there was an action submitted from intro card
if (dc.context.activity.value) {
// tslint:disable-next-line: no-unsafe-any
if (dc.context.activity.value.action === 'startOnboarding') {
await dc.beginDialog(OnboardingDialog.name);
return;
}
}
let forward: boolean = true;
const ev: Activity = dc.context.activity;
if (ev.name !== undefined && ev.name.trim().length > 0) {
switch (ev.name) {
case Events.timeZoneEvent: {
try {
const timezone: string = <string> ev.value;
const tz: string = new Date().toLocaleString(timezone);
const timeZoneObj: {
timezone: string;
} = {
timezone: tz
};
const skillContext: SkillContext = await this.skillContextAccessor.get(dc.context, new SkillContext());
skillContext.setObj(timezone, timeZoneObj);
await this.skillContextAccessor.set(dc.context, skillContext);
} catch {
await dc.context.sendActivity(
{
type: ActivityTypes.Trace,
text: `"Timezone passed could not be mapped to a valid Timezone. Property not set."`
}
);
}
forward = false;
break;
}
case Events.locationEvent: {
const location: string = <string> ev.value;
const locationObj: {
location: string;
} = {
location: location
};
const skillContext: SkillContext = await this.skillContextAccessor.get(dc.context, new SkillContext());
skillContext.setObj(location, locationObj);
await this.skillContextAccessor.set(dc.context, skillContext);
forward = true;
break;
}
case TokenEvents.tokenResponseEventName: {
forward = true;
break;
}
default: {
await dc.context.sendActivity(
{
type: ActivityTypes.Trace,
text: `"Unknown Event ${ ev.name } was received but not processed."`
}
);
forward = false;
}
}
}
if (forward) {
const result: DialogTurnResult = await dc.continueDialog();
if (result.status === DialogTurnStatus.complete) {
await this.complete(dc);
}
}
}
protected async complete(dc: DialogContext, result?: DialogTurnResult): Promise<void> {
// The active dialog's stack ended with a complete status
await this.responder.replyWith(dc.context, MainResponses.responseIds.completed);
}
protected async onInterruptDialog(dc: DialogContext): Promise<InterruptionAction> {
if (dc.context.activity.type === ActivityTypes.Message) {
const locale: string = i18next.language.substring(0, 2);
const cognitiveModels: ICognitiveModelSet | undefined = this.services.cognitiveModelSets.get(locale);
if (cognitiveModels === undefined) {
throw new Error('There is no cognitiveModels value');
}
// check luis intent
const luisService: LuisRecognizerTelemetryClient | undefined = cognitiveModels.luisServices.get(this.luisServiceGeneral);
if (luisService === undefined) {
throw new Error('The general LUIS Model could not be found in your Bot Services configuration.');
} else {
const luisResult: RecognizerResult = await luisService.recognize(dc.context);
const intent: string = LuisRecognizer.topIntent(luisResult);
// Only triggers interruption if confidence level is high
if (luisResult.intents[intent] !== undefined && luisResult.intents[intent].score > 0.5) {
switch (intent) {
case 'Cancel': {
return this.onCancel(dc);
}
case 'Help': {
return this.onHelp(dc);
}
case 'Logout': {
return this.onLogout(dc);
}
default:
}
}
}
}
return InterruptionAction.NoAction;
}
private async onCancel(dc: DialogContext): Promise<InterruptionAction> {
if (dc.activeDialog !== undefined && dc.activeDialog.id !== CancelDialog.name) {
// Don't start restart cancel dialog
await dc.beginDialog(CancelDialog.name);
// Signal that the dialog is waiting on user response
return InterruptionAction.StartedDialog;
}
const view: CancelResponses = new CancelResponses();
await view.replyWith(dc.context, CancelResponses.responseIds.nothingToCancelMessage);
return InterruptionAction.StartedDialog;
}
private async onHelp(dc: DialogContext): Promise<InterruptionAction> {
await this.responder.replyWith(dc.context, MainResponses.responseIds.help);
// Signal the conversation was interrupted and should immediately continue
return InterruptionAction.MessageSentToUser;
}
private async onLogout(dc: DialogContext): Promise<InterruptionAction> {
let adapter: BotFrameworkAdapter;
const supported: boolean = dc.context.adapter instanceof BotFrameworkAdapter;
if (!supported) {
throw new Error('OAuthPrompt.SignOutUser(): not supported by the current adapter');
} else {
adapter = <BotFrameworkAdapter> dc.context.adapter;
}
await dc.cancelAllDialogs();
// Sign out user
// PENDING check adapter.getTokenStatusAsync
const tokens: TokenStatus[] = [];
tokens.forEach(async (token: TokenStatus): Promise<void> => {
if (token.connectionName !== undefined) {
await adapter.signOutUser(dc.context, token.connectionName);
}
});
await dc.context.sendActivity(i18next.t('main.logOut'));
return InterruptionAction.StartedDialog;
}
}
=================================================================================onboardingDialog.ts
import {
BotTelemetryClient,
StatePropertyAccessor,
TurnContext } from 'botbuilder';
import {
ComponentDialog,
DialogTurnResult,
TextPrompt,
WaterfallDialog,
WaterfallStepContext } from 'botbuilder-dialogs';
import { IOnboardingState } from '../models/onboardingState';
import { OnboardingResponses } from '../responses/onboardingResponses';
import { BotServices } from '../services/botServices';
enum DialogIds {
namePrompt = 'namePrompt',
emailPrompt = 'emailPrompt',
locationPrompt = 'locationPrompt'
}
export class OnboardingDialog extends ComponentDialog {
// Fields
private static readonly responder: OnboardingResponses = new OnboardingResponses();
private readonly accessor: StatePropertyAccessor<IOnboardingState>;
private state!: IOnboardingState;
// Constructor
public constructor(botServices: BotServices, accessor: StatePropertyAccessor<IOnboardingState>, telemetryClient: BotTelemetryClient) {
super(OnboardingDialog.name);
this.accessor = accessor;
this.initialDialogId = OnboardingDialog.name;
const onboarding: ((sc: WaterfallStepContext<IOnboardingState>) => Promise<DialogTurnResult>)[] = [
this.askForName.bind(this),
this.finishOnboardingDialog.bind(this)
];
// To capture built-in waterfall dialog telemetry, set the telemetry client
// to the new waterfall dialog and add it to the component dialog
this.telemetryClient = telemetryClient;
this.addDialog(new WaterfallDialog(this.initialDialogId, onboarding));
this.addDialog(new TextPrompt(DialogIds.namePrompt));
}
public async askForName(sc: WaterfallStepContext<IOnboardingState>): Promise<DialogTurnResult> {
this.state = await this.getStateFromAccessor(sc.context);
if (this.state.name !== undefined && this.state.name.trim().length > 0) {
return sc.next(this.state.name);
}
return sc.prompt(DialogIds.namePrompt, {
prompt: await OnboardingDialog.responder.renderTemplate(
sc.context,
OnboardingResponses.responseIds.namePrompt,
<string> sc.context.activity.locale)
});
}
public async finishOnboardingDialog(sc: WaterfallStepContext<IOnboardingState>): Promise<DialogTurnResult> {
this.state = await this.getStateFromAccessor(sc.context);
this.state.name = <string> sc.result;
await this.accessor.set(sc.context, this.state);
await OnboardingDialog.responder.replyWith(
sc.context,
OnboardingResponses.responseIds.haveNameMessage,
{
name: this.state.name
});
return sc.endDialog();
}
private async getStateFromAccessor(context: TurnContext): Promise<IOnboardingState> {
const state: IOnboardingState | undefined = await this.accessor.get(context);
if (state === undefined) {
const newState: IOnboardingState = {
email: '',
location: '',
name: ''
};
await this.accessor.set(context, newState);
return newState;
}
return state;
}
}
=================================================================================dialogBot.ts
import {
ActivityHandler,
BotTelemetryClient,
ConversationState,
EndOfConversationCodes,
Severity,
TurnContext } from 'botbuilder';
import {
Dialog,
DialogContext,
DialogSet,
DialogState } from 'botbuilder-dialogs';
export class DialogBot<T extends Dialog> extends ActivityHandler {
private readonly telemetryClient: BotTelemetryClient;
private readonly solutionName: string = 'samplevirtualassistant';
private readonly rootDialogId: string;
private readonly dialogs: DialogSet;
public constructor(
conversationState: ConversationState,
telemetryClient: BotTelemetryClient,
dialog: T) {
super();
this.rootDialogId = dialog.id;
this.telemetryClient = telemetryClient;
this.dialogs = new DialogSet(conversationState.createProperty<DialogState>(this.solutionName));
this.dialogs.add(dialog);
this.onTurn(this.turn.bind(this));
}
// eslint-disable-next-line #typescript-eslint/no-explicit-any, #typescript-eslint/tslint/config
public async turn(turnContext: TurnContext, next: () => Promise<void>): Promise<any> {
// Client notifying this bot took to long to respond (timed out)
if (turnContext.activity.code === EndOfConversationCodes.BotTimedOut) {
this.telemetryClient.trackTrace({
message: `Timeout in ${ turnContext.activity.channelId } channel: Bot took too long to respond`,
severityLevel: Severity.Information
});
return;
}
const dc: DialogContext = await this.dialogs.createContext(turnContext);
if (dc.activeDialog !== undefined) {
await dc.continueDialog();
} else {
await dc.beginDialog(this.rootDialogId);
}
await next();
}
}

while deny the camera permission in android it wont ask again

first time application asking permission for the camera, if we deny the permission it won't ask again if we allow its working fine ??
var scanPage = new ZXingScannerPage();
var cameraStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);
if (cameraStatus != PermissionStatus.Granted)
{
var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Camera });
cameraStatus = results[Permission.Camera];
if (cameraStatus == PermissionStatus.Granted)
{
// Navigate to our scanner page
await Navigation.PushAsync(scanPage);
scanPage.OnScanResult += (result) =>
{
Device.BeginInvokeOnMainThread(async () =>
{
await Navigation.PopAsync();
txtbarcode.Text = result.Text;
});
};
}
else if (cameraStatus == PermissionStatus.Unknown)
{
await Navigation.PushAsync(scanPage);
scanPage.OnScanResult += (result) =>
{
Device.BeginInvokeOnMainThread(async () =>
{
await Navigation.PopAsync();
txtbarcode.Text = result.Text;
});
};
}
If we deny the camera permission, again its asks while opening camera until we allow the permission.
I wrote a demo about this.
https://github.com/851265601/CheckPermissionDemo
This a GIF of this demo.
Did you check the permission every time when you use the camera function? In this demo, when i click the button ,it will check the permission, then give the result to users, if not give the permission, it will still ask the persmission like the following code.
async void ButtonPermission_OnClicked(object sender, EventArgs e)
{
if (busy)
return;
busy = true;
((Button)sender).IsEnabled = false;
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera);
await DisplayAlert("Pre - Results", status.ToString(), "OK");
if (status != PermissionStatus.Granted)
{
status = await Utils.CheckPermissions(Permission.Camera);
await DisplayAlert("Results", status.ToString(), "OK");
}
busy = false;
((Button)sender).IsEnabled = true;
}
}
When DisplayAlert was appear, it are used MainApplication for different life cycle
namespace CheckPermissionDemo.Droid
{
//You can specify additional application information in this attribute
[Application]
public class MainApplication : Application, Application.IActivityLifecycleCallbacks
{
public MainApplication(IntPtr handle, JniHandleOwnership transer)
: base(handle, transer)
{
}
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
//A great place to initialize Xamarin.Insights and Dependency Services!
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityDestroyed(Activity activity)
{
}
public void OnActivityPaused(Activity activity)
{
}
public void OnActivityResumed(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
public void OnActivityStarted(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityStopped(Activity activity)
{
}
}
}

Can I use HostingEnvironment.QueueBackgroundWorkItem in my bots?

Can I use HostingEnvironment.QueueBackgroundWorkItem like this?
Does these codes cause some error when many people using my bot at the same time?
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (HostingEnvironment.IsHosted)
{
HostingEnvironment.QueueBackgroundWorkItem(c => DoBotTaskAsync(activity));
}
else
{
await Task.Run(() => DoBotTaskAsync(activity));
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
private async Task DoBotTaskAsync(Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new RootDialog());
}
else
{
HandleSystemMessage(activity);
}
}

Why the resume function don't work for context.Forward in bot framework?

I'm new in Bot framework and I face this issue:
I want to move from dialog to another dialog, the callback function is working for context.Call but not for context.Forward?
I try multiple solutions such as put this.CallbackFunctionName but it dosen't work.
Here is my code for call new dialog:
switch (submitType)
{
case "alarm":
context.Call(new AlarmDialog(), ResumeAfterAlarmDialog);
context.Done(true);
return;
case "game":
await context.Forward(new AlarmDialog(), ResumeAfterAlarmDialog, value, CancellationToken.None);
return;
}
And here the method that I call:
private async Task ResumeAfterAlarmDialog(IDialogContext context, IAwaitable<object> result)
{
await context.PostAsync($"You are finish the alarm dialog");
context.Wait(this.MessageReceivedAsync);
}
And this is the error that I have for the context.Forward:
cannot use a method group as an argument to a dynamically dispatched operation.Did you intend to invoke the method?
Here the full implementation of the class:
namespace CardEx.Dialogs
{
[Serializable]
public class RootDialog : IDialog<object>
{
public Task StartAsync(IDialogContext context)
{
context.Wait(MessageReceivedAsync);
return Task.CompletedTask;
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
if (activity.Value != null)
{
// Got an Action Submit
dynamic value = activity.Value;
string submitType = value.Type.ToString();
switch (submitType)
{
case "alarm":
context.Call(new AlarmDialog(), ResumeAfterAlarmDialog);
return;
case "alarm2":
await context.Forward(new AlarmDialog(), ResumeAfterAlarmDialog, value, CancellationToken.None);
return;
}
}
AdaptiveCard aCard = new AdaptiveCard()
{
Body = new List<AdaptiveElement>()
{
new AdaptiveTextBlock()
{
Text = "Welcome!",
Weight = AdaptiveTextWeight.Bolder,
Size = AdaptiveTextSize.Large
},
new AdaptiveTextBlock() { Text = "Please choose one of the following:" },
},
Actions = new List<AdaptiveAction>()
{
new AdaptiveSubmitAction()
{
Title = "Set an alarm",
DataJson = "{ \"Type\": \"alarm\" }"
},
new AdaptiveSubmitAction()
{
Title = "Play a game",
DataJson = "{ \"Type\": \"game\" }"
}
}
};
Attachment attachment = new Attachment()
{
ContentType = AdaptiveCard.ContentType,
Content = aCard
};
var reply = context.MakeMessage();
reply.Attachments.Add(attachment);
await context.PostAsync(reply, CancellationToken.None);
context.Wait(MessageReceivedAsync);
}
private async Task ResumeAfterAlarmDialog(IDialogContext context, IAwaitable<object> result)
{
await context.PostAsync($"You are finish the alarm dialog");
context.Wait(this.MessageReceivedAsync);
}
}
}
Thank you.
cannot use a method group as an argument to a dynamically dispatched operation.Did you intend to invoke the method?
the parameter value used in context.Forward is a dynamic type, which raised this issue.
Please try following code:
await context.Forward(new TestDialog(), ResumeAfterAlarmDialog, (object)value, CancellationToken.None);

Resources