gpt4 book ai didi

c# - 如何使用 ASP.Net core ModelMetadata 属性

转载 作者:行者123 更新时间:2023-12-04 01:40:32 28 4
gpt4 key购买 nike

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

在 Startup.cs ....

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

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

最佳答案

Json.NET 目前不支持 Microsoft.AspNetCore.Mvc.ModelMetadataTypeAttribute .在 Issue #1349: Add support for ModelMetadataType for dotnetcore like supported MetadataTypeAttribute in previous versions拒绝对其实现支持的请求。

Json.NET 确实支持 System.ComponentModel.DataAnnotations.MetadataTypeAttribute ,尽管在 this answer 中描述了一些限制,但是即使此属性存在于 .Net 核心中(不确定是否存在),它也无济于事,因为您正在尝试使用派生类的元数据类型来重命名属性 在基类型,这不是元数据类型信息的预期用途。 IE。以下开箱即用(完整的 .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. 这样做会违反 Liskov substitution principle .

那么,您有哪些选择?

  1. 您可以序列化 DTO代替您的 LegalEntity,并使用类似 的东西在它们之间映射:

    public class LegalEntityDTO
    {
    [JsonProperty(PropertyName = "LegalEntityId")]
    public long Id { get; set; }

    [JsonProperty(PropertyName = "LegalEntityName")]
    public string Name { get; set; }
    }
  2. 您可以创建一个 custom JsonConverter具有必要逻辑的 LegalEntity

  3. 您可以创建一个 custom contract resolver具有必要的逻辑,类似于 here ,例如以下内容:

    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 fiddle .

    要直接序列化,请执行:

    var settings = new JsonSerializerSettings
    {
    ContractResolver = new ModelMetadataTypeAttributeContractResolver(),
    };

    var json = JsonConvert.SerializeObject(entity, Formatting.Indented, settings);

    要将契约(Contract)解析器安装到 Asp.Net Core 中,请参阅 here .

    请注意,我是使用完整的 .Net 4.5.1 编写的,因此它只是一个原型(prototype)。 .Net Core 使用 different reflection API , 但是如果你安装 System.Reflection.TypeExtensions如所述here我相信它应该有效。

关于c# - 如何使用 ASP.Net core ModelMetadata 属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47164280/

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