无服务器Azure Function使用SignalROutput能否返回多个SignalRMessageAction?
我有一个搭载CosmosDBTrigger的无服务器Azure Function,需要向SignalR客户端推送通知。Cosmos触发器会返回IEnumerable类型的条目集合,这些条目可能分属不同客户端。我尝试返回List<SignalRMessageAction>,但遭遇序列化错误。请问通过[SignalROutput]能否从Function返回多个条目?
代码示例
public class UpdatesAvailableFunction { [Function(nameof(UpdatesAvailableFunction))] [SignalROutput(HubName = "serverless", ConnectionStringSetting = "AzureSignalRConnectionString")] public List<SignalRMessageAction> UpdatesAvailable( [CosmosDBTrigger( databaseName: "%DatabaseName%", collectionName: "%ContainerName%", ConnectionStringSetting = "ConnectionString", LeaseCollectionName = "leases", LeaseCollectionPrefix = "UpdatesAvailable")] IReadOnlyList<BrowserFeedNotification> input) { return input.Select(x => new SignalRMessageAction("updatesAvailable") { UserId = x.UserId }).ToList(); } }
报错信息
[2022-11-04T11:01:32.319Z] Executed 'Functions.UpdatesAvailableFunction' (Failed, Id=b7ebfc4a-40cc-48ef-9f31-52c7c414daf3, Duration=15342ms)
[2022-11-04T11:01:32.320Z] System.Private.CoreLib: Exception while executing function: Functions.UpdatesAvailableFunction. Microsoft.Azure.WebJobs.Extensions.SignalRService: Unable to convert JObject to valid output binding type, check parameters.
解决方案
[SignalROutput]绑定支持返回多个消息,但不能直接返回List<SignalRMessageAction>,可以通过以下两种方式解决:
方法1:返回数组类型
将函数返回值改为SignalRMessageAction[]数组,绑定可以正确解析数组中的每个条目为独立的SignalR消息:
public class UpdatesAvailableFunction { [Function(nameof(UpdatesAvailableFunction))] [SignalROutput(HubName = "serverless", ConnectionStringSetting = "AzureSignalRConnectionString")] public SignalRMessageAction[] UpdatesAvailable( [CosmosDBTrigger( databaseName: "%DatabaseName%", collectionName: "%ContainerName%", ConnectionStringSetting = "ConnectionString", LeaseCollectionName = "leases", LeaseCollectionPrefix = "UpdatesAvailable")] IReadOnlyList<BrowserFeedNotification> input) { return input.Select(x => new SignalRMessageAction("updatesAvailable") { UserId = x.UserId }).ToArray(); } }
方法2:使用ICollector输出参数(推荐)
将SignalR输出作为函数的参数,使用ICollector<SignalRMessageAction>来逐个添加消息,这种方式更符合Azure Functions的绑定设计逻辑:
public class UpdatesAvailableFunction { [Function(nameof(UpdatesAvailableFunction))] public void UpdatesAvailable( [CosmosDBTrigger( databaseName: "%DatabaseName%", collectionName: "%ContainerName%", ConnectionStringSetting = "ConnectionString", LeaseCollectionName = "leases", LeaseCollectionPrefix = "UpdatesAvailable")] IReadOnlyList<BrowserFeedNotification> input, [SignalROutput(HubName = "serverless", ConnectionStringSetting = "AzureSignalRConnectionString")] ICollector<SignalRMessageAction> signalRMessages) { foreach (var item in input) { signalRMessages.Add(new SignalRMessageAction("updatesAvailable") { UserId = item.UserId }); } } }
错误原因
SignalR输出绑定的序列化逻辑对集合类型支持有限,List<T>无法被正确识别为多个消息条目,而数组或ICollector<T>是绑定原生支持的多消息输出方式。
内容的提问来源于stack exchange,提问作者Greg B

