47164280/how-to-use-asp-net-core-modelmetadata-attribute

CSharp · Console

/Program.cs

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");
        }
    }
}
;