-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IStatePropertyAccessor can not be injected through DI in 45.state-management sample #1705
Comments
@mutanttech I'm asking our support team to help you. |
@mdrichardson, please attempt a repro and if found investigate an update for the sample to include the context of multiple dialogs accessing the state and updating. |
@mutanttech Can you provide a code sample of what you're attempting to do? It's a little unclear. |
@mdrichardson, I am just trying to move this code in Startup.cs And Instead of Injecting ConversationState in the dialog I want to inject - IStatePropertyAccessor A very simple repro for you would be to add a new dialog in the example, then the PromptedforUserName property should be accessed in the new dialog. The main point would be how you acquire the StateAccessor in Dialog. Using Below Lines inside a Dialog Step or something else.
|
@mutanttech Understood. I wasn't able to DI from Startup.cs either. I'm working on a mockup sample to show how to create the accessor once in MyBot.cs and pass it to dialogs as an argument. Will let you know when its done |
I actually won't be writing up a sample; our old samples used to do this (although not through DI).
var conversationStateAccessors = _ConversationState.CreateProperty<ConversationStateDataModel>(nameof(ConversationStateDataModel)); Dialogs.Add(new MyDialog(conversationStateAccessors, loggerFactory)); var conversationData = await conversationStateAccessors.GetAsync(stepContext.Context, () => new ConversationStateDataModel()); |
I don't see that we have a current sample that shows how to address this. Would it be worth writing one up? I'm not sure if there's a better way than my suggestion that uses the newer changes to the SDK like using DI for dialogs and using the DialogExtensions ...or am I just missing something? Like @mutanttech, I tried to use DI but encountered the same error. |
@mutanttech I played around with this some more and you actually can use DI. Basic steps:
using Microsoft.Bot.Builder;
using Microsoft.BotBuilderSamples;
namespace Microsoft.BotBuilderSamples
{
public class StateAccessors
{
public IStatePropertyAccessor<ConversationData> ConversationStateAccessors { get; }
public IStatePropertyAccessor<UserProfile> UserStateAccessors { get; }
public StateAccessors(ConversationState conversationState, UserState userState)
{
ConversationStateAccessors = conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
UserStateAccessors = userState.CreateProperty<UserProfile>(nameof(UserProfile));
}
}
}
services.AddSingleton<StateAccessors>();
services.AddSingleton<RootDialog>();
services.AddSingleton<ChildDialog>();
// Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
services.AddTransient<IBot, StateManagementBot<RootDialog>>();
public class MyBot<T> : ActivityHandler
where T : Dialog
[...]
public StateManagementBot(ConversationState conversationState, UserState userState, StateAccessors stateAccessors, T dialog)
{
_conversationState = conversationState;
_userState = userState;
Dialog = dialog;
[...]
await Dialog.RunAsync(turnContext, _conversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
public RootDialog(StateAccessors stateAccessors, ChildDialog childDialog)
[...]
AddDialog(childDialog);
public ChildDialog(StateAccessors stateAccessors) I think some of our older samples used this method, as well. I'm not sure if this is the best method or not. @johnataylor: If you could chime in on this, that would be great. |
@mdrichardson, Thanks for putting up some serious thought here. I stumbled upon few old threads not related to this just yesterday. They were having similar idea. I will wait for @johnataylor comments. |
@johnataylor. please let us know if you need anything else on our end, otherwise I think this is a good point for the support team to hand off to you so we can free @mdrichardson up for other issues. |
We're still looking at this - @johnataylor will comment.. |
There's this thing I fail to understand. If you want to make your RootDialog receive the StateAccessor object you need to call the RootDialog constructor. But where is the constructor called in the samples? I only see the RunAsync method with this new BotState property that's created (that I don't know why it is used for either). I would like to DI the accessors to be able to get the properties in all the dialogs that are called from the RootDialog but I don't know where the RootDialog constructor is called. What am I missing? |
@fcapallera I'm far from an expert in Dependency Injection, but my basic understanding is that Dependency Injection in services.AddSingleton<RootDialog>(); ...it makes services.AddTransient<IBot, StateManagementBot<RootDialog>>(); ...we're passing the public class MyBot<T> : ActivityHandler
where T : Dialog
[...]
public StateManagementBot(ConversationState conversationState, UserState userState, StateAccessors stateAccessors, T dialog) ...because we're setting it as We don't need to pass anything to the constructor of public RootDialog(StateAccessors stateAccessors, ChildDialog childDialog) ...and we've also Dependency Injected those with: services.AddSingleton<StateAccessors>();
services.AddSingleton<ChildDialog>(); |
@johnataylor, are you still looking into this? Could you update this thread? |
Please check out the pattern we have in the samples. For example take a look at Core Bot sample 13. Here you can see the BotState objects injected - it is OK to make these singleton because the calls that are made that need to be scoped to the current request are parameterized with TurnContext. This model is a little different than the basic ASP and has had the implication that all the DI objects are in general singleton. (Its OK to have the Bot transient - its used in the transient Controller.) The pattern we follow is to defer the creation of the accessor until we need it - this seems to hide the inherent noise the most effectively. |
Sample information
Describe the bug
The Conversation State and User State are creating property inside bot and using the value.
In case same property needs to be updated for a separate dialog, then will it require Creating the Property Again.
Dont seem to find a way to achieve this using DI.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
DI should allow injecting the IStatePropertyAccessor and the same Conversation Property should be accessed and updated from different dialogs.
Screenshots
None
Additional context
Update the sample to include the context of multiple dialogs accessing the state and updating.
The text was updated successfully, but these errors were encountered: