AppFabric キャッシュを使用した MVC SessionState での WCF DataContract の使用
-
26-09-2019 - |
質問
データ アクセス層、サービス層、プレゼンテーション層があります。プレゼンテーション層は ASP.NET MVC2 RTM (Web)、サービス層は WCF (サービス) です。すべて .NET 3.5 SP1 です。
問題は、サービス内で返されるオブジェクトにマークが付けられていることです。 [DataContract]
属性。Web は、AppFabric Cache (別名 Velocity) SessionStateProvider を使用してセッション状態を保存します。このため、セッションに保存するものはすべてシリアル化可能である必要があります。
ここで問題が発生します。DataContract には のマークが付いていません [Serializable]
そして、私が覚えている限りでは、すでにマークされているクラスにそれを導入することで、 [DataContract]
いくつかの問題が発生するため、これが解決策であるとは思えません。
私は当初、DataContracts を Web レイヤーで直接使用し、DataContracts のレンダリングに関連するビューへのモデルとして使用することを計画していました (おそらく、高レベルの ViewModel クラス内にネストされています)。しかし、セッション状態プロバイダーは内部に保存されているすべてのオブジェクトをシリアル化可能にする必要があるため、この戦略を再考し始めています。ただし、これらには、 IDataErrorInfo
インターフェイスと同じ検証ロジックをモデル バインディングの一部として MVC で再利用できます。
必要な作業を減らすための最善の方法は何だと思いますか?
現在、次のようなさまざまな方法を考えています。
A.Web プロジェクトに「ServiceIntegration」パーツを作成します。
これは、コントローラーと WCF サービス層の間の仲介者になります。ServiceIntegration 部分は、DataContract を使用してサービス層と通信し、ViewModel を使用して Web 層と通信しますが、双方向の Transformer を使用して DataContract と ViewModel の間で変換する必要があります。
また、IDataErrorInfo 検証は再利用できないため、DataContract ごとに Validator も作成する必要があります。これは、Transformer を使用して ViewModel から DataContract に変換し、IDataErrorInfo を使用して検証を実行し、その結果を返します。これは、コントローラーのアクション メソッド内で使用されます (例: if (!MyValidator.IsValid(viewModel)) return View();
)
さまざまなクラスが必要です:xDataContract、xViewModel、xTransformer、xValidator
B.Web プロジェクトに「SessionIntegration」パーツを作成する
これは、コントローラー (またはセッションにアクセスするもの) とセッション自体の間の仲介者になります。セッションへのアクセスが必要なものはすべて、このクラスを経由します。DataContract は、セッションに保存されていない限り、アプリケーション全体で使用されます。SessionIntegration 部分は、DataContract を ISerializable 形式に変換したり、その逆の変換を行ったりします。DataContract で IDataErrorInfo インターフェイスを使用するため、追加の Validator は必要ありません。
さまざまなクラスが必要です:xDataContract、xTransformer、xSerializableForm
注記:どちらのシナリオでも ViewModel が存在しますが、(B) では DataContract から ViewModel を構成できます。
(B) には、追加のバリデーターが必要ないという利点があります。
(A)/(B) を完全に実装する前に、フィードバックが必要です。現時点では(B)に傾き始めていますが、(A)の方が柔軟かもしれません。いずれにせよ、その価値に対してあまりにも大変な作業のように思えます。他にこの問題に遭遇した人はいますか。私に同意しますか、反対しますか、あるいは問題を解決する他の方法はありますか?
ありがとう、
ジェームス
解決
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);
}
}
}
}
他のヒント
は提供答えるために拡張されるように、私は、データを検索/格納緩和するために、これらの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");