microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/close-pull-request

Branches

Tags

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

Clone

HTTPS

Download ZIP

Samples/Samples.Dialogs/Program.cs

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