views:

766

answers:

4

Without going into whether this is a good or bad idea:

Is it possible to store a LINQ-to-SQL domain object in the ASP.NET Session, when the session is out-of-process?

[EDIT] I'm currently getting the following error and asked this question because I suspect the LINQ-to-SQL objects:

Unable to serialize the session state. In 'StateServer' and 'SQLServer' mode, ASP.NET will serialize the session state objects, and as a result non-serializable objects or MarshalByRef objects are not permitted. The same restriction applies if similar serialization is done by the custom session state store in 'Custom' mode. [/EDIT]

e.g.

Session["Zoo"] = new Zoo() { 
                         new Lion(),
                         new Tiger(), 
                         new Elephant()
                  }

where:

  • Zoo, Lion, Tiger, Elephant all come out of a ZooDataContext

and the web.config file contains

<sessionState
       mode="StateServer"
       stateConnectionString="tcpip=127.0.0.1:42424"
       stateNetworkTimeout="10"
       sqlConnectionString="SqlStateConnectionString"
       sqlCommandTimeout="30"
       timeout="20"
       regenerateExpiredSessionId="true"/>
+1  A: 

I would believe that you would need to mark your objects as being serializable. I'm not sure if there is way to do this for all the generated objects, but for those that you are putting into session, you could create a partial class (e.g. of Lion) and give it the Serializable attribute.

Paddy
Thanks. It seemed like a promising idea, but unfortunately it doesn't work. In a way I was glad :) because it would also be a real pain for a large model with lots of classes. It was nagging at me that tihs article: "How to: Make Entities Serializable (LINQ to SQL)" http://msdn.microsoft.com/en-us/library/bb546185.aspx implies that they should be serialisable.
Neil Fenwick
A: 

After digging into this a little more, the answer is looking like:

Mostly NO, you can't serialize a LINQ-to-SQL generated domain object.

It depends on whether the LINQ-to-SQL object relational mapping references any one-to-many relationships (which I bet 99% do)...

... because looking at the .designer.cs class that is generated by the LINQ-to-SQL designer interface, there are

EntitySet<T>
EntiryRef<T>

property references on the class that I want to store in the Session and they are not serializable

Well written article by Ian Cooper here, describing good design patterns for Object Relational Mapping technologies, persistance ignorance and working with disconencted data sets. In my opinion, a far better and more loosely coupled design pattern than trying to persist data in Session.

Neil Fenwick
You need to make events also non-serialized.
leppie
+1  A: 

Serialize them using the datacontractserializer before storing in session or anything else that may want to serialize... Recently discussed here:

http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/81c84ff4-059b-474f-9c69-b8c59027fd48

KristoferA - Huagati.com
Thanks for giving me the idea. I had assumed that if the classes were serializable, then they were *serializable*, as in the XmlSerializer would have worked. In the end I wrapped and XmlTextWriter around a MemoryStream and then used the DataContractSerializer to serialise into the XmlTextWriter. After that, the byte[] buffer of the memorystream could be serialised and stored out-of-process. I really don't like this kludge of a fix, but I was backed into a corner by someone elses design relying on state instead of a "replay" pattern.
Neil Fenwick
+2  A: 

To use the binary formatter (like SessionState use I believe), you would need to generated your code yourself from the DBML (I do that currently with a Linq2Sql T4 template).

The following need to be mark as [NonSerialized]:

  • EntityRef
  • EntitySet
  • All events (you will need to think outside the box to do this, exercise for reader)

Also the constructor logic need to be moved to OnCreated. You must also make sure OnCreated is called when deserializing so the object can be useful again. The is done with the [OnDeserializing] attribute.

leppie