【问题标题】:Azure WebJob ProcessQueueMessage fails to read CloudQueueMessageAzure WebJob ProcessQueueMessage 无法读取 CloudQueueMessage
【发布时间】:2016-03-03 17:57:42
【问题描述】:

总之,我有一个 Azure Web 作业通过 WebJobs SDK 的 ProcessQueueMessage 机制链接到 CloudQueue,使用 CloudQueueMessage 参数类型。当通过QueueTrigger 触发时,这会给我一个FunctionInvocationException


详情

项目使用AddMessageAsync方法成功添加到CloudQueue

await queue.AddMessageAsync(new CloudQueueMessage(JsonConvert.SerializeObject(myObject)));

并作为我的对象的预期 JSON 表示形式出现在队列中(来自 Cloud Explorer 中的消息文本预览):

{"EmailAddress":"example@mail.com",
 "Subject":"Test",
 "TemplateId":"00-00-00-00-00",
 "Model":{"PropertyName1":"Test1","PropertyName2":"Test2"}
 }

但是,当ProcessQueueMessage方法被触发时:

public static async void ProcessQueueMessage(
    [QueueTrigger(queueName)] CloudQueueMessage message, TextWriter log)

...我收到FunctionInvocationException:

Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: Functions.ProcessQueueMessage ---> System.InvalidOperationException: Exception binding parameter 'message' ---> System.ArgumentNullException: String reference not set to an instance of a String.
 Parameter name: s
 at System.Text.Encoding.GetBytes(String s)
 at Microsoft.WindowsAzure.Storage.Queue.CloudQueueMessage.get_AsBytes() in c:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\Common\Queue\CloudQueueMessage.Common.cs:line 146
 at Microsoft.Azure.WebJobs.Host.PropertyHelper.CallPropertyGetter[TDeclaringType,TValue](Func`2 getter, Object this)
 at Microsoft.Azure.WebJobs.Host.PropertyHelper.GetValue(Object instance)
 at Microsoft.Azure.WebJobs.Host.Bindings.BindingDataProvider.GetBindingData(Object value)
 at Microsoft.Azure.WebJobs.Host.Queues.Triggers.UserTypeArgumentBindingProvider.UserTypeArgumentBinding.BindAsync(IStorageQueueMessage value, ValueBindingContext context)
 at Microsoft.Azure.WebJobs.Host.Queues.Triggers.QueueTriggerBinding.<BindAsync>d__0.MoveNext()
 --- End of stack trace from previous location where exception was thrown ---
 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 at Microsoft.Azure.WebJobs.Host.Triggers.TriggeredFunctionBinding`1.<BindCoreAsync>d__7.MoveNext()
 --- End of inner exception stack trace ---
 at Microsoft.Azure.WebJobs.Host.Executors.DelayedException.Throw()
 at Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.<ExecuteWithWatchersAsync>d__31.MoveNext()
 --- End of stack trace from previous location where exception was thrown

这似乎表明 message 参数未能将 JSON 读入 CloudQueueMessage 对象......但它似乎不是我可以控制的。

有人对为什么会发生这种情况有任何建议吗?


版本信息

Microsoft.Azure.Webjobs 1.1.1

WindowsAzure.Storage 6.2.2-预览版

DNX 4.5.1

背景

Troy Hunt - Web Job primer

MSDN - How to... article

【问题讨论】:

    标签: azure azure-webjobs azure-webjobssdk azure-storage-queues


    【解决方案1】:

    更改您的 ProcessQueueMessage 以接受一个字符串(这是您实际传递给 CloudQueuMessage 的内容),然后将其反序列化为您的对象:

    public static async void ProcessQueueMessage(
        [QueueTrigger(queueName)] string message, TextWriter log)
    {
       JsonConvert.DeserializeObject<YourObjectType>(json);
    }
    

    或者事件更好,如果这是一个 POCO 对象,那么你所要做的就是使用它来代替:

    public static async void ProcessQueueMessage
    (
       [QueueTrigger(queueName)] YourObjectType message, 
       TextWriter log
    )
    {      //....    }
    

    更新: 虽然在 CloudQueueMessage 对象中获取整个内容会很好,但要获取在 CloudQueueMessage 中发送的属性,您可以将以下参数添加到 webjob 方法:

    public static async void ProcessQueueMessage(
            [QueueTrigger(queueName)] string logMessage, 
            DateTimeOffset expirationTime,
            DateTimeOffset insertionTime,
            DateTimeOffset nextVisibleTime,
            string id,
            string popReceipt,
            int dequeueCount,
            string queueTrigger,
            CloudStorageAccount cloudStorageAccount,
            TextWriter logger)
        {
            logger.WriteLine(
                "logMessage={0}\n" +
            "expirationTime={1}\ninsertionTime={2}\n" +
                "nextVisibleTime={3}\n" +
                "id={4}\npopReceipt={5}\ndequeueCount={6}\n" +
                "queue endpoint={7} queueTrigger={8}",
                logMessage, expirationTime,
                insertionTime,
                nextVisibleTime, id,
                popReceipt, dequeueCount,
                cloudStorageAccount.QueueEndpoint,
                queueTrigger);
        }
    

    【讨论】:

    • 感谢@zaid。您的两个建议都避免了该错误。使用CloudQueueMessage 也可以让我访问消息的属性(例如InsertionTime)并且应该是有效的。从引用的 MSDN 链接:“除了字符串,参数可能是字节数组、CloudQueueMessage 对象或您定义的 POCO。”
    • @richaux,这些属性可以添加到方法参数中。您在发送方对 CloudQueueMessage 进行排队,但在接收方的方法参数上获取内容和元数据,请参阅上面引用的 Azure 文档 URL 中的“获取队列或队列消息元数据”部分。为了完整起见,我将更新我的答案。
    • 感谢您的示例。在github docs 中也找到了一些进一步的背景。
    • 请注意,CloudQueueMessage 不是列出的受支持的输入绑定类型之一(请参阅here),它仅支持作为输出绑定。我认为它可能/应该是输入绑定,但目前不是。
    • 感谢@mathewc -- tbh 我没有发现快速参考澄清了问题:) 它在页面顶部将CloudQueueMessage 列为QueueTrigger 绑定的选项,并且2.1 节中的示例也使用了它。 article by Tom D referenced from the Quick Ref 也有 CloudQueueMessage 作为选项(但没有示例)。这不是问题:POCO 和字符串选项非常适合我当前的需求。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多