In summary, I have an Azure Web Job linked to a CloudQueue
via the WebJobs SDK's ProcessQueueMessage
mechanism, using the CloudQueueMessage
parameter type. This gives me a FunctionInvocationException
when triggered via QueueTrigger
.
Detail
The item is added successfully to the CloudQueue
using the AddMessageAsync
method:
await queue.AddMessageAsync(new CloudQueueMessage(JsonConvert.SerializeObject(myObject)));
And appears on the queue as the expected JSON representation of my object (from Message Text Preview in Cloud Explorer):
{"EmailAddress":"example@mail.com",
"Subject":"Test",
"TemplateId":"00-00-00-00-00",
"Model":{"PropertyName1":"Test1","PropertyName2":"Test2"}
}
However, when the ProcessQueueMessage
method is triggered:
public static async void ProcessQueueMessage(
[QueueTrigger(queueName)] CloudQueueMessage message, TextWriter log)
... I get a 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
This seems to suggest that the message
parameter is failing to read the JSON into the CloudQueueMessage
object ... but it doesn't appear that it's something I have control of.
Does anyone have any suggestions as to why this might be happening?
Version Info
Microsoft.Azure.Webjobs 1.1.1
WindowsAzure.Storage 6.2.2-preview
DNX 4.5.1
Background
change your ProcessQueueMessage to accept a string (which is what you actually passing to the CloudQueuMessage), then take that and deserialize it to your object:
public static async void ProcessQueueMessage(
[QueueTrigger(queueName)] string message, TextWriter log)
{
JsonConvert.DeserializeObject<YourObjectType>(json);
}
Or event better, if this is a POCO object then all you have to do is to use that instead:
public static async void ProcessQueueMessage
(
[QueueTrigger(queueName)] YourObjectType message,
TextWriter log
)
{ //.... }
Update: Although it would be nice to get the entire thing in a CloudQueueMessage object, but to get the properties that is sent in the CloudQueueMessage you can add the following parameters to the webjob method:
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);
}