using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Teams.Apps.Activities; using Microsoft.Teams.Apps.Activities.Invokes; using Microsoft.Teams.Apps.Extensions; using Microsoft.Teams.Common; using Microsoft.Teams.Plugins.AspNetCore.Extensions; var builder = WebApplication.CreateBuilder(args); builder.Services.AddOpenApi(); builder.AddTeams(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.MapOpenApi(); } app.UseHttpsRedirection(); var teams = app.UseTeams(); app.AddTab("dialog-form", "Web/dialog-form"); teams.OnMessage(async (context, cancellationToken) => { var activity = context.Activity; context.Log.Info($"[MESSAGE] Received: {SanitizeForLog(activity.Text)}"); context.Log.Info($"[MESSAGE] From: {SanitizeForLog(activity.From?.Name ?? "unknown")}"); var card = CreateDialogLauncherCard(); await context.Send(card, cancellationToken); }); teams.OnTaskFetch((context, cancellationToken) => { var activity = context.Activity; context.Log.Info("[TASK_FETCH] Task fetch request received"); var data = activity.Value?.Data as JsonElement?; if (data == null) { context.Log.Info("[TASK_FETCH] No data found in the activity value"); return Task.FromResult(new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("No data found in the activity value"))); } var dialogType = data.Value.TryGetProperty("dialog_id", out var dialogTypeElement) && dialogTypeElement.ValueKind == JsonValueKind.String ? dialogTypeElement.GetString() : null; context.Log.Info($"[TASK_FETCH] Dialog type: {dialogType}"); var response = dialogType switch { "simple_form" => CreateSimpleFormDialog(), "webpage_dialog" => CreateWebpageDialog(app.Configuration, context.Log), "multi_step_form" => CreateMultiStepFormDialog(), "mixed_example" => CreateMixedExampleDialog(), _ => new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Unknown dialog type")) }; return Task.FromResult(response); }); teams.OnTaskSubmit(async (context, cancellationToken) => { var activity = context.Activity; context.Log.Info("[TASK_SUBMIT] Task submit request received"); var data = activity.Value?.Data as JsonElement?; if (data == null) { context.Log.Info("[TASK_SUBMIT] No data found in the activity value"); return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("No data found in the activity value")); } var submissionType = data.Value.TryGetProperty("submissiondialogtype", out var submissionTypeObj) && submissionTypeObj.ValueKind == JsonValueKind.String ? submissionTypeObj.ToString() : null; context.Log.Info($"[TASK_SUBMIT] Submission type: {submissionType}"); string? GetFormValue(string key) { if (data.Value.TryGetProperty(key, out var val)) { if (val is JsonElement element) return element.GetString(); return val.ToString(); } return null; } switch (submissionType) { case "simple_form": var name = GetFormValue("name") ?? "Unknown"; await context.Send($"Hi {name}, thanks for submitting the form!", cancellationToken); return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Form was submitted")); case "webpage_dialog": var webName = GetFormValue("name") ?? "Unknown"; var email = GetFormValue("email") ?? "No email"; await context.Send($"Hi {webName}, thanks for submitting the form! We got that your email is {email}", cancellationToken); return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Form submitted successfully")); case "webpage_dialog_step_1": var nameStep1 = GetFormValue("name") ?? "Unknown"; var nextStepCardJson = $$""" { "type": "AdaptiveCard", "version": "1.4", "body": [ { "type": "TextBlock", "text": "Email", "size": "Large", "weight": "Bolder" }, { "type": "Input.Text", "id": "email", "label": "Email", "placeholder": "Enter your email", "isRequired": true } ], "actions": [{ "type": "Action.Submit", "title": "Submit", "data": {"submissiondialogtype": "webpage_dialog_step_2", "name": "{{nameStep1}}"} }] } """; var nextStepCard = JsonSerializer.Deserialize(nextStepCardJson) ?? throw new InvalidOperationException("Failed to deserialize next step card"); var nextStepTaskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo { Title = $"Thanks {nameStep1} - Get Email", Card = new Microsoft.Teams.Api.Attachment { ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"), Content = nextStepCard } }; return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(nextStepTaskInfo)); case "webpage_dialog_step_2": var nameStep2 = GetFormValue("name") ?? "Unknown"; var emailStep2 = GetFormValue("email") ?? "No email"; await context.Send($"Hi {nameStep2}, thanks for submitting the form! We got that your email is {emailStep2}", cancellationToken); return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Multi-step form completed successfully")); default: return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Unknown submission type")); } }); app.Run(); static string SanitizeForLog(string? input) { if (input == null) return ""; return input.Replace("\r", "").Replace("\n", ""); } static Microsoft.Teams.Cards.SubmitAction CreateTaskFetchSubmitAction(string title, string dialogId) { return new Microsoft.Teams.Cards.SubmitAction { Title = title, Data = new Microsoft.Teams.Common.Union( new Microsoft.Teams.Cards.OpenDialogData(dialogId)) }; } static Microsoft.Teams.Cards.AdaptiveCard CreateDialogLauncherCard() { var card = new Microsoft.Teams.Cards.AdaptiveCard { Body = new List { new Microsoft.Teams.Cards.TextBlock("Select the examples you want to see!") { Size = Microsoft.Teams.Cards.TextSize.Large, Weight = Microsoft.Teams.Cards.TextWeight.Bolder } }, Actions = new List { CreateTaskFetchSubmitAction("Simple form test", "simple_form"), CreateTaskFetchSubmitAction("Webpage Dialog", "webpage_dialog"), CreateTaskFetchSubmitAction("Multi-step Form", "multi_step_form"), CreateTaskFetchSubmitAction("Mixed Example", "mixed_example") } }; var serializedCard = JsonSerializer.Serialize(card, new JsonSerializerOptions { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }); Console.WriteLine($"[DEBUG] Launcher Card JSON: {serializedCard}"); return card; } static Microsoft.Teams.Api.TaskModules.Response CreateSimpleFormDialog() { var cardJson = """ { "type": "AdaptiveCard", "version": "1.4", "body": [ { "type": "TextBlock", "text": "This is a simple form", "size": "Large", "weight": "Bolder" }, { "type": "Input.Text", "id": "name", "label": "Name", "placeholder": "Enter your name", "isRequired": true } ], "actions": [{"type": "Action.Submit", "title": "Submit", "data": {"submissiondialogtype": "simple_form"}}] } """; var dialogCard = JsonSerializer.Deserialize(cardJson) ?? throw new InvalidOperationException("Failed to deserialize simple form card"); var serializedCard = JsonSerializer.Serialize(dialogCard); Console.WriteLine($"[DEBUG] Simple Form Card JSON: {serializedCard}"); var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo { Title = "Simple Form Dialog", Card = new Microsoft.Teams.Api.Attachment { ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"), Content = dialogCard } }; var continueTask = new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo); Console.WriteLine($"[DEBUG] continueTask.Value is null: {continueTask.Value == null}"); Console.WriteLine($"[DEBUG] continueTask.Value.Title: '{continueTask.Value?.Title}'"); Console.WriteLine($"[DEBUG] continueTask.Value.Card is null: {continueTask.Value?.Card == null}"); var debugOptions = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.Never, WriteIndented = true }; var continueTaskJson = JsonSerializer.Serialize(continueTask, debugOptions); Console.WriteLine($"[DEBUG] ContinueTask JSON (no ignore): {continueTaskJson}"); var response = new Microsoft.Teams.Api.TaskModules.Response(continueTask); var serializedResponse = JsonSerializer.Serialize(response, debugOptions); Console.WriteLine($"[DEBUG] Response JSON (no ignore): {serializedResponse}"); return response; } static Microsoft.Teams.Api.TaskModules.Response CreateWebpageDialog(IConfiguration configuration, Microsoft.Teams.Common.Logging.ILogger log) { var botEndpoint = configuration["BotEndpoint"]; if (string.IsNullOrEmpty(botEndpoint)) { log.Warn("No remote endpoint detected. Using webpages for dialog will not work as expected"); botEndpoint = "http://localhost:3978"; } else { log.Info($"Using BotEndpoint: {botEndpoint}/tabs/dialog-form"); } var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo { Title = "Webpage Dialog", Width = new Union(1000), Height = new Union(800), Url = $"{botEndpoint}/tabs/dialog-form" }; return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo)); } static Microsoft.Teams.Api.TaskModules.Response CreateMultiStepFormDialog() { var cardJson = """ { "type": "AdaptiveCard", "version": "1.4", "body": [ { "type": "TextBlock", "text": "This is a multi-step form", "size": "Large", "weight": "Bolder" }, { "type": "Input.Text", "id": "name", "label": "Name", "placeholder": "Enter your name", "isRequired": true } ], "actions": [{ "type": "Action.Submit", "title": "Submit", "data": {"submissiondialogtype": "webpage_dialog_step_1"} }] } """; var dialogCard = JsonSerializer.Deserialize(cardJson) ?? throw new InvalidOperationException("Failed to deserialize multi-step form card"); var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo { Title = "Multi-step Form Dialog", Card = new Microsoft.Teams.Api.Attachment { ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"), Content = dialogCard } }; return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo)); } static Microsoft.Teams.Api.TaskModules.Response CreateMixedExampleDialog() { var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo { Title = "Mixed Example (C# Sample)", Width = new Union(800), Height = new Union(600), Url = "https://teams.microsoft.com/l/task/example-mixed" }; return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo)); }