ASP.NET MVCで作る携帯サイト(3)

Smart.Web.Mobileソース解説編(・ω・)
設定、コンテキスト、入出力エンコーディング、出力フィルタに分けてクラス概要を。

設定

まずは設定関連のクラスについて。

  • Carrier

3キャリア+その他のEnumです。

public enum Carrier
{
    Other,
    DoCoMo,
    Au,
    Softbank,
}
  • CarrierMatchngRule

mobile.xmlの/mobile/rules/ruleに相当する容れ物です。

public class CarrierMatchingRule
{
    public Carrier Carrier { get; set; }
    public string Contains { get; set; }
}
  • MobileSetting

キャリア毎にListやコード変換用のDictionaryを保持します。

public class MobileSettings
{
    // デフォルトインスタンス
    public static MobileSettings Default { get; }

    // マッチングルール
    public List<CarrierMatchingRule> MatchingRules { get; set; }

    // キャリア毎の設定
    public Dictionary<Carrier, CarrierSettings> CarrierSettings { get; set; }

    // 初期化
    public void Init(string filename);
}
  • CarrierSetting

設定ファイルのローダー&キャリア毎のMobileSettingを保持します。

public class CarrierSettings
{
    // 絵文字一覧
    public List<Pictgram> Pictgrams { get; }

    // キャリア
    public Carrier Carrier { get; }

    // MobileEncodingファクトリ
    public MobileEncoding GetMobileEncoding(string name, PictgramTreat pictgramTreat);

    // Noで絵文字を取得
    public Pictgram GetPictgramByNo(int no);

    // Unicodeで絵文字を取得
    public Pictgram GetPictgramByUnicode(char c);

    // キャリア間コンバータ
    public char[] Convert(char src);
}
  • Pictgram

docomo.xmlとかの/carrier/pictgrams/pictgramに相当する容れ物です。

public class Pictgram
{
    public int No { get; set; }
    public byte[] Sjis { get; set; }
    public char Unicode { get; set; }
    public string Name { get; set; }
}

コンテキスト

次は実行コンテキスト。

  • MobileContext

User-AgentとCarrierMatchngRuleを使用して、現在のリクエストのキャリアを判定する仕組みです。
作った後はHttpContext.Currentに入れて持ち回し。
携帯固有番号とかもに対応したければ、ここに処理を追加する方向で(・ω・)

public class MobileContext
{
    // モバイル判定
    public bool IsMobile { get; }

    // キャリア取得
    public Carrier Carrier { get; }

    // CarrierSettings取得
    public CarrierSettings CarrierSettings { get; }

    // 初期化
    public void Initialize(string ua, MobileSettings mobileSettings);
}
public class WebMobileContext
{
    // コンテキスト取得
    public static MobileContext Current { get; }
}

入出力エンコーディング

HttpWebRequest.ContentEncoding/HttpWebRequest.ContentEncodingに設定するEncoding派生クラスです。

  • MobileEncoding

絵文字削除と、固有のエンコーディング処理を行うベースクラスです。
実装はMobileSJISEncodingとMobileUTF8Encoding。
基本的な処理は、元となるEncodingに処理を委譲しています(・ω・)

public enum PictgramTreat
{
    Convert,
    Erase,
}
public abstract class MobileEncoding : Encoding
{
    // 基準となるEncoding
    public Encoding BaseEncoding { get; }

    // 絵文字の扱い
    public PictgramTreat PictgramTreat { get; }

    // コンストラクタ
    protected MobileEncoding(Encoding encoding, PictgramTreat pictgramTreat);

    // 携帯固有エンコーディング処理
    protected abstract int GetMobileBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex);

    // 携帯固有エンコーディング処理
    protected abstract int GetMobileChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex);
}
  • MobileSJISEncoding

キャリア規定のSjift_JIS-Unicode変換は、DoCoMo以外Encoding.GetEncoding( "Shift_JIS" )とは一致しないので、CarrierSettingのデータを使用して独自のエンコードを行う処理を実装しています。

