Keywords: Serialization | Serializable Attribute | ASP.NET Session
Abstract: This article provides an in-depth analysis of the common serialization error "Type 'OrgPermission' is not marked as serializable" encountered in ASP.NET applications. It explores the root cause, which lies in the absence of the [Serializable] attribute when storing custom objects in Session. Through practical code examples, the necessity of serialization is explained, and complete solutions are provided, including adding the Serializable attribute, handling complex type serialization, and alternative approaches. The article also discusses the importance of serialization in distributed environments and web services, helping developers gain a deep understanding of the .NET serialization mechanism.
Problem Background and Error Analysis
In ASP.NET development, developers frequently use Session to store user state information. When attempting to store custom objects in Session, the following error may occur:
Type 'OrgPermission' in Assembly 'App_Code.ptjvczom, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
This error typically occurs in the following scenarios:
- Using
ObjectDataSourcebound to objects stored in Session - Running the application in Web Farm or Web Garden environments
- Using out-of-process Session state (such as StateServer or SQLServer mode)
Fundamentals of Serialization
Serialization is the process of converting an object's state into a storable or transmittable format. In .NET, objects must be serialized when they need to:
- Be passed across application domains
- Be stored in persistent media
- Be transmitted over a network
While ASP.NET Session in default InProc mode doesn't require serialization, when using StateServer or SQLServer modes, all objects stored in Session must support serialization.
Root Cause Analysis
From the provided code example, the issue is evident in the OrgPermission class:
public class OrgPermission
{
public string Org { get; set; }
public List<string> type { get; set; }
public OrgPermission()
{ }
}
This class lacks the [Serializable] attribute, so when ASP.NET attempts to serialize it for storage in Session, an exception is thrown. Even when using InProc mode, certain ASP.NET internal mechanisms may trigger serialization requirements.
Solution
1. Adding the Serializable Attribute
The simplest solution is to add the [Serializable] attribute before the class definition:
[Serializable]
public class OrgPermission
{
public string Org { get; set; }
public List<string> type { get; set; }
public OrgPermission()
{ }
}
Similarly, if the cUser class also needs serialization, it should also have this attribute:
[Serializable]
public class cUser
{
public string userid { get; set; }
public List<OrgPermission> orgs { get; set; }
public clsUser(string username)
{
// initialization code
}
}
2. Handling Complex Type Serialization
When a class contains complex types, ensure all member types are serializable. List<string> and List<OrgPermission> are already serializable in .NET, but note:
- All custom class members must be marked with
[Serializable] - Avoid using non-serializable types (such as file streams, database connections, etc.)
- Consider using the
[NonSerialized]attribute for fields that don't need serialization
3. Implementing the ISerializable Interface (Advanced Usage)
For complex scenarios requiring custom serialization logic, implement the ISerializable interface:
[Serializable]
public class OrgPermission : ISerializable
{
public string Org { get; set; }
public List<string> type { get; set; }
public OrgPermission() { }
// Deserialization constructor
protected OrgPermission(SerializationInfo info, StreamingContext context)
{
Org = info.GetString("Org");
type = (List<string>)info.GetValue("type", typeof(List<string>));
}
// Serialization method
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Org", Org);
info.AddValue("type", type);
}
}
Alternative Approaches
1. Using Simple Types for Storage
If modifying class definitions is undesirable, consider converting complex objects to simple types for storage:
// Convert to JSON string when storing
string orgsJson = JsonConvert.SerializeObject(orgs);
Session["UserOrgs"] = orgsJson;
// Deserialize when reading
var orgs = JsonConvert.DeserializeObject<List<OrgPermission>>(Session["UserOrgs"] as string);
2. Changing Session State Mode
If out-of-process Session is definitely not needed, ensure InProc mode is used:
<system.web>
<sessionState mode="InProc" timeout="20" />
</system.web>
However, this approach limits application scalability.
Best Practice Recommendations
- Always Mark Serializable Classes: Even if serialization isn't currently needed, allow for future expansion
- Keep Class Structures Simple: Avoid including complex resources in classes that need serialization
- Consider Version Compatibility: Serialized data may not be compatible across different versions
- Performance Considerations: Serialization/deserialization of large objects may impact performance
- Security Considerations: Serialized data may contain sensitive information and require appropriate protection
Debugging Techniques
When encountering serialization errors, you can:
- Use
try-catchblocks to catch serialization exceptions - Check the serializability of all nested objects
- Test serialization using
BinaryFormatterorDataContractSerializer - Examine InnerException for more detailed error information
Conclusion
Serialization is a crucial concept in the .NET framework, particularly in web application development. By correctly marking classes with the [Serializable] attribute, common runtime errors can be avoided, ensuring application stability across different deployment environments. Understanding serialization mechanisms not only helps resolve current issues but also lays the foundation for designing more robust and scalable applications.