microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
87729f780a04a94c40e3816a99f39edf8c0379b7

Branches

Tags

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

Clone

HTTPS

Download ZIP

Samples/Samples.Cards/Program.cs

357lines · modecode

1using System.Text.Json;
2
3using Microsoft.Teams.Api.AdaptiveCards;
4using Microsoft.Teams.Apps.Activities;
5using Microsoft.Teams.Apps.Activities.Invokes;
6using Microsoft.Teams.Apps.Extensions;
7using Microsoft.Teams.Cards;
8using Microsoft.Teams.Common;
9using Microsoft.Teams.Plugins.AspNetCore.DevTools.Extensions;
10using Microsoft.Teams.Plugins.AspNetCore.Extensions;
11
12var builder = WebApplication.CreateBuilder(args);
13builder.WebHost.UseUrls("http://localhost:3978");
14builder.Services.AddOpenApi();
15builder.AddTeams().AddTeamsDevTools();
16
17var app = builder.Build();
18
19if (app.Environment.IsDevelopment())
20{
21 app.MapOpenApi();
22}
23
24app.UseHttpsRedirection();
25var teams = app.UseTeams();
26
27teams.OnMessage(async (context, cancellationToken) =>
28{
29 var activity = context.Activity;
30 context.Log.Info($"[MESSAGE] Received: {SanitizeForLog(activity.Text)}");
31 context.Log.Info($"[MESSAGE] From: {SanitizeForLog(activity.From?.Name ?? "unknown")}");
32
33 var text = activity.Text?.ToLowerInvariant() ?? "";
34
35 if (text.Contains("card"))
36 {
37 context.Log.Info("[CARD] Basic card requested");
38 var card = CreateBasicAdaptiveCard();
39 await context.Send(card, cancellationToken);
40 }
41 else if (text.Contains("profile"))
42 {
43 context.Log.Info("[PROFILE] Profile card requested");
44 var card = CreateProfileCard();
45 await context.Send(card, cancellationToken);
46 }
47 else if (text.Contains("validation"))
48 {
49 context.Log.Info("[VALIDATION] Validation card requested");
50 var card = CreateProfileCardWithValidation();
51 await context.Send(card, cancellationToken);
52 }
53 else if (text.Contains("feedback"))
54 {
55 context.Log.Info("[FEEDBACK] Feedback card requested");
56 var card = CreateFeedbackCard();
57 await context.Send(card, cancellationToken);
58 }
59 else if (text.Contains("form"))
60 {
61 context.Log.Info("[FORM] Task form card requested");
62 var card = CreateTaskFormCard();
63 await context.Send(card, cancellationToken);
64 }
65 else if (text.Contains("json"))
66 {
67 context.Log.Info("[JSON] JSON deserialization card requested");
68 var card = CreateCardFromJson();
69 await context.Send(card, cancellationToken);
70 }
71 else if (text.Contains("reply"))
72 {
73 await context.Send("Hello! How can I assist you today?", cancellationToken);
74 }
75 else
76 {
77 await context.Typing(cancellationToken: cancellationToken);
78 await context.Send($"You said '{activity.Text}'. Try typing: card, profile, validation, feedback, form, json, or reply", cancellationToken);
79 }
80});
81
82teams.OnAdaptiveCardAction(async (context, cancellationToken) =>
83{
84 var activity = context.Activity;
85 context.Log.Info("[CARD_ACTION] Card action received");
86
87 var data = activity.Value?.Action?.Data;
88
89 context.Log.Info($"[CARD_ACTION] Raw data: {JsonSerializer.Serialize(data)}");
90
91 if (data == null)
92 {
93 context.Log.Error("[CARD_ACTION] No data in card action");
94 return new ActionResponse.Message("No data specified") { StatusCode = 400 };
95 }
96
97 string? action = data.TryGetValue("action", out var actionObj) ? actionObj?.ToString() : null;
98
99 if (string.IsNullOrEmpty(action))
100 {
101 context.Log.Error("[CARD_ACTION] No action specified in card data");
102 return new ActionResponse.Message("No action specified") { StatusCode = 400 };
103 }
104 context.Log.Info($"[CARD_ACTION] Processing action: {action}");
105
106 string? GetFormValue(string key)
107 {
108 if (data.TryGetValue(key, out var val))
109 {
110 if (val is JsonElement element)
111 return element.GetString();
112 return val?.ToString();
113 }
114 return null;
115 }
116
117 switch (action)
118 {
119 case "submit_basic":
120 var notifyValue = GetFormValue("notify") ?? "false";
121 await context.Send($"Basic card submitted! Notify setting: {notifyValue}", cancellationToken);
122 break;
123
124 case "submit_feedback":
125 var feedbackText = GetFormValue("feedback") ?? "No feedback provided";
126 await context.Send($"Feedback received: {feedbackText}", cancellationToken);
127 break;
128
129 case "create_task":
130 var title = GetFormValue("title") ?? "Untitled";
131 var priority = GetFormValue("priority") ?? "medium";
132 var dueDate = GetFormValue("due_date") ?? "No date";
133 await context.Send($"Task created!\nTitle: {title}\nPriority: {priority}\nDue: {dueDate}", cancellationToken);
134 break;
135
136 case "save_profile":
137 var name = GetFormValue("name") ?? "Unknown";
138 var email = GetFormValue("email") ?? "No email";
139 var subscribe = GetFormValue("subscribe") ?? "false";
140 var age = GetFormValue("age");
141 var location = GetFormValue("location") ?? "Not specified";
142
143 var response = $"Profile saved!\nName: {name}\nEmail: {email}\nSubscribed: {subscribe}";
144 if (!string.IsNullOrEmpty(age))
145 response += $"\nAge: {age}";
146 if (location != "Not specified")
147 response += $"\nLocation: {location}";
148
149 await context.Send(response, cancellationToken);
150 break;
151
152 case "test_json":
153 await context.Send("JSON deserialization test successful!", cancellationToken);
154 break;
155
156 default:
157 context.Log.Error($"[CARD_ACTION] Unknown action: {action}");
158 return new ActionResponse.Message("Unknown action") { StatusCode = 400 };
159 }
160
161 return new ActionResponse.Message("Action processed successfully") { StatusCode = 200 };
162});
163
164app.Run();
165
166static string SanitizeForLog(string? input)
167{
168 if (input == null) return "";
169 return input.Replace("\r", "").Replace("\n", "");
170}
171
172static Microsoft.Teams.Cards.AdaptiveCard CreateBasicAdaptiveCard()
173{
174 return new Microsoft.Teams.Cards.AdaptiveCard
175 {
176 Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
177 Body = new List<CardElement>
178 {
179 new TextBlock("Hello world") { Wrap = true, Weight = TextWeight.Bolder },
180 new ToggleInput("Notify me") { Id = "notify" }
181 },
182 Actions = new List<Microsoft.Teams.Cards.Action>
183 {
184 new ExecuteAction
185 {
186 Title = "Submit",
187 Data = new Union<string, SubmitActionData>(new SubmitActionData { NonSchemaProperties = new Dictionary<string, object?> { { "action", "submit_basic" } } }),
188 AssociatedInputs = AssociatedInputs.Auto
189 }
190 }
191 };
192}
193
194static Microsoft.Teams.Cards.AdaptiveCard CreateProfileCard()
195{
196 return new Microsoft.Teams.Cards.AdaptiveCard
197 {
198 Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
199 Body = new List<CardElement>
200 {
201 new TextBlock("User Profile") { Weight = TextWeight.Bolder, Size = TextSize.Large },
202 new TextInput { Id = "name", Label = "Name", Value = "John Doe" },
203 new TextInput { Id = "email", Label = "Email", Value = "john@contoso.com" },
204 new ToggleInput("Subscribe to newsletter") { Id = "subscribe", Value = "false" }
205 },
206 Actions = new List<Microsoft.Teams.Cards.Action>
207 {
208 new ExecuteAction
209 {
210 Title = "Save",
211 Data = new Union<string, SubmitActionData>(new SubmitActionData { NonSchemaProperties = new Dictionary<string, object?> { { "action", "save_profile" }, { "entity_id", "12345" } } }),
212 AssociatedInputs = AssociatedInputs.Auto
213 },
214 new OpenUrlAction("https://adaptivecards.microsoft.com") { Title = "Learn More" }
215 }
216 };
217}
218
219static Microsoft.Teams.Cards.AdaptiveCard CreateProfileCardWithValidation()
220{
221 return new Microsoft.Teams.Cards.AdaptiveCard
222 {
223 Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
224 Body = new List<CardElement>
225 {
226 new TextBlock("Profile with Validation") { Weight = TextWeight.Bolder, Size = TextSize.Large },
227 new NumberInput { Id = "age", Label = "Age", IsRequired = true, Min = 0, Max = 120 },
228 new TextInput { Id = "name", Label = "Name", IsRequired = true, ErrorMessage = "Name is required" },
229 new TextInput { Id = "location", Label = "Location" }
230 },
231 Actions = new List<Microsoft.Teams.Cards.Action>
232 {
233 new ExecuteAction
234 {
235 Title = "Save",
236 Data = new Union<string, SubmitActionData>(new SubmitActionData { NonSchemaProperties = new Dictionary<string, object?> { { "action", "save_profile" } } }),
237 AssociatedInputs = AssociatedInputs.Auto
238 }
239 }
240 };
241}
242
243static Microsoft.Teams.Cards.AdaptiveCard CreateFeedbackCard()
244{
245 return new Microsoft.Teams.Cards.AdaptiveCard
246 {
247 Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
248 Body = new List<CardElement>
249 {
250 new TextBlock("Feedback Form") { Weight = TextWeight.Bolder, Size = TextSize.Large },
251 new TextInput { Id = "feedback", Label = "Your Feedback", Placeholder = "Please share your thoughts...", IsMultiline = true, IsRequired = true }
252 },
253 Actions = new List<Microsoft.Teams.Cards.Action>
254 {
255 new ExecuteAction
256 {
257 Title = "Submit Feedback",
258 Data = new Union<string, SubmitActionData>(new SubmitActionData { NonSchemaProperties = new Dictionary<string, object?> { { "action", "submit_feedback" } } }),
259 AssociatedInputs = AssociatedInputs.Auto
260 }
261 }
262 };
263}
264
265static Microsoft.Teams.Cards.AdaptiveCard CreateTaskFormCard()
266{
267 return new Microsoft.Teams.Cards.AdaptiveCard
268 {
269 Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
270 Body = new List<CardElement>
271 {
272 new TextBlock("Create New Task") { Weight = TextWeight.Bolder, Size = TextSize.Large },
273 new TextInput { Id = "title", Label = "Task Title", Placeholder = "Enter task title" },
274 new TextInput { Id = "description", Label = "Description", Placeholder = "Enter task details", IsMultiline = true },
275 new ChoiceSetInput
276 {
277 Id = "priority",
278 Label = "Priority",
279 Value = "medium",
280 Choices = new List<Choice>
281 {
282 new() { Title = "High", Value = "high" },
283 new() { Title = "Medium", Value = "medium" },
284 new() { Title = "Low", Value = "low" }
285 }
286 },
287 new DateInput { Id = "due_date", Label = "Due Date", Value = DateTime.Now.ToString("yyyy-MM-dd") }
288 },
289 Actions = new List<Microsoft.Teams.Cards.Action>
290 {
291 new ExecuteAction
292 {
293 Title = "Create Task",
294 Data = new Union<string, SubmitActionData>(new SubmitActionData { NonSchemaProperties = new Dictionary<string, object?> { { "action", "create_task" } } }),
295 AssociatedInputs = AssociatedInputs.Auto,
296 Style = ActionStyle.Positive
297 }
298 }
299 };
300}
301
302static Microsoft.Teams.Cards.AdaptiveCard CreateCardFromJson()
303{
304 var cardJson = @"{
305 ""type"": ""AdaptiveCard"",
306 ""body"": [
307 {
308 ""type"": ""ColumnSet"",
309 ""columns"": [
310 {
311 ""type"": ""Column"",
312 ""verticalContentAlignment"": ""center"",
313 ""items"": [{ ""type"": ""Image"", ""style"": ""Person"", ""url"": ""https://aka.ms/AAp9xo4"", ""size"": ""Small"", ""altText"": ""Portrait of David Claux"" }],
314 ""width"": ""auto""
315 },
316 {
317 ""type"": ""Column"",
318 ""spacing"": ""medium"",
319 ""verticalContentAlignment"": ""center"",
320 ""items"": [{ ""type"": ""TextBlock"", ""weight"": ""Bolder"", ""text"": ""David Claux"", ""wrap"": true }],
321 ""width"": ""auto""
322 },
323 {
324 ""type"": ""Column"",
325 ""spacing"": ""medium"",
326 ""verticalContentAlignment"": ""center"",
327 ""items"": [{ ""type"": ""TextBlock"", ""text"": ""Principal Platform Architect at Microsoft"", ""isSubtle"": true, ""wrap"": true }],
328 ""width"": ""stretch""
329 }
330 ]
331 },
332 { ""type"": ""TextBlock"", ""text"": ""This card was created from JSON deserialization!"", ""wrap"": true, ""color"": ""good"", ""spacing"": ""medium"" }
333 ],
334 ""actions"": [{ ""type"": ""Action.Execute"", ""title"": ""Test JSON Action"", ""data"": { ""Value"": { ""action"": ""test_json"" } }, ""associatedInputs"": ""auto"" }],
335 ""version"": ""1.5"",
336 ""schema"": ""http://adaptivecards.io/schemas/adaptive-card.json""
337 }";
338
339 try
340 {
341 var card = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(cardJson);
342 return card ?? throw new InvalidOperationException("Failed to deserialize card");
343 }
344 catch (Exception ex)
345 {
346 Console.WriteLine($"Error deserializing card JSON: {ex.Message}");
347 return new Microsoft.Teams.Cards.AdaptiveCard
348 {
349 Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
350 Body = new List<CardElement>
351 {
352 new TextBlock("JSON Deserialization Test") { Weight = TextWeight.Bolder, Size = TextSize.Large, Color = TextColor.Attention },
353 new TextBlock($"Deserialization failed: {ex.Message}") { Wrap = true, Color = TextColor.Attention }
354 }
355 };
356 }
357}