Edit

Share via


Feedback (C#)

User feedback is essential for the improvement of any application. Teams provides specialized UI components to help facilitate the gathering of feedback from users.

Feedback Message

Storage

Once you receive a feedback event, you can choose to store it in some persistent storage. In the example below, we are storing it in an in-memory store.

// This store would ideally be persisted in a database
public static class FeedbackStore
{
    public static readonly Dictionary<string, FeedbackData> StoredFeedbackByMessageId = new();

    public class FeedbackData
    {
        public string IncomingMessage { get; set; } = string.Empty;
        public string OutgoingMessage { get; set; } = string.Empty;
        public int Likes { get; set; }
        public int Dislikes { get; set; }
        public List<string> Feedbacks { get; set; } = new();
    }
}

Including Feedback Buttons

When sending a message that you want feedback in, simply AddFeedback() to the message you are sending.

var sentMessageId = await context.Send(
    result.Content != null
        ? new MessageActivity(result.Content)
            .AddAiGenerated()
            /** Add feedback buttons via this method */
            .AddFeedback()
        : "I did not generate a response."
);

FeedbackStore.StoredFeedbackByMessageId[sentMessageId.Id] = new FeedbackStore.FeedbackData
{
    IncomingMessage = context.Activity.Text,
    OutgoingMessage = result.Content ?? string.Empty,
    Likes = 0,
    Dislikes = 0,
    Feedbacks = new List<string>()
};

Handling the feedback

Once the user decides to like/dislike the message, you can handle the feedback in a received event. Once received, you can choose to include it in your persistent store.

[Microsoft.Teams.Apps.Activities.Invokes.Message.Feedback]
    public Task OnFeedbackReceived([Context] Microsoft.Teams.Api.Activities.Invokes.Messages.SubmitActionActivity activity)
    {
        var reaction = activity.Value?.ActionValue?.GetType().GetProperty("reaction")?.GetValue(activity.Value?.ActionValue)?.ToString();
        var feedbackJson = activity.Value?.ActionValue?.GetType().GetProperty("feedback")?.GetValue(activity.Value?.ActionValue)?.ToString();
        
        if (activity.ReplyToId == null)
        {
            _log.LogWarning("No replyToId found for messageId {ActivityId}", activity.Id);
            return Task.CompletedTask;
        }
        
        var existingFeedback = FeedbackStore.StoredFeedbackByMessageId.GetValueOrDefault(activity.ReplyToId);
        /**
         * feedbackJson looks like:
         * {"feedbackText":"Nice!"}
         */
        if (existingFeedback == null)
        {
            _log.LogWarning("No feedback found for messageId {ActivityId}", activity.Id);
        }
        else
        {
            var updatedFeedback = new FeedbackStore.FeedbackData
            {
                IncomingMessage = existingFeedback.IncomingMessage,
                OutgoingMessage = existingFeedback.OutgoingMessage,
                Likes = existingFeedback.Likes + (reaction == "like" ? 1 : 0),
                Dislikes = existingFeedback.Dislikes + (reaction == "dislike" ? 1 : 0),
                Feedbacks = existingFeedback.Feedbacks.Concat(new[] { feedbackJson ?? string.Empty }).ToList()
            };
            
            FeedbackStore.StoredFeedbackByMessageId[activity.Id] = updatedFeedback;
        }
        
        return Task.CompletedTask;
    }
}