CSharp · Console
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters;
using System.IO;
using System.Data;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
// https://stackoverflow.com/questions/47164280/how-to-use-asp-net-core-modelmetadata-attribute#comment81278862_47164280
namespace Microsoft.AspNetCore.Mvc
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ModelMetadataTypeAttribute : Attribute
{
public ModelMetadataTypeAttribute(Type type)
{
if (type == null)
{
throw new ArgumentNullException();
}
MetadataType = type;
}
public Type MetadataType { get; private set; }
}
}
namespace Question47164280
{
using Microsoft.AspNetCore.Mvc;
public class Entity<T>
{
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; }
}
class TestClass
{
public static void Test()
{
var entity = new LegalEntity
{
Id = 101010101,
Name = "my name",
};
var settings = new JsonSerializerSettings
{
ContractResolver = new ModelMetadataTypeAttributeContractResolver { /* NamingStrategy = new CamelCaseNamingStrategy() */ },
};
var json = JsonConvert.SerializeObject(entity, Formatting.Indented, settings);
Console.WriteLine(json);
}
}
public class ModelMetadataTypeAttributeContractResolver : DefaultContractResolver
{
public ModelMetadataTypeAttributeContractResolver()
{
// Default from https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Formatters.Json/JsonSerializerSettingsProvider.cs
//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;
}
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine();
try
{
TestClass.Test();
}
catch (Exception ex)
{
Console.WriteLine("Failed with unhandled exception: ");
Console.WriteLine(ex);
throw;
}
}
}
public class AssertionFailedException : System.Exception
{
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
}
public static class Assert
{
public static void IsTrue(bool value)
{
IsTrue(value, "failed");
}
public static void IsTrue(bool value, string message)
{
if (value == false)
throw new AssertionFailedException(message ?? "failed");
}
}
}