无论如何将用DataContract
属性修饰但没有用Serializable
属性修饰的对象粘贴到 SqlServer StateServer 中?换句话说,我宁愿不必用Serializable
属性来装饰这些对象,因为我还必须在所有这些对象上实现 IXmlSerizable,因为它们没有空构造函数和属性的非公共设置器。
2 回答
不幸的是,没有绝对简单的方法可以做到这一点。
但是:ASP.NET 会话状态机制是可扩展的,因此您可以想象编写自己的 ASP.NET 会话状态提供程序,它基本上使用 DataContractSerializer,并将序列化的对象存储到 SQL Server(或任何其他存储)中。
不是一个简单的小切换到轻弹 - 但它肯定是可行的。
或者只是用它来装饰你的物品[Serializable]
并完成它......
我认为您想要的是实现 ISerializable 并使用 DataContractSerializer 手动序列化。
看看这里的答案:
在使用 AppFabric 缓存的 MVC SessionState 中使用 WCF DataContract
虽然这是在谈论使用 AppFabric (StateServer),但同样的问题也适用于 SqlSessionStateStore(所有 OOB StateProviders 都将 BinaryFormatter 用于复杂的对象图)
我只需要在一个项目上执行此操作,并且效果很好。(这很容易)
然而,就我而言,我不想只序列化标有 [DataContract] 的项目,因为我的 [DataContract] 类嵌套在整个层次结构中,我不想在每个级别包装所有这些实体。(DataContract 项是服务引用 DTO,用作状态对象的支持数据)。相反,我只是简单地包装了根元素,它是我要填充到 Session 中的项目的成员。
我承认这有点难以理解,所以我在下面包含了代码:
/// <summary>
/// Represents a thread-safe, per-session state object, stored in the ASP.NET Session.
/// </summary>
[Serializable]
public class SessionContext
{
#region Static
private const string SESSION_CONTEXT_KEY = "SessionContext";
private static object _syncRoot = new object();
public static SessionContext Current
{
get
{
HttpSessionState session = HttpContext.Current.Session;
if (session[SESSION_CONTEXT_KEY] == null)
{
lock (_syncRoot)
{
if (session[SESSION_CONTEXT_KEY] == null)
{
session[SESSION_CONTEXT_KEY] = new SessionContext();
}
}
}
return (SessionContext)session[SESSION_CONTEXT_KEY];
}
}
#endregion
private SessionContext()
{
}
public User User { get; set; }
private CustomerWrapper _customerWrapper = new CustomerWrapper();
/// <summary>
/// ignore serializing the Customer object because we're serializing the wrapper object instead, which uses the more robust DataContractSerializer.
/// </summary>
[XmlIgnore]
public Customer Customer
{
get
{
return this._customerWrapper.Customer;
}
set
{
this._customerWrapper.Customer = value;
}
}
}
/// <summary>
/// Custom wrapper object to instruct the OutOfProc StateProvider how to serialize this item.
/// Instead of using the BinaryFormatter, we'll use the more robust DataContractSerializer.
/// </summary>
[Serializable]
public class CustomerWrapper : ISerializable
{
public Customer Customer { get; set; }
internal CustomerWrapper() { }
internal CustomerWrapper(Customer customer) : this() { this.Customer = customer; }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (this.Customer != null)
{
info.AddValue("IsNull", false);
using (var ms = new MemoryStream())
{
try
{
var serializer = new DataContractSerializer(this.Customer.GetType());
serializer.WriteObject(ms, this.Customer);
info.AddValue("Bytes", ms.ToArray());
info.AddValue("IsDataContract", true);
}
catch (Exception ex)
{ // breakpoint never hit
}
}
info.AddValue("Type", this.Customer.GetType());
}
else
{
info.AddValue("IsNull", true);
}
}
public CustomerWrapper(SerializationInfo info, StreamingContext context)
{
if (!info.GetBoolean("IsNull"))
{
var type = info.GetValue("Type", typeof(Type)) as Type;
using (var ms = new MemoryStream(info.GetValue("Bytes", typeof(byte[])) as byte[]))
{
var serializer = new DataContractSerializer(type);
this.Customer = (Customer)serializer.ReadObject(ms);
}
}
}
}