microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/add-oauth-support-regional-bots

Branches

Tags

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

Clone

HTTPS

Download ZIP

Samples/Samples.Dialogs/Program.cs

385lines · modecode

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