如何使用 ASP.Net 核心模型元数据属性


[Table("LegalEntity")]
[ModelMetadataType(typeof(LegalEntityMeta))]
public class LegalEntity : Entity<long>
{
}
public class LegalEntityMeta
{
[JsonProperty(PropertyName = "LegalEntityId")]
public long Id { get; set; }
[JsonProperty(PropertyName = "LegalEntityName")]
public string Name { get; set; }
}

在启动中.cs....

services
.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
})
.AddAutoMapper(typeof(Startup))
.AddMvcCore()
.AddJsonFormatters()
.AddApiExplorer();

我的期望是看到具有属性 legalEntityId 和 legalEntityName 的 json,但生成的 json 具有 id 和名称作为属性。 有人可以帮我如何更改 json 属性吗? 谢谢 阿南德

Json.NET 目前不支持Microsoft.AspNetCore.Mvc.ModelMetadataTypeAttribute。 在问题 #1349:添加对 dotnetcore 的 ModelMetadataType 的支持,就像以前版本中支持的 MetadataTypeAttribute 一样,实现对它的支持的请求被拒绝。

Json.NET 确实支持System.ComponentModel.DataAnnotations.MetadataTypeAttribute,尽管本答案中描述了一些限制,但是即使此属性存在于 .Net core 中(不确定是否存在),它也无济于事,因为您正在尝试使用派生类的元数据类型来重命名基类型中的属性,这不是元数据类型信息的预期用法。 即以下内容开箱即用(在完整的 .Net 中):

[System.ComponentModel.DataAnnotations.MetadataType(typeof(EntityMeta))]
public class Entity<T>
{
public T Id { get; set; }
public string Name { get; set; }
}
public class EntityMeta
{
[JsonProperty(PropertyName = "LegalEntityId")]
public long Id { get; set; }
[JsonProperty(PropertyName = "LegalEntityName")]
public string Name { get; set; }
}

但以下没有:

[System.ComponentModel.DataAnnotations.MetadataType(typeof(LegalEntityMeta))]
public class LegalEntity : Entity<long>
{
}
public class LegalEntityMeta
{
[JsonProperty(PropertyName = "LegalEntityId")]
public long Id { get; set; }
[JsonProperty(PropertyName = "LegalEntityName")]
public string Name { get; set; }
}

为什么 Json.NET 不允许派生类型元数据信息修改基本类型协定? 你将不得不问Newtonsoft,但猜测包括:

  1. Json.NET 是基于协定的序列化程序,其中每种类型都通过属性指定其协定。 不打算让一种类型重写另一种类型的合约。

  2. DataContractJsonSerializerDataContractSerializer的工作方式相同。

  3. 这样做会违反利斯科夫替代原则。

那么,您有什么选择?

  1. 你可以序列化一个DTO来代替你的LegalEntity,并使用类似自动映射器的东西来映射:

    public class LegalEntityDTO
    {
    [JsonProperty(PropertyName = "LegalEntityId")]
    public long Id { get; set; }
    [JsonProperty(PropertyName = "LegalEntityName")]
    public string Name { get; set; }
    }
    
  2. 您可以使用必要的逻辑为LegalEntity创建自定义JsonConverter

  3. 您可以使用必要的逻辑创建自定义合约解析程序,类似于此处的逻辑,例如以下内容:

    using System.Reflection;
    public class ModelMetadataTypeAttributeContractResolver : DefaultContractResolver
    {
    public ModelMetadataTypeAttributeContractResolver()
    {
    // Default from https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonSerializerSettingsProvider.cs
    this.NamingStrategy = new CamelCaseNamingStrategy();
    }
    const string ModelMetadataTypeAttributeName = "Microsoft.AspNetCore.Mvc.ModelMetadataTypeAttribute";
    const string ModelMetadataTypeAttributeProperty = "MetadataType";
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
    var properties = base.CreateProperties(type, memberSerialization);
    var propertyOverrides = GetModelMetadataTypes(type)
    .SelectMany(t => t.GetProperties())
    .ToLookup(p => p.Name, p => p);
    foreach (var property in properties)
    {
    var metaProperty = propertyOverrides[property.UnderlyingName].FirstOrDefault();
    if (metaProperty != null)
    {
    var jsonPropertyAttribute = metaProperty.GetCustomAttributes<JsonPropertyAttribute>().FirstOrDefault();
    if (jsonPropertyAttribute != null)
    {
    property.PropertyName = jsonPropertyAttribute.PropertyName;
    // Copy other attributes over if desired.
    }
    }
    }
    return properties;
    }
    static Type GetModelMetadataType(Attribute attribute)
    {
    var type = attribute.GetType();
    if (type.FullName == ModelMetadataTypeAttributeName)
    {
    var property = type.GetProperty(ModelMetadataTypeAttributeProperty);
    if (property != null && property.CanRead)
    {
    return property.GetValue(attribute, null) as Type;
    }
    }
    return null;
    }
    static Type[] GetModelMetadataTypes(Type type)
    {
    var query = from t in type.BaseTypesAndSelf()
    from a in t.GetCustomAttributes(false).Cast<System.Attribute>()
    let metaType = GetModelMetadataType(a)
    where metaType != null
    select metaType;
    return query.ToArray();
    }
    }
    public static partial class TypeExtensions
    {
    public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
    {
    while (type != null)
    {
    yield return type;
    type = type.BaseType;
    }
    }
    }
    

    示例 .Net 小提琴。

    要直接序列化,请执行以下操作:

    var settings = new JsonSerializerSettings
    {
    ContractResolver = new ModelMetadataTypeAttributeContractResolver(),
    };
    var json = JsonConvert.SerializeObject(entity, Formatting.Indented, settings);
    

    要将合约解析器安装到 Asp.Net Core 中,请参阅此处。

    请注意,我使用完整的.Net 4.5.1编写了此内容,因此它只是一个原型。 .Net Core使用不同的反射API,但是如果你安装System.Reflection.TypeExtensions,我相信它应该可以工作。

切换到Newtonsoft.Json会有所帮助:

  1. Add nuget package Microsoft.AspNetCore.Mvc.Newtonsoft.Json

  2. 在启动中.cs -> 配置服务(有关详细信息,请阅读 https://www.ryadel.com/en/use-json-net-instead-of-system-text-json-in-asp-net-core-3-mvc-projects/)

    服务业。AddControllers()。AddNewtonsoftJson();

  3. 使用 System.Text.Json.Serialization 替换并使用 MetadataType 而不是 ModelMetadataType:

    using Newtonsoft.Json;
    namespace YourDbDataNamespace
    {
    [MetadataType(typeof(UserMetadata))]
    public partial class User {}
    public class UserMetadata
    {
    [JsonProperty(PropertyName = "LegalEntityId")]
    int Id { get; set; }
    [JsonIgnore]
    public string PasswordHash { get; set; }
    }
    }
    

最新更新