public class MobileSJISEncoding : MobileEncoding
{
    // コンストラクタ
    public MobileSJISEncoding(PictgramTreat pictgramTreat, Dictionary<char, byte[]> unicodeToSjis, Dictionary<int, char> sjisToUnicode);
}
  • MobileUTF8Encoding

UTF-8Unicodeの変換は標準のEncodingに従うだけです。

public class MobileUTF8Encoding : MobileEncoding
{
    // コンストラクタ
    public MobileUTF8Encoding(PictgramTreat pictgramTreat);
}

出力フィルタ

出力時の加工処理を行うクラスです。
MobileOutputEncodingとMobileOutputStreamはニコイチ。

  • MobileOutputEncoding

HttpWebResponse.Filterに渡されるbyte配列はHttpWebResponse.ContentEncodingによる処理済みのものになります。
よって、HttpWebResponse.Filterでchar配列として出力内容の加工を行う場合、一端Unicodeに再エンコードを行う必要があるわけですが。
キャリア間の絵文字変換を行う前にUnicodeShift_JIS変換が発生すると、正しく変換が行えない可能性があるため、HttpWebResponse.ContentEncodingに直接MobileSJISEncodingを指定することは出来ません(´・ω・`)
そこで、HttpWebResponse.ContentEncodingには仮にEncoding.Unicodeを指定しておき、HttpWebResponse.Filter内で出力用のエンコードも行うことでこの問題に対処することにしています( ゜Д゜)
ただし、HttpWebResponse.ContentEncoding.WebName等がHTTPヘッダの出力にも使用されるため、MobileOutputEncodingは内部処理用のEncoding(Encoding.Unicode)と、最終的な出力用のEncoding(MobileSJISEncoding or MobileUTF8Encoding)の2つを保持し、処理に応じてどちらかへ処理を委譲するようなクラスとなっています。


この辺、トリッキーな事をやっていてぐんにょりな感じ(´・ω・`)

public class MobileOutputEncoding : Encoding
{
    // コンストラクタ
    public MobileOutputEncoding(Encoding dmuuyEncoding, Encoding outputEncoding)
}
  • MobileOutputStream

っで、加工して出力を行うのがMobileOutputStreamです。
空行削除、ユーザ定義変換(かな文字の半角変換等)、絵文字のキャリア間変換とレンダリング処理を実装。

public class MobileOutputStream : Stream
{
    // 空行削除
    public bool Trim { get; set; }

    // ユーザ定義変換
    public Func<string, string> Effect { get; set; }

    // レンダリング方法
    public IPictgramRender PictgramRender { get; set; }

    // コンストラクタ
    public MobileOutputStream(Stream stream, Encoding inputEncoding, Encoding outputEncoding, CarrierSettings carrierSessings);

    // override
    public override void Flush();

    // override
    public override void Write(byte[] buffer, int offset, int count);
}
  • PictgramRenders

絵文字のレンダリング方法についてはIPictgramRender実装クラスで切り替えます。
キャリアと文字コードを考慮して、レンダリング方法を選択します。
設定がなければ文字がそのまま出力されます。


IPictgramRenderの実装としては、Unicode実体参照で出力するUnicodeNumberRender、Shift_JIS実体参照で出力するSjisNumberRender、DoCoMo用に絵文字は10進実体参照で拡張絵文字は16進実体参照で出力するDocomoMixedRender等を用意しています。
これらを文字コードとキャリアにあわせて使用します。

public interface IPictgramRender
{
    // レンダリング処理
    void Render(StreamWriter writer, Pictgram pictgram);
}

public class UnicodeNumberRender : IPictgramRender

public class SjisNumberRender : IPictgramRender

public class DocomoMixedRender : IPictgramRender

public class ImgageLocalSrcRender : IPictgramRender


っで、Smart.Web.Mobileの解説は以上になります。
エンコーディングごにょごにょとか、Dictionaryを引いて引いてとか、いまいち気に入らない感じのところもあるんですが。
もう少しマシなものにしようとするなら、まずはエンコーディングのところをもう少しちゃんとやるようにするところから始めるかな(・ω・)


っで、Smart.Web.Mobileを使った携帯サイトの話はこれで終わりですが、携帯つながりでおまけをもう1回やるかも。