DTO中是否有用于数据转换的注释



我想创建一个.NET核心REST API,作为两个系统之间的代理。接收系统接收特定值,但发送系统发送不同变体的值。

给定以下示例,接收系统期望以下类型为string的性别密钥

  • 男性
  • 女性
  • 多样化
  • 未定义的

发送系统可以发送";男性";例如";m〃;。如果DTO中的值是"0";m〃;我想把它转换成";男性";。如果密钥不匹配,它应该简单地发回一个400。我知道我可以创建验证属性,但我也可以创建转换属性吗?

也许我可以直接转换属性中的DTO值?

这是我目前的例子,展示了我想要实现的

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class MyValidationAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute
{
public override bool IsValid(object value)
{
if (value != null)
{
string key = value.ToString();
switch (key)
{
case "male":
case "m":
key = "male"; // Transform the value from the DTO here
break;
case "female":
case "f":
key = "female"; // ...
break;

// ...
default:
return false; // Throw 400 because the value didn't match
}
}
return false;
}
public override string FormatErrorMessage(string name) => "... Invalid ...";
}

您可以为DTO中的字段创建一个自定义转换器。假设您的代码中有某种性别枚举,您可以引入自定义属性来登记枚举值的可能值。如DescriptionsAttribute:

using System;
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class DescriptionsAttribute : Attribute
{
public DescriptionsAttribute(params string[] values)
{
Values = values ?? throw new ArgumentNullException(nameof(values));
}
public string[] Values { get; }
}

此属性实现将允许您在枚举中为每个值添加一对多的描述。然后,您可以使用此自定义属性来描述Gender枚举中的字段。我故意没有对Undefined值进行任何描述,因为我计划稍后将其用作后备值,但您可以根据需要进行更改。

public enum Gender
{
[Descriptions("m", "male")]
Male,
[Descriptions("f", "female")]
Female,
[Descriptions("d", "diverse")]
Diverse,
Undefined
}

您还需要一些从枚举字段中提取DescriptionsAttribute值的方法。我已经将该逻辑封装在一个扩展方法中。

using System;
using System.Linq;
using System.Reflection;
public static class EnumExtensions
{
public static T GetAttribute<T>(this Enum value) where T : Attribute
{
string stringValue = value.ToString();
MemberInfo memberInfo = value
.GetType()
.GetMember(stringValue)
.FirstOrDefault();
return memberInfo?
.GetCustomAttributes(typeof(T), false)
.Cast<T>()
.FirstOrDefault();
}
}

完成这些操作后,就可以提供自定义的JsonConverter<Gender>实现。在下面的示例中,我允许不区分大小写的Gender匹配,并在没有适当匹配时将Undefined作为所有情况的回退值。

using System;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
public class GenderConverter : JsonConverter<Gender>
{
public override Gender Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string value = reader.GetString();
foreach (Gender gender in Enum.GetValues(typeof(Gender)))
{
string[] descriptions = gender.GetAttribute<DescriptionsAttribute>()?.Values;
if (descriptions != null &&
descriptions.Any(description => description.Equals(value, StringComparison.OrdinalIgnoreCase)))
{
return gender;
}
}
return Gender.Undefined;
}
public override void Write(Utf8JsonWriter writer, Gender value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}

最后,您只需要使用适当的JsonConverter实现用法来装饰DTO中的Gender属性。

using System.Text.Json.Serialization;
public class SomeDto
{
[JsonConverter(typeof(GenderConverter))]
public Gender Gender { get; set; }
}

最新更新