2015年6月24日

DataSnapサーバまとめ

DataSnapサーバを作るにあたって、ヘルプのDataSnap アプリケーションの開発あたりに載っていなかったり、載っていても気をつけたほうがいいと個人的に思ったことをまとめました(ユニットやクラス、あるいはそのリンクはDelphi XE8のものです)。
  • サーバメソッドでサポートされているデータ型

  • クラスインスタンスのマーシャリング/アンマーシャリング

    • Delphiのオブジェクト(クラスインスタンス)は、基本的に送信側でTJSONMarshalMarshalメソッドでTJSONValueにマーシャリング(変換)したものを送信し、受信側では受信したTJSONValueをTJSONUnMarshalUnmarshalメソッドでアンマーシャリング(逆変換)して元のクラスのインスタンスに戻します(アンマーシャリングの結果の型はTObjectなのでasで本来のクラスにキャストします)。
    • クラスインスタンスのリスト(TObjectListTObjectList<T>)はそのままではマーシャリング/アンマーシャリングできないため、
      var
        Values: TJSONArray;
        Item: TFoo;
        List: TObjectList<TFoo>;
      begin
        ...
        for Item in List do
        begin
          Values.AddElement(Marshal.Marshal(Item));
        end;
      
      のようにそれぞれの要素をマーシャリングしたものをTJSONArrayAddElementメソッドで追加していって、そのTJSONArrayを受け渡して、
      var
        Values: TJSONArray;
        Item: TJSONValue;
        List: TObjectList<TFoo>;
      begin
        ...
        for Item in Values do
        begin
          List.Add(UnMarshal.Unmarshal(Item) as TFoo);
        end;
      
      TJSONArrayのItems[]プロパティ(またはenumerator)で取り出したJSONValueをアンマーシャリングする、という方法が考えられます。
    • RTL経由で適切にシリアライズできないようなクラスのメンバを扱う場合は、マーシャラ(TJSONMarshal)およびアンマーシャラ(TJSONUnMarshal)に特定の型またはメンバに対応する変換/逆変換処理をRegisterConverterRegisterReverterで登録して処理させる、ということになります。詳細はユーザー オブジェクトのシリアル化を参照。

  • TJSONValueとその派生クラスについて

    • DelphiでJSON形式の値を扱うときにはTJSONValueの派生クラスを使用します。
      • TJSONNullはJSONのnull値に対応します。
      • TJSONFalse/TJSONTrueはJSONの真偽値(false/true)に対応します。
      • TJSONStringはJSONの文字列値に対応します。
      • TJSONNumberはJSONの数値(整数、浮動小数点数)に対応します。
      • TJSONArrayはJSONの配列("JSON形式の値"の配列)に対応します。
      • TJSONObjectはJSONのオブジェクト("文字列のキーと値のペア"の順序付けされていない集合)に対応します。"文字列のキーと値のペア"はTJSONPairとして実装されています。ペアはAddPairメソッドで追加し、逆に文字列のキーからペアを取り出すにはGetメソッドを使用します。

  • サーバクラスのインスタンスのライフサイクルについて

  • セッションの管理について

    • サーバメソッド内でセッションを取得するときはTDSSessionManager.GetThreadSessionメソッドを使用します。またセッションに関する操作にはSessionIdが必要になります。詳細はサーバー側セッション管理を参照。
    • 全てのセッションに対して処理を行いたいときはTDSSessionManagerのForEachSessionメソッドを使用して、
      TDSSessionManager.Instance.ForEachSession(
          procedure (const Session: TDSSession)
          begin
            //
          end);
      
      とします。
    • セッションごとにデータを保持させたいときは、TDSSessionのPutObjectGetObjectHasObjectRemoveObjectの各メソッドで特定のキー(文字列)と結びつける形でTObjectのインスタンスの保持、取得、問い合わせ、削除ができます。保持させたデータはセッションが所有しており、セッションが破棄されるときに解放されます。
    • セッションが生成、破棄されるごとに処理を行いたい場合はTDSSessionManagerのシングルトンインスタンスであるInstanceAddSessionEventでイベント(イベントハンドラや無名メソッド)を登録します(RemoveSessionEventで登録を削除することもできます)。
      TDSSessionManager.Instance.AddSessionEvent(
          procedure(Sender: TObject;
                    const EventType: TDSSessionEventType;
                    const Session: TDSSession)
          begin
            case EventType of
              SessionCreate:
              begin
                // Session is created
              end;
      
              SessionClose:
              begin
                // Session is closed
              end;
            end
          end);
      

  • 重量コールバック(クライアントコールバック)の管理

    • TDSCallbackTunnelManagerのAddTunnelEventRemoveTunnelEventメソッドでトンネルおよびコールバックの登録、解除を通知するコールバック関数を登録、解除できます。
      TDSCallbackTunnelManager.Instance.AddTunnelEvent(
          procedure(Sender: TObject; const EventItem: TDSCallbackTunnelEventItem)
          begin
            case EventItem.EventType of
              TunnelCreate:
              begin
                // Tunnel is created
              end;
      
              TunnelClose:
              begin
                // Tunnel is closed
              end;
      
              TunnelClosedByServer:
              begin
                // Tunnel is closed by user
              end;
      
              CallbackAdded:
              begin
                // Callback is added
              end;
      
              CallbackRemoved:
              begin
                // Callback is removed
              end;
            end;
          end);
      

  • TCP/IP接続を監視

2015/06/25追記: Mat DeLongさんとJim Tierneyさんのブログを参考に一部の項目を追加。

0 件のコメント: