SessionとかViewStateの外部ファイルへの書き出し
XmlSerializerを使えば良かったのでしょうか。書いた後に気がついた。
自分で書いた版
コード
using System; using System.IO; using System.Text; namespace SessionSave { public partial class _Default : System.Web.UI.Page { protected void Page_Load( object sender, EventArgs e ) { Session["data"] = "Hello"; } protected void saveBt_click( object sender, EventArgs e ) { string filePath = String.Format( Server.MapPath( @"~/App_Data/" ) + Session.SessionID + ".xml" ); StringBuilder xml = new StringBuilder(); xml.AppendLine( "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" ); xml.AppendLine( String.Format( "<session id=\"{0}\">", Session.SessionID ) ); for( int i = 0; i < Session.Keys.Count; i++ ) xml.AppendLine( String.Format( "<data name=\"{0}\">{1}</data>", Session.Keys[i].ToString(), Session[i].ToString() ) ); xml.AppendLine( "</session></xml>" ); string forWrite = xml.ToString(); using( StreamWriter writer = new StreamWriter( filePath ) ) writer.Write( forWrite ); } } }
結果
<?xml version="1.0" encoding="utf-8" ?> <session id="te4sqginiw4xok552mjogo45"> <data name="data">Hello</data> </session></xml>
System.Xml.Serialization.XmlSerializer を使った場合
とりあえずSessionをそのまま(System.Web.SessionState.HttpSettionState型として)Serializerにつっこんでみる。しかし、
XMLシリアル化を実現するには。ICollectionから継承される型は継承階層のすべてのレベルでAdd(System.Object)が実装される必要があります。System.Web.SettionState.HttpSettionStateにはAdd(System.Object)が実装されていません。」
とのことなので、OrderedDictionary(要素の順序が勝手に変わらない)に入れ直してからつっこんでみます。しかし、
型System.Collection.Generics.OrderedDictionaryはIDictionaryを実装するため、サポートされません。
と例外が。ICollectionを実装していてもIDictionaryを実装しているとシリアル化できないようです。
とりあえずめんどくさいので、自分でKey(String型)とValue(String型)を持つクラスを付くって、List
コード
using System; using System.IO; using System.Xml.Serialization; using System.Collections.Generic; using System.Web.UI.MobileControls; namespace SessionSave { public class Set { public string Key { get; set; } public string Value { get; set; } public Set() { } public Set( string key, string value ) { this.Key = key; this.Value = value; } } public partial class _Default : System.Web.UI.Page { protected void Page_Load( object sender, EventArgs e ) { Session["data"] = "Hello"; } protected void saveBt_click( object sender, EventArgs e ) { string filePath = String.Format( Server.MapPath( @"~/App_Data/" ) + Session.SessionID + ".xml" ); List<Set> col = new List<Set>(); for( int i = 0; i < Session.Keys.Count; i++ ) col.Add( new Set( Session.Keys[i].ToString(), Session[i].ToString() ) ); XmlSerializer serializer = new XmlSerializer( typeof( List<Set> ) ); FileStream stream = new FileStream( filePath, FileMode.CreateNew ); serializer.Serialize( stream, col ); } } }
これでちゃんとシリアル化できるんですが、クラスSetに「引数なしコンストラクタ」を定義しておかないと、
SessionSave.Setにはパラメータを持たないコンストラクタが含まれていないため、これをシリアル化することはできません。
と怒られます。
結果
<?xml version="1.0"?> <ArrayOfSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Set> <Key xsi:type="xsd:string">data</Key> <Value xsi:type="xsd:string">Hello</Value> </Set> </ArrayOfSet>
まとめ
- 自分で書いた方が簡単だった(なんだかんだで)
- SerializableAttribute が宣言されてるクラスだったらXmlSerialization出来るのかと思ったらそうでもなかった
- XmlAttributeを宣言していないとダメなようです