I understood that anonymous types are marked private by the compiler and the properties are read-only. Is there a way to serialize them to xml (without deserialize) ? It wor
My first post to contribute to a website that always always helps a lot
Bellow is a full solution that can be used with .net core (tested using 3.1)
just call ConvertAnonymousToType.Convert("MyNewType", target, out Type newType)
The return will be an object that you can use to return inside a controller or to serialize manually (System.Xml.Serialization.XmlSerializer).
Using the object as a return Inside a controller:
1. configure the service (Startup.cs > ConfigureServices > services.AddMvcCore(options => options.OutputFormatters.Add(new XmlSerializerOutputFormatter());),
2. Target Action: use [FormatFilter] and [Route(".......{format}")],
3. Return the object
If any extra anonymous type needs to compose the reply (Metadata, Resultset, etc) DynamicTypeBuilder.CreateNewObject can be used to do service :)
Thanks again
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace Configuration
{
public static class DynamicTypeBuilder
{
public static object CreateNewObject(string typeName, Dictionary properties, out Type newType)
{
newType = CompileResultType(typeName, properties);
return Activator.CreateInstance(newType);
}
public static Type CompileResultType(string typeName, Dictionary properties)
{
TypeBuilder tb = GetTypeBuilder(typeName);
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
//Add properties
properties.ToList().ForEach(p => CreateProperty(tb, p.Key, p.Value));
//Created Type with properties
Type objectType = tb.CreateType();
return objectType;
}
//Create Type with an standard configuration
private static TypeBuilder GetTypeBuilder(string typeName)
{
string assemblyName = typeName + "InternalAssembly";
var an = new AssemblyName(assemblyName);
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeName,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
null);
return tb;
}
private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] { propertyType });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
public static class ConvertAnonymousToType
{
public static object Convert(string typeName, object target, out Type newType)
{
var properties = GetProperties(target);
newType = DynamicTypeBuilder.CompileResultType(typeName, properties);
return Convert(newType, target);
}
public static object Convert(Type type, object target)
{
if (target.GetType().Name == typeof(List<>).Name)
{
var newListType = typeof(List<>).MakeGenericType(type);
var newList = Activator.CreateInstance(newListType);
MethodInfo addMethod = newList.GetType().GetMethod("Add");
((IList