views:

555

answers:

5

I get a serialization error on a page containing a custom control. the control has a member (dataContext) of a type (EntityContext) that is non-serializable, and marked as such.

this is the error:

Type 'Entities.EntityContext' in Assembly '...' is not marked as serializable.

[SerializationException: Type '...Entities.EntityContext' in Assembly '...' is not marked as serializable.]
System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) +7733643
System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) +258
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() +111 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) +161 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) +51 System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) +410
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) +134 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph) +13 System.Web.UI.ObjectStateFormatter.SerializeValue(SerializerBinaryWriter writer, Object value) +4966

[ArgumentException: Error serializing value '...Entities.EntityContext' of type '...Entities.EntityContext.'] System.Web.UI.ObjectStateFormatter.SerializeValue(SerializerBinaryWriter writer, Object value) +5425
System.Web.UI.ObjectStateFormatter.Serialize(Stream outputStream, Object stateGraph) +163 System.Web.UI.ObjectStateFormatter.Serialize(Object stateGraph) +99
System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Serialize(Object state) +37
System.Web.UI.Util.SerializeWithAssert(IStateFormatter formatter, Object stateGraph) +55
System.Web.UI.HiddenFieldPageStatePersister.Save() +143 System.Web.UI.Page.SavePageStateToPersistenceMedium(Object state) +190
System.Web.UI.Page.SaveAllState() +1466 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5477

This is the control:

    public class EntityDataSource : ObjectDataSource
    {
        [NonSerialized] private EntityContext dataContext;

    /// <summary>
    /// Gets the data context. (This is used by the page at runtime.)
    /// </summary>
    /// <value>The data context.</value>
    // ReSharper disable MemberCanBePrivate.Global
    public EntityContext DataContext
    // ReSharper restore MemberCanBePrivate.Global
    {
        get { return dataContext; }
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        dataContext = new EntityContext(SessionProvider.GetContext());
    }
    /// <summary>
    /// Viewstate is not implemented. This value allways return <c>false</c>.
    /// </summary>
    /// <exception cref="NotSupportedException">Exception is thrown when setting this value.</exception>
    [Browsable(false)]
    public override bool EnableViewState
    {
        get
        {
            return false;
        }
        set
        {
            //Throws exception if value is true.
            if (value)
            {
                throw new NotSupportedException("Viewstate is not enabled on this control.");
            }
        }
    }

    public override void Dispose()
    {
        if (DataContext != null)
        {
            DataContext.Dispose();
        }
        base.Dispose();
    }
}

It almost seems like the page doesn't honor the NonSerializedAttribute. I have omitted the company and product names from the namespaces.

A: 

Did you try to put the [NonSerialized] attribute on the property as well? Also, if any of the types you use in your class (and that you may have omitted in the example) inherits from EntityContext you are in trouble.

Dabblernl
[NonSerialized] may only decorate fields. Nothing inherits from EntityContext.
Øyvind Skaar
OK, but then I think the problem is not that the [NonSerialized] Attribute is ignored.
Dabblernl
+1  A: 

Make sure you add the SerializableAttribute to the EntityDataSource class:

[Serializable]
public class EntityDataSource : ObjectDataSource
{
    [NonSerialized] private EntityContext dataContext;
    // etc...
}

The [NonSerialized] attribute is ignored if the class is not marked as [Serializable].

Whether the system can actually serialize the class you're wanting it to is another matter.

Michael Hart
Well, this class isn't really serializable, so it wouldn't solve my problem.
Øyvind Skaar
The control inheriting ObjectDataSource is declared in the page markup, and thus is serialized by the page when saving view state. I have no need for serialization at all.
Øyvind Skaar
The NonSerialized attribute is ignored if the class is not marked as [Serializable]. Whether you can actually serialize your class or not depends on your situation. I'm answering your question of why you're seeing what you're seeing.
Michael Hart
A: 

Is there anything else that you aren't showing on the control? In particular; you inherit from ObjectDataSource - I assume you give it the data-context (or some related object) at some point?

I would personally have no expectation that ObjectDataSource should serialize. It isn't ISerializable nor [Serializable], for starters. Additionally it has lots of events... and events are rarely the friend of serialization (when using BinaryFormatter, at least).

Ultimately, you should serialize state; but ObjectDataSource isn't state - it is (more-or-less) part of the UI implementation. Just attempting to serialize a vanilla ObjectDataSource is enough to cause an exception.

In short; I don't think that you should be including this control in the scope of SaveAllState, perhaps marking the field to your control as [NonSerialized].

Marc Gravell
A: 

Im not sure I fully understand... your trying to serialise a class that is not serialisable, and are wondering why the NonSerialised attribute is not being applied?

Is there something I am missing?

David Kiff
+4  A: 

If I am understanding the problem ...

I take it the instance is beeing serialized and you wish it not to be so. Well, if you cannot change the way the instance is handled, change the way it serializes. Implement System.Runtime.Serialization.ISerializable and just set the initial state in the deserialization constructor (required when implementing the interface). This way at least you circumvent the exception (be sure this still results in correct behaviour) and you add nothing much to the stream (other than type information). As you need no state persisted, you simply do not add items to the dictionary.

MaLio
This was the workaround I ended up with. Still, it almost seems like a bug, though.
Øyvind Skaar
It is a bug, some bugs require workarounds.
MaLio