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

时间:2019-12-17 09:43:48

标签: c# asp.net-core azure-functions asp.net-core-3.0 asp.net-core-3.1

我尝试在Azure Functions 3.0 / 3.1应用程序中获取HTTP触发器以返回枚举的字符串表示形式,但没有任何运气。我已经尝试了Core 3.0和Core 3.1。

提供此类:

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 });
}

返回{ "test": "TestValue" }。而是返回{ "test": 0 }

在.Net Core 2中,我可以使用命名空间[JsonConverter(typeof(StringEnumConverter))]中的Newtonsoft.Json装饰枚举,以实现此目的。现在这行不通。

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

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

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

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

然后更改http触发器以返回内部带有枚举的对象。

我的版本:

> 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以外的所有其他格式化程序,这本身很奇怪(为什么是全新的3.0使用兼容垫片的应用程序?)。

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

options.OutputFormatters.RemoveType<NewtonsoftJsonOutputFormatter>();

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

当我以另一种方式删除它时,没关系,无论如何它都被选中了,所以似乎MvcOptions中注入的DefaultOutputFormatterSelector与我们可以配置的MvcOptions不同在启动中。

在这一点上,我用尽了线索,转向了你们。我希望有人可以指出正确的方向。

3 个答案:

答案 0 :(得分:4)

我可以使用下面的代码来使它工作

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上的netcoreapp3.1中(3.0.2534提交哈希:bc1e9efa8fa78dd1a138dd1ac1ebef97aac8d78e)和函数运行时版本:3.0.13353.0,带有以下软件包:

<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))]正常工作。我不确定最近是否发生了更新,但是为了以防万一,我将保留上述解决方案。

答案 1 :(得分:2)

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

"FUNCTIONS_V2_COMPATIBILITY_MODE": true

这解决了我的issue

答案 2 :(得分:0)

请尝试Enum.GetName

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

Enum.GetName(Type, Object) Method