Azure / azure-functions-dotnet-worker

Azure Functions out-of-process .NET language worker
MIT License
419 stars 181 forks source link

WriteAsJsonAsync throws exception when using NewtonsoftJson serializer #2735

Open CSharpBender opened 2 days ago

CSharpBender commented 2 days ago

Description

In Azure Functions isolated model an exception is thrown when overriding the serializer from ConfigureFunctionsWebApplication() and response.WriteAsJsonAsync() is used: System.InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead. I followed the Microsoft guide for migrating an in-process Azure function to the isolated model which clearly states that I need to override the Json serializer in ConfigureFunctionsWebApplication and use services.AddMvc().AddNewtonsoftJson(). While searching for a fix to my issue I found issue1 and issue2

Steps to reproduce

1) Create an Azure Function

 [Function("MyIsolatedFunction")]
        public async Task<HttpResponseData> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestData request)
        { 
            var response = request.CreateResponse(HttpStatusCode.OK);
            await response.WriteAsJsonAsync(new { Name="Error"});
            return response;
 }

2) Override Json serializer in Program.cs

public static class Program
{
    public static void Main(string[] args)
    {
        var host = new HostBuilder()
                .ConfigureFunctionsWebApplication((IFunctionsWorkerApplicationBuilder builder) =>
                {
                    builder.Services.Configure<WorkerOptions>(workerOptions =>
                    {
                        //<PackageReference Include="Microsoft.Azure.Core.NewtonsoftJson" Version="1.0.0" />
                        var settings = NewtonsoftJsonObjectSerializer.CreateJsonSerializerSettings();
                        settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                        settings.NullValueHandling = NullValueHandling.Ignore;

                        workerOptions.Serializer = new NewtonsoftJsonObjectSerializer(settings);
                    });
                })
                .ConfigureServices(services =>
                {
                    services.AddApplicationInsightsTelemetryWorkerService();
                    services.ConfigureFunctionsApplicationInsights();
                    services.ConfigureSerializer();
                })
                .Build();

        host.Run();
    }
    public static IServiceCollection ConfigureSerializer(this IServiceCollection services)
    {
        services.AddMvc().AddNewtonsoftJson();
        return services;
    }
}

3) Exception is thrown: System.InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.

4) If I remove this line the exception disappears but the serialization is wrong because I'm using NewtonsoftJson attributes. workerOptions.Serializer = new NewtonsoftJsonObjectSerializer(settings); also this breaks the swagger definition. Another workaround is to serialize the object myself and use the WriteAsync method instead of WriteAsJsonAsync