5

データ アクセス層、サービス層、およびプレゼンテーション層があります。プレゼンテーション レイヤーは ASP.NET MVC2 RTM (Web) で、サービス レイヤーは WCF (サービス) です。すべて.NET 3.5 SP1です。

問題は、サービスで、返されるオブジェクトが[DataContract]属性でマークされていることです。Web は AppFabric キャッシュ (別名 Velocity) SessionStateProvider を使用してセッション状態を保存しています。このため、セッションに保存するものはすべてシリアライズ可能でなければなりません。

ここで問題が発生します: DataContracts はマークされておらず[Serializable]、私が覚えている限り、すでに[DataContract]いくつかの問題が発生しているクラスに導入することで発生するため、これが解決策であるとは思いません。

私は当初、Web レイヤーで DataContracts を使用することを計画していました。それらを DataContracts のレンダリングに関連するビューのモデルとして使用します (おそらく、より高いレベルの ViewModel クラス内にネストされます)。しかし、セッション状態プロバイダーは、内部に格納されているすべてのオブジェクトをシリアライズ可能にする必要があるため、この戦略を再考し始めています。ただし、インターフェイスを使用した検証ロジックが含まれてIDataErrorInfoおり、同じ検証ロジックをモデル バインディングの一部として MVC で再利用できるため、あると便利です。

必要な作業を減らすことができる最善の方法は何だと思いますか?

私は現在、次のさまざまな方法を考えています。

A. Web プロジェクトで「ServiceIntegration」パーツを作成します。

これは、コントローラーと WCF サービス層の間の仲介者になります。ServiceIntegration 部分は、DataContracts を使用してサービス層と通信し、ViewModels を使用して Web 層と通信しますが、双方向トランスフォーマーを使用して DataContracts と ViewModels の間で変換する必要があります。

また、IDataErrorInfo Validation は再利用できないため、Transformer を使用して ViewModel から DataContract に変換し、IDataErrorInfo を使用して検証を実行し、その結果を返す、DataContract ごとの Validator も作成する必要があります。これは、コントローラーのアクション メソッド内で使用されます (例: if (!MyValidator.IsValid(viewModel)) return View();)

必要なさまざまなクラス: xDataContract、xViewModel、xTransformer、xValidator

B. Web プロジェクトで「SessionIntegration」パーツを作成する

これは、コントローラー (またはセッションにアクセスするもの) とセッション自体の間の仲介者になります。セッションへのアクセスを必要とするものはすべて、このクラスを通過します。DataContracts は、セッションに格納されていない限り、アプリケーション全体で使用されます。SessionIntegration 部分は、DataContract を何らかの ISerializable 形式に変換し、元に戻す責任を負います。DataContract で IDataErrorInfo インターフェイスを使用するため、追加の Validator は必要ありません。

必要なさまざまなクラス: xDataContract、xTransformer、xSerializableForm


注: どちらのシナリオでも ViewModel は存在しますが、(B) を使用すると、DataContract から ViewModel を構成できます。

(B) 追加のバリデーターを必要としないという利点があります。


(A)/(B) を完全に実装する前に、フィードバックをお願いします。現時点では(B)に傾き始めていますが、(A)の方が柔軟かもしれません。いずれにせよ、その価値に対してあまりにも多くの作業が行われているようです。他の誰かがこの問題に遭遇しましたか、私に同意/反対しますか、そして/または問題を解決する他の方法はありますか?

ありがとう、

ジェームズ

4

2 に答える 2

5

A または B の本格的なルートに行かずに、一般的な ISerializable ラッパー オブジェクトを作成して、それらを SessionState に入れることはできますか?

    [Serializable]
    public class Wrapper : ISerializable
    {
        public object Value { get; set; }

        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (Value != null)
            {
                info.AddValue("IsNull", false);
                if (Value.GetType().GetCustomAttributes(typeof(DataContractAttribute), false).Length == 1)
                {
                    using (var ms = new MemoryStream())
                    {
                        var serializer = new DataContractSerializer(Value.GetType());
                        serializer.WriteObject(ms, Value);
                        info.AddValue("Bytes", ms.ToArray());
                        info.AddValue("IsDataContract", true);
                    }
                }
                else if (Value.GetType().IsSerializable)
                {
                    info.AddValue("Value", Value);
                    info.AddValue("IsDataContract", false);
                }
                info.AddValue("Type", Value.GetType());
            }
            else
            {
                info.AddValue("IsNull", true);
            }
        }

        public Wrapper(SerializationInfo info, StreamingContext context)
        {
            if (!info.GetBoolean("IsNull"))
            {
                var type = info.GetValue("Type", typeof(Type)) as Type;

                if (info.GetBoolean("IsDataContract"))
                {
                    using (var ms = new MemoryStream(info.GetValue("Bytes", typeof(byte[])) as byte[]))
                    {
                        var serializer = new DataContractSerializer(type);
                        Value = serializer.ReadObject(ms);
                    }
                }
                else
                {
                    Value = info.GetValue("Value", type);   
                }
            }
        }
    }
于 2010-08-31T19:20:17.663 に答える
3

提供された回答の拡張として、これら2つの方法を追加して、データの保存/取得を容易にしました。

    public static void Set<T>(HttpSessionStateBase session, string key, T value)
    {
        session[key] = new Wrapper(value);
    }

    public static T Get<T>(HttpSessionStateBase session, string key)
    {
        object value = session[key];
        if (value != null && typeof(T) == value.GetType())
        {
            return (T) value;
        }
        Wrapper wrapper = value as Wrapper;
        return (T) ((wrapper == null) ? null : wrapper.Value);
    }

これにより、セッションからの値の設定/取得が少し簡単になります。

    MyDataContract c = ...;
    Wrapper.Set(Session, "mykey", c);
    c = Wrapper.Get<MyDataContract>(Session, "mykey");

さらに簡単にするために、拡張メソッドを追加します。

public static class SessionWrapperEx
{
    public static void SetWrapped<T>(this HttpSessionStateBase session, string key, T value)
    {
        Wrapper.Set<T>(session, key, value);
    }

    public static T GetWrapped<T>(this HttpSessionStateBase session, string key)
    {
        return Wrapper.Get<T>(session, key);
    }
}

そして、以下のように使用します:

    MyDataContract c = ...;
    Session.SetWrapped("mykey", c);
    c = Session.GetWrapped<MyDataContract>("mykey");
于 2010-09-01T09:43:43.473 に答える