How to Use SerializeEntity() and DeserializeEntity()

Jul 24, 2008 at 6:52 AM
Hi Matt,

This looks really excellent. I'd like to use it in an ASP.Net project I'm working on, but I can't seem to find the right syntax for using SerializeEntity() and DeserializeEntity() to save and retrieve an instance of an entity to/from Viewstate. I think you mention somewhere that there is an example in the code download, but I just downloaded the lastest code and didn't find anything.

Thanks.
Jul 24, 2008 at 3:09 PM
Hi Matt,

I worked it out this morning over the first cup of coffee. Here's the code I came up with that seems to work. Am I using this correctly? Thanks!

/// <summary> /// Method to retrieve the current ServiceCode object from the DB and persist to ViewState ///</summary>
private void PersistServiceCode ()
{
ServiceCode code = new ServiceCode();
code = ServiceCodeService.GetCodeDetails( int codeID );
this.CurrentServiceCode = code;
}

private const string CURRENT_CODE = "theCode";
/// <summary>
/// This property stores/retrieves the current Service Code to/from Viewstate
///</summary>
private ServiceCode CurrentServiceCode
{
 get
{
ServiceCode code = new ServiceCode();
code = (ServiceCode)ServiceCode.DeserializeEntity( ViewState[CURRENT_CODE].ToString(), code.GetType(), null );
if ( code != null )
{ return code; }
 else
{
//special case
return NoServiceCode.Instance;
}
}
 set{this.ViewState[CURRENT_CODE] = ServiceCode.SerializeEntity( value, null );} }
Coordinator
Jul 25, 2008 at 1:06 PM

Yep,

Looks good to me!

The known types is a bit confusing, but basically to do Data Contract serialization properly in some circumstances you need to pass in the possible types that can be serialized (i.e. entity types).  I had to use this because in the Linq To Entity base class it's based on inheritence which is one of the times you need to provide known types. 

However, in regards to KnownTypes, i've taken care of it (via relflection) when the LEB class is in the same assembly as your Data Context.  Otherwise, if the LEB class is not in the same assembly - you would have to provide these to the data contract serializer (via either directly in code or in the config file).

Cheers

Matt.

Jul 25, 2008 at 5:26 PM
Edited Jul 25, 2008 at 5:27 PM
Thanks Matt!

For the record, there were some problems with the code I posted above, mainly related to  null checks. I've posted the corrected code below in case it might be of help to somebody.

Do you think that there would be a performance gain by putting the LEB in a different assembly and thereby avoiding the overhead of reflection? And if so, how exactly would you represent the KnownTypes IEnumerable in the calls to Serialize and Deserialize?

I like using the Special Case pattern exemplified by the NoServiceCode object in my sample code - it  makes the application code more readable. The NoServiceCode type inherits from the ServiceCode entity object, and although it simply represents a failure to find a ServiceCode in the database and itself doesn't need to be updated, saved, deleted, created or tracked, when I stepped through with the debugger I realized that the reflection was being performed on the NoServiceCode type as well as the parent ServiceCode type, which is probably unnecesary - but of course the LEB doesn't know that. I wonder if there's a way to indicate that to the LEB...

-----------------------------------------------------------------------
Updated code below:
-----------------------------------------------------------------------

/// <summary>
/// Retrieves the current Service Code from the datastore and stores it in ViewState using a page-level property.
/// Returns either a ServiceCode or a NoServiceCode object
/// </summary>
/// </remarks>
private ServiceCode RetrieveAndPersistServiceCode()
{
//only go to the database if we have a valid service code ID, since the user could
//have browsed directly to the page without a ServiceCode querystring
if ( this.RequestedServiceCodeID > 0 )
{
ServiceCode code = ServiceCodeService.GetCodeDetails( this.RequestedServiceCodeID, Master.CurrentUserPropertyCache.OrgID );

if (code is NoServiceCode)
{
return NoServiceCode.Instance;
}
else
{
this.CurrentServiceCode = code;

return this.CurrentServiceCode;
}
}
else
{
return NoServiceCode.Instance;
}
}

 private const string CURRENT_CODE = "currentCode";

/// <summary>
/// Persists and retrieves the current Service Code object to/from Viewstate.
/// Returns a NoServiceCode object if there is nothing in ViewState.
/// </summary>
private ServiceCode CurrentServiceCode
{
get
{
ServiceCode code = new ServiceCode();
if ( ViewState[CURRENT_CODE] == null )
{
return NoServiceCode.Instance;
}
else
{
code = (ServiceCode)ServiceCode.DeserializeEntity( ViewState[CURRENT_CODE].ToString(), code.GetType(), null );
}
if ( code != null )
{
return code;
}
else
{
//special case
return NoServiceCode.Instance;
}
}
set { this.ViewState[CURRENT_CODE] = ServiceCode.SerializeEntity( value, null ); }
}

Coordinator
Jul 26, 2008 at 6:26 AM
Edited Jul 26, 2008 at 6:30 AM
"For the record, there were some problems with the code I posted above, mainly related to  null checks. I've posted the corrected code below in case it might be of help to somebody."

Thanks for the code, it will be useful for others - I might actually put an example on the "How to's " page at some stage.

"Do you think that there would be a performance gain by putting the LEB in a different assembly and thereby avoiding the overhead of reflection? And if so, how exactly would you represent the KnownTypes IEnumerable in the calls to Serialize and Deserialize? "

Yes, there would be a performance advantage if you can avoid reflection in this case espeically if you are doing a lot of serialization/deserialization in your system - however if you are doing this you may want to remove the [KnownTypes("GetKnownTypes")] line in the LEB - as it may execute anyway even if you use a different mechanism to provide the types.  If you want to provide the known types for those methods, just wack the types (using TypeOf(<entityclass>) into a list/array and pass them through to the method OR include them in the config file (like Ingo has here). 

I've done a general solution to reduce the amount of "Gotcha's" with the LEB, and in most cases where people are just writing applications that aren't going to get hammered - so for these people it's probably not even worth declaring the types somewhere specifically (unless you are putting hundreds and hundreds of types in the same assembly with the LEB).  I may do some optimizations on this later by caching the first exeuction of the GetKnownTypes method - as it's static the cache will be available process wide which reduce processing.

"I like using the Special Case pattern exemplified by the NoServiceCode object in my sample code - it  makes the application code more readable. The NoServiceCode type inherits from the ServiceCode entity object, and although it simply represents a failure to find a ServiceCode in the database and itself doesn't need to be updated, saved, deleted, created or tracked, when I stepped through with the debugger I realized that the reflection was being performed on the NoServiceCode type as well as the parent ServiceCode type, which is probably unnecesary - but of course the LEB doesn't know that. I wonder if there's a way to indicate that to the LEB."

Yep, this is because they both derive from the LEB.  Hmmm, one idea is that I could just look for all classes that implemented a "DataContract" or "Table" attribute instead - probably looking for "DataContract" would be best as this is a requirement for serialization anyway.  If you'd like to try it first, go ahead - just update the "GetKnownTypes" method - i'll look at it for the next RC/Final build.
Jul 26, 2008 at 3:40 PM
Matt,

Thanks for the explanations.

I'm actually not overly concerned with performance in development of the current version of my app. I'll probably wait to look into the KnownTypes array and/or the DataContract solution when I do a performance tweak in a future incremental version upgrade.