2012-05-09 47 views
7

在我的Visual Studio 2010項目中,我使用以下Post-Build事件命令行來使用sgen創建XmlSerializers.dll。XmlSerializer未使用由sgen創建的XmlSerializers.dll

後生成事件:

"$(ProgramFiles)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\sgen.exe" /a:"$(TargetPath)" /c:/keyfile:"c:\myproject\mykey.snk" /f 

我的項目是強命名,所以使用相同的密鑰,以強名稱「XmlSerializers.dll」。 VS在輸出文件夾中創建XmlSerializers.dll。

但是,我注意到使用ProcessMonitor,.NET仍然在運行時調用CSC.exe。我來到這個post,其中用戶有類似的問題,並通過使用XmlSerializer(Type)構造函數解決。

我用同樣的方法在我的代碼,但它仍然調用CSC.EXE:

var fs = new FileStream(SettingsFilePath, FileMode.Open); 
try 
{ 
var serializer = new XmlSerializer(typeof(AppSettings)); 
settings = (AppSettings)serializer.Deserialize(fs); 
} 
finally 
{ 
fs.Close(); 
} 

我之所以需要使用預編譯的XML序列化的,因爲性能,並且還我已經有時可見CSC.EXE誤差修改Windows關機。當窗體關閉時,我的應用程序會保存數據,在關閉期間,它會失敗,因爲Windows在關閉序列期間不會允許啓動新流程。我已經看到了通過預編譯XML序列化來解決這個問題的建議。

有關爲什麼XmlSerializer不使用由sgen創建的XmlSerializers.dll的任何建議?

謝謝。

+0

關機問題的最簡單方法是在啓動時加載數據。使用fuslogvw.exe檢查程序集解析。 –

+0

謝謝,當MainForm關閉時,我需要保存數據(序列化爲XML)。在用戶正常關閉期間沒事,沒有錯誤,數據序列化。但是,如果我的應用程序運行和Windows關機,然後我看到CSC.exe錯誤。 – Din

回答

0

你試過在生成的dll上運行ngen.exe嗎?

運行

ngen.exe install myproject.XmlSerializers.dll 

將安裝在圖像緩存中的DLL,應該在運行時使用,而不是調用JIT編譯器的原生圖像。

+0

謝謝,我已經嘗試過使用ngen.exe的建議,但仍然可以在ProcessMonitor中看到cse.exe調用。 – Din

+0

以下是ProcessMonitor的屏幕截圖:http://screencast.com/t/iyKu79yv 「DataSerializer.XmlSerializers.dll」是由sgen創建的序列化程序dll。 – Din

4

Possiby問題是不同目標平臺:由默認sgen使用「任何CPU」(MSIL),如果要被反序列化或串行化被編譯用於x86 x64的ø包含類型的組件,它不會加載.XmlSerializers.dll

更一般,我一看那個加載序列化程序集的.NET代碼 - 這裏是一些代碼,重現相同的行爲作爲一個單元測試:

/// <summary>Generates an identifier for the assembly of a specified type</summary> 
/// <remarks>Code copied from the .NET serialization classes - to emulate the same bahavior</remarks> 
/// <param name="type">The type</param> 
/// <returns>String identifying the type's assembly</returns> 
static string GenerateAssemblyId(Type type) 
{ 
    Module[] modules = type.Assembly.GetModules(); 
    ArrayList list = new ArrayList(); 
    for (int i = 0; i < modules.Length; i++) { 
    list.Add(modules[i].ModuleVersionId.ToString()); 
    } 
    list.Sort(); 
    StringBuilder sb = new StringBuilder(); 
    for (int i = 0; i < list.Count; i++) { 
    sb.Append(list[i].ToString()); 
    sb.Append(","); 
    } 
    return sb.ToString(); 
} // GenerateAssemblyId 

/// <summary>Verifies that the serialization assembly for the specified type can be loaded</summary> 
/// <remarks>Code copied from the .NET serialization classes - to emulate the same behavior and tests</remarks> 
/// <param name="type">The type</param> 
static void AssertCanLoadXmlSerializers(Type type) 
{ 
    if (type == null) 
    throw new ArgumentNullException("type"); 
    Assembly serializerAssembly = null; 
    // Create the name of the XML serilizers assembly from the type's one 
    AssemblyName name = type.Assembly.GetName(true); 
    name.Name = name.Name + ".XmlSerializers"; 
    name.CodeBase = null; 
    name.CultureInfo = CultureInfo.InvariantCulture; 
    try { 
    serializerAssembly = Assembly.Load(name); 
    } catch (Exception e) { 
    Assert.Fail("Unable to load XML serialization assembly for type '{0}': {1}", type.FullName, e.Message); 
    } 
    object[] attrs = serializerAssembly.GetCustomAttributes(typeof(XmlSerializerVersionAttribute), false); 
    if (attrs == null || attrs.Length == 0) { 
    Assert.Fail(
     "Unable to use XML serialization assembly '{1}' for type '{0}': it does not contain XmlSerializerVersionAttribute", 
     type.FullName, 
     serializerAssembly.FullName 
    ); 
    } 
    if (attrs.Length > 1) { 
    Assert.Fail(
     "Unable to use XML serialization assembly '{1}' for type '{0}': it contains multiple XmlSerializerVersionAttribute", 
     type.FullName, 
     serializerAssembly.FullName 
    ); 
    } 
    XmlSerializerVersionAttribute assemblyInfo = (XmlSerializerVersionAttribute)attrs[0]; 
    string assemblyId = GenerateAssemblyId(type); 
    if (assemblyInfo.ParentAssemblyId != assemblyId) { 
    Assert.Fail(
     "Unable to use XML serialization assembly '{1}' for type '{0}': it does not match assembly id '{2}'", 
     type.FullName, 
     serializerAssembly.FullName, 
     assemblyId 
    ); 
    } 
} // AssertCanLoadXmlSerializers 

只需撥打AssertCanLoadXmlSerializers()傳遞型比需要序列化/反序列化。如果序列化程序集不加載,您可以從錯誤消息中獲得相當好的理由。

我將它添加到我們的單元測試中,以便我可以合理確定序列化程序集是否正常。

+0

這段代碼非常有用。謝謝。我試圖瞭解如果斷言失敗的最後一個塊(「它不匹配程序集ID」)如何解決問題。你能否提供更多的解釋,說明這意味着什麼以及如何去修復它? –

+0

它已經有一段時間了...組件ID是由該組件中的模塊版本號組成的,如果它們不同,這意味着兩個組件(包含類型和序列化的組件)由不同的模塊 - 或者相同模塊的不同版本 - 所以在創建序列化程序集後可能會有所改變?看着ID應該給你一個線索 – MiMo

+0

謝謝 - 這是一個很好的起點。 –

0

您確定序列化程序集是否正確簽名?通常你需要避開引號。有關更多信息,請參見here

你也可以檢查ID是否匹配。如果在構建序列化程序集後修改源程序集,則ID不再匹配,並且不會使用序列化程序集。有關更多信息,請參見here

如果一切正確:禁用工具 - >選項 - >調試 - >「啓用只是我的代碼」並啓用調試 - >強制 - >公共語言運行時異常 - >引發。然後調試你的應用程序到串行化完成的地步。將拋出第一次機會異常,說明爲什麼不能使用序列化程序集。