2016-07-21 121 views
3

我创建了一个WCF Web服务。序列化类型构建器列表

我想创建一个基于从数据库返回的信息类型,与数据建立一个类型列表,并发送回来。

但是,我得到的数据合同名称的

类型“MyDynamicType 'MyDynamicType:http://schemas.datacontract.org/2004/07/' 预计不会。考虑使用DataContractResolver或将任何不知道的类型静态添加到已知类型的列表中 - 例如,使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型的列表中。跟踪查看器中出现 错误。

研究异常。它建议将该类型添加到[KnownTypes(Type)]。我如何用这种方式创建一个类型?

类型生成器类代码从 How to dynamically create a class in C#?进行了很小的修改。 (即分离创建类型和实例的创建。)

Web服务端点

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

} 

在此先感谢。

+0

当前你的问题的反复无常。请在您的问题中添加更多选项,以便某人可以重复测试您的问题并重现问题。 –

+0

我不确定除了放入源代码之外还可以添加哪些内容。 Web服务是非常基础的。该查询只是“SELECT * FROM table”。动态类型位于链接页面上。我将放入导致它的代码片段。并希望有所帮助 – Seige

+0

请在您的问题中添加'TypeBuilder'类代码并对其进行小修改。 –

回答

0

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

+0

好主意,我还在学习TypeBuilder代码。我相信我已经能够设置父母,但到目前为止,仍然没有运气。同样的例外。 – Seige

+0

你不需要WebApi中的装饰器。考虑切换,如果这是一个选项。 –

0

下面是一些简单的代码,让你开始,

[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 

现在你的周转基金应解决KnownTypes。作为一种方法来学习这个,僵尸Explorer将有足够的信息,关于IOC/WCF/PRISM针对.NET 这里是一个链接到WCF的相当详尽的例子,http://www.codeproject.com/Articles/474212/Zombie-Explorer-An-n-tier-application-from-top-to

+0

我的问题是,我不能或不现在如何将装饰添加到生成的类型。在编译时,Type不存在。因此,将[KnownType]放在子项的父项上将无法正常工作,因为它不存在。 – Seige

+0

使用ExpandoObject学习KnownTypes应涵盖在运行时序列化未知类型时需要做的事情。 – Programmer

0

我做它一个完全不同的,更简单的方法。我的解决方案是基于以下理由:

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

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

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

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

+0

这几乎是我回来的。我想将数据转化为类的大部分原因是,它返回的JSON格式很好。字典的默认值被处理成一个列表,即每个值的{key:'a',value:'b'}。我会做出一个不受检查的答案来解释我做了什么。 – Seige

+0

至于fomatting。对象在JSON中作为字典序列化,所以应该没有区别。 –

0

所以,不幸的是,即使在这里所有人给我的所有重要信息,我都无法真正让TypeBuilder正常工作。

但是,我试图使用TypeBuilder的原因是因为我的数据没有格式化为JSON,因为我会喜欢它。它返回的

{关键:数据名称,值:值}

当我真正想要的是

{数据名称:值}

做完一个带有JSON的Web服务和其他一些经验。我知道一个类型将符合这种布局。不幸的是,这些数据是未知的,可以随时改变,Web服务必须处理(不幸的需求)。

即使我无法让TypeBuilder工作,我希望如何。我可以使用Newtonsoft.Json获得想要的结果,然后在服务器序列化字典中的数据之后,尝试为我序列化它。

感谢大家的帮助。我学到了一些我可能用在其他项目中的有趣而令人敬畏的新东西。

谢谢