gpt4 book ai didi

c# - 如何在 Web API 请求的 FromBody ViewModel 中使用具有 EnumMember 属性的枚举?

转载 作者:行者123 更新时间:2023-12-03 23:10:35 24 4
gpt4 key购买 nike

我正在尝试使用 [FromBody] 在 ASP.NET Core Web API 项目中实现 HttpPost 方法查看模型和枚举。过去,使用 [FromBody] 绑定(bind) View 模型属性运作良好。

在我的特定场景中,我想提供一个 JSON 端点,在其中将给定值转换为具有不同名称的 C# 枚举。这个例子应该解释我想要实现的目标:

    public enum WeatherEnum    {        [EnumMember(Value = "good")]        Good,        [EnumMember(Value = "bad")]        Bad    }

Internally, I want to use WeatherEnum.Good and WeatherEnum.Bad and the consumer of my endpoint wants to use lowercase values. Therefore, I'm trying to map the values which will be passed in the JSON body to my Enum representation.

I've read about the EnumMember attribute and StringEnumConverter. I've created a minimal example from the new ASP.NET Core Web API 3.0 template (You need to add these NuGet packages Microsoft.Extensions.DependencyInjection, Microsoft.AspNetCore.Mvc.NewtonsoftJson, and Newtonsoft.Json)

ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddNewtonsoftJson(json =>
{
json.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
json.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
});
services.AddControllers();
}

WheatherForecastController :
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Runtime.Serialization;

namespace WebAPITestEnum.Controllers
{
[ApiController]
[Produces("application/json")]
[Consumes("application/json")]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
[HttpPost]
[Route("method")]
public ActionResult<QueryResponseClass> TestMethod([FromBody] QueryRequestClass request)
{
// do something with the request ...

return new QueryResponseClass()
{
Foo = "bar"
};
}
}

public class QueryRequestClass
{
public WeatherEnum Weather { get; set; }
}

public class QueryResponseClass
{
public string Foo { get; set; }
}


[JsonConverter(typeof(StringEnumConverter))]
public enum WeatherEnum
{
[EnumMember(Value = "good")]
Good,

[EnumMember(Value = "bad")]
Bad
}
}

我的端点是从 Postman 调用的,其正文如下
{
"Weather": "good"
}

导致此错误:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|245d862e-4ab01d3956be5f60.",
"errors": {
"$.Weather": [
"The JSON value could not be converted to WebAPITestEnum.Controllers.WeatherEnum. Path: $.Weather | LineNumber: 1 | BytePositionInLine: 18."
]
}
}

感觉就像我只在某处遗漏了一行。可以通过 FromBody 在 View 模型中使用枚举属性?

最佳答案

我发布的问题中的代码确实有效。在我的最小示例中,我忘记设置 [Required]枚举上的属性。但是,如果没有设置值,那么我遇到了该方法应该如何 react 的问题。它正确地(?)假设了枚举的默认值,这不是我想要的。

我四处寻找,找到了这个解决方案https://stackoverflow.com/a/54206737/225808枚举是可空的,这并不理想,但至少我有验证,如果缺少值,我会收到一条错误消息

更新/警告 : 你可以使用上面提到的解决方案,但是!似乎代码会编译,但会从问题中抛出错误消息。我进一步将我自己的项目与测试项目进行了比较,并注意到我还需要两个包含 2 个 NuGet 包才能使一切正常运行:

  • Microsoft.AspNetCore.Mvc.NewtonsoftJson
  • Newtonsoft.Json

  • 似乎 Microsoft.AspNetCore.Mvc.NewtonsoftJson 覆盖了默认行为?如果有人能对此有所了解,我将不胜感激。

    更新 2 :我还更新了引用的 so 解决方案来解析基于 EnumMemberAttribute 的枚举值:
    [JsonConverter(typeof(CustomStringToEnumConverter<WeatherEnum>))]
    public enum WeatherEnum
    {
    [EnumMember(Value = "123good")]
    Good,

    [EnumMember(Value = "bad")]
    Bad
    }

    public class CustomStringToEnumConverter<T> : StringEnumConverter
    {
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
    if (string.IsNullOrEmpty(reader.Value?.ToString()))
    {
    return null;
    }
    try
    {
    return EnumExtensions.GetValueFromEnumMember<T>(reader.Value.ToString());
    }
    catch (Exception ex)
    {
    return null;
    }
    }
    }

    public static class EnumExtensions
    {
    public static T GetValueFromEnumMember<T>(string value)
    {
    var type = typeof(T);
    if (!type.IsEnum) throw new InvalidOperationException();
    foreach (var field in type.GetFields())
    {
    var attribute = Attribute.GetCustomAttribute(field,
    typeof(EnumMemberAttribute)) as EnumMemberAttribute;
    if (attribute != null)
    {
    if (attribute.Value == value)
    return (T)field.GetValue(null);
    }
    else
    {
    if (field.Name == value)
    return (T)field.GetValue(null);
    }
    }
    throw new ArgumentException($"unknow value: {value}");
    }
    }

    关于c# - 如何在 Web API 请求的 FromBody ViewModel 中使用具有 EnumMember 属性的枚举?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58270237/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com