// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Text.Json;
using System.Text.Json.Nodes;
using AllInvokesBot;
using Microsoft.Teams.Apps;
using Microsoft.Teams.Apps.Handlers;
using Microsoft.Teams.Apps.Handlers.TaskModules;
using Microsoft.Teams.Apps.Schema;
using Microsoft.Teams.Core.Hosting;
WebApplicationBuilder webAppBuilder = WebApplication.CreateSlimBuilder(args);
webAppBuilder.Services.AddTeamsBotApplication();
WebApplication webApp = webAppBuilder.Build();
TeamsBotApplication bot = webApp.UseBotApplication<TeamsBotApplication>();
// ==================== MESSAGE - SEND SIMPLE CARD ====================
bot.OnMessage(async (context, cancellationToken) =>
{
Console.WriteLine("✓ OnMessage");
JsonObject card = Cards.CreateWelcomeCard();
TeamsAttachment attachment = TeamsAttachment.CreateBuilder()
.WithAdaptiveCard(card)
.Build();
await context.SendActivityAsync(new MessageActivity([attachment]), cancellationToken);
});
// ==================== ADAPTIVE CARD ACTION ====================
bot.OnAdaptiveCardAction(async (context, cancellationToken) =>
{
Console.WriteLine("✓ OnAdaptiveCardAction");
AdaptiveCardActionValue? value = context.Activity.Value;
AdaptiveCardAction? action = value?.Action;
string? verb = action?.Verb;
Dictionary<string, object>? data = action?.Data;
Console.WriteLine($" Verb: {verb}");
Console.WriteLine($" Data: {JsonSerializer.Serialize(data)}");
// Handle file upload request
if (verb == "requestFileUpload")
{
JsonObject fileConsentCard = Cards.CreateFileConsentCard();
TeamsAttachment fileConsentCardResponse = TeamsAttachment.CreateBuilder()
.WithContent(fileConsentCard).WithContentType(AttachmentContentType.FileConsentCard)
.WithName("file_consent.json").Build();
await context.SendActivityAsync(new MessageActivity([fileConsentCardResponse]), cancellationToken);
return AdaptiveCardResponse.CreateMessageResponse("File Consent requested!");
}
string? message = data != null && data.TryGetValue("message", out object? msgValue) ? msgValue?.ToString() : null;
JsonObject adaptiveActionCard = Cards.CreateAdaptiveActionResponseCard(verb, message);
TeamsAttachment adaptiveActionCardResponse = TeamsAttachment.CreateBuilder().WithAdaptiveCard(adaptiveActionCard).Build();
await context.SendActivityAsync(new MessageActivity([adaptiveActionCardResponse]), cancellationToken);
return AdaptiveCardResponse.CreateMessageResponse("Action submitted!");
});
// ==================== TASK MODULE - FETCH ====================
bot.OnTaskFetch(async (context, cancellationToken) =>
{
Console.WriteLine("✓ OnTaskFetch");
TeamsAttachment taskModuleCardResponse = TeamsAttachment.CreateBuilder()
.WithAdaptiveCard(Cards.CreateTaskModuleCard()).Build();
return TaskModuleResponse.CreateBuilder()
.WithType(TaskModuleResponseType.Continue)
.WithTitle("Task")
.WithHeight("medium")
.WithWidth("medium")
.WithCard(taskModuleCardResponse)
.Build();
});
// ==================== TASK MODULE - SUBMIT ====================
bot.OnTaskSubmit(async (context, cancellationToken) =>
{
Console.WriteLine("✓ OnTaskSubmit");
return TaskModuleResponse.CreateBuilder()
.WithType(TaskModuleResponseType.Message)
.WithMessage("Done")
.Build();
});
// ==================== FILE CONSENT ====================
bot.OnFileConsent(async (context, cancellationToken) =>
{
Console.WriteLine("✓ OnFileConsent");
FileConsentValue? value = context.Activity.Value;
string? action = value?.Action;
FileUploadInfo? uploadInfo = value?.UploadInfo;
object? consentContext = value?.Context;
if (action == "accept")
{
Console.WriteLine($" File accepted!");
// Upload the file
string? uploadUrl = uploadInfo?.UploadUrl?.ToString();
string? fileName = uploadInfo?.Name;
string? contentUrl = uploadInfo?.ContentUrl?.ToString();
string? uniqueId = uploadInfo?.UniqueId;
if (uploadUrl != null && contentUrl != null)
{
// Create sample file content
string fileContent = "This is a sample file uploaded via file consent!";
byte[] fileBytes = System.Text.Encoding.UTF8.GetBytes(fileContent);
int fileSize = fileBytes.Length;
using HttpClient httpClient = new();
using ByteArrayContent content = new(fileBytes);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
content.Headers.ContentRange = new System.Net.Http.Headers.ContentRangeHeaderValue(0, fileSize - 1, fileSize);
try
{
HttpResponseMessage uploadResponse = await httpClient.PutAsync(uploadUrl, content, cancellationToken);
Console.WriteLine($" Upload Status: {uploadResponse.StatusCode}");
if (uploadResponse.IsSuccessStatusCode)
{
JsonObject fileInfoContent = Cards.CreateFileInfoCard(uniqueId, uploadInfo?.FileType);
TeamsAttachment fileUploadResponse = TeamsAttachment.CreateBuilder()
.WithName(fileName)
.WithContentType(AttachmentContentType.FileInfoCard)
.WithContentUrl(contentUrl != null ? new Uri(contentUrl) : null)
.WithContent(fileInfoContent).Build();
await context.SendActivityAsync(new MessageActivity([fileUploadResponse]), cancellationToken);
}
else
{
Console.WriteLine($" File upload failed: {await uploadResponse.Content.ReadAsStringAsync(cancellationToken)}");
}
}
catch (Exception ex)
{
Console.WriteLine($" File upload error: {ex.Message}");
}
}
}
else if (action == "decline")
{
Console.WriteLine($" File declined!");
Console.WriteLine($" Context: {JsonSerializer.Serialize(consentContext)}");
}
return AdaptiveCardResponse.CreateBuilder()
.WithStatusCode(200)
.Build();
});
/*
// ==================== EXECUTE ACTION ====================
bot.OnExecuteAction(async (context, cancellationToken) =>
{
Console.WriteLine("✓ OnExecuteAction");
var responseBody = new JsonObject
{
["status"] = "completed"
};
return new CoreInvokeResponse(200, responseBody);
});
// ==================== HANDOFF ====================
bot.OnHandoff(async (context, cancellationToken) =>
{
Console.WriteLine("✓ OnHandoff");
return new CoreInvokeResponse(200);
});
// ==================== SEARCH ====================
bot.OnSearch(async (context, cancellationToken) =>
{
Console.WriteLine("✓ OnSearch");
var responseBody = new JsonObject
{
["results"] = new JsonArray
{
new JsonObject
{
["id"] = "1",
["title"] = "Result"
}
}
};
return new CoreInvokeResponse(200, responseBody);
});
// ==================== MESSAGE SUBMIT ACTION ====================
bot.OnMessageSubmitAction(async (context, cancellationToken) =>
{
Console.WriteLine("✓ OnMessageSubmitAction");
var data = context.Activity.Value;
Console.WriteLine($" Data: {System.Text.Json.JsonSerializer.Serialize(data)}");
// Extract data fields
var jsonData = System.Text.Json.JsonSerializer.Deserialize<System.Text.Json.JsonElement>(
System.Text.Json.JsonSerializer.Serialize(data));
string? action = jsonData.TryGetProperty("action", out var a) ? a.GetString() : "unknown";
string? value = jsonData.TryGetProperty("value", out var v) ? v.GetString() : "no value";
Console.WriteLine($" Action: {action}");
Console.WriteLine($" Value: {value}");
var responseBody = new JsonObject
{
["statusCode"] = 200,
["type"] = "application/vnd.microsoft.activity.message",
["value"] = $"Message action '{action}' submitted! Value: {value}"
};
return new CoreInvokeResponse(200, responseBody);
});
// ==================== CONFIG FETCH ====================
bot.OnConfigFetch(async (context, cancellationToken) =>
{
Console.WriteLine("✓ OnConfigFetch");
var card = new
{
contentType = AttachmentContentType.AdaptiveCard,
content = new
{
type = "AdaptiveCard",
version = "1.4",
body = new object[]
{
new { type = "TextBlock", text = "Extension Settings", size = "large", weight = "bolder" },
new { type = "TextBlock", text = "Configure your messaging extension settings below:", wrap = true },
new { type = "Input.Text", id = "apiKey", label = "API Key", placeholder = "Enter your API key" },
new { type = "Input.Toggle", id = "enableNotifications", label = "Enable Notifications", value = "true" }
},
actions = new object[]
{
new { type = "Action.Submit", title = "Save Settings" }
}
}
};
var response = TaskModuleResponse.CreateBuilder()
.WithType(TaskModuleResponseType.Continue)
.WithTitle("Configure Messaging Extension")
.WithHeight(TaskModuleSize.Medium)
.WithWidth(TaskModuleSize.Medium)
.WithCard(card)
.Build();
return new CoreInvokeResponse<MessageExtensionResponse>(200, response);
});
// ==================== CONFIG SUBMIT ====================
bot.OnConfigSubmit(async (context, cancellationToken) =>
{
Console.WriteLine("✓ OnConfigSubmit");
var data = context.Activity.Value;
Console.WriteLine($" Config data: {System.Text.Json.JsonSerializer.Serialize(data)}");
// In a real app, you would save these settings to a database
// associated with the user/team
var response = TaskModuleResponse.CreateBuilder()
.WithType(TaskModuleResponseType.Message)
.WithMessage("Settings saved successfully!")
.Build();
return new CoreInvokeResponse<MessageExtensionResponse>(200, response);
});
*/
webApp.Run();microsoft/teams.net
Publicmirrored fromhttps://github.com/microsoft/teams.netAvailable
core/samples/AllInvokesBot/Program.cs
289lines · modepreview