使用 Azure Functions 3.0 中的属性将 Enum 序列化为字符串

Serializing Enum as string using attribute in Azure Functions 3.0

我曾尝试在 Azure Functions 3.0/3.1 应用程序中获取 HTTP 触发器 return 枚举的字符串表示形式,但没有成功。 Core 3.0和Core 3.1我都试过了

鉴于此 class:

public enum TestEnum
{
   TestValue
}

public class TestClass
{ 
   public TestEnum Test { get; set; }
}

我期待这个 HTTP 触发器:

[FunctionName("MyHttpTrigger")]
public static IActionResult Run(
   [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log)
{
    return new OkObjectResult(new TestClass { Test = TestEnum.TestValue });
}

到return{ "test": "TestValue" }。相反,它 returns { "test": 0 }.

在 .Net Core 2 中,我可以使用命名空间 Newtonsoft.Json 中的 [JsonConverter(typeof(StringEnumConverter))] 装饰枚举来实现这一点。这现在不起作用。

我知道 .Net Core 3 已切换到 System.Text.Json-命名空间中的转换器,因此我尝试使用命名空间 System.Text.Json.Serialization 中的 [JsonConverter(typeof(JsonStringEnumConverter))] 装饰相同的枚举。这也没有用。

所有其他类似的问题或者说上面的应该有效,或者像 一样,说通过在 .AddControllers().AddMvc()-chain 中配置 JsonOptions 来解决它,但对于无法运行的函数应用程序。函数运行时负责设置控制器,因此我们无法直接访问进一步的配置 AFAIK。

使用核心工具的准系统 Azure Functions 项目应该可以重现该问题:

func init MyFunctionProj
cd MyFunctionProj
func new --name MyHttpTrigger --template "HttpTrigger"

然后将 http 触发器更改为 return 一个包含枚举的对象。

我的版本:

> func --version
3.0.1975
> dotnet --version
3.1.100

附加信息

我已经尝试了多种解决方法,所以这里是我的一些观察结果。 OkObjectResultObjectResultExecutor 处理。我尝试将实现复制到我的解决方案中并将其添加到 DI 容器中以便我可以调试:

builder.Services.AddSingleton<IActionResultExecutor<ObjectResult>, TestExecutor>();

在链接源代码的第 101 行,选择了格式化程序。有趣的是,当我在此时中断时,选择的格式化程序是 NewtonsoftJsonOutputFormatter!我认为第一个 JsonConverter-属性应该适用于此,但它不适用。

我认为修改可用输出格式化程序列表值得一试。 ActionResultExecutor 使用 DefaultOutputFormatterSelector 进行选择,然后注入 IOptions<MvcOptions> 以获得输出格式化程序。

为了强制 DefaultOutputFormatterSelector 选择不同,我尝试了这个:

class MvcOptionsConfiguration : IPostConfigureOptions<MvcOptions> 
{
...
}

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.ConfigureOptions<MvcOptionsConfiguration>();
    }
}

请注意,常规 IConfigureOptions<T> 无法使用,因为 options.Outputformatters 集合缺少除 Microsoft.AspNetCore.Mvc.WebApiCompatShim.HttpResponseMessageOutputFormatter 之外的所有其他格式化程序,即 st运行ge本身(为什么 b运行d 新 3.0 应用程序使用兼容性垫片?)。

我尝试使用以下方法从集合中删除类型 NewtonsoftJsonOutputFormatter

options.OutputFormatters.RemoveType<NewtonsoftJsonOutputFormatter>();

为此,我必须引用 nuget 包 Microsoft.AspNetCore.Mvc.NewtonsoftJson 来访问该类型,但我引用它时的类型与运行时使用的类型不同。 type.Assembly.CodeBase 用于运行时使用的类型位于 %USERPROFILE%/AppData/Local/AzureFunctionsTools/ 但来自 nuget 的类型位于 Project root/bin/Debug。我以前从未遇到过这种情况。通常,该包将是一个 t运行sient 依赖项,因此我可以引用它而无需自己明确依赖该包,所以我不太确定这里发生了什么。这是正常现象,还是我的环境有问题?

当我以另一种方式删除它时,没关系,它还是被选中了,所以看起来 DefaultOutputFormatterSelector 中注入的 MvcOptions 与我们不一样 MvcOptions可以在启动时配置。

在这一点上,我 运行 没有线索,转向你们。我希望有人能给我指出正确的方向。

请尝试Enum.GetName

   var result = Enum.GetName(typeof(TestEnum), TestEnum.TestValue);

Enum.GetName(Type, Object) Method

我还 运行 解决了 .NET Core 3.1 Function App 的序列化问题。建议我使用此应用程序设置作为临时解决方法:

"FUNCTIONS_V2_COMPATIBILITY_MODE": true

这解决了我的 issue

我能够使用以下代码使它正常工作

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Converters;

[assembly: FunctionsStartup(typeof(Configs.Startup))]

namespace Configs
{
    class Startup : FunctionsStartup
    {
       public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddMvcCore().AddNewtonsoftJson(x =>
            {
                x.SerializerSettings.Converters.Add(new StringEnumConverter());
            });
        }
    }
}

这是在 Azure Functions Core Tools(3.0.2534 提交哈希:bc1e9efa8fa78dd1a138dd1ac1ebef97aac8d78e)和函数运行时版本:3.0.13353.0 上的 netcoreapp3.1 中,包含以下程序包:

<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
<PackageReference Include="AzureFunctions.Autofac" Version="4.0.0" />
<PackageReference Include="CsvHelper" Version="15.0.5" />
<PackageReference Include="Dapper" Version="2.0.35" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.4" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.0.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.7" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.1" />

希望这对某人有所帮助。

我在这里推送了一个示例回购:https://github.com/rawrspace/string-enum-example

编辑:我今天再次使用相同的设置并使用 [JsonConverter(typeof(StringEnumConverter))] 工作得很好。我不确定最近是否有更新,但我会保留上述解决方案以防万一。