Azure / azure-functions-host

The host/runtime that powers Azure Functions
https://functions.azure.com
MIT License
1.93k stars 440 forks source link

How to get JSON result from HTTP trigger in Azure Functions v3 to be Pascal Case like previous versions of Azure Functions? #6490

Closed ahawes-clarity closed 6 months ago

ahawes-clarity commented 4 years ago

I have C# code that I am porting from an Azure Function v1 app to v3. I have most of it working now but the JSON I get back from the HTTP triggers is now formatted with Camel Case as opposed to the Pascal Case I was expecting and how it was in previous versions.

I have read lots of things and tried lots of things and I can't get the correct solution.

vijaymarada commented 4 years ago

This is very much needed to one who wanted to migrate from Web API's to function API's. Need to have a both the options as WebAPis have it. I hope this would be addressed soon.

Mostly, Deserialization matters here, if you deserialize with model contains Pascal case properties then the result is in Pascal case only. Seems by default the raw response is always camel case.

prabh-62 commented 4 years ago

@ahawes-clarity You could use a custom OkObjectResult() to keep casing as Pascal Case

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace <namespace>
{
    public class OkDefaultObjectResult : OkObjectResult
    {
        public OkDefaultObjectResult(object value) : base(value)
        {
            Formatters = new FormatterCollection<IOutputFormatter>();
            var settings = new JsonSerializerSettings
            {
                ContractResolver = new DefaultContractResolver()
            };
            Formatters.Add(new NewtonsoftJsonOutputFormatter(settings, System.Buffers.ArrayPool<char>.Shared, new MvcOptions()));
        }
    }
}

Nuget: Microsoft.AspNetCore.Mvc.NewtonsoftJson

// JSON will be Pascal case
return new OkDefaultObjectResult(object)
ahawes-clarity commented 4 years ago

@prabh-62 Thanks.

I did try setting the ContractResolver but I could not get it to work. I am looking for a solution that doesn't require me to change all the existing code. I may try again in the near future if there isn't a better solution.

My current workaround is that I have control on the receiving end and can accommodate the Camel Case JSON. But, there should be flexibility in the JSON output or at least backward compatibility.

prabh-62 commented 4 years ago
pascal_case_function

I had no issues getting PascalCase json back from Azure Function API. What specific error did you encounter?

ahawes-clarity commented 4 years ago

@prabh-62, yes your solution works but it would mean changing code I did not want to change. If I need to I can use your solution.

In my case most of my functions are similar to this, where a handler returns an IActionResult that is then returned by the function. I would need to refactor all the handlers (which return more than just Ok results) to specify the JsonSerializer settings. Like I said, it's not that it can't be done I was just imagining that there should be a better global solution. image

I tried this in the Startup Configure method but it didn't work. That's what prompted my question. image

The issue is how to get PascalCase by default.

mpalese commented 3 years ago

I solved it using the following dependency injection:

using <namespace>;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Serialization;

[assembly: FunctionsStartup(typeof(Startup))]
namespace <namespace>
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddControllers()
            .AddNewtonsoftJson(options =>
            {
                // Use the default property (Pascal) casing
                options.SerializerSettings.ContractResolver = new DefaultContractResolver();
            });
        }
    }
}
nikramakrishnan commented 3 years ago

Using the dependency injection method by @mpalese causes unexpected side effects. Opening the Functions list on Azure portal shows Azure Functions Runtime is unreachable.

tyson-benson commented 3 years ago

It's not a perfect solution for those with existing Azure Function apps, but the dotnet-isolate runtime allows you to configure the JSON serialization options now. So for anyone starting new azure functions or have the budget and energy to upgrade existing ones, there's now first-class support for configuring the serializer exactly how you like it. It's unfortunate that enums have been second class citizens until just now, but better late than never.

Program.cs

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace MyFunctionApp
{
    public class Program
    {
        public static void Main()
        {
            var host = new HostBuilder()
                .ConfigureFunctionsWorkerDefaults()
                .ConfigureServices(services =>
                {
                    services.Configure<JsonSerializerOptions>(options => 
                    {
                        options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
                        options.Converters.Add(new JsonStringEnumConverter());
                    });
                })
                .Build();

            host.Run();
        }
    }
}
thsbrown commented 2 years ago

Just curious if there has been any progress on this.

Thanks in advance!

aishwaryabh commented 6 months ago

Closing this issue since multiple workarounds have been posted. Updating the Program.cs is a good way to have the JSON result be Pascal case