如何使用ASP.Net核心ModelMetadata属性 [英] How to use ASP.Net core ModelMetadata attribute

查看:111
本文介绍了如何使用ASP.Net核心ModelMetadata属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[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中....

In the Startup.cs ....

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

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

My expectation is to see json with attributes legalEntityId and legalEntityName yet the json produced has id and name as attributes. Can someone pleas help me with how to change the json attributes? Thanks Anand

推荐答案

Json.NET当前不支持 问题#1349:添加对dotnetcore的ModelMetadataType的支持,例如以前版本中支持的MetadataTypeAttribute 对其实施支持的请求被拒绝.

Json.NET currently has no support for Microsoft.AspNetCore.Mvc.ModelMetadataTypeAttribute. In Issue #1349: Add support for ModelMetadataType for dotnetcore like supported MetadataTypeAttribute in previous versions a request to implement support for it was declined.

Json.NET确实支持此答案中有一些限制,但是即使存在此属性在.Net core中(不确定是这样),这对您无济于事,因为您正尝试使用派生类的元数据类型来将属性重命名为基本类型,这不是有意元数据类型信息的用法. IE.现成的以下作品(完整的.Net):

Json.NET does support System.ComponentModel.DataAnnotations.MetadataTypeAttribute, albeit with some limitations described in this answer, however even if this attribute were present in .Net core (not sure it is) it would not help you, because you are trying to use the metadata type of a derived class to rename the properties in a base type, which is not an intended usage for metadata type information. I.e. the following works out of the box (in full .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,但猜测包括:

Why doesn't Json.NET allow derived type metadata information to modify base type contracts? You would have to ask Newtonsoft, but guesses include:

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

  1. Json.NET is a contract-based serializer where each type specifies its contract through attributes. It's not intended that one type could rewrite the contract of a second type.

DataContractJsonSerializerDataContractSerializer的工作方式相同.

这样做会违反李斯科夫替代原则.

那么,您有什么选择?

  1. 您可以序列化 DTO 代替您的LegalEntity,并使用类似于的问题,以便在随后之间进行映射:

  1. You could serialize a DTO in place of your LegalEntity, and use something like automapper to map between then:

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

    [JsonProperty(PropertyName = "LegalEntityName")]
    public string Name { get; set; }
}

  • 您可以为自定义JsonConverter LegalEntity具有必要的逻辑.

  • You could create a custom JsonConverter for LegalEntity with the necessary logic.

    您可以创建自定义合同解析器具有必要的逻辑,类似于此处,例如以下内容:

    You could create a custom contract resolver with the necessary logic, similar to the one here, for instance the following:

    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小提琴.

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

    To serialize directly, do:

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

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

    To install the contract resolver into Asp.Net Core see here.

    请注意,我是使用完整的.Net 4.5.1编写的,因此它只是一个原型. .Net Core使用不同的反射API ,但是,如果您安装此处所述>我相信它会起作用.

    Note I wrote this using full .Net 4.5.1 so it is just a prototype. .Net Core uses a different reflection API, however if you install System.Reflection.TypeExtensions as described here I believe it should work.

    这篇关于如何使用ASP.Net核心ModelMetadata属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