Azure Function - ServiceBusTrigger - Exception Bin

2019-08-23 11:28发布

问题:

I have an Azure Function that is subscribed to an Azure Service Bus Queue - however before the function is able to trigger an exception is thrown by the run time before it reaches any of my code.

Exception while executing function: <functionName>. Microsoft.Azure.WebJobs.Host: Exception binding parameter 'message'. System.Private.CoreLib: Unable to translate bytes [9A] at index 60 from specified code page to Unicode.

In this instance I am not in control of the incoming message (it's actually being sent from an Azure DevOps Subscription) so I need to be able to make the function more flexible so that this exception isn't thrown.

My function looks like this:

[FunctionName("FunctionName")]
public static async Task Run(
    [ServiceBusTrigger("Queue", Connection = "ConnectionString")] byte[] message)

I have seen other question that suggest moving away from using a Message or BrokeredMessage object and to use byte[] instead (and write your own encoding to deal with the issue) but this hasn't worked for me. It appears that the runtime is still trying and failing to do something to the message before it reaches my function.

How can I avoid this issue?


I will leave this question open because I haven't yet found how to solve this problem - however I have now seen how to fix it in my instance. The messages that I've been struggling to handle are messages that are delivered by AzureDevOps ServiceHooks. If I go into the settings (when creating or editing) the service hooks found here -> https://.visualstudio.com//_settings/serviceHooks

There is a tick box that I missed. In order for an Azure Function to be able to process the message this tick box needs to selected. I.e. you want to send as a non-serialised string. This must be because whatever client sits in-between my function and the queue can't handle a .Net serialised message.

Tl;Dr -> If you have this issue make sure this option above is selected

GitHub Issue Tracking the problem

回答1:

The issue is that the Functions library is looking at the message type instead of the type specified in the function when deciding whether or not to decode it. Since Devops is sending the message as type application/json, the library is trying, and failing to decode it using UTF8.

For now, choosing "send as non-serialized string" is a valid workaround. The issue can be tracked on Github: https://github.com/Azure/azure-webjobs-sdk/issues/2234

Relevant code (Microsoft.Azure.WebJobs.ServiceBus.Triggers.UserTypeArgumentBindingProvider)

 private static TInput GetBody(Message message, ValueBindingContext context)
        {
            if (message.ContentType == ContentTypes.ApplicationJson) //This is looking at the message type
            {
                string contents;

                contents = StrictEncodings.Utf8.GetString(message.Body);

                try
                {
                    return JsonConvert.DeserializeObject<TInput>(contents, Constants.JsonSerializerSettings);
                }
                catch (JsonException e)
                {
                    // Easy to have the queue payload not deserialize properly. So give a useful error. 
                    string msg = string.Format(
    @"Binding parameters to complex objects (such as '{0}') uses Json.NET serialization. 
    1. Bind the parameter type as 'string' instead of '{0}' to get the raw values and avoid JSON deserialization, or
    2. Change the queue payload to be valid json. The JSON parser failed: {1}
    ", typeof(TInput).Name, e.Message);
                    throw new InvalidOperationException(msg);
                }
            }
            else
            {
                return message.GetBody<TInput>();
            }
        }
    }