[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
。在 问题 #1349:为 dotnetcore 添加对 ModelMetadataType 的支持,就像以前版本中支持的 MetadataTypeAttribute 实现对其支持的请求已被拒绝。
System.ComponentModel.DataAnnotations.MetadataTypeAttribute
,尽管存在这个答案中描述的一些限制,但是即使这个属性存在于.Net core中(不确定)它也不会帮助你,因为你正在尝试使用派生类的元数据类型来重命名“基类型”中的属性,这不是元数据类型信息的预期用途。 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,但猜测包括:
DataContractJsonSerializer
和
DataContractSerializer
的工作方式相同。
来代替您的 LegalEntity
,并使用类似
automapper的东西来映射:
public class LegalEntityDTO
{
[JsonProperty(PropertyName = "LegalEntityId")]
public long Id { get; set; }
[JsonProperty(PropertyName = "LegalEntityName")]
public string Name { get; set; }
}
JsonConverter
创建一个 自定义
LegalEntity
。
,类似于此处,例如以下内容:
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 中,请参阅此处
。 注意我使用完整的 .Net 4.5.1 编写了此内容,因此它只是一个原型。 .Net Core 使用
不同的反射 API,但是如果您按照此处所述安装System.Reflection.TypeExtensions,我相信它应该可以工作。
了解更多信息) services.AddControllers().AddNewtonsoftJson();
using Newtonsoft.Json;
namespace YourDbDataNamespace
{
[MetadataType(typeof(UserMetadata))]
public partial class User {}
public class UserMetadata
{
[JsonProperty(PropertyName = "LegalEntityId")]
int Id { get; set; }
[JsonIgnore]
public string PasswordHash { get; set; }
}
}
某些类首先使用数据库生成:
public class Entity<T>
{
public T Id { get; set; }
public string Name { get; set; }
}
创建MetadataBasedConverter.cs
using System.Reflection;
using System.Text.Json;
namespace Mynamespace.JsonConverter;
public class MetadataBasedConverter : JsonConverter<object>
{
private PropertyInfo[] GetCombinedProperties(Type type)
{
var metadataAttr = type.GetCustomAttribute<MetadataTypeAttribute>();
var metadataProps = metadataAttr?.MetadataClassType.GetProperties() ?? Array.Empty<PropertyInfo>();
var originalProps = type.GetProperties();
return originalProps.Union(metadataProps).ToArray();
}
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using (JsonDocument doc = JsonDocument.ParseValue(ref reader))
{
object result = (object)Activator.CreateInstance(typeToConvert)!;
var combinedProps = GetCombinedProperties(typeToConvert);
foreach (JsonProperty prop in doc.RootElement.EnumerateObject())
{
foreach (var property in combinedProps)
{
var metaAttr = property.GetCustomAttribute<JsonPropertyNameAttribute>();
var nameToUse = metaAttr?.Name ?? property.Name;
if (prop.Name.Equals(nameToUse, StringComparison.OrdinalIgnoreCase))
{
var actualProperty = typeToConvert.GetProperty(property.Name);
if (actualProperty != null)
{
object? value = JsonSerializer.Deserialize(prop.Value.GetRawText(), actualProperty.PropertyType);
actualProperty.SetValue(result, value);
break;
}
}
}
}
return result;
}
}
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
{
writer.WriteStartObject();
var combinedProps = GetCombinedProperties(value.GetType());
foreach (var property in combinedProps)
{
var metaAttr = property.GetCustomAttribute<JsonPropertyNameAttribute>();
var nameToUse = metaAttr?.Name ?? property.Name;
var actualProperty = value.GetType().GetProperty(property.Name);
if (actualProperty != null)
{
writer.WritePropertyName(nameToUse);
JsonSerializer.Serialize(writer, actualProperty.GetValue(value), actualProperty.PropertyType, options);
}
}
writer.WriteEndObject();
}
public override bool CanConvert(Type typeToConvert)
{
return typeof(object).IsAssignableFrom(typeToConvert);
}
}
创建一个分部类,并添加 MetadataTypeAttribute 和 MetadataBasedConverter
[MetadataType(typeof(Metadata))]
[JsonConverter(typeof(MetadataBasedConverter))]
public partial class Entity<T>
{
internal sealed class Metadata
{
[JsonPropertyName("LegalEntityId")]
public long Id { get; set; }
[JsonPropertyName("LegalEntityName")]
public string Name { get; set; }
}
}