2010-06-30 40 views
4

當前,我們使用一個巨大的配置對象,該對象被序列化到XML中或從XML中序列化。這在大多數情況下工作得很好,但是我們發現,在斷電和應用程序崩潰的情況下,文件可能處於一種狀態,導致它無法正確反序列化,從而有效破壞配置信息。用於配置的XML序列化的替代方案

我想使用內置的app.config,但它似乎並不輕鬆支持自定義類。例如,使用XML序列化,我可以輕鬆地序列化一個通用的list<ComplexClass>而不需要額外的代碼。它只是工作。看起來,當使用app.config時,你必須提供大量的信息和自定義類才能工作。另外,大多數「自定義配置」教程都是從2007年左右開始的,而且我可能已經過時了。有沒有人有最新的方式來在.NET 4.0中做到這一點的信息?

另外,當應用程序出現問題時,9/10次是因爲配置不當造成的。對於不熟悉隱藏目錄等的用戶,App.config喜歡將用戶可更改的設置存儲在非常難以訪問的位置。有什麼辦法可以讓一個位置存儲配置文件,當出現問題時用戶可以輕鬆發送電子郵件給我們。或者,比我記得它在2.0天初期更容易嗎?任何關於如何輕鬆完成自定義app.config信息的鏈接或快速示例都會很棒。

作爲進一步的示例,這是由於Alarm的數量可以變化或爲空而我想序列化爲List<Alarm>的對象類型之一的削減版本。有沒有類似的方式在app.config中存儲這樣的東西?

[Serializable] 
public class Alarm 
{ 
    [Serializable] 
    public class AlarmSetting 
    { 
     public enum AlarmVariables { Concentration, RSquared } 
     public enum AlarmComparisons { LessThan, GreaterThan } 

     [Description("Which entity is being alarmed on.")] 
     public AlarmVariables Variable { get; set; } 
     [Description("Method of comparing the entity to the setpoint.")] 
     public AlarmComparisons Comparator { get; set; } 
     [Description("Value at which to alarm.")] 
     public Double Setpoint { get; set; } 
    } 

    public String Name { get; set; } 
    public Boolean Enabled { get; set; } 
    public String Parameter { get; set; } 
    public List<AlarmSetting> AlarmSettings { get; set; } 
    public System.Drawing.Color RowColor { get; set; } 
} 
+0

最佳做法將取決於許多不同的東西,如你到底有什麼樣的應用? – NotMe 2010-06-30 21:06:32

+0

這是一個WinForms應用程序。 – drharris 2010-06-30 21:08:30

+3

您是否嘗試編寫XML文件「transactional」? I.E.將其寫入文件「newconfig.xml」,並在寫入正確時,將「config.xml」重命名爲「oldconfig.xml」,將「newconfig.xml」重命名爲「config.xml」。即使這兩個重命名操作之間存在斷電,如果沒有「config.xml」,您可以使用「oldconfig.xml」輕鬆實現回退策略。 – 2010-06-30 21:10:06

回答

7

我建議從移動任何類型的配置文件之外,而使用某種類型的本地數據庫,如sqlite或SQL Server Express這是更爲彈性的應用程序崩潰。

恕我直言,配置設置不應該是用戶設置的默認容器。給我一個配置文件是爲了確保應用程序在給定的環境中運行。例如,定義連接字符串或輪詢速率或這種性質的事物。

用戶設置,特別是經常變化的用戶設置需要更好的存儲機制,例如本地數據庫。當然,除非它是客戶端/服務器應用程序。在這種情況下,這些設置應該位於服務器本身,並且只有在應用程序必須處於斷開連接狀態時才能在本地持久保存。

您給出的例子之一是配置看起來像是一個或多個警報,這是屬於數據庫表格的一個完美例子。

+0

我同意。我使用System.Data.Sqlite將配置數據作爲XML存儲在Sqlite數據庫中。優點是可以保留多個版本的配置數據,並且可以將數據庫訪問包裝在事務中,以防止崩潰損壞。 – 2010-06-30 21:27:51

+0

我可以看到這個工作非常好,但我也不想運行數據庫服務器,或者最好甚至處理數據庫特定的驅動程序(即sqlite)或外部DLL。是否有任何時間基於文件的數據庫內置到.NET中,可用於這種情況? – drharris 2010-06-30 21:28:21

+0

你真的要看看這個頁面:http://www.sqlite.org/whentouse.html sqlite的全部目的是解決你遇到的問題。 – NotMe 2010-06-30 21:39:49

2

多年來,我一直在使用XML序列化,類似於你所描述的,在很多不同的項目上。除非你想咬掉SQL的配置,這似乎是最好的解決方案。

恕我直言,app.config機制並不比直接的XML序列化更好。從許多不同的項目中訪問這個配置實際上更加困難。如果您只是從WinForms應用程序保存瞬態狀態(用戶選項等),那麼對於簡單的數據類型,應用程序設置可以很方便。

在我看來,你似乎有另一個導致腐敗的問題。這些XML文件很少會導致文件損壞。每當我這樣做,它都與序列化期間引發的異常有關,而不是由於應用程序崩潰等原因引起的。如果您想仔細檢查這一點,您可能需要序列化爲內存流,然後將內存流轉儲到磁盤。您可以實際序列化,反序列化流,以確保在將文件轉儲到磁盤之前它是有效的。

除非你寫這個文件很多我會懷疑文件損壞是由於停電。

+0

鑑於drharris已經說過,我會賭大筆錢,他們幾乎不斷地寫入XML文件。它似乎是應用程序的唯一存儲機制。 – NotMe 2010-06-30 21:36:53

+0

這是奇怪的事情。我不能在我的開發機器上覆制腐敗,而且它看起來完全是隨機的,我確實發現了任何異常並記錄下來(並將其顯示給用戶)。腐敗似乎只能發生在應用程序本身之外,我們似乎無法追查到這一點。真正的啓發是,當在記事本或類似文件中打開損壞的文件時,沒有看起來不正確,但它總是失敗(沒有有用的信息)。我可能會嘗試首先將此序列化實現到存儲器流;也許這可能會抓住一些東西 – drharris 2010-06-30 21:39:16

+0

是的,隨着軟件的變化,這個文件會有不斷的讀/寫。關鍵在於我們不斷更新外部硬件的配置,因此這些值始終在變化。其他數據記錄到平面文件中,但此配置是整個應用程序的狀態,包括所有外部硬件。 – drharris 2010-06-30 21:41:12

1

除非您能夠追蹤錯誤的來源,否則您只是猜測它與Xml文件有關。內置的XmlSerializer完全有可能失敗。你可能有一個循環引用的地方,但很難發表評論,除非你知道你的錯誤是什麼。

有時使用內置的Xml Serializer並不是最好的選擇,當對象變得複雜時,最好自己執行序列化和反序列化。您將擁有更多控制權,並能夠更準確地從錯誤的文件數據中確定/恢復。

XDocument doc = new XDocument(
    new XElement("attachments", 
     new XElement("directory", attachmentDirectory), 
     new XElement("attachment-list", 
      from attached in attachedFiles 
      select new XElement("file", 
       new XAttribute("name", attached.FileName), 
       new XAttribute("size", attached.FileSize)) 
      ) 
     ) 
    ); 

除此之外,配置文件用於配置,而不是程序數據。區別在於配置數據不應該經常變化,並且通常不會從用戶直接編輯。在winforms應用程序中,您不會在配置文件中的用戶之間共享數據。如果你這樣做,那麼你應該考慮你的應用程序是否真的是數據庫應用程序。