Alright, I got it to work.
Basically I duplicated all the code for the conversationReferences, because those get stored in the Bot and are used in NotifyController.
Some code, in case somebody else is trying to do the same:
Startup.cs
Create another Singleton.
services.AddSingleton<ConcurrentDictionary<string, UserProfile>>();
In the bot class
I have a variable storing UserProfile
s just like the one for ConversationReference
s
private readonly ConcurrentDictionary<string, ConversationReference> _conversationReferences;
private readonly ConcurrentDictionary<string, UserProfile> _userProfiles;
The constructor now starts like this
public RmindrBot(ConversationState conversationState,
UserState userState,
ConcurrentDictionary<string, ConversationReference> conversationReferences,
ConcurrentDictionary<string, UserProfile> userProfiles)
{
_conversationReferences = conversationReferences;
_userProfiles = userProfiles;
...
(I think this is the most surprising bit for me - didn't think the framework would just magically figure out the new signature.)
A method for adding references:
private void AddConversationReference(Activity activity)
{
var conversationReference = activity.GetConversationReference();
_conversationReferences.AddOrUpdate(
conversationReference.User.Id,
conversationReference,
(key, newValue) => conversationReference);
}
...which is called in OnMessageActivityAsync
:
var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile());
userProfile.ID = turnContext.Activity.From.Id;
AddUserProfile(userProfile);
NotifyController
private readonly ConcurrentDictionary<string, UserProfile> _userProfiles;
public NotifyController(
IBotFrameworkHttpAdapter adapter,
IConfiguration configuration,
ConcurrentDictionary<string, ConversationReference> conversationReferences)
ConcurrentDictionary<string, ConversationReference> conversationReferences,
ConcurrentDictionary<string, UserProfile> userProfiles)
{
_adapter = adapter;
_conversationReferences = conversationReferences;
_userProfiles = userProfiles;
...
And then we can finally use it in the callback method and match the user to their ID:
private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
{
var userProfile = _userProfiles[turnContext.Activity.From.Id];
await turnContext.SendActivityAsync("proactive hello " + userProfile.ID);
}