使用 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
附加信息
我已经尝试了多种解决方法,所以这里是我的一些观察结果。
OkObjectResult
由 ObjectResultExecutor 处理。我尝试将实现复制到我的解决方案中并将其添加到 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);
我还 运行 解决了 .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))] 工作得很好。我不确定最近是否有更新,但我会保留上述解决方案以防万一。
我曾尝试在 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
附加信息
我已经尝试了多种解决方法,所以这里是我的一些观察结果。
OkObjectResult
由 ObjectResultExecutor 处理。我尝试将实现复制到我的解决方案中并将其添加到 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);
我还 运行 解决了 .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))] 工作得很好。我不确定最近是否有更新,但我会保留上述解决方案以防万一。