Azure / Azure/azure-functions-dotnet-worker
Isolated Http Trigger [FromQuery] bool parameterName cannot serialize Pascal case True or False
- Dominant language
- C#
- Stars
- 466
- Forks
- 215
- Avg merge
- 3d 10h
- Merged PRs (30d)
- 7
Description
#### Repro steps
1. Create a function as follows on a default .net 8 isolated function app:
```
public class Function1
{
public Function1()
{
}
[Function("Function1")]
public IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequest req,
[FromQuery] bool includeSomething = false)
{
return new OkObjectResult($"Did you include something? {includeSomething}");
}
}
```
2. Run function app
3. Send get request to function endpoint: `http://localhost:7107/api/Function1?includeSomething=False`
#### Expected behavior
Expected response body: `Did you include something? False`
#### Actual behavior
Http Error - 500 Internal Server Error occurs
Function app console logs are as follows:
```
[2024-10-17T09:17:56.773Z] Function 'Function1', Invocation id '07a9025c-876f-4f43-a6a1-2421edad600c': An exception was thrown by the invocation.
[2024-10-17T09:17:56.775Z] Result: Function 'Function1', Invocation id '07a9025c-876f-4f43-a6a1-2421edad600c': An exception was thrown by the invocation.
Exception: Microsoft.Azure.Functions.Worker.FunctionInputConverterException: Error converting 1 input parameters for Function 'Function1': Cannot convert input parameter 'includeSomething' to type 'System.Boolean' from type 'System.String'. Error:System.Text.Json.JsonException: 'F' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
[2024-10-17T09:17:56.777Z] ---> System.Text.Json.JsonReaderException: 'F' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
[2024-10-17T09:17:56.780Z] at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
[2024-10-17T09:17:56.783Z] at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)
[2024-10-17T09:17:56.784Z] at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first)
[2024-10-17T09:17:56.786Z] at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
[2024-10-17T09:17:56.799Z] at System.Text.Json.Utf8JsonReader.Read()
[2024-10-17T09:17:56.800Z] at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
[2024-10-17T09:17:56.802Z] --- End of inner exception stack trace ---
[2024-10-17T09:17:56.805Z] at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, JsonReaderException ex)
[2024-10-17T09:17:56.807Z] at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
[2024-10-17T09:17:56.813Z] at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.ContinueDeserialize(ReadBufferState& bufferState, JsonReaderState& jsonReaderState, ReadStack& readStack)
[2024-10-17T09:17:56.817Z] at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsync(Stream utf8Json, CancellationToken cancellationToken)
[2024-10-17T09:17:56.820Z] at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsObjectAsync(Stream utf8Json, CancellationToken cancellationToken)
[2024-10-17T09:17:56.822Z] at Microsoft.Azure.Functions.Worker.Converters.JsonPocoConverter.GetConversionResultFromDeserialization(Byte[] bytes, Type type) in D:\a\_work\1\s\src\DotNetWorker.Core\Converters\JsonPocoConverter.cs:line 66
[2024-10-17T09:17:56.824Z] at Microsoft.Azure.Functions.Worker.Context.Features.DefaultFunctionInputBindingFeature.BindFunctionInputAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Context\Features\DefaultFunctionInputBindingFeature.cs:line 97
[2024-10-17T09:17:56.828Z] at FromQueryTest.DirectFunctionExecutor.ExecuteAsync(FunctionContext context) in C:\Users\momsend\source\repos\FromQueryTest\FromQueryTest\obj\Debug\net8.0\Microsoft.Azure.Functions.Worker.Sdk.Generators\Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator\GeneratedFunctionExecutor.g.cs:line 31
[2024-10-17T09:17:56.831Z] at Microsoft.Azure.Functions.Worker.OutputBindings.OutputBindingsMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a\_work\1\s\src\DotNetWorker.Core\OutputBindings\OutputBindingsMiddleware.cs:line 13
[2024-10-17T09:17:56.834Z] at Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.FunctionsHttpProxyingMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in /mnt/vss/_work/1/s/extensions/Worker.Extensions.Http.AspNetCore/src/FunctionsMiddleware/FunctionsHttpProxyingMiddleware.cs:line 54
[2024-10-17T09:17:56.835Z] at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 91
Stack: at Microsoft.Azure.Functions.Worker.Context.Features.DefaultFunctionInputBindingFeature.BindFunctionInputAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Context\Features\DefaultFunctionInputBindingFeature.cs:line 97
[2024-10-17T09:17:56.837Z] at FromQueryTest.DirectFunctionExecutor.ExecuteAsync(FunctionContext context) in C:\Users\momsend\source\repos\FromQueryTest\FromQueryTest\obj\Debug\net8.0\Microsoft.Azure.Functions.Worker.Sdk.Generators\Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator\GeneratedFunctionExecutor.g.cs:line 31
[2024-10-17T09:17:56.840Z] at Microsoft.Azure.Functions.Worker.OutputBindings.OutputBindingsMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a\_work\1\s\src\DotNetWorker.Core\OutputBindings\OutputBindingsMiddleware.cs:line 13
[2024-10-17T09:17:56.843Z] at Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.FunctionsHttpProxyingMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in /mnt/vss/_work/1/s/extensions/Worker.Extensions.Http.AspNetCore/src/FunctionsMiddleware/FunctionsHttpProxyingMiddleware.cs:line 54
[2024-10-17T09:17:56.845Z] at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 91.
[2024-10-17T09:17:56.862Z] Executed 'Functions.Function1' (Failed, Id=07a9025c-876f-4f43-a6a1-2421edad600c, Duration=217ms)
[2024-10-17T09:17:56.864Z] System.Private.CoreLib: Exception while executing function: Functions.Function1. System.Private.CoreLib: Result: Failure
Exception: Microsoft.Azure.Functions.Worker.FunctionInputConverterException: Error converting 1 input parameters for Function 'Function1': Cannot convert input parameter 'includeSomething' to type 'System.Boolean' from type 'System.String'. Error:System.Text.Json.JsonException: 'F' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
[2024-10-17T09:17:56.866Z] ---> System.Text.Json.JsonReaderException: 'F' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
[2024-10-17T09:17:56.868Z] at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
[2024-10-17T09:17:56.870Z] at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)
[2024-10-17T09:17:56.873Z] at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first)
[2024-10-17T09:17:56.875Z] at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
[2024-10-17T09:17:56.877Z] at System.Text.Json.Utf8JsonReader.Read()
[2024-10-17T09:17:56.878Z] at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
[2024-10-17T09:17:56.880Z] --- End of inner exception stack trace ---
[2024-10-17T09:17:56.882Z] at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, JsonReaderException ex)
[2024-10-17T09:17:56.883Z] at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
[2024-10-17T09:17:56.886Z] at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.ContinueDeserialize(ReadBufferState& bufferState, JsonReaderState& jsonReaderState, ReadStack& readStack)
[2024-10-17T09:17:56.889Z] at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsync(Stream utf8Json, CancellationToken cancellationToken)
[2024-10-17T09:17:56.890Z] at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsObjectAsync(Stream utf8Json, CancellationToken cancellationToken)
[2024-10-17T09:17:56.890Z] at Microsoft.Azure.Functions.Worker.Converters.JsonPocoConverter.GetConversionResultFromDeserialization(Byte[] bytes, Type type) in D:\a\_work\1\s\src\DotNetWorker.Core\Converters\JsonPocoConverter.cs:line 66
[2024-10-17T09:17:56.891Z] at Microsoft.Azure.Functions.Worker.Context.Features.DefaultFunctionInputBindingFeature.BindFunctionInputAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Context\Features\DefaultFunctionInputBindingFeature.cs:line 97
[2024-10-17T09:17:56.892Z] at FromQueryTest.DirectFunctionExecutor.ExecuteAsync(FunctionContext context) in C:\Users\momsend\source\repos\FromQueryTest\FromQueryTest\obj\Debug\net8.0\Microsoft.Azure.Functions.Worker.Sdk.Generators\Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator\GeneratedFunctionExecutor.g.cs:line 31
[2024-10-17T09:17:56.893Z] at Microsoft.Azure.Functions.Worker.OutputBindings.OutputBindingsMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a\_work\1\s\src\DotNetWorker.Core\OutputBindings\OutputBindingsMiddleware.cs:line 13
[2024-10-17T09:17:56.894Z] at Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.FunctionsHttpProxyingMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in /mnt/vss/_work/1/s/extensions/Worker.Extensions.Http.AspNetCore/src/FunctionsMiddleware/FunctionsHttpProxyingMiddleware.cs:line 54
[2024-10-17T09:17:56.895Z] at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 91
[2024-10-17T09:17:56.897Z] at Microsoft.Azure.Functions.Worker.Handlers.InvocationHandler.InvokeAsync(InvocationRequest request) in D:\a\_work\1\s\src\DotNetWorker.Grpc\Handlers\InvocationHandler.cs:line 88
Stack: at Microsoft.Azure.Functions.Worker.Context.Features.DefaultFunctionInputBindingFeature.BindFunctionInputAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\Context\Features\DefaultFunctionInputBindingFeature.cs:line 97
[2024-10-17T09:17:56.898Z] at FromQueryTest.DirectFunctionExecutor.ExecuteAsync(FunctionContext context) in C:\Users\momsend\source\repos\FromQueryTest\FromQueryTest\obj\Debug\net8.0\Microsoft.Azure.Functions.Worker.Sdk.Generators\Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator\GeneratedFunctionExecutor.g.cs:line 31
[2024-10-17T09:17:56.899Z] at Microsoft.Azure.Functions.Worker.OutputBindings.OutputBindingsMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a\_work\1\s\src\DotNetWorker.Core\OutputBindings\OutputBindingsMiddleware.cs:line 13
[2024-10-17T09:17:56.900Z] at Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.FunctionsHttpProxyingMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in /mnt/vss/_work/1/s/extensions/Worker.Extensions.Http.AspNetCore/src/FunctionsMiddleware/FunctionsHttpProxyingMiddleware.cs:line 54
[2024-10-17T09:17:56.901Z] at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 91
[2024-10-17T09:17:56.902Z] at Microsoft.Azure.Functions.Worker.Handlers.InvocationHandler.InvokeAsync(InvocationRequest request) in D:\a\_work\1\s\src\DotNetWorker.Grpc\Handlers\InvocationHandler.cs:line 88.
```
#### Known workarounds
The obvious workaround is the use lowercase first letter true or false e.g.
`http://localhost:7107/api/Function1?includeSomething=false`
This will work.
To support pascal case we can use a string input parameter and parse it:
```
[Function("StringInputParam")]
public IActionResult StringInputParam([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequest req,
[FromQuery] string includeSomething)
{
bool convertedToBool = bool.Parse(includeSomething);
return new OkObjectResult($"Function2 Did you include something? {convertedToBool}");
}
```
#### Related information
The issue is the same whether you run the application locally or deployed in azure.
Can be replicated on a default .net isolated azure function app
Program.cs:
```
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services =>
{
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
})
.Build();
host.Run();
```
host.json:
```
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
},
"enableLiveMetricsFilters": true
}
}
}
```
local.settings.json:
```
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
}
}
```
Azure Logic Apps that use the Http Swagger action or the API Management action will automatically provide a "False" or "True" to query parameters coded as boolean, so I have to support both camel and pascal case when migrating to the isolated worker.
This is mostly just frustrating but there are simple ways to work around it.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by tracing query-parameter conversion through src/DotNetWorker.Core/Converters/JsonPocoConverter.cs and src/DotNetWorker.Core/Context/Features/DefaultFunctionInputBindingFeature.cs, using the supplied isolated .NET 8 reproduction as the failing case. Identify the existing input-conversion tests, then verify that Pascal-case query values True and False are accepted for bool parameters without breaking lowercase values or other conversions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, csharp
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100