diff --git a/.github/workflows/build-complete-samples.yml b/.github/workflows/build-complete-samples.yml
index 9e357bec34..c26f51179a 100644
--- a/.github/workflows/build-complete-samples.yml
+++ b/.github/workflows/build-complete-samples.yml
@@ -34,7 +34,7 @@ jobs:
- project_path: 'samples/app-checkin-location/csharp/AppCheckinLocation/AppCheckinLocation.csproj'
name: 'app-checkin-location'
- version: '6.0.x'
+ version: '10.0.x'
- project_path: 'samples/app-installation-using-qr-code/csharp/QRAppInstallation/QRAppInstallation.csproj'
name: 'app-installation-using-qr-code'
diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation.sln b/samples/app-checkin-location/csharp/AppCheckinLocation.sln
deleted file mode 100644
index b53d012805..0000000000
--- a/samples/app-checkin-location/csharp/AppCheckinLocation.sln
+++ /dev/null
@@ -1,37 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.11.35327.3
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppCheckinLocation", "AppCheckinLocation\AppCheckinLocation.csproj", "{BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}"
-EndProject
-Project("{A9E3F50B-275E-4AF7-ADCE-8BE12D41E305}") = "M365Agent", "M365Agent\M365Agent.ttkproj", "{C7FD0E24-2254-4184-BF12-6C75D2752F28}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5D189F39-4203-4965-B996-947F7A8EA57E}"
- ProjectSection(SolutionItems) = preProject
- AppCheckinLocation.slnLaunch.user = AppCheckinLocation.slnLaunch.user
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BFDF6B3D-BB62-42DD-88EF-528FFE9FCBAD}.Release|Any CPU.Build.0 = Release|Any CPU
- {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
- {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C7FD0E24-2254-4184-BF12-6C75D2752F28}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {8F7F570D-74C3-4CF3-AACD-361A3D3F8E37}
- EndGlobalSection
-EndGlobal
diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation.slnLaunch.user b/samples/app-checkin-location/csharp/AppCheckinLocation.slnLaunch.user
index 8aba718afc..c104d6bb7a 100644
--- a/samples/app-checkin-location/csharp/AppCheckinLocation.slnLaunch.user
+++ b/samples/app-checkin-location/csharp/AppCheckinLocation.slnLaunch.user
@@ -1,31 +1,52 @@
[
{
- "Name": "Microsoft Teams (browser)",
+ "Name": "Microsoft 365 Agents Playground (browser)",
"Projects": [
+ {
+ "Path": "M365Agent\\M365Agent.atkproj",
+ "Name": "M365Agent\\M365Agent.atkproj",
+ "Action": "StartWithoutDebugging",
+ "DebugTarget": "Microsoft 365 Agents Playground (browser)"
+ },
{
"Path": "AppCheckinLocation\\AppCheckinLocation.csproj",
+ "Name": "AppCheckinLocation\\AppCheckinLocation.csproj",
"Action": "Start",
- "DebugTarget": "Start Project"
- },
+ "DebugTarget": "Microsoft 365 Agents Playground"
+ }
+ ]
+ },
+ {
+ "Name": "Microsoft Teams (browser)",
+ "Projects": [
{
- "Path": "M365Agent\\M365Agent.ttkproj",
+ "Path": "M365Agent\\M365Agent.atkproj",
+ "Name": "M365Agent\\M365Agent.atkproj",
"Action": "StartWithoutDebugging",
"DebugTarget": "Microsoft Teams (browser)"
+ },
+ {
+ "Path": "AppCheckinLocation\\AppCheckinLocation.csproj",
+ "Name": "AppCheckinLocation\\AppCheckinLocation.csproj",
+ "Action": "Start",
+ "DebugTarget": "Start Project"
}
]
},
{
"Name": "Microsoft Teams (browser) (skip update app)",
"Projects": [
+ {
+ "Path": "M365Agent\\M365Agent.atkproj",
+ "Name": "M365Agent\\M365Agent.atkproj",
+ "Action": "StartWithoutDebugging",
+ "DebugTarget": "Microsoft Teams (browser) (skip update app)"
+ },
{
"Path": "AppCheckinLocation\\AppCheckinLocation.csproj",
+ "Name": "AppCheckinLocation\\AppCheckinLocation.csproj",
"Action": "Start",
"DebugTarget": "Start Project"
- },
- {
- "Path": "M365Agent\\M365Agent.ttkproj",
- "Action": "StartWithoutDebugging",
- "DebugTarget": "Microsoft Teams (browser) (skip update app)"
}
]
}
diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation.slnx b/samples/app-checkin-location/csharp/AppCheckinLocation.slnx
new file mode 100644
index 0000000000..5b174f95fe
--- /dev/null
+++ b/samples/app-checkin-location/csharp/AppCheckinLocation.slnx
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/.gitignore b/samples/app-checkin-location/csharp/AppCheckinLocation/.gitignore
index 7466c01f9c..89b80db704 100644
--- a/samples/app-checkin-location/csharp/AppCheckinLocation/.gitignore
+++ b/samples/app-checkin-location/csharp/AppCheckinLocation/.gitignore
@@ -22,4 +22,8 @@ bld/
[Ll]og/
# Notification local store
-.notification.localstore.json
\ No newline at end of file
+.notification.localstore.json
+.notification.playgroundstore.json
+
+# devTools
+devTools/
\ No newline at end of file
diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/AdapterWithErrorHandler.cs b/samples/app-checkin-location/csharp/AppCheckinLocation/AdapterWithErrorHandler.cs
deleted file mode 100644
index da746e2cd4..0000000000
--- a/samples/app-checkin-location/csharp/AppCheckinLocation/AdapterWithErrorHandler.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-using System;
-using System.Threading.Tasks;
-using Microsoft.Bot.Builder;
-using Microsoft.Bot.Connector;
-using Microsoft.Bot.Builder.Integration.AspNet.Core;
-using Microsoft.Bot.Schema;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Logging;
-using System.Net.Http;
-
-namespace AppCheckinLocation
-{
- public class AdapterWithErrorHandler : CloudAdapter
- {
- public AdapterWithErrorHandler(IConfiguration configuration, IHttpClientFactory httpClientFactory, ILogger logger, ConversationState conversationState = default)
- : base(configuration, httpClientFactory, logger)
- {
- OnTurnError = async (turnContext, exception) =>
- {
- // Log any leaked exception from the application.
- // NOTE: In production environment, you should consider logging this to
- // Azure Application Insights. Visit https://aka.ms/bottelemetry to see how
- // to add telemetry capture to your bot.
- logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");
-
- // Send a trace activity, which will be displayed in the Bot Framework Emulator
- await SendTraceActivityAsync(turnContext, exception);
-
- // Uncomment below commented line for local debugging.
- // await turnContext.SendActivityAsync($"Sorry, it looks like something went wrong. Exception Caught: {exception.Message}");
- };
- }
-
- private static async Task SendTraceActivityAsync(ITurnContext turnContext, Exception exception)
- {
- // Only send a trace activity if we're talking to the Bot Framework Emulator
- if (turnContext.Activity.ChannelId == Channels.Emulator)
- {
- Activity traceActivity = new Activity(ActivityTypes.Trace)
- {
- Label = "TurnError",
- Name = "OnTurnError Trace",
- Value = exception.Message,
- ValueType = "https://www.botframework.com/schemas/error",
- };
-
- // Send a trace activity
- await turnContext.SendActivityAsync(traceActivity);
- }
- }
- }
-}
diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/AppCheckinLocation.csproj b/samples/app-checkin-location/csharp/AppCheckinLocation/AppCheckinLocation.csproj
index 8960c930af..d7886df2e7 100644
--- a/samples/app-checkin-location/csharp/AppCheckinLocation/AppCheckinLocation.csproj
+++ b/samples/app-checkin-location/csharp/AppCheckinLocation/AppCheckinLocation.csproj
@@ -1,25 +1,29 @@
-
+
- net6.0
- latest
+ net10.0
+ enable
-
-
-
-
+
+
+
+
+
-
-
- Always
+
+
+
+
+ PreserveNewest
+ None
+
+
+
+ PreserveNewest
+ None
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/Bots/ActivityBot.cs b/samples/app-checkin-location/csharp/AppCheckinLocation/Bots/ActivityBot.cs
deleted file mode 100644
index 267b0e8829..0000000000
--- a/samples/app-checkin-location/csharp/AppCheckinLocation/Bots/ActivityBot.cs
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-// Generated with Bot Builder V4 SDK Template for Visual Studio v4.14.0
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using AdaptiveCards;
-using AppCheckinLocation.Models;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Bot.Builder;
-using Microsoft.Bot.Builder.Teams;
-using Microsoft.Bot.Schema;
-using Microsoft.Bot.Schema.Teams;
-using Microsoft.Extensions.Configuration;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-
-namespace AppCheckinLocation.Bots
-{
- ///
- /// Bot Activity handler class.
- ///
- public class ActivityBot : TeamsActivityHandler
- {
- private readonly string _applicationBaseUrl;
- private readonly IWebHostEnvironment _env;
- protected readonly BotState _conversationState;
- protected readonly IStatePropertyAccessor _UserDetail;
-
- public ActivityBot(IConfiguration configuration, IWebHostEnvironment env, ConversationState conversationState)
- {
- _conversationState = conversationState;
- _env = env;
- _applicationBaseUrl = configuration["ApplicationBaseUrl"] ?? throw new NullReferenceException("ApplicationBaseUrl");
- _UserDetail = conversationState.CreateProperty(nameof(UserLocationDetail));
- }
-
- ///
- /// Handle when a message is addressed to the bot.
- ///
- /// The turn context.
- /// The cancellation token.
- /// A task that represents the work queued to execute.
- protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken)
- {
- if(turnContext.Activity.Text.ToLower().Trim() == "viewcheckin")
- {
- var currentUserDetail = await this._UserDetail.GetAsync(turnContext, () => new UserLocationDetail());
- List userDetailsList = new List();
-
- if (currentUserDetail.UserDetails == null)
- {
- await turnContext.SendActivityAsync(MessageFactory.Text("No last check in found"));
- }
- else
- {
- await turnContext.SendActivityAsync(MessageFactory.Attachment(GetAdaptiveCardForUserLastCheckIn(currentUserDetail.UserDetails)), cancellationToken);
- }
- }
- else
- {
- await turnContext.SendActivityAsync(MessageFactory.Attachment(GetAdaptiveCardForTaskModule()), cancellationToken);
- }
- }
-
- ///
- /// Handle request from bot.
- ///
- /// The turn context.
- /// The cancellation token.
- /// A task that represents the work queued to execute.
- public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
- {
- await base.OnTurnAsync(turnContext, cancellationToken);
-
- // Save any state changes that might have occurred during the turn.
- await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
- }
-
- ///
- /// Invoked when bot (like a user) are added to the conversation.
- ///
- /// A list of all the members added to the conversation.
- /// Context object containing information cached for a single turn of conversation with a user.
- /// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
- /// A task that represents the work queued to execute.
- ///
- protected override async Task OnMembersAddedAsync(IList membersAdded, ITurnContext turnContext, CancellationToken cancellationToken)
- {
- foreach (var member in turnContext.Activity.MembersAdded)
- {
- if (member.Id != turnContext.Activity.Recipient.Id)
- {
- await turnContext.SendActivityAsync(MessageFactory.Text($"Hello and welcome! With this sample you can checkin your location (use command 'checkin') and view your checked in location(use command 'viewcheckin')."), cancellationToken);
- }
- }
- }
-
- ///
- /// Handle task module is fetch.
- ///
- /// The turn context.
- /// The task module invoke request value payload.
- /// The cancellation token.
- /// A Task Module Response for the request.
- protected override Task OnTeamsTaskModuleFetchAsync(ITurnContext turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken)
- {
- var asJobject = JObject.FromObject(taskModuleRequest.Data);
- var buttonType = (string)asJobject.ToObject>()?.Id;
- var taskModuleResponse = new TaskModuleResponse();
-
- if (buttonType == "checkin")
- {
- taskModuleResponse.Task = new TaskModuleContinueResponse
- {
- Type = "continue",
- Value = new TaskModuleTaskInfo()
- {
- Url = _applicationBaseUrl + "/" + "CheckIn",
- Height = 350,
- Width = 350,
- Title = "Check in details",
- },
- };
- }
- else if (buttonType == "viewLocation")
- {
- var latitude = (double)asJobject.ToObject>()?.Latitude;
- var longitude = (double)asJobject.ToObject>()?.Longitude;
- taskModuleResponse.Task = new TaskModuleContinueResponse
- {
- Type = "continue",
- Value = new TaskModuleTaskInfo()
- {
- Url = _applicationBaseUrl + "/" + "ViewLocation?latitude="+ latitude+"&longitude="+longitude,
- Height = 350,
- Width = 350,
- Title = "View location",
- },
- };
- }
-
- return Task.FromResult(taskModuleResponse);
- }
-
- ///
- /// Handle task module is submit.
- ///
- /// The turn context.
- /// The task module invoke request value payload.
- /// The cancellation token.
- /// A Task Module Response for the request.
- protected override async Task OnTeamsTaskModuleSubmitAsync(ITurnContext turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken)
- {
- var locationInfo = JObject.FromObject(taskModuleRequest.Data);
- var latitude = (double)locationInfo.ToObject>()?.Latitude;
- var longitude = (double)locationInfo.ToObject>()?.Longitude;
- string user = turnContext.Activity.From.Name;
- string time = turnContext.Activity.LocalTimestamp.ToString();
-
- UserDetail userDetails = new UserDetail {
- CheckInTime = time,
- UserName = user,
- Longitude = longitude,
- Latitude = latitude,
- UserId = turnContext.Activity.From.AadObjectId
- };
-
- await SaveUserDetailsAsync(turnContext,userDetails);
- await turnContext.SendActivityAsync(MessageFactory.Attachment(GetAdaptiveCardForUserLocation(time, user, latitude, longitude)), cancellationToken);
-
- return null;
- }
-
- ///
- /// Sample Adaptive card for check in button.
- ///
- private Attachment GetAdaptiveCardForTaskModule()
- {
- AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion("1.2"))
- {
- Body = new List
- {
- new AdaptiveTextBlock
- {
- Text = "Please click on check in",
- Weight = AdaptiveTextWeight.Bolder,
- Spacing = AdaptiveSpacing.Medium,
- }
- },
- Actions = new List
- {
- new AdaptiveSubmitAction
- {
- Title = "Check in",
- Data = new AdaptiveCardAction
- {
- MsteamsCardAction = new CardAction
- {
- Type = "task/fetch",
- },
- Id="checkin"
- },
- }
- },
- };
-
- return new Attachment()
- {
- ContentType = AdaptiveCard.ContentType,
- Content = card,
- };
- }
-
- ///
- /// Sample Adaptive card for user current location info.
- ///
- private Attachment GetAdaptiveCardForUserLocation(string time, string user, double latitude, double longitude)
- {
- AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion("1.2"))
- {
- Body = new List
- {
- new AdaptiveTextBlock
- {
- Text = $"User name :{user}",
- Weight = AdaptiveTextWeight.Bolder,
- Spacing = AdaptiveSpacing.Medium,
- Wrap = true
- },
- new AdaptiveTextBlock
- {
- Text = $"Check in time: {time}",
- Weight = AdaptiveTextWeight.Bolder,
- Spacing = AdaptiveSpacing.Medium,
- Wrap = true
- }
- },
- Actions = new List
- {
- new AdaptiveSubmitAction
- {
- Title = "View location",
- Data = new AdaptiveCardAction
- {
- MsteamsCardAction = new CardAction
- {
- Type = "task/fetch",
- },
- Id = "viewLocation",
- Latitude = latitude,
- Longitude = longitude
- },
- }
- },
- };
-
- return new Attachment()
- {
- ContentType = AdaptiveCard.ContentType,
- Content = card,
- };
- }
-
- ///
- /// Sample Adaptive card for user's last check in's.
- ///
- private List GetAdaptiveCardForUserLastCheckIn(List userDetails)
- {
- List attachmentList = new List();
-
- foreach (var user in userDetails)
- {
- AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion("1.2"))
- {
- Body = new List
- {
- new AdaptiveTextBlock
- {
- Text = $"User name :{user.UserName}",
- Weight = AdaptiveTextWeight.Bolder,
- Spacing = AdaptiveSpacing.Medium,
- Wrap = true
- },
- new AdaptiveTextBlock
- {
- Text = $"Check in time: {user.CheckInTime}",
- Weight = AdaptiveTextWeight.Bolder,
- Spacing = AdaptiveSpacing.Medium,
- Wrap = true
- }
- },
- Actions = new List
- {
- new AdaptiveSubmitAction
- {
- Title = "View location",
- Data = new AdaptiveCardAction
- {
- MsteamsCardAction = new CardAction
- {
- Type = "task/fetch",
- },
- Id = "viewLocation",
- Latitude = user.Latitude,
- Longitude = user.Longitude
- },
- }
- },
- };
-
- Attachment attachment = new Attachment()
- {
- ContentType = AdaptiveCard.ContentType,
- Content = card,
- };
-
- attachmentList.Add(attachment);
- }
-
- return attachmentList;
- }
-
- // Save user details in json file.
- private async Task SaveUserDetailsAsync(ITurnContext turnContext, UserDetail userDetails)
- {
- var currentUserDetail = await this._UserDetail.GetAsync(turnContext, () => new UserLocationDetail());
- List userDetailsList = new List();
- if (currentUserDetail.UserDetails == null)
- {
- userDetailsList.Add(userDetails);
- currentUserDetail.UserDetails = userDetailsList;
- await this._UserDetail.SetAsync(turnContext, currentUserDetail);
- }
- else if (currentUserDetail.UserDetails.Count == 10)
- {
- currentUserDetail.UserDetails.RemoveAt(0);
- userDetailsList = currentUserDetail.UserDetails;
- userDetailsList.Add(userDetails);
- currentUserDetail.UserDetails = userDetailsList;
- await this._UserDetail.SetAsync(turnContext, currentUserDetail);
- }
- else
- {
- userDetailsList = currentUserDetail.UserDetails;
- userDetailsList.Add(userDetails);
- currentUserDetail.UserDetails = userDetailsList;
- await this._UserDetail.SetAsync(turnContext, currentUserDetail);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/Config.cs b/samples/app-checkin-location/csharp/AppCheckinLocation/Config.cs
new file mode 100644
index 0000000000..2594790b29
--- /dev/null
+++ b/samples/app-checkin-location/csharp/AppCheckinLocation/Config.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace AppCheckinLocation
+{
+ public class ConfigOptions
+ {
+ public string ApplicationBaseUrl { get; set; }
+ public TeamsConfigOptions Teams { get; set; }
+ }
+
+ public class TeamsConfigOptions
+ {
+ public string BotType { get; set; }
+ public string ClientId { get; set; }
+ public string ClientSecret { get; set; }
+ public string TenantId { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/Controllers/BotController.cs b/samples/app-checkin-location/csharp/AppCheckinLocation/Controllers/BotController.cs
deleted file mode 100644
index f5f3f859a9..0000000000
--- a/samples/app-checkin-location/csharp/AppCheckinLocation/Controllers/BotController.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-//
-// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.14.0
-
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Bot.Builder;
-using Microsoft.Bot.Builder.Integration.AspNet.Core;
-using System.Threading.Tasks;
-
-namespace AppCheckinLocation.Controllers
-{
- // This ASP Controller is created to handle a request. Dependency Injection will provide the Adapter and IBot
- // implementation at runtime. Multiple different IBot implementations running at different endpoints can be
- // achieved by specifying a more specific type for the bot constructor argument.
- [Route("api/messages")]
- [ApiController]
- public class BotController : ControllerBase
- {
- private readonly IBotFrameworkHttpAdapter Adapter;
- private readonly IBot Bot;
-
- public BotController(IBotFrameworkHttpAdapter adapter, IBot bot)
- {
- Adapter = adapter;
- Bot = bot;
- }
-
- [HttpPost, HttpGet]
- public async Task PostAsync()
- {
- // Delegate the processing of the HTTP POST to the adapter.
- // The adapter will invoke the bot.
- await Adapter.ProcessAsync(Request, Response, Bot);
- }
- }
-}
diff --git a/samples/app-checkin-location/csharp/AppCheckinLocation/Controllers/Controller.cs b/samples/app-checkin-location/csharp/AppCheckinLocation/Controllers/Controller.cs
new file mode 100644
index 0000000000..b201be3b61
--- /dev/null
+++ b/samples/app-checkin-location/csharp/AppCheckinLocation/Controllers/Controller.cs
@@ -0,0 +1,347 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using AppCheckinLocation.Models;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Teams.Api.Activities;
+using Microsoft.Teams.Apps;
+using Microsoft.Teams.Apps.Activities;
+using Microsoft.Teams.Apps.Annotations;
+using Microsoft.Teams.Cards;
+using System.Collections.Concurrent;
+using System.Text.Json;
+
+namespace AppCheckinLocation.Controllers
+{
+ ///
+ /// Handles location check-in functionality with task modules
+ ///
+ [TeamsController]
+ public class Controller
+ {
+ private readonly string _applicationBaseUrl;
+ private static readonly ConcurrentDictionary _userLocationData = new();
+
+ public Controller(IConfiguration configuration)
+ {
+ _applicationBaseUrl = configuration["ApplicationBaseUrl"] ?? throw new NullReferenceException("ApplicationBaseUrl");
+ }
+
+ ///
+ /// Handles conversation members added event
+ /// Sends welcome message with check-in instructions
+ ///
+ [Conversation.MembersAdded]
+ public async Task OnMembersAdded([Context] ConversationUpdateActivity activity, [Context] IContext.Client client, [Context] Microsoft.Teams.Common.Logging.ILogger log)
+ {
+ foreach (var member in activity.MembersAdded)
+ {
+ if (member.Id != activity.Recipient.Id)
+ {
+ await client.Send("Hello and welcome! With this sample you can checkin your location (use command 'checkin') and view your checked in location(use command 'viewcheckin').");
+ }
+ }
+ }
+
+ ///
+ /// Handles incoming messages
+ ///
+ [Message]
+ public async Task OnMessage([Context] MessageActivity activity, [Context] IContext.Client client, [Context] Microsoft.Teams.Common.Logging.ILogger log)
+ {
+ if (string.IsNullOrEmpty(activity.Text))
+ {
+ var card = GetAdaptiveCardForTaskModule();
+ if (card != null)
+ {
+ await client.Send(card);
+ }
+ return;
+ }
+
+ var text = activity.Text.ToLower().Trim();
+ if (text == "viewcheckin")
+ {
+ var userId = activity.From.AadObjectId ?? activity.From.Id;
+ if (_userLocationData.TryGetValue(userId, out var currentUserDetail) && currentUserDetail.UserDetails != null)
+ {
+ var attachments = GetAdaptiveCardForUserLastCheckIn(currentUserDetail.UserDetails);
+ foreach (var attachment in attachments)
+ {
+ if (attachment != null)
+ {
+ await client.Send(attachment);
+ }
+ }
+ }
+ else
+ {
+ await client.Send("No last check in found");
+ }
+ }
+ else
+ {
+ var card = GetAdaptiveCardForTaskModule();
+ if (card != null)
+ {
+ await client.Send(card);
+ }
+ }
+ }
+
+ ///
+ /// Handles task/fetch invoke - Opens task module for check-in or location view
+ ///
+ [Microsoft.Teams.Apps.Activities.Invokes.Invoke("task/fetch")]
+ public object OnTaskFetch([Context] InvokeActivity activity, [Context] Microsoft.Teams.Common.Logging.ILogger log)
+ {
+ if (activity.Value == null)
+ {
+ return new
+ {
+ task = new
+ {
+ type = "continue",
+ value = new
+ {
+ url = $"{_applicationBaseUrl}/CheckIn",
+ height = 350,
+ width = 350,
+ title = "Check in details"
+ }
+ }
+ };
+ }
+
+ var valueJson = JsonSerializer.Serialize(activity.Value);
+ var taskData = JsonSerializer.Deserialize(valueJson);
+ JsonElement dataProperty = taskData;
+ if (taskData.TryGetProperty("data", out var dataNode))
+ {
+ dataProperty = dataNode;
+ }
+ string? buttonType = null;
+ if (dataProperty.TryGetProperty("id", out var idProperty))
+ {
+ buttonType = idProperty.GetString();
+ }
+
+ if (buttonType == "checkin")
+ {
+ return new
+ {
+ task = new
+ {
+ type = "continue",
+ value = new
+ {
+ url = $"{_applicationBaseUrl}/CheckIn",
+ height = 350,
+ width = 350,
+ title = "Check in details"
+ }
+ }
+ };
+ }
+ else if (buttonType == "viewLocation")
+ {
+ var latitude = dataProperty.GetProperty("latitude").GetDouble();
+ var longitude = dataProperty.GetProperty("longitude").GetDouble();
+ return new
+ {
+ task = new
+ {
+ type = "continue",
+ value = new
+ {
+ url = $"{_applicationBaseUrl}/ViewLocation?latitude={latitude}&longitude={longitude}",
+ height = 350,
+ width = 350,
+ title = "View location"
+ }
+ }
+ };
+ }
+ return new { task = new { type = "continue" } };
+ }
+
+ ///
+ /// Handles task/submit invoke - Saves location data and sends confirmation
+ ///
+ [Microsoft.Teams.Apps.Activities.Invokes.Invoke("task/submit")]
+ public async Task