microsoft/teams.net

Public

mirrored fromhttps://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
next/core-claude-agents

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

Samples/Samples.Dialogs/Program.cs

307lines · modecode

1using System.Text.Json;
2using System.Text.Json.Serialization;
3
4using Microsoft.Teams.Apps.Activities;
5using Microsoft.Teams.Apps.Activities.Invokes;
6using Microsoft.Teams.Apps.Extensions;
7using Microsoft.Teams.Common;
8using Microsoft.Teams.Plugins.AspNetCore.DevTools.Extensions;
9using Microsoft.Teams.Plugins.AspNetCore.Extensions;
10
11var builder = WebApplication.CreateBuilder(args);
12builder.Services.AddOpenApi();
13builder.AddTeams().AddTeamsDevTools();
14
15var app = builder.Build();
16
17if (app.Environment.IsDevelopment())
18{
19 app.MapOpenApi();
20}
21
22app.UseHttpsRedirection();
23var teams = app.UseTeams();
24app.AddTab("dialog-form", "Web/dialog-form");
25
26teams.OnMessage(async (context, cancellationToken) =>
27{
28 var activity = context.Activity;
29 context.Log.Info($"[MESSAGE] Received: {SanitizeForLog(activity.Text)}");
30 context.Log.Info($"[MESSAGE] From: {SanitizeForLog(activity.From?.Name ?? "unknown")}");
31
32 var card = CreateDialogLauncherCard();
33 await context.Send(card, cancellationToken);
34});
35
36teams.OnTaskFetch((context, cancellationToken) =>
37{
38 var activity = context.Activity;
39 context.Log.Info("[TASK_FETCH] Task fetch request received");
40
41 var data = activity.Value?.Data as JsonElement?;
42 if (data == null)
43 {
44 context.Log.Info("[TASK_FETCH] No data found in the activity value");
45 return Task.FromResult(new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("No data found in the activity value")));
46 }
47
48 var dialogType = data.Value.TryGetProperty("dialog_id", out var dialogTypeElement) && dialogTypeElement.ValueKind == JsonValueKind.String
49 ? dialogTypeElement.GetString()
50 : null;
51
52 context.Log.Info($"[TASK_FETCH] Dialog type: {dialogType}");
53
54 var response = dialogType switch
55 {
56 "simple_form" => CreateSimpleFormDialog(),
57 "webpage_dialog" => CreateWebpageDialog(app.Configuration, context.Log),
58 "multi_step_form" => CreateMultiStepFormDialog(),
59 "mixed_example" => CreateMixedExampleDialog(),
60 _ => new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Unknown dialog type"))
61 };
62 return Task.FromResult(response);
63});
64
65teams.OnTaskSubmit(async (context, cancellationToken) =>
66{
67 var activity = context.Activity;
68 context.Log.Info("[TASK_SUBMIT] Task submit request received");
69
70 var data = activity.Value?.Data as JsonElement?;
71 if (data == null)
72 {
73 context.Log.Info("[TASK_SUBMIT] No data found in the activity value");
74 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("No data found in the activity value"));
75 }
76
77 var submissionType = data.Value.TryGetProperty("submissiondialogtype", out var submissionTypeObj) && submissionTypeObj.ValueKind == JsonValueKind.String
78 ? submissionTypeObj.ToString()
79 : null;
80
81 context.Log.Info($"[TASK_SUBMIT] Submission type: {submissionType}");
82
83 string? GetFormValue(string key)
84 {
85 if (data.Value.TryGetProperty(key, out var val))
86 {
87 if (val is JsonElement element)
88 return element.GetString();
89 return val.ToString();
90 }
91 return null;
92 }
93
94 switch (submissionType)
95 {
96 case "simple_form":
97 var name = GetFormValue("name") ?? "Unknown";
98 await context.Send($"Hi {name}, thanks for submitting the form!", cancellationToken);
99 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Form was submitted"));
100
101 case "webpage_dialog":
102 var webName = GetFormValue("name") ?? "Unknown";
103 var email = GetFormValue("email") ?? "No email";
104 await context.Send($"Hi {webName}, thanks for submitting the form! We got that your email is {email}", cancellationToken);
105 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Form submitted successfully"));
106
107 case "webpage_dialog_step_1":
108 var nameStep1 = GetFormValue("name") ?? "Unknown";
109 var nextStepCardJson = $$"""
110 {
111 "type": "AdaptiveCard",
112 "version": "1.4",
113 "body": [
114 { "type": "TextBlock", "text": "Email", "size": "Large", "weight": "Bolder" },
115 { "type": "Input.Text", "id": "email", "label": "Email", "placeholder": "Enter your email", "isRequired": true }
116 ],
117 "actions": [{ "type": "Action.Submit", "title": "Submit", "data": {"submissiondialogtype": "webpage_dialog_step_2", "name": "{{nameStep1}}"} }]
118 }
119 """;
120
121 var nextStepCard = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(nextStepCardJson)
122 ?? throw new InvalidOperationException("Failed to deserialize next step card");
123
124 var nextStepTaskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
125 {
126 Title = $"Thanks {nameStep1} - Get Email",
127 Card = new Microsoft.Teams.Api.Attachment
128 {
129 ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"),
130 Content = nextStepCard
131 }
132 };
133 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(nextStepTaskInfo));
134
135 case "webpage_dialog_step_2":
136 var nameStep2 = GetFormValue("name") ?? "Unknown";
137 var emailStep2 = GetFormValue("email") ?? "No email";
138 await context.Send($"Hi {nameStep2}, thanks for submitting the form! We got that your email is {emailStep2}", cancellationToken);
139 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Multi-step form completed successfully"));
140
141 default:
142 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Unknown submission type"));
143 }
144});
145
146app.Run();
147
148static string SanitizeForLog(string? input)
149{
150 if (input == null) return "";
151 return input.Replace("\r", "").Replace("\n", "");
152}
153
154static Microsoft.Teams.Cards.SubmitAction CreateTaskFetchSubmitAction(string title, string dialogId)
155{
156 return new Microsoft.Teams.Cards.SubmitAction
157 {
158 Title = title,
159 Data = new Microsoft.Teams.Common.Union<string, Microsoft.Teams.Cards.SubmitActionData>(
160 new Microsoft.Teams.Cards.OpenDialogData(dialogId))
161 };
162}
163
164static Microsoft.Teams.Cards.AdaptiveCard CreateDialogLauncherCard()
165{
166 var card = new Microsoft.Teams.Cards.AdaptiveCard
167 {
168 Body = new List<Microsoft.Teams.Cards.CardElement>
169 {
170 new Microsoft.Teams.Cards.TextBlock("Select the examples you want to see!")
171 {
172 Size = Microsoft.Teams.Cards.TextSize.Large,
173 Weight = Microsoft.Teams.Cards.TextWeight.Bolder
174 }
175 },
176 Actions = new List<Microsoft.Teams.Cards.Action>
177 {
178 CreateTaskFetchSubmitAction("Simple form test", "simple_form"),
179 CreateTaskFetchSubmitAction("Webpage Dialog", "webpage_dialog"),
180 CreateTaskFetchSubmitAction("Multi-step Form", "multi_step_form"),
181 CreateTaskFetchSubmitAction("Mixed Example", "mixed_example")
182 }
183 };
184
185 var serializedCard = JsonSerializer.Serialize(card, new JsonSerializerOptions { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
186 Console.WriteLine($"[DEBUG] Launcher Card JSON: {serializedCard}");
187
188 return card;
189}
190
191static Microsoft.Teams.Api.TaskModules.Response CreateSimpleFormDialog()
192{
193 var cardJson = """
194 {
195 "type": "AdaptiveCard",
196 "version": "1.4",
197 "body": [
198 { "type": "TextBlock", "text": "This is a simple form", "size": "Large", "weight": "Bolder" },
199 { "type": "Input.Text", "id": "name", "label": "Name", "placeholder": "Enter your name", "isRequired": true }
200 ],
201 "actions": [{"type": "Action.Submit", "title": "Submit", "data": {"submissiondialogtype": "simple_form"}}]
202 }
203 """;
204
205 var dialogCard = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(cardJson)
206 ?? throw new InvalidOperationException("Failed to deserialize simple form card");
207
208 var serializedCard = JsonSerializer.Serialize(dialogCard);
209 Console.WriteLine($"[DEBUG] Simple Form Card JSON: {serializedCard}");
210
211 var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
212 {
213 Title = "Simple Form Dialog",
214 Card = new Microsoft.Teams.Api.Attachment
215 {
216 ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"),
217 Content = dialogCard
218 }
219 };
220
221 var continueTask = new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo);
222
223 Console.WriteLine($"[DEBUG] continueTask.Value is null: {continueTask.Value == null}");
224 Console.WriteLine($"[DEBUG] continueTask.Value.Title: '{continueTask.Value?.Title}'");
225 Console.WriteLine($"[DEBUG] continueTask.Value.Card is null: {continueTask.Value?.Card == null}");
226
227 var debugOptions = new JsonSerializerOptions
228 {
229 DefaultIgnoreCondition = JsonIgnoreCondition.Never,
230 WriteIndented = true
231 };
232 var continueTaskJson = JsonSerializer.Serialize(continueTask, debugOptions);
233 Console.WriteLine($"[DEBUG] ContinueTask JSON (no ignore): {continueTaskJson}");
234
235 var response = new Microsoft.Teams.Api.TaskModules.Response(continueTask);
236 var serializedResponse = JsonSerializer.Serialize(response, debugOptions);
237 Console.WriteLine($"[DEBUG] Response JSON (no ignore): {serializedResponse}");
238
239 return response;
240}
241
242static Microsoft.Teams.Api.TaskModules.Response CreateWebpageDialog(IConfiguration configuration, Microsoft.Teams.Common.Logging.ILogger log)
243{
244 var botEndpoint = configuration["BotEndpoint"];
245 if (string.IsNullOrEmpty(botEndpoint))
246 {
247 log.Warn("No remote endpoint detected. Using webpages for dialog will not work as expected");
248 botEndpoint = "http://localhost:3978";
249 }
250 else
251 {
252 log.Info($"Using BotEndpoint: {botEndpoint}/tabs/dialog-form");
253 }
254
255 var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
256 {
257 Title = "Webpage Dialog",
258 Width = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(1000),
259 Height = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(800),
260 Url = $"{botEndpoint}/tabs/dialog-form"
261 };
262
263 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo));
264}
265
266static Microsoft.Teams.Api.TaskModules.Response CreateMultiStepFormDialog()
267{
268 var cardJson = """
269 {
270 "type": "AdaptiveCard",
271 "version": "1.4",
272 "body": [
273 { "type": "TextBlock", "text": "This is a multi-step form", "size": "Large", "weight": "Bolder" },
274 { "type": "Input.Text", "id": "name", "label": "Name", "placeholder": "Enter your name", "isRequired": true }
275 ],
276 "actions": [{ "type": "Action.Submit", "title": "Submit", "data": {"submissiondialogtype": "webpage_dialog_step_1"} }]
277 }
278 """;
279
280 var dialogCard = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(cardJson)
281 ?? throw new InvalidOperationException("Failed to deserialize multi-step form card");
282
283 var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
284 {
285 Title = "Multi-step Form Dialog",
286 Card = new Microsoft.Teams.Api.Attachment
287 {
288 ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"),
289 Content = dialogCard
290 }
291 };
292
293 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo));
294}
295
296static Microsoft.Teams.Api.TaskModules.Response CreateMixedExampleDialog()
297{
298 var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
299 {
300 Title = "Mixed Example (C# Sample)",
301 Width = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(800),
302 Height = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(600),
303 Url = "https://teams.microsoft.com/l/task/example-mixed"
304 };
305
306 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo));
307}