在MVC SessionState的使用WCF DataContract使用的AppFabric缓存
-
26-09-2019 - |
题
我有一个数据访问层,一服务层和表示层。表示层ASP.NET MVC2 RTM(网页),和业务层是WCF(服务)。它的所有.NET 3.5 SP1。
的问题是,在服务,正在返回的对象都标有[DataContract]
属性。该网站使用的AppFabric缓存(a.k.a速度)SessionStateProvider存储会话状态。由于这个原因,在会话什么我店必须可序列化。
这里谈到的问题:DataContracts都没有标明[Serializable]
而据我的记忆,通过将其上已经打上[DataContract]
出现的一些问题的一类,所以我不相信这是一个解决方案。
我最初打算使用正好在网层的DataContracts,使用它们作为模型来与呈现DataContracts次(大概嵌套更高水平ViewModel类内侧)。但由于需要存储在它里面是序列化的所有对象的会话状态提供者,我开始重新考虑这一策略。这将是不错的,虽然,因为它们使用IDataErrorInfo
接口包含验证逻辑,和相同的验证逻辑可以被重新使用在MVC作为结合模型的一部分。
你相信什么,是让我减少所需的工作的最好方式?
我目前认为以下不同的方式:
:一种。创建在web项目 'ServiceIntegration' 部分。强>
这将是我的控制器和我的WCF服务层之间的中间人。所述ServiceIntegration部分将向服务层使用DataContracts使用的ViewModels说话,到Web层,但必须使用一个双向变压器的DataContracts和的ViewModels之间变换。
另外,由于IDataErrorInfo的验证不会重复使用的,这将是必要的,以创建每DataContract太一个验证程序,使用该变压器转换从视图模型到DataContract,使用IDataErrorInfo的执行验证并返回它的结果。这然后将内部控制器的动作方法中使用(例如if (!MyValidator.IsValid(viewModel)) return View();
)
所需的不同的类:xDataContract,xViewModel,xTransformer,xValidator
<强> B中。在web项目创建 'SessionIntegration' 部分强>
这将是控制器(或任何访问会话)和会话本身之间的中间人。任何需要访问会话会去通过这个类。 DataContracts将在整个应用程序中使用,除非它们被存储到会话中。该SessionIntegration部分将采取改造DataContract一些ISerializable的形式,和背部的责任。因为使用对DataContract IDataErrorInfo的接口中的每一个不需要附加的验证。
所需的不同的类:xDataContract,xTransformer,xSerializableForm
注意:仍然会有的ViewModels围绕在这两种情况下,但是与(B)我能够从DataContracts撰写的ViewModels
(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);
}
}
}
}
其他提示
作为扩展到所提供的答案,我添加这两种方法,以减轻存储/检索数据。
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");