【问题标题】:Serializing TypeBuilder Lists序列化 TypeBuilder 列表
【发布时间】:2016-11-25 17:50:42
【问题描述】:

我正在创建 WCF Web 服务。

我正在尝试根据从数据库返回的信息创建类型,使用数据构建类型列表,然后将其发回。

但是,我得到了一个

不应使用数据合同名称“MyDynamicType:http://schemas.datacontract.org/2004/07/”键入“MyDynamicType”。考虑使用 DataContractResolver 或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中。 跟踪查看器中的错误。

正在研究异常。它建议将类型添加到[KnownTypes(Type)]。我将如何使用以这种方式创建的类型来执行此操作?

Type Builder 类代码来自 How to dynamically create a class in C#? 进行了非常小的修改。 (即分离创建类型和创建实例。)

网络服务端点

   [OperationContract]
        [WebInvoke(Method = "GET",
            UriTemplate = "/DB/{Q}")]
        List<object> DB(string Q);

Web 服务端点代码

public List<object> DB(string Q)
    {
        List<object> rows = DLL.DB.RunQuery(IQueries.LoadQuery(Q));
        return rows;
    }

运行查询方法

public static List<object> RunQuery(string query)
        {            
            using (SqlConnection connection = new SqlConnection(ConnectionString))
            {
                using (SqlCommand command = new SqlCommand())
                {
                    command.Connection = connection;
                    command.CommandText = query;
                    connection.Open();
                    using (SqlDataAdapter da = new SqlDataAdapter(command))
                    {
                        DataTable dt = new DataTable();
                        da.Fill(dt);

                        Dictionary<string, Type> columns = new Dictionary<string, Type>();
                        foreach (DataColumn dc in dt.Columns)
                        {
                            columns.Add(dc.ColumnName, dc.DataType);
                        }
                        Type customType = MyTypeBuilder.CreateNewObject(columns);                                                
                        List <object> rows = new List<object>();

                        foreach (DataRow dr in dt.Rows)
                        {
                            List<object> row = new List<object>();
                            foreach (DataColumn col in dt.Columns)
                            {
                                object customInstance = MyTypeBuilder.CreateObjectInstance(customType);
                                PropertyInfo pi = customType.GetProperty(col.ColumnName);
                                pi.SetValue(customInstance, dr[col]);
                                row.Add(customInstance);                                
                            }
                            rows.Add(row);
                        }
                        return rows;
                    }
                }
            }
        }

我的类型生成器

public class MyTypeBuilder
{        
    public static object CreateObjectInstance(Type myType)
    {
        var myObject = Activator.CreateInstance(myType);
        return myObject;
    }
    public static Type CreateNewObject(Dictionary<string,Type> values)
    {
        var myType = CompileResultType(values);            
        return myType;
    }
    public static Type CompileResultType(Dictionary<string, Type> values)
    {
        TypeBuilder tb = GetTypeBuilder();
        ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

        // NOTE: assuming your list contains Field objects with fields FieldName(string) and FieldType(Type)
        foreach (var field in values)
            CreateProperty(tb, field.Key, field.Value);

        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 = moduleBuilder.DefineType(typeSignature
                            , TypeAttributes.Public |
                            TypeAttributes.Class |
                            TypeAttributes.AutoClass |
                            TypeAttributes.AnsiClass |
                            TypeAttributes.BeforeFieldInit |
                            TypeAttributes.AutoLayout |
                            TypeAttributes.Serializable
                            , 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);
    }

}

提前致谢。

【问题讨论】:

  • 目前您的问题无法重现。请为您的问题添加更多选项,以便有人可以重现测试您的问题并重现问题。
  • 我不确定如果不输入源代码我还能添加什么。 Web 服务非常基础。查询只是“SELECT * FROM table”。动态类型在链接页面上。我将放入导致它的代码的 sn-ps。并希望对您有所帮助
  • 请在您的问题中添加 TypeBuilder 类代码以及您的小修改。
  • 客户端如何使用?
  • 数据预计以JSON格式返回。用户将按照自己的意愿处理它。

标签: c# web-services wcf


【解决方案1】:

也许您可以拥有一个所有动态类型都继承自的基类。然后,您可以将基类作为放入 knownTypes 装饰器的基类。

【讨论】:

  • 好主意,我还在学习 TypeBuilder 代码。我相信我已经能够设置父级,但到目前为止,仍然没有运气。同样的例外。
  • 你不需要 WebApi 中的装饰器。如果可以,请考虑切换。
【解决方案2】:

这里有一些简单的代码让你开始,

[KnownType(typeof(YourSpecialObject))]
    [DataContract]
    public abstract class BusinessObjectInfo
    {
        [DataMember]
        public int Id { get; set; }

        [DataMember]
        public Byte[] Version { get; set; }

    }

现在是你的特殊对象

[DataContract]
    public class YourSpecialObject: BusinessObjectInfo

现在您的 WCF 应该解析 KnownTypes。至于学习方法,Zombie Explorer 将提供大量有关 .NET 的 IOC/WCF/PRISM 的信息 这是一个相当详尽的 WCF 示例的链接,http://www.codeproject.com/Articles/474212/Zombie-Explorer-An-n-tier-application-from-top-to

【讨论】:

  • 我的问题是我现在不能或不知道如何将装饰器添加到生成的类型中。并且在编译时,类型不存在。所以将 [KnownType] 放在孩子的父母身上是行不通的,因为它不存在。
  • Learning KnownTypes with ExpandoObject 应该涵盖在运行时序列化未知类型需要做的事情。
【解决方案3】:

我会以一种完全不同且更容易的方式来做。我的解决方案基于以下推理:

  1. 您的动态类型,即MyDynamicType 是根据数据创建的 表结构->
  2. MyDynamicType 的实例实际上是行。 ->
  3. MyDynamicType 的实例实际上是键/值集合。 ->
  4. 您不必创建动态类型MyDynamicType。使用简单的字典就足够了。此字典中的键将是列的名称,值将对应于单元格(列的值)。

据我所知,WCF 使用DataContractJsonSerializer 将数据序列化为 JSON 格式,我很确定它可以正确处理字典。另请阅读this 文章。

您还可以使用另一个序列化程序代替默认序列化程序,例如 Newtonsoft Json.Net 序列化程序。请参阅thisthis 问题。

最后,您为什么实际使用 WCF 来创建类似 API 的 REST?我认为 WebApi 更容易使用,除非你有一些特定的理由使用 WCF。

【讨论】:

  • 这几乎是我回来的。我想将数据转换为类的大部分原因,以便它返回的 JSON 格式正确。默认情况下,字典被处理成一个列表,即每个值的 {key:'a', value:'b'}。我会做一个未经检查的答案来解释我做了什么。
  • 至于格式化。对象在 JSON 中被序列化为字典,所以应该没有区别。
【解决方案4】:

不幸的是,即使这里的每个人都向我提供了所有重要信息,我仍然无法真正让 TypeBuilder 正常工作。

但是,我尝试使用 TypeBuilder 的原因是因为我的数据没有像我希望的那样格式化为 JSON。它以

的形式返回

{键:数据名,值:值}

当我真正想要的是

{ 数据名 : 值 }

使用 JSON 和其他一些经验做过 Web Service。我知道 Type 会符合这种布局。不幸的是,数据是未知的,并且可以随时更改,Web 服务必须处理它(不幸的要求)。

即使我无法让 TypeBuilder 以我想要的方式工作。在服务器尝试为我序列化数据之前,我能够使用 Newtonsoft.Json 并序列化 Dictionary 中的数据来获得所需的结果。

感谢大家的帮助。我学到了一些有趣且很棒的新东西,我可能会在其他项目中使用这些东西。

谢谢

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-20
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    相关资源
    最近更新 更多