Reputation: 355
I'm having an issue with BotAccessors
when I pass it from the main dialog into another dialog. I'm motivated to send accessors up because I need to access and then save state within a UserProfile
from any dialog.
This is how I'm passing it:
await dialogContext.BeginDialogAsync(SiteReviewDialog.id, _accessors, cancellationToken: cancellationToken);
The SiteReviewDialog
runs its first step fine and prompts the user, but it errors before even getting to the second step (breakpoints do not get hit).
I tried removing all references to accessors
in the SiteReviewDialog
, and it seems the only way to fix this is to not pass accessors
at all. If I pass accessors
the error I get is: http://freetexthost.com/sdgdilpyxv
From the error, on line 232 is within my OnTurnAsync
:
var dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);
I tried to follow the code execution in the SiteReviewDialog
from the first AddStep(async (stepContext, cancellationToken)
and it exits out line by line then hits OnTurnAsync
and gets to line 232 then errors. Does anyone have any suggestions?
Upvotes: 1
Views: 160
Reputation: 33379
To explain what's going on first: the parameter you're passing the _accessors
to is reserved for an "options" object for the Dialog. This would be something like settings for how the Dialog should behave. For example, in the case of prompts this is always a PromptOptions
subclass. These options objects get serialized and stored on the stack for the execution lifetime of the dialog, so the reason you're getting an exception passing your _accessors
is because it contains types that are not serializable. So, long story short, you don't want to pass your accessors this way.
Accessors are effectively singletons and what you would want to do is pass them through the constructor chain of your dialogs. So you would take IStatePropertyAccessor<T>
(or an "accessors" class if you've decided to follow that pattern) to your SiteReviewDialog
constructor and then make sure that passes it on to any child dialogs it creates via their constructors. NOTE: dialogs themselves should really be created as singletons as well.
From there it's just a matter of using the accessor when you need it because you always give it a ITurnContext
from which it should be loading its data and the singleton instance uses identifiers specific to that context to ensure the correct data is loaded.
Upvotes: 1