microsoft/teams.net

Public

mirrored from https://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/sub-pr-199

Branches

Tags

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

Clone

HTTPS

Download ZIP

Samples/Samples.Dialogs/Program.cs

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