如何使用ASP.Net核心ModelMetadata属性

Ana*_*and 2 json.net data-annotations asp.net-core-2.0

[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; }
}
Run Code Online (Sandbox Code Playgroud)

在Startup.cs中...

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

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

dbc*_*dbc 5

Json.NET当前不支持Microsoft.AspNetCore.Mvc.ModelMetadataTypeAttribute。在问题#1349中:添加对dotnetcore的ModelMetadataType的支持,例如以前版本中支持的MetadataTypeAttribute,但拒绝实现对它的支持的请求。

Json.NET确实支持System.ComponentModel.DataAnnotations.MetadataTypeAttribute,尽管此答案中描述了一些限制,但是即使此属性存在于.Net核心中(不确定是否存在),它也无济于事,因为您正尝试使用派生的元数据类型。类来重命名基本类型的属性,这不是元数据类型信息的预期用法。即以下作品开箱即用(完整的.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; }
}
Run Code Online (Sandbox Code Playgroud)

但是以下内容却没有:

[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; }
}
Run Code Online (Sandbox Code Playgroud)

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

  1. Json.NET是基于契约的序列化器,其中每种类型都通过属性指定其契约。并不是说一种类型可以重写另一种类型的合同。

  2. DataContractJsonSerializerDataContractSerializer以相同的方式工作。

  3. 这样做会违反Liskov替代原则

那么,您有什么选择呢?

  1. 您可以序列化一个DTO来代替您的DTOLegalEntity,然后使用方法在之后之间进行映射:

    public class LegalEntityDTO
    {
        [JsonProperty(PropertyName = "LegalEntityId")]
        public long Id { get; set; }
    
        [JsonProperty(PropertyName = "LegalEntityName")]
        public string Name { get; set; }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您可以创建一个自定义JsonConverterLegalEntity必要逻辑。

  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;
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    样本.Net小提琴

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

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

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

    请注意,我是使用完整的.Net 4.5.1编写的,因此它只是一个原型。.Net Core使用不同的反射API,但是,如果您按此处所述安装System.Reflection.TypeExtensions,我认为它应该可以工作。


归档时间:

查看次数:

3498 次

最近记录:

7 年 前