How to bind a model to a dynamically created class

2020-05-01 09:38发布

问题:

first of all thanks for anyone who's willing to have a look at my problem. I'm pretty new with Nancyfx and I'm having issues with trying to bind a JSON payload to a dynamically created class. I created the class dynamically by following the code in this post - Dynamically create a class in C#

This is my block of code that creates the dynamic class, which I admit is essentially a cut and paste of the code given by danijels

 public static Type CompileResultType(List<Metadata> metadata)
    {            
        TypeBuilder tb = GetTypeBuilder();
        ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

        foreach (var field in metadata)
        {
            if(field.datatype == "String")
            {
               Type datatype = Type.GetType("System.String");
               CreateProperty(tb, field.columnname, datatype);
            }
            if (field.datatype == "int")
            {
                Type datatype = Type.GetType("System.Int32");
                CreateProperty(tb, field.columnname, datatype);
            }
            if(field.datatype == "datetime")
            {
                Type datatype = Type.GetType("System.DateTime");
                CreateProperty(tb, field.columnname, datatype);
            }

        }

        Type objectType = tb.CreateType();

        return objectType;

    }


    private static TypeBuilder GetTypeBuilder()
    {
        var typeSignature = "MyDynamicType";
        var an = new AssemblyName(typeSignature);
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");

        TypeBuilder tb;

        tb = moduleBuilder.DefineType(typeSignature, 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.Public); //changed field attributes from private to public

        PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, System.Reflection.PropertyAttributes.None, propertyType, null);

        MethodBuilder getPropMethdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes); //changed get_ to get

        ILGenerator getIl = getPropMethdBldr.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 }); //changed set_to set

        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(getPropMethdBldr);
        propertyBuilder.SetGetMethod(setPropMthdBldr);
    }

//List<Metadata> metadata is a Dictionary

I then bind it by doing this

  var myType = CompileResultType(metadata);
  var myObject = Activator.CreateInstance(myType);
  var b = this.BindTo(myObject);

I can't have a normal model class for Nancy because I will have too many models just for harvesting the data.

//usual model class
public Class PayloadModel
{
   public string firstName {get; set;}
   public string lastName {get; set;}
}

The reason I have to create the class dynamically is because the JSON payload that I receive varies from having 1 field to having 30. Another reason is that I'd like to keep it as flexible as possible. and by having the above class means that I'm tied down to whatever is in that class. Any advice or direction will be of great help!

回答1:

It sounds like you may be better off using a Dynamic type:

https://gist.github.com/thecodejunkie/5521941

TheCodeJunkie has a custom model binder for Dynamic. You should be able to use this to do:

dynamic model = this.Bind<DynamicDictionary>();



标签: c# json nancy