using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace Microsoft.AspNetCore.Mvc
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ModelMetadataTypeAttribute : Attribute
public ModelMetadataTypeAttribute(Type type)
throw new ArgumentNullException();
public Type MetadataType { get; private set; }
namespace Question47164280
using Microsoft.AspNetCore.Mvc;
public T Id { get; set; }
public string Name { get; set; }
[Microsoft.AspNetCore.Mvc.ModelMetadataType(typeof(LegalEntityMeta))]
public class LegalEntity : Entity<long>
public string LegalData { get; set; }
public class LegalEntityMeta
[JsonProperty(PropertyName = "LegalEntityId")]
public long Id { get; set; }
[JsonProperty(PropertyName = "LegalEntityName")]
public string Name { get; set; }
[JsonProperty(PropertyName = "LegalEntityDataValue")]
public string LegalData { get; set; }
public static void Test()
var entity = new LegalEntity
var settings = new JsonSerializerSettings
ContractResolver = new ModelMetadataTypeAttributeContractResolver { },
var json = JsonConvert.SerializeObject(entity, Formatting.Indented, settings);
public class ModelMetadataTypeAttributeContractResolver : DefaultContractResolver
public ModelMetadataTypeAttributeContractResolver()
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;
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;
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)
public static partial class TypeExtensions
public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
public static void Main()
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public class AssertionFailedException : System.Exception
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
public static class Assert
public static void IsTrue(bool value)
public static void IsTrue(bool value, string message)
throw new AssertionFailedException(message ?? "failed");