OAuth登录后Teams通知完成失败,旧代码报错求助
问题背景
原本正常运行的Teams应用搁置后重新启用,OAuth登录重定向后出现异常:认证完成后的前端JS代码原本会回到OnTeamsMessagingExtensionSubmitActionAsync活动,但现在触发OnInvokeActivityAsync,随后触发全局错误处理程序,抛出异常信息:"Error reading string. Unexpected token: StartObject. Path 'state'."
前端核心代码:
var userId = document.getElementById("UserId").value; var tenantId = document.getElementById("TenantId").value; var isSuccess = document.getElementById("IsSuccessful").value; microsoftTeams.initialize(() => { if (isSuccess == "True") microsoftTeams.authentication.notifySuccess({ "UserID": userId }); else microsoftTeams.authentication.notifyFailure(); });
全局错误处理代码:
public AdapterWithErrorHandler(IConfiguration configuration, ILogger<BotFrameworkHttpAdapter> logger) : base(configuration, logger) { OnTurnError = async (turnContext, exception) => { logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}"); await turnContext.SendActivityAsync("The bot encountered an error or bug."); await turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError"); }; }
触发异常时,turnContext.Activity.Value的JSON结构:
{ "state": { "UserID": "12345678-362b-4942-a5b0-cda1198c8223" }, "commandId": "exportContent", "commandContext": "compose", "requestId": "db113a08fde34abbb1d4b5da8e5f385c", "context": { "theme": "default" }, "data": { "TenantId": "12345678-92aa-4476-9dcf-3953b4efcec2", "TeamId": "19:123456788945ce8fb07a532d8b71ee@thread.tacv2", "ChannelId": "19:1234567825451ea6115bba2ab70322@thread.tacv2", "MessageId": "1234567866366", "Op": "channel" } }
当前环境:Teams JS SDK 1.5.2,C#项目使用Microsoft.Bot.Builder.Integration.AspNet.Core 4.19.3。
错误原因
Teams JS SDK 1.5.2调用notifySuccess传入对象时,Teams会将该对象封装为JSON对象放在state字段中返回,但Bot Framework SDK 4.19.3的默认反序列化逻辑要求state是字符串类型,类型不匹配导致反序列化失败,触发全局错误。
解决方案
方案1:修改前端代码,将state转为字符串
把notifySuccess的参数转为JSON字符串,让后端可以正常解析:
if (isSuccess == "True") microsoftTeams.authentication.notifySuccess(JSON.stringify({ "UserID": userId })); else microsoftTeams.authentication.notifyFailure();
后端处理时,再将state字符串反序列化为对象即可。
方案2:后端自定义解析逻辑,适配state对象
如果不想修改前端,可以在OnInvokeActivityAsync中手动解析Value的JSON结构,绕过默认的反序列化限制:
protected override async Task<InvokeResponse> OnInvokeActivityAsync(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken) { if (turnContext.Activity.Name == "composeExtension/submitAction") { // 手动序列化再反序列化为自定义类型 var valueJson = JsonConvert.SerializeObject(turnContext.Activity.Value); var submitActionData = JsonConvert.DeserializeObject<CustomSubmitActionData>(valueJson); // 提取state中的UserID,执行原有的提交逻辑 var response = await OnTeamsMessagingExtensionSubmitActionAsync(turnContext, submitActionData.Data, cancellationToken); return CreateInvokeResponse(response); } return await base.OnInvokeActivityAsync(turnContext, cancellationToken); } // 自定义类匹配返回的JSON结构 public class CustomSubmitActionData { public UserState State { get; set; } public string CommandId { get; set; } public string CommandContext { get; set; } public string RequestId { get; set; } public ContextInfo Context { get; set; } public SubmitData Data { get; set; } } public class UserState { public string UserID { get; set; } } public class ContextInfo { public string Theme { get; set; } } public class SubmitData { public string TenantId { get; set; } public string TeamId { get; set; } public string ChannelId { get; set; } public string MessageId { get; set; } public string Op { get; set; } }
方案3:升级Bot Framework SDK版本
Bot Framework SDK的新版本(如4.22及以上)已修复state字段的类型兼容问题,支持直接解析对象类型的state。升级到稳定新版本后,无需修改代码即可恢复正常逻辑。
内容的提问来源于stack exchange,提问作者Steve Peschka

