在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,我相信它应该可行.