microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
733a37f2b7310e6fd954187427f2af0e713dc286

Branches

Tags

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

Clone

HTTPS

Download ZIP

Samples/Samples.Cards/Program.cs

356lines · modepreview

using System.Text.Json;

using Microsoft.Teams.Api.AdaptiveCards;
using Microsoft.Teams.Apps.Activities;
using Microsoft.Teams.Apps.Activities.Invokes;
using Microsoft.Teams.Apps.Extensions;
using Microsoft.Teams.Cards;
using Microsoft.Teams.Common;
using Microsoft.Teams.Plugins.AspNetCore.Extensions;

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseUrls("http://localhost:3978");
builder.Services.AddOpenApi();
builder.AddTeams();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();
var teams = app.UseTeams();

teams.OnMessage(async (context, cancellationToken) =>
{
    var activity = context.Activity;
    context.Log.Info($"[MESSAGE] Received: {SanitizeForLog(activity.Text)}");
    context.Log.Info($"[MESSAGE] From: {SanitizeForLog(activity.From?.Name ?? "unknown")}");

    var text = activity.Text?.ToLowerInvariant() ?? "";

    if (text.Contains("card"))
    {
        context.Log.Info("[CARD] Basic card requested");
        var card = CreateBasicAdaptiveCard();
        await context.Send(card, cancellationToken);
    }
    else if (text.Contains("profile"))
    {
        context.Log.Info("[PROFILE] Profile card requested");
        var card = CreateProfileCard();
        await context.Send(card, cancellationToken);
    }
    else if (text.Contains("validation"))
    {
        context.Log.Info("[VALIDATION] Validation card requested");
        var card = CreateProfileCardWithValidation();
        await context.Send(card, cancellationToken);
    }
    else if (text.Contains("feedback"))
    {
        context.Log.Info("[FEEDBACK] Feedback card requested");
        var card = CreateFeedbackCard();
        await context.Send(card, cancellationToken);
    }
    else if (text.Contains("form"))
    {
        context.Log.Info("[FORM] Task form card requested");
        var card = CreateTaskFormCard();
        await context.Send(card, cancellationToken);
    }
    else if (text.Contains("json"))
    {
        context.Log.Info("[JSON] JSON deserialization card requested");
        var card = CreateCardFromJson();
        await context.Send(card, cancellationToken);
    }
    else if (text.Contains("reply"))
    {
        await context.Send("Hello! How can I assist you today?", cancellationToken);
    }
    else
    {
        await context.Typing(cancellationToken: cancellationToken);
        await context.Send($"You said '{activity.Text}'. Try typing: card, profile, validation, feedback, form, json, or reply", cancellationToken);
    }
});

teams.OnAdaptiveCardAction(async (context, cancellationToken) =>
{
    var activity = context.Activity;
    context.Log.Info("[CARD_ACTION] Card action received");

    var data = activity.Value?.Action?.Data;

    context.Log.Info($"[CARD_ACTION] Raw data: {JsonSerializer.Serialize(data)}");

    if (data == null)
    {
        context.Log.Error("[CARD_ACTION] No data in card action");
        return new ActionResponse.Message("No data specified") { StatusCode = 400 };
    }

    string? action = data.TryGetValue("action", out var actionObj) ? actionObj?.ToString() : null;

    if (string.IsNullOrEmpty(action))
    {
        context.Log.Error("[CARD_ACTION] No action specified in card data");
        return new ActionResponse.Message("No action specified") { StatusCode = 400 };
    }
    context.Log.Info($"[CARD_ACTION] Processing action: {action}");

    string? GetFormValue(string key)
    {
        if (data.TryGetValue(key, out var val))
        {
            if (val is JsonElement element)
                return element.GetString();
            return val?.ToString();
        }
        return null;
    }

    switch (action)
    {
        case "submit_basic":
            var notifyValue = GetFormValue("notify") ?? "false";
            await context.Send($"Basic card submitted! Notify setting: {notifyValue}", cancellationToken);
            break;

        case "submit_feedback":
            var feedbackText = GetFormValue("feedback") ?? "No feedback provided";
            await context.Send($"Feedback received: {feedbackText}", cancellationToken);
            break;

        case "create_task":
            var title = GetFormValue("title") ?? "Untitled";
            var priority = GetFormValue("priority") ?? "medium";
            var dueDate = GetFormValue("due_date") ?? "No date";
            await context.Send($"Task created!\nTitle: {title}\nPriority: {priority}\nDue: {dueDate}", cancellationToken);
            break;

        case "save_profile":
            var name = GetFormValue("name") ?? "Unknown";
            var email = GetFormValue("email") ?? "No email";
            var subscribe = GetFormValue("subscribe") ?? "false";
            var age = GetFormValue("age");
            var location = GetFormValue("location") ?? "Not specified";

            var response = $"Profile saved!\nName: {name}\nEmail: {email}\nSubscribed: {subscribe}";
            if (!string.IsNullOrEmpty(age))
                response += $"\nAge: {age}";
            if (location != "Not specified")
                response += $"\nLocation: {location}";

            await context.Send(response, cancellationToken);
            break;

        case "test_json":
            await context.Send("JSON deserialization test successful!", cancellationToken);
            break;

        default:
            context.Log.Error($"[CARD_ACTION] Unknown action: {action}");
            return new ActionResponse.Message("Unknown action") { StatusCode = 400 };
    }

    return new ActionResponse.Message("Action processed successfully") { StatusCode = 200 };
});

app.Run();

static string SanitizeForLog(string? input)
{
    if (input == null) return "";
    return input.Replace("\r", "").Replace("\n", "");
}

static Microsoft.Teams.Cards.AdaptiveCard CreateBasicAdaptiveCard()
{
    return new Microsoft.Teams.Cards.AdaptiveCard
    {
        Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
        Body = new List<CardElement>
        {
            new TextBlock("Hello world") { Wrap = true, Weight = TextWeight.Bolder },
            new ToggleInput("Notify me") { Id = "notify" }
        },
        Actions = new List<Microsoft.Teams.Cards.Action>
        {
            new ExecuteAction
            {
                Title = "Submit",
                Data = new Union<string, SubmitActionData>(new SubmitData("submit_basic")),
                AssociatedInputs = AssociatedInputs.Auto
            }
        }
    };
}

static Microsoft.Teams.Cards.AdaptiveCard CreateProfileCard()
{
    return new Microsoft.Teams.Cards.AdaptiveCard
    {
        Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
        Body = new List<CardElement>
        {
            new TextBlock("User Profile") { Weight = TextWeight.Bolder, Size = TextSize.Large },
            new TextInput { Id = "name", Label = "Name", Value = "John Doe" },
            new TextInput { Id = "email", Label = "Email", Value = "john@contoso.com" },
            new ToggleInput("Subscribe to newsletter") { Id = "subscribe", Value = "false" }
        },
        Actions = new List<Microsoft.Teams.Cards.Action>
        {
            new ExecuteAction
            {
                Title = "Save",
                Data = new Union<string, SubmitActionData>(new SubmitData("save_profile", new Dictionary<string, object?> { ["entity_id"] = "12345" })),
                AssociatedInputs = AssociatedInputs.Auto
            },
            new OpenUrlAction("https://adaptivecards.microsoft.com") { Title = "Learn More" }
        }
    };
}

static Microsoft.Teams.Cards.AdaptiveCard CreateProfileCardWithValidation()
{
    return new Microsoft.Teams.Cards.AdaptiveCard
    {
        Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
        Body = new List<CardElement>
        {
            new TextBlock("Profile with Validation") { Weight = TextWeight.Bolder, Size = TextSize.Large },
            new NumberInput { Id = "age", Label = "Age", IsRequired = true, Min = 0, Max = 120 },
            new TextInput { Id = "name", Label = "Name", IsRequired = true, ErrorMessage = "Name is required" },
            new TextInput { Id = "location", Label = "Location" }
        },
        Actions = new List<Microsoft.Teams.Cards.Action>
        {
            new ExecuteAction
            {
                Title = "Save",
                Data = new Union<string, SubmitActionData>(new SubmitData("save_profile")),
                AssociatedInputs = AssociatedInputs.Auto
            }
        }
    };
}

static Microsoft.Teams.Cards.AdaptiveCard CreateFeedbackCard()
{
    return new Microsoft.Teams.Cards.AdaptiveCard
    {
        Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
        Body = new List<CardElement>
        {
            new TextBlock("Feedback Form") { Weight = TextWeight.Bolder, Size = TextSize.Large },
            new TextInput { Id = "feedback", Label = "Your Feedback", Placeholder = "Please share your thoughts...", IsMultiline = true, IsRequired = true }
        },
        Actions = new List<Microsoft.Teams.Cards.Action>
        {
            new ExecuteAction
            {
                Title = "Submit Feedback",
                Data = new Union<string, SubmitActionData>(new SubmitData("submit_feedback")),
                AssociatedInputs = AssociatedInputs.Auto
            }
        }
    };
}

static Microsoft.Teams.Cards.AdaptiveCard CreateTaskFormCard()
{
    return new Microsoft.Teams.Cards.AdaptiveCard
    {
        Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
        Body = new List<CardElement>
        {
            new TextBlock("Create New Task") { Weight = TextWeight.Bolder, Size = TextSize.Large },
            new TextInput { Id = "title", Label = "Task Title", Placeholder = "Enter task title" },
            new TextInput { Id = "description", Label = "Description", Placeholder = "Enter task details", IsMultiline = true },
            new ChoiceSetInput
            {
                Id = "priority",
                Label = "Priority",
                Value = "medium",
                Choices = new List<Choice>
                {
                    new() { Title = "High", Value = "high" },
                    new() { Title = "Medium", Value = "medium" },
                    new() { Title = "Low", Value = "low" }
                }
            },
            new DateInput { Id = "due_date", Label = "Due Date", Value = DateTime.Now.ToString("yyyy-MM-dd") }
        },
        Actions = new List<Microsoft.Teams.Cards.Action>
        {
            new ExecuteAction
            {
                Title = "Create Task",
                Data = new Union<string, SubmitActionData>(new SubmitData("create_task")),
                AssociatedInputs = AssociatedInputs.Auto,
                Style = ActionStyle.Positive
            }
        }
    };
}

static Microsoft.Teams.Cards.AdaptiveCard CreateCardFromJson()
{
    var cardJson = @"{
        ""type"": ""AdaptiveCard"",
        ""body"": [
            {
                ""type"": ""ColumnSet"",
                ""columns"": [
                    {
                        ""type"": ""Column"",
                        ""verticalContentAlignment"": ""center"",
                        ""items"": [{ ""type"": ""Image"", ""style"": ""Person"", ""url"": ""https://aka.ms/AAp9xo4"", ""size"": ""Small"", ""altText"": ""Portrait of David Claux"" }],
                        ""width"": ""auto""
                    },
                    {
                        ""type"": ""Column"",
                        ""spacing"": ""medium"",
                        ""verticalContentAlignment"": ""center"",
                        ""items"": [{ ""type"": ""TextBlock"", ""weight"": ""Bolder"", ""text"": ""David Claux"", ""wrap"": true }],
                        ""width"": ""auto""
                    },
                    {
                        ""type"": ""Column"",
                        ""spacing"": ""medium"",
                        ""verticalContentAlignment"": ""center"",
                        ""items"": [{ ""type"": ""TextBlock"", ""text"": ""Principal Platform Architect at Microsoft"", ""isSubtle"": true, ""wrap"": true }],
                        ""width"": ""stretch""
                    }
                ]
            },
            { ""type"": ""TextBlock"", ""text"": ""This card was created from JSON deserialization!"", ""wrap"": true, ""color"": ""good"", ""spacing"": ""medium"" }
        ],
        ""actions"": [{ ""type"": ""Action.Execute"", ""title"": ""Test JSON Action"", ""data"": { ""Value"": { ""action"": ""test_json"" } }, ""associatedInputs"": ""auto"" }],
        ""version"": ""1.5"",
        ""schema"": ""http://adaptivecards.io/schemas/adaptive-card.json""
    }";

    try
    {
        var card = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(cardJson);
        return card ?? throw new InvalidOperationException("Failed to deserialize card");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error deserializing card JSON: {ex.Message}");
        return new Microsoft.Teams.Cards.AdaptiveCard
        {
            Schema = "http://adaptivecards.io/schemas/adaptive-card.json",
            Body = new List<CardElement>
            {
                new TextBlock("JSON Deserialization Test") { Weight = TextWeight.Bolder, Size = TextSize.Large, Color = TextColor.Attention },
                new TextBlock($"Deserialization failed: {ex.Message}") { Wrap = true, Color = TextColor.Attention }
            }
        };
    }
}