2016-07-21 119 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獲得想要的結果,然後在服務器序列化字典中的數據之後,嘗試爲我序列化它。

感謝大家的幫助。我學到了一些我可能用在其他項目中的有趣而令人敬畏的新東西。

謝謝