microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
c3acedab068481dc35ed1b11e297eb2ddb432fcf

Branches

Tags

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

Clone

HTTPS

Download ZIP

Samples/Samples.Cards/Program.cs

358lines · modecode

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