2011-09-07 62 views
2

我在我的類中使用不同於使用默認序列化程序生成的XML結構進行序列化/反序列化的方法。這些方法爲我的類型創建了一個XmlSerializer,但有一大堆覆蓋。當這些方法被調用時,我猜內部.NET仍然會生成一個序列化程序集,但是我想在編譯後生成這個程序集,所以它不會在運行時生成。我如何生成這個自定義序列化的序列化程序集?如果我爲該類型使用sgen.exe,它似乎只會生成默認的序列化程序。爲自定義XmlSerializer生成一個Xml序列化程序集

特別是我需要生成序列化程序集的原因是我的代碼是從Internet Explorer進程中調用的,該程序在保護模式下運行。如果.net運行時嘗試生成序列化程序集,它會調用csc.exe,並提示用戶詢問是否允許運行此進程。我不希望用戶被提示!所以需要在沒有csc.exe的情況下完成所有序列化/反序列化。

我能想到的一個選擇是捕獲在運行時生成的.cs文件,並將其放入單獨的程序集中,然後將其包含在我的產品中。除了有點噁心,這引發瞭如何自動生成.cs作爲我的構建過程的一部分...

也許還值得一提:我的自定義XML序列化也序列化嵌套類,所以也許那裏也會自動生成序列化程序。我的自定義序列化大部分都是按照以下幾行完成的 - 它將XmlIgnore添加到某些屬性並從其他位置移除XmlIgnore。許多這些屬性返回需要序列化的對象,其中一些實現IXmlSerializable,一些使用默認序列化。

public void SerializeToCustomXml1(XmlWriter writer) 
    { 
     try 
     { 
      CustomXmlSerializer1.Serialize(writer, this); 
     } 
     catch (Exception) 
     { 
     } 
    } 

    /// <summary> 
    /// Static serializer so it's created just once. There's another one like this CustomXmlSerializer2 with a slightly different format again. 
    /// </summary> 
    private static XmlSerializer CustomXmlSerializer1 
    { 
     get 
     { 
      if (_customXmlSerializer == null) 
      { 
       XmlAttributes dontIgnore = new XmlAttributes(); 
       dontIgnore.XmlIgnore = false; 

       XmlAttributes attributes; 
       XmlAttributeOverrides overrides = new XmlAttributeOverrides(); 

       // Include some fields in the XML that wouldn't be there otherwise. 
       overrides.Add(typeof (WebResource), "ID", dontIgnore); 
       overrides.Add(typeof (WebResource), "HasDestinationURLs", dontIgnore); 
       overrides.Add(typeof (Resource), "AccessDefindBy", dontIgnore); 

       attributes = new XmlAttributes(); 
       attributes.XmlIgnore = false; 
       attributes.XmlElements.Add(new XmlElementAttribute("ActionID")); 
       overrides.Add(typeof(Action), "ID", attributes); 

       // Instead of serializing the Actions field we serialize CustomActionsXmlSerializer, 
       // which outputs different content in the XML 
       overrides.Add(typeof (WebResource), "Actions", ignore); 
       attributes = new XmlAttributes(); 
       attributes.XmlIgnore = false; 
       attributes.XmlElements.Add(new XmlElementAttribute("Actions")); 
       overrides.Add(typeof (WebResource), "CustomActionsXmlSerializer", attributes);     

       // ... more of these overrides here ... 
       _customXmlSerializer1 = new XmlSerializer(typeof(WebResource), overrides); 
      } 
      return _customXmlSerializer1; 
     } 

交叉貼herehere

UPDATE: 哦,this answer表明,它只是不可能的,因爲XmlSerializer的甚至不找一個預編譯的組件,如果你正在使用XmlOverrides。該死。然後我猜我最好的選擇是生成序列化代碼並將其包含在我的項目中,並直接調用它而不是調用XmlSerializer。任何想法如何做到這一點整齊?

+0

啊,直到現在我還沒有看到你在使用XmlOverrides。你真的需要這樣做嗎?或者你可以通過實現'IXmlSerializable'來實現嗎?從你的代碼中,我會說通過使用靜態的'[XmlAttribute]'和'IXmlSerializable',你所做的大部分事情都可以通過覆蓋來實現。 –

+0

我使用XmlOverrides,因爲我有三種不同的XML格式,我正在序列化到。一個使用默認的序列化,另外兩個使用XmlSerializer對象和一大堆覆蓋。我認爲IXmlSerializable只會讓我選擇輸出到一種格式。 – Rory

+0

使用'IXmlSerializable',您可以從'XmlReader'或'XmlWriter'手動讀寫元素和屬性,這樣您就可以完全掌控您想要如何讀寫數據。假設你正在序列化或反序列化的上下文,你可以做許多'if's並且有你想要的許多代碼路徑。 –

回答

1

如果通過「自定義XmlSerializer的」意味着你使用System.Xml.XmlSerializer與自定義序列代碼(通過IXmlSerializable[XmlElement]屬性和朋友),它應該尋找序列化時調用MyAssembly.XmlSerializers.dll組裝。

程序集的命名非常重要,如果您不確定是否正在查找它以及正在查找的是什麼確切的程序集名稱,則可以將事件處理程序附加到AppDomain.CurrentDomain.FirstChanceException,該程序將針對應用程序域,包括程序集加載異常。您還可以掛接AppDomain.CurrentDomain.AssemblyLoadAppDomain.CurrentDomain.AssemblyResolve事件,每次程序集首次加載到應用程序域時應激發這些事件。

另一個重要的事情是MyAssembly.dllMyAssembly.XmlSerializers.dll的版本(也許是關鍵;我不確定)必須匹配,它們也應該放在一起。有關更多信息,請參閱thisthis MSDN article

+0

是的,我創建了一個帶有各種覆蓋的XmlSerializer,將會發布一些代碼 – Rory

+0

謝謝,我會看看FirstChanceException,看看會發生什麼。我認爲它必須尋找一個不同於MyAssembly.XmlSerializers.dll的組件,或者它不同的類,因爲它需要每個類的每個'new XmlSerializer(theType,overrides)'都需要一個不同的類並且覆蓋參數。該文檔說,它不會緩存序列化程序,當您使用覆蓋創建它們時我不知道它是否根本無法查找現有程序集......但是看f或者程序集加載異常或通過procmon應該有所幫助。 – Rory

+0

你可以嘗試我剛纔提到的'AssemblyLoad'和'AssemblyResolve'事件。 –

0

(尚未足夠的積分,評論)

你應該考慮咬咬牙,以這樣的方式,可以讓你決定什麼序列化並沒有什麼,沒有在運行時更改屬性實現IXmlSerializable的。定義您自己的屬性,構造函數要求並對它們進行序列化。也許你甚至可以解開XML序列化並切換到JSon.Net,在這種情況下需要跳過這樣的箍環是不太可能的。