Put objects which are decorated with [DataContract] into a StateServer?
Is there anyway to stick objects which are decorated with DataContract
attributes but not decorated with Serializable
attributes in to a SqlServer StateServer? In other words, I would prefer not having to decorate these objects with the Serializable
attribute as I will also have to implement IXmlSerizable on all of these objects because they do not h开发者_运维问答ave empty contstructors, and non-public setters for properties.
There's no absolutely easy-peasy way to do this, no, unfortunately.
But: the ASP.NET session state mechanism is extensible, so you could imagine writing your own ASP.NET session state provider which basically uses the DataContractSerializer, and stores the serialized objects into SQL Server (or any other store, for that matter).
Check out MSDN Session-State Modes and Implementing a Session-State Store Provider.
Not a simple little switch to flick - but it would definitely be doable.
Or just decorate your objects with [Serializable]
and be done with it...
I think what you want is to implement ISerializable and manually serialize with the DataContractSerializer.
Have a look at the answer here:
Using WCF DataContract in MVC SessionState using AppFabric cache
While this is talking about using AppFabric (StateServer), the same problem applies to SqlSessionStateStore (all the OOB StateProviders use BinaryFormatter for complex object graphs)
I just had to do this on a project and it worked great. (and it was easy-peasy)
In my case, however, I didn't want to only serialize items marked with [DataContract] because my [DataContract] classes were nested throughout the hierarchy, and I did not want to wrap all of those entities at every level. (the DataContract items are Service Reference DTOs used as backing data for state objects). Instead I simply wrapped the root element that was a member of the item I was stuffing into the Session.
I'll admit that's kinda hard to follow, so I've included the code below:
/// <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);
}
}
}
}
精彩评论