[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属性?
谢谢
阿南德
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核心中(不确定它)它也无济于事,因为你试图使用派生的元数据类型用于重命名基类型属性的类,这不是元数据类型信息的预期用途.即以下工作开箱即用(完整.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不允许派生类型元数据信息来修改基类型契约?你不得不问问牛顿软件,但猜测包括:
> Json.NET是一个基于合同的序列化程序,其中每种类型都通过属性指定其合同.并不是说一种类型可以重写第二种类型的合同.
> DataContractJsonSerializer和DataContractSerializer的工作方式相同.
>这样做会违反Liskov substitution principle.
那么,你有什么选择?
>您可以序列化DTO代替您的LegalEntity,并使用类似automapper之类的内容进行映射:
public class LegalEntityDTO { [JsonProperty(PropertyName = "LegalEntityId")] public long Id { get; set; } [JsonProperty(PropertyName = "LegalEntityName")] public string Name { get; set; } }
>您可以使用必要的逻辑为LegalEntity创建custom JsonConverter
.
>您可以使用必要的逻辑创建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);
要将合同解析程序安装到Asp.Net Core,请参阅here.
注意我使用完整的.Net 4.5.1编写了这个,所以它只是一个原型. .Net Core使用different reflection API,但如果您按照here所述安装System.Reflection.TypeExtensions,我相信它应该可行.