发送主动消息时无法获取Twilio短信状态回调



我正在尝试使用bot框架跟踪我发送的消息的短信传递状态。我正在使用Twilio,并发送主动消息。现在我正试图用twilio状态回调来做到这一点

这与这个问题类似,我尝试过这种方法,但我无法使其发挥作用。我已经在TwiML应用程序上添加了我的url,但它没有启动。我已经检查了两次和三次,我怀疑这个url在某种程度上被忽略了,或者没有通过我当前的设置。我没有收到任何关于主动消息的回调,也没有收到机器人发送给用户的回复。然而,流程运行良好,我可以回复并从机器人中获得正确的响应;方法1">

方法2:我也尝试过对Twilio适配器进行一些轻微的修改,以便能够在创建消息之前添加回调。(我更改了它,使其使用自定义的客户端包装器,在创建twilio资源时添加我的回调url(这确实起到了部分作用:当我回复来自我的机器人的消息时,我会得到状态回调。但是,由于主动消息是使用默认适配器发送的,因此我不会对初始消息进行回调。

方法3:最后,我还在发送主动消息时尝试使用TwilioAdapter,但由于某种原因,一旦我发送活动,TurnContext就会被丢弃,因此我无法保存状态或执行任何后续操作。这让我相信twilio适配器不打算以这种方式使用(不能用于主动消息(,但如果有必要,我愿意探索这条路径。

这是经过修改的Twilio适配器:

public class TwilioAdapterWithErrorHandler : TwilioAdapter
{
private const string TwilioNumberKey = "TwilioNumber";
private const string TwilioAccountSidKey = "TwilioAccountSid";
private const string TwilioAuthTokenKey = "TwilioAuthToken";
private const string TwilioValidationUrlKey = "TwilioValidationUrl";
public TwilioAdapterWithErrorHandler(IConfiguration configuration, ILogger<TwilioAdapter> logger, TwilioAdapterOptions adapterOptions = null)
: base(
new TwilioClientWrapperWithCallback(new TwilioClientWrapperOptions(configuration[TwilioNumberKey], configuration[TwilioAccountSidKey], configuration[TwilioAuthTokenKey], new Uri(configuration[TwilioValidationUrlKey]))), adapterOptions, logger)
{
OnTurnError = async (turnContext, exception) =>
{
// Log any leaked exception from the application.
logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");
Task[] tasks = {
// Send a message to the user
turnContext.SendActivityAsync("We're sorry but this bot encountered an error when processing your answer."),
// Send a trace activity, which will be displayed in the Bot Framework Emulator
turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError")
};
Task all = Task.WhenAll(tasks); //task with the long running tasks
await Task.WhenAny(all, Task.Delay(5000)); //wait with a timeout
};
}
}

修改的客户端包装:

public class TwilioClientWrapperWithCallback : TwilioClientWrapper
{
public TwilioClientWrapperWithCallback(TwilioClientWrapperOptions options) : base(options) { }
public async override Task<string> SendMessageAsync(TwilioMessageOptions messageOptions, CancellationToken cancellationToken)
{
var createMessageOptions = new CreateMessageOptions(messageOptions.To)
{
ApplicationSid = messageOptions.ApplicationSid,
MediaUrl = messageOptions.MediaUrl,
Body = messageOptions.Body,
From = messageOptions.From,
};
createMessageOptions.StatusCallback = new System.Uri("https://myApp.ngrok.io/api/TwilioSms/SmsStatusUpdated");
var messageResource = await MessageResource.CreateAsync(createMessageOptions).ConfigureAwait(false);
return messageResource.Sid;
}
}

最后,这里是我总结的发送主动消息的代码:

[HttpPost("StartConversationWithSuperBill/{superBillId:long}")]
[HttpPost("StartConversationWithSuperBill/{superBillId:long}/Campaign/{campaignId:int}")]
public async Task<IActionResult> StartConversation(long superBillId, int? campaignId)
{
ConversationReference conversationReference = this.GetConversationReference("+17545517768");
//Start a new conversation.
await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, async (turnContext, token) =>
{
await turnContext.SendActivityAsync("proactive message 1");
//this code was edited for brevity. Here I would start a new dialog that would cascade into another, but the end result is the same, as soon as a message is sent, the turn context is disposed.
await turnContext.SendActivityAsync("proactive message 2"); //throws ObjectDisposedException
}, default(CancellationToken));
var result = new { status = "Initialized fine!" };
return new JsonResult(result);
}
private ConversationReference GetConversationReference(string targetNumber)
{
string fromNumber = "+18632704234";
return new ConversationReference
{
User = new ChannelAccount { Id = targetNumber, Role = "user" },
Bot = new ChannelAccount { Id = fromNumber, Role = "bot" },
Conversation = new ConversationAccount { Id = targetNumber },
//ChannelId = "sms",
ChannelId = "twilio-sms", //appparently when using twilio adapter we need to set this. if using TwiML app and not using Twilio Adapter, use the above. Otherwise the frameworks interprets answers from SMS as new conversations instead.
ServiceUrl = "https://sms.botframework.com/",
};
}

(我可以看到,我可以只调用create conversation reference并进行两次回调,每个消息一次,但在我的实际代码中,我创建了一个对话框,发送一条消息,然后调用另一个对话框来启动另一条消息(

编辑2:

一些澄清:

方法2中,我使用了两个适配器,这是关于使用twilio适配器的代码示例和文档所建议的。启动主动消息的控制器使用默认适配器的实例(与此类似(,TwilioController(获取twilio传入消息的控制器(使用TwilioAdapterWithErrorHandler。

方法3中,我排除了默认适配器,并且两个控制器都使用TwilioAdapterWithErrorHandler。

编辑3:

这是一个有问题的小额回购。

我找到了解决这个问题的方法,围绕方法3,通过更改我用于ContinueConversion的重载。替换此:

//Start a new conversation.
await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, async (turnContext, token) =>

有了这个:

//Start a new conversation.
var twilioAdapter = (TwilioAdapterWithErrorHandler)_adapter;
await twilioAdapter.ContinueConversationAsync(_appId, conversationReference, async (context, token) =>

这样,上下文就不会被处理,我可以使用twilio适配器来处理主动消息,并对所有消息进行状态回调。

最新更新