microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
aamirj/minimal

Branches

Tags

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

Clone

HTTPS

Download ZIP

Samples/Samples.Dialogs/Program.cs

543lines · modecode

1using System.Text.Json;
2
3using Microsoft.Teams.Api.Activities.Invokes;
4using Microsoft.Teams.Cards;
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.WebHost.UseUrls("http://localhost:3978");
22 builder.Services.AddOpenApi();
23
24 // Use environment variable to choose between Controller and Minimal API approaches
25 var useMinimalApi = builder.Configuration.GetValue<bool>("USE_MINIMAL_API", false);
26 if (useMinimalApi)
27 {
28 Console.WriteLine("Using Minimal API approach");
29 }
30 else
31 {
32 Console.WriteLine("Using Controller approach");
33 }
34
35 if (!useMinimalApi)
36 {
37 builder.Services.AddTransient<Controller>();
38 }
39
40 builder.AddTeams().AddTeamsDevTools();
41
42 var app = builder.Build();
43
44 if (app.Environment.IsDevelopment())
45 {
46 app.MapOpenApi();
47 }
48
49 app.UseHttpsRedirection();
50 var teams = app.UseTeams();
51
52 if (useMinimalApi)
53 {
54 RegisterMinimalApiHandlers(teams, app.Configuration);
55 }
56
57 app.AddTab("dialog-form", "Web/dialog-form");
58 app.Run();
59 }
60
61 private static void RegisterMinimalApiHandlers(Microsoft.Teams.Apps.App teams, IConfiguration configuration)
62 {
63 // Handle messages using minimal API
64 teams.OnMessage(async context =>
65 {
66 var activity = context.Activity;
67
68 context.Log.Info($"[MESSAGE] Received: {SanitizeForLog(activity.Text)}");
69 context.Log.Info($"[MESSAGE] From: {SanitizeForLog(activity.From?.Name ?? "unknown")}");
70
71 // Create the launcher adaptive card
72 var card = CreateDialogLauncherCard();
73 await context.Send(card);
74 });
75
76 // Handle task fetch using minimal API
77 teams.OnTaskFetch(async context =>
78 {
79 var activity = context.Activity;
80
81 context.Log.Info("[TASK_FETCH] Task fetch request received");
82
83 var data = activity.Value?.Data as JsonElement?;
84 if (data == null)
85 {
86 context.Log.Info("[TASK_FETCH] No data found in the activity value");
87 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("No data found in the activity value"));
88 }
89
90 var dialogType = data.Value.TryGetProperty("opendialogtype", out var dialogTypeElement) && dialogTypeElement.ValueKind == JsonValueKind.String
91 ? dialogTypeElement.GetString()
92 : null;
93
94 context.Log.Info($"[TASK_FETCH] Dialog type: {dialogType}");
95
96 return dialogType switch
97 {
98 "simple_form" => CreateSimpleFormDialog(),
99 "webpage_dialog" => CreateWebpageDialog(configuration, context.Log),
100 "multi_step_form" => CreateMultiStepFormDialog(),
101 "mixed_example" => CreateMixedExampleDialog(),
102 _ => new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Unknown dialog type"))
103 };
104 });
105
106 // Handle task submit using minimal API
107 teams.OnTaskSubmit(async context =>
108 {
109 var activity = context.Activity;
110
111 context.Log.Info("[TASK_SUBMIT] Task submit request received");
112
113 var data = activity.Value?.Data as JsonElement?;
114 if (data == null)
115 {
116 context.Log.Info("[TASK_SUBMIT] No data found in the activity value");
117 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("No data found in the activity value"));
118 }
119
120 var submissionType = data.Value.TryGetProperty("submissiondialogtype", out var submissionTypeObj) && submissionTypeObj.ValueKind == JsonValueKind.String
121 ? submissionTypeObj.ToString()
122 : null;
123
124 context.Log.Info($"[TASK_SUBMIT] Submission type: {submissionType}");
125
126 string? GetFormValue(string key)
127 {
128 if (data.Value.TryGetProperty(key, out var val))
129 {
130 if (val is System.Text.Json.JsonElement element)
131 return element.GetString();
132 return val.ToString();
133 }
134 return null;
135 }
136
137 switch (submissionType)
138 {
139 case "simple_form":
140 var name = GetFormValue("name") ?? "Unknown";
141 await context.Send($"Hi {name}, thanks for submitting the form!");
142 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Form was submitted"));
143
144 case "webpage_dialog":
145 var webName = GetFormValue("name") ?? "Unknown";
146 var email = GetFormValue("email") ?? "No email";
147 await context.Send($"Hi {webName}, thanks for submitting the form! We got that your email is {email}");
148 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Form submitted successfully"));
149
150 case "webpage_dialog_step_1":
151 var nameStep1 = GetFormValue("name") ?? "Unknown";
152 var nextStepCardJson = $$"""
153 {
154 "type": "AdaptiveCard",
155 "version": "1.4",
156 "body": [
157 {
158 "type": "TextBlock",
159 "text": "Email",
160 "size": "Large",
161 "weight": "Bolder"
162 },
163 {
164 "type": "Input.Text",
165 "id": "email",
166 "label": "Email",
167 "placeholder": "Enter your email",
168 "isRequired": true
169 }
170 ],
171 "actions": [
172 {
173 "type": "Action.Submit",
174 "title": "Submit",
175 "data": {"submissiondialogtype": "webpage_dialog_step_2", "name": "{{nameStep1}}"}
176 }
177 ]
178 }
179 """;
180
181 var nextStepCard = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(nextStepCardJson)
182 ?? throw new InvalidOperationException("Failed to deserialize next step card");
183
184 var nextStepTaskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
185 {
186 Title = $"Thanks {nameStep1} - Get Email",
187 Card = new Microsoft.Teams.Api.Attachment
188 {
189 ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"),
190 Content = nextStepCard
191 }
192 };
193
194 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(nextStepTaskInfo));
195
196 case "webpage_dialog_step_2":
197 var nameStep2 = GetFormValue("name") ?? "Unknown";
198 var emailStep2 = GetFormValue("email") ?? "No email";
199 await context.Send($"Hi {nameStep2}, thanks for submitting the form! We got that your email is {emailStep2}");
200 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Multi-step form completed successfully"));
201
202 default:
203 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Unknown submission type"));
204 }
205 });
206 }
207
208 // Helper method to sanitize user input for logging
209 private static string SanitizeForLog(string? input)
210 {
211 if (input == null) return "";
212 return input.Replace("\r", "").Replace("\n", "");
213 }
214
215 private static Microsoft.Teams.Cards.AdaptiveCard CreateDialogLauncherCard()
216 {
217 var card = new Microsoft.Teams.Cards.AdaptiveCard
218 {
219 Body = new List<Microsoft.Teams.Cards.CardElement>
220 {
221 new Microsoft.Teams.Cards.TextBlock("Select the examples you want to see!")
222 {
223 Size = Microsoft.Teams.Cards.TextSize.Large,
224 Weight = Microsoft.Teams.Cards.TextWeight.Bolder
225 }
226 },
227 Actions = new List<Microsoft.Teams.Cards.Action>
228 {
229 new Microsoft.Teams.Cards.TaskFetchAction(
230Microsoft.Teams.Cards.TaskFetchAction.FromObject(new { opendialogtype = "simple_form" }))
231{
232Title = "Simple form test"
233},
234new Microsoft.Teams.Cards.TaskFetchAction(
235Microsoft.Teams.Cards.TaskFetchAction.FromObject(new { opendialogtype = "webpage_dialog" }))
236{
237Title = "Webpage Dialog"
238},
239new Microsoft.Teams.Cards.TaskFetchAction(
240Microsoft.Teams.Cards.TaskFetchAction.FromObject(new { opendialogtype = "multi_step_form" }))
241{
242Title = "Multi-step Form"
243},
244new Microsoft.Teams.Cards.TaskFetchAction(
245Microsoft.Teams.Cards.TaskFetchAction.FromObject(new { opendialogtype = "mixed_example" }))
246{
247Title = "Mixed Example"
248}
249 }
250 };
251
252 return card;
253 }
254
255 private static Microsoft.Teams.Api.TaskModules.Response CreateSimpleFormDialog()
256 {
257 // Create card from JSON similar to Python's model_validate approach
258 var cardJson = """
259 {
260 "type": "AdaptiveCard",
261 "version": "1.4",
262 "body": [
263 {
264 "type": "TextBlock",
265 "text": "This is a simple form",
266 "size": "Large",
267 "weight": "Bolder"
268 },
269 {
270 "type": "Input.Text",
271 "id": "name",
272 "label": "Name",
273 "placeholder": "Enter your name",
274 "isRequired": true
275 }
276 ],
277 "actions": [
278 {"type": "Action.Submit", "title": "Submit", "data": {"submissiondialogtype": "simple_form"}}
279 ]
280 }
281 """;
282
283 var dialogCard = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(cardJson)
284 ?? throw new InvalidOperationException("Failed to deserialize simple form card");
285
286 var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
287 {
288 Title = "Simple Form Dialog",
289 Card = new Microsoft.Teams.Api.Attachment
290 {
291 ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"),
292 Content = dialogCard
293 }
294 };
295
296 var continueTask = new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo);
297
298 // Debug the ContinueTask before wrapping in Response
299 Console.WriteLine($"[DEBUG] continueTask.Value is null: {continueTask.Value == null}");
300 Console.WriteLine($"[DEBUG] continueTask.Value.Title: '{continueTask.Value?.Title}'");
301 Console.WriteLine($"[DEBUG] continueTask.Value.Card is null: {continueTask.Value?.Card == null}");
302
303 var serializedCard = JsonSerializer.Serialize(dialogCard);
304 Console.WriteLine($"[DEBUG] Simple Form Card JSON: {serializedCard}");
305
306 var response = new Microsoft.Teams.Api.TaskModules.Response(continueTask);
307
308 return response;
309 }
310
311 private static Microsoft.Teams.Api.TaskModules.Response CreateWebpageDialog(IConfiguration configuration, Microsoft.Teams.Common.Logging.ILogger log)
312 {
313 var botEndpoint = configuration["BotEndpoint"];
314 if (string.IsNullOrEmpty(botEndpoint))
315 {
316 log.Warn("No remote endpoint detected. Using webpages for dialog will not work as expected");
317 botEndpoint = "http://localhost:3978"; // Fallback for local development
318 }
319 else
320 {
321 log.Info($"Using BotEndpoint: {botEndpoint}/tabs/dialog-form");
322 }
323
324 var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
325 {
326 Title = "Webpage Dialog",
327 Width = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(1000),
328 Height = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(800),
329 Url = $"{botEndpoint}/tabs/dialog-form"
330 };
331
332 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo));
333 }
334
335 private static Microsoft.Teams.Api.TaskModules.Response CreateMultiStepFormDialog()
336 {
337 var cardJson = """
338 {
339 "type": "AdaptiveCard",
340 "version": "1.4",
341 "body": [
342 {
343 "type": "TextBlock",
344 "text": "This is a multi-step form",
345 "size": "Large",
346 "weight": "Bolder"
347 },
348 {
349 "type": "Input.Text",
350 "id": "name",
351 "label": "Name",
352 "placeholder": "Enter your name",
353 "isRequired": true
354 }
355 ],
356 "actions": [
357 {
358 "type": "Action.Submit",
359 "title": "Submit",
360 "data": {"submissiondialogtype": "webpage_dialog_step_1"}
361 }
362 ]
363 }
364 """;
365
366 var dialogCard = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(cardJson)
367 ?? throw new InvalidOperationException("Failed to deserialize multi-step form card");
368
369 var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
370 {
371 Title = "Multi-step Form Dialog",
372 Card = new Microsoft.Teams.Api.Attachment
373 {
374 ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"),
375 Content = dialogCard
376 }
377 };
378
379 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo));
380 }
381
382 private static Microsoft.Teams.Api.TaskModules.Response CreateMixedExampleDialog()
383 {
384 var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
385 {
386 Title = "Mixed Example (C# Sample)",
387 Width = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(800),
388 Height = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(600),
389 Url = "https://teams.microsoft.com/l/task/example-mixed"
390 };
391
392 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo));
393 }
394
395 [TeamsController]
396 public class Controller
397 {
398 private readonly IConfiguration _configuration;
399
400 public Controller(IConfiguration configuration)
401 {
402 _configuration = configuration;
403 }
404
405 [Message]
406 public async Task OnMessage([Context] Microsoft.Teams.Api.Activities.MessageActivity activity, [Context] IContext.Client client, [Context] Microsoft.Teams.Common.Logging.ILogger log)
407 {
408 log.Info($"[MESSAGE] Received: {SanitizeForLog(activity.Text)}");
409 log.Info($"[MESSAGE] From: {SanitizeForLog(activity.From?.Name ?? "unknown")}");
410
411 // Create the launcher adaptive card
412 var card = CreateDialogLauncherCard();
413 await client.Send(card);
414 }
415
416 [TaskFetch]
417 public Microsoft.Teams.Api.TaskModules.Response OnTaskFetch([Context] Tasks.FetchActivity activity, [Context] IContext.Client client, [Context] Microsoft.Teams.Common.Logging.ILogger log)
418 {
419 log.Info("[TASK_FETCH] Task fetch request received");
420
421 var data = activity.Value?.Data as JsonElement?;
422 if (data == null)
423 {
424 log.Info("[TASK_FETCH] No data found in the activity value");
425 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("No data found in the activity value"));
426 }
427
428 var dialogType = data.Value.TryGetProperty("opendialogtype", out var dialogTypeElement) && dialogTypeElement.ValueKind == JsonValueKind.String
429 ? dialogTypeElement.GetString()
430 : null;
431
432 log.Info($"[TASK_FETCH] Dialog type: {dialogType}");
433
434 return dialogType switch
435 {
436 "simple_form" => CreateSimpleFormDialog(),
437 "webpage_dialog" => CreateWebpageDialog(_configuration, log),
438 "multi_step_form" => CreateMultiStepFormDialog(),
439 "mixed_example" => CreateMixedExampleDialog(),
440 _ => new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Unknown dialog type"))
441 };
442 }
443
444 [TaskSubmit]
445 public async Task<Microsoft.Teams.Api.TaskModules.Response> OnTaskSubmit([Context] Tasks.SubmitActivity activity, [Context] IContext.Client client, [Context] Microsoft.Teams.Common.Logging.ILogger log)
446 {
447 log.Info("[TASK_SUBMIT] Task submit request received");
448
449 var data = activity.Value?.Data as JsonElement?;
450 if (data == null)
451 {
452 log.Info("[TASK_SUBMIT] No data found in the activity value");
453 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("No data found in the activity value"));
454 }
455
456 var submissionType = data.Value.TryGetProperty("submissiondialogtype", out var submissionTypeObj) && submissionTypeObj.ValueKind == JsonValueKind.String
457 ? submissionTypeObj.ToString()
458 : null;
459
460 log.Info($"[TASK_SUBMIT] Submission type: {submissionType}");
461
462 string? GetFormValue(string key)
463 {
464 if (data.Value.TryGetProperty(key, out var val))
465 {
466 if (val is System.Text.Json.JsonElement element)
467 return element.GetString();
468 return val.ToString();
469 }
470 return null;
471 }
472
473 switch (submissionType)
474 {
475 case "simple_form":
476 var name = GetFormValue("name") ?? "Unknown";
477 await client.Send($"Hi {name}, thanks for submitting the form!");
478 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Form was submitted"));
479
480 case "webpage_dialog":
481 var webName = GetFormValue("name") ?? "Unknown";
482 var email = GetFormValue("email") ?? "No email";
483 await client.Send($"Hi {webName}, thanks for submitting the form! We got that your email is {email}");
484 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Form submitted successfully"));
485
486 case "webpage_dialog_step_1":
487 var nameStep1 = GetFormValue("name") ?? "Unknown";
488 var nextStepCardJson = $$"""
489 {
490 "type": "AdaptiveCard",
491 "version": "1.4",
492 "body": [
493 {
494 "type": "TextBlock",
495 "text": "Email",
496 "size": "Large",
497 "weight": "Bolder"
498 },
499 {
500 "type": "Input.Text",
501 "id": "email",
502 "label": "Email",
503 "placeholder": "Enter your email",
504 "isRequired": true
505 }
506 ],
507 "actions": [
508 {
509 "type": "Action.Submit",
510 "title": "Submit",
511 "data": {"submissiondialogtype": "webpage_dialog_step_2", "name": "{{nameStep1}}"}
512 }
513 ]
514 }
515 """;
516
517 var nextStepCard = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(nextStepCardJson)
518 ?? throw new InvalidOperationException("Failed to deserialize next step card");
519
520 var nextStepTaskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
521 {
522 Title = $"Thanks {nameStep1} - Get Email",
523 Card = new Microsoft.Teams.Api.Attachment
524 {
525 ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"),
526 Content = nextStepCard
527 }
528 };
529
530 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(nextStepTaskInfo));
531
532 case "webpage_dialog_step_2":
533 var nameStep2 = GetFormValue("name") ?? "Unknown";
534 var emailStep2 = GetFormValue("email") ?? "No email";
535 await client.Send($"Hi {nameStep2}, thanks for submitting the form! We got that your email is {emailStep2}");
536 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Multi-step form completed successfully"));
537
538 default:
539 return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Unknown submission type"));
540 }
541 }
542 }
543}