Problem deserializing after recompiling

404 views
Skip to first unread message

Brad Bruce

unread,
Sep 3, 2011, 6:06:55 PM9/3/11
to quar...@googlegroups.com
I've been experimenting with Quartz.Net for a few weeks. I'm using the
ADO storage on an Oracle database.

I recompiled the Quartz DLL as a part of rebuilding the server apps.
Now I cannot read the BLOB data for the jobs I scheduled before the
recompile. I get a JobPersistenceException thrown from the
JobDetail.RetrieveJob method.

Full text of exception message:
Couldn't retrieve job because the BLOB couldn't be deserialized: Could
not load file or assembly 'Quartz, Version=1.0.3.2, Culture=neutral,
PublicKeyToken=f6b8c98a402cc8a4' or one of its dependencies. The located
assembly's manifest definition does not match the assembly reference.
(Exception from HRESULT: 0x80131040)

Is there a way to work around this? Is there a way to save without
being version specific? I'd really like to be able to migrate to the
next release of Quartz.Net without having to recreate all of the
scheduled jobs, and this looks like it could cause an issue.

Brad Bruce

Jay Vilalta

unread,
Sep 3, 2011, 10:30:27 PM9/3/11
to quar...@googlegroups.com
You can configure Quartz.net to save the data as strings. It's a PITA
because then you have to deal with dates in a string format but, it works:
quartz.jobStore.useProperties = true

Brad Bruce

--
You received this message because you are subscribed to the Google Groups
"Quartz.NET" group.
To post to this group, send email to quar...@googlegroups.com.
To unsubscribe from this group, send email to
quartznet+...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/quartznet?hl=en.


Brad Bruce

unread,
Sep 4, 2011, 8:11:04 AM9/4/11
to quar...@googlegroups.com
I recalculate dates on execution. This looks like it will work great.

Are other serialization techniques, such as JSON, on the drawing board?

Brad

Jay Vilalta

unread,
Sep 4, 2011, 11:14:14 AM9/4/11
to quar...@googlegroups.com
I don't think there are other techniques planned, but maybe Marko has some
insight?

Brad

--

Marko Lahma

unread,
Sep 4, 2011, 3:06:36 PM9/4/11
to quar...@googlegroups.com
The dll versioning hell is here again. Yes, the object in database is
bound to be version dependent and you need assembly redirect with
matching public key. So using string based properties is always
advisable.

I just committed to GitHub master support for pluggable serialization
strategy. I did some tests but didn't get DataContractJSONSerializer
to work yet. The basic thing you would need are:

properties["quartz.serializer.type"] =
typeof(JSONObjectSerializer).AssemblyQualifiedName;

and the actual implementation (not working yet):

public class JSONObjectSerializer : IObjectSerializer
{
public byte[] Serialize<T>(T obj) where T : class
{
DataContractJsonSerializer serializer = new
DataContractJsonSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
return ms.ToArray();
}
}

public T DeSerialize<T>(byte[] data) where T : class
{
using (MemoryStream ms = new MemoryStream(data))
{
DataContractJsonSerializer serializer = new
DataContractJsonSerializer(typeof(T));
var readObject = serializer.ReadObject(ms);
return (T) readObject;
}
}
}

Maybe this is a start. The problem could be the open typing used here.
Ideas and enhancements are always welcome.

-Marko

Nathan Baulch

unread,
Sep 4, 2011, 10:52:53 PM9/4/11
to quar...@googlegroups.com
I'd like to see a binary serialization format that supports all primitive types (plus strings and dates) but doesn't use the version sensitive BinaryFormatter. Perhaps something based on BinaryReader/BinaryWriter with TypeCode prefixed values:

    public byte[] Serialize(IDictionary<stringobject> values)
    {
        
using (var stream = new MemoryStream())
        
using (var writer = new BinaryWriter(stream))
        {
            writer.Write(values.Count);
            
foreach (var pair in values)
            {
                writer.Write(pair.Key);
                
var code = pair.Value != null ? Type.GetTypeCode(pair.Value.GetType()) : TypeCode.Empty;
                writer.Write((
byte) code);
                
if (pair.Value != null)
                {
                    
switch (code)
                    {
                        
case TypeCode.DateTime:
                            writer.Write(((
DateTime) pair.Value).Ticks);
                            
break;
                        
case TypeCode.String:
                            writer.Write((
string)pair.Value);
                            
break;
                        
case TypeCode.Boolean:
                            writer.Write((
bool) pair.Value);
                            
break;
                        
case TypeCode.Char:
                            writer.Write((
char) pair.Value);
                            
break;
                        
case TypeCode.Single:
                            writer.Write((
float)pair.Value);
                            
break;
                        
case TypeCode.Double:
                            writer.Write((
double)pair.Value);
                            
break;
                        
case TypeCode.Decimal:
                            writer.Write((
decimal) pair.Value);
                            
break;
                        
case TypeCode.SByte:
                            writer.Write((
sbyte)pair.Value);
                            
break;
                        
// remaining integer types...
                        
default:
                            
throw new Exception("Type not supported");
                    }
                }
            }
            writer.Flush();
            
return stream.ToArray();
        }
    }
 
    
public IDictionary<stringobject> Deserialize(byte[] data)
    {
        
var values = new Dictionary<stringobject>();
        
using (var stream = new MemoryStream(data))
        
using (var reader = new BinaryReader(stream))
        {
            
var count = reader.ReadInt32();
            
for (var i = 0; i < count; i++)
            {
                
var key = reader.ReadString();
                
var code = (TypeCode) reader.ReadByte();
                
object value;
 
                
switch (code)
                {
                    
case TypeCode.Empty:
                        value = 
null;
                        
break;
                    
case TypeCode.DateTime:
                        value = 
new DateTime(reader.ReadInt64());
                        
break;
                    
case TypeCode.String:
                        value = reader.ReadString();
                        
break;
                    
case TypeCode.Boolean:
                        value = reader.ReadBoolean();
                        
break;
                    
case TypeCode.Byte:
                        value = reader.ReadByte();
                        
break;
                    
case TypeCode.Char:
                        value = reader.ReadChar();
                        
break;
                    
case TypeCode.Single:
                        value = reader.ReadSingle();
                        
break;
                    
case TypeCode.Double:
                        value = reader.ReadDouble();
                        
break;
                    
case TypeCode.Decimal:
                        value = reader.ReadDecimal();
                        
break;
                    
case TypeCode.SByte:
                        value = reader.ReadSByte();
                        
break;
                    
// remaining integer types...
                    
default:
                        
throw new Exception("Type not supported");
                }
 
                values.Add(key, value);
            }
        }
        
return values;
    }

Marko Lahma

unread,
Sep 25, 2011, 3:54:53 PM9/25/11
to quar...@googlegroups.com
I've worked a bit today to help with this problem of having binary
backwards compatibility. I have now successfully loaded serialized
calendars and job data map (containing primitive types) from 1.x
version to 2.0. It required just some custom deserialization and
serialization tweaks. There's still some things to do but hopefully
I'll have something soon on GitHub for you to test.

-Marko

> --
> You received this message because you are subscribed to the Google Groups
> "Quartz.NET" group.

> To view this discussion on the web visit
> https://groups.google.com/d/msg/quartznet/-/eBq8D4e3swgJ.

Marko Lahma

unread,
Sep 26, 2011, 12:05:45 PM9/26/11
to quar...@googlegroups.com
OK, I've just committed a fix to GitHub master. I would be really glad
if Nathan you had the time to test whether it works as expected for
you.

I had to remove AllowPartiallyTrustedCallers for .NET 4.0 build
because of custom serialization for now, but I believe the semantics
have changed anyway so it might not be necessary anymore.

-Marko

Reply all
Reply to author
Forward
0 new messages