Quartz.Serialization.Newtonsoft
4.0.0-alpha.1
Prefix Reserved
See the version list below for details.
dotnet add package Quartz.Serialization.Newtonsoft --version 4.0.0-alpha.1
NuGet\Install-Package Quartz.Serialization.Newtonsoft -Version 4.0.0-alpha.1
<PackageReference Include="Quartz.Serialization.Newtonsoft" Version="4.0.0-alpha.1" />
<PackageVersion Include="Quartz.Serialization.Newtonsoft" Version="4.0.0-alpha.1" />
<PackageReference Include="Quartz.Serialization.Newtonsoft" />
paket add Quartz.Serialization.Newtonsoft --version 4.0.0-alpha.1
#r "nuget: Quartz.Serialization.Newtonsoft, 4.0.0-alpha.1"
#:package Quartz.Serialization.Newtonsoft@4.0.0-alpha.1
#addin nuget:?package=Quartz.Serialization.Newtonsoft&version=4.0.0-alpha.1&prerelease
#tool nuget:?package=Quartz.Serialization.Newtonsoft&version=4.0.0-alpha.1&prerelease
title: JSON Serialization
::: tip
JSON is the recommended format for data a job store persists. Consider also setting
StoreJobDataAsStrings, which keeps job data out of the serializer altogether by restricting it to
strings.
:::
::: tip
System.Text.Json serialization is built into the Quartz package and is the default; see
Serialization (System.Text.Json).
:::
JSON.NET
Quartz.Serialization.Newtonsoft provides JSON serialization support for job stores using Json.NET to handle the actual serialization process.
Installation
You need to add NuGet package reference to your project which uses Quartz.
dotnet add package Quartz.Serialization.Newtonsoft
Configuring
Configuring the store
builder.Services.AddQuartz(q => q.UsePersistentStore(store =>
{
store.UseSqlServer(connectionString);
// it's generally recommended to stick with
// string property keys and values when serializing
store.Configure(options => options.StoreJobDataAsStrings = true);
store.UseNewtonsoftJsonSerializer();
}));
Without a host, the same calls hang off QuartzSchedulerBuilder:
await using StandaloneSchedulerFactory schedulerFactory = QuartzSchedulerBuilder.Create()
.UsePersistentStore(store =>
{
store.UseGenericDatabase("MyProvider", "my connection string");
store.Configure(options => options.StoreJobDataAsStrings = true);
store.UseNewtonsoftJsonSerializer();
})
.Build();
Build() returns a StandaloneSchedulerFactory, which owns the container it built: dispose it — with
await using, as above — and the scheduler shuts down with it.
Classic property-based configuration
The flat keys 3.x used still work, and mean the same thing:
NameValueCollection properties = new()
{
["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.LocalTransactionJobStore, Quartz",
["quartz.serializer.type"] = "newtonsoft"
};
await using StandaloneSchedulerFactory schedulerFactory = QuartzSchedulerBuilder.Create()
.UseProperties(properties)
.Build();
UseGenericDatabase is the right method only for a database Quartz has no specific support for; use
UseSqlServer, UsePostgres and the rest otherwise. If Quartz ships no description of your ADO.NET
driver either, describe it in the same call — see
the configuration reference.
Migrating from binary serialization
Quartz 4 no longer ships the BinaryObjectSerializer: the underlying BinaryFormatter
has been removed from modern .NET and throws on .NET 9 and later. If you still have
binary-serialized data in your database you need to migrate it to JSON.
The recommended path is to perform the migration while you are still on Quartz 3.x,
which still includes BinaryObjectSerializer - see the Quartz 3.x version of this page
for a ready-made hybrid serializer. Either let the system migrate gradually as it runs,
or write a small program that loads and writes back every serialized asset in the
database.
If you must read legacy binary data after upgrading to Quartz 4 on .NET 9 or later, you
can re-enable BinaryFormatter with Microsoft's unsupported
compatibility package.
Because the package does not change BinaryFormatter's type identity, only your
application project needs it - Quartz itself does not reference it:
<PropertyGroup>
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0" />
</ItemGroup>
The package restores a working - but still unsafe - BinaryFormatter, so read the Microsoft
guidance before relying on it and remove it once the migration is complete. The Quartz types a
blob can be made of - the job data maps, the keys that can sit in them as values, the calendars
and the trigger classes - keep their [Serializable] / ISerializable support, so the hybrid
serializer below can read the old binary payloads and write everything back as JSON. Types that
could never be part of a blob lost those attributes in 4.0; see
the migration guide
for the full list.
One column is the exception: BLOB_TRIGGERS.BLOB_DATA holds whole trigger objects, and
BinaryFormatter records private base-class fields under the base class's name - which 4.0
renamed (AbstractTrigger is TriggerBase) and whose field set 4.0 extended. Migrate binary
blob triggers while still on 3.x; the hybrid serializer on 4.x is for the job data map, key and
calendar payloads.
Example hybrid serializer
using System.Runtime.Serialization.Formatters.Binary;
using Newtonsoft.Json;
using Quartz.Impl;
using Quartz.Extensibility;
namespace Quartz;
public sealed class MigratorSerializer : IObjectSerializer
{
// you might need custom configuration, see sections about customizing in documentation
private readonly NewtonsoftJsonObjectSerializer jsonSerializer = new();
public T Deserialize<T>(byte[] data) where T : class
{
try
{
// Attempt to deserialize data as JSON
return jsonSerializer.Deserialize<T>(data)!;
}
catch (JsonReaderException)
{
// The data was not JSON, so fall back to the legacy binary format. This branch needs
// the System.Runtime.Serialization.Formatters compatibility package and
// EnableUnsafeBinaryFormatterSerialization to be set in the application project.
using var stream = new MemoryStream(data);
#pragma warning disable SYSLIB0011
var binaryData = (T) new BinaryFormatter().Deserialize(stream);
#pragma warning restore SYSLIB0011
if (binaryData is JobDataMap jobDataMap)
{
// make sure we mark the map as dirty so it will be serialized as JSON next time
jobDataMap[SchedulerConstants.ForceJobDataMapDirty] = "true";
}
return binaryData;
}
}
public byte[] Serialize<T>(T obj) where T : class => jsonSerializer.Serialize(obj);
}
Customizing JSON.NET
If you need to customize JSON.NET settings, you need to inherit custom implementation and override CreateSerializerSettings.
class CustomJsonSerializer : NewtonsoftJsonObjectSerializer
{
protected override JsonSerializerSettings CreateSerializerSettings()
{
var settings = base.CreateSerializerSettings();
settings.Converters.Add(new MyCustomConverter());
return settings;
}
}
And then configure it to use
store.UseSerializer<CustomJsonSerializer>();
or, as a flat property key:
quartz.serializer.type = MyProject.CustomJsonSerializer, MyProject
Customizing calendar serialization
If you have implemented a custom calendar, you need to implement a ICalendarSerializer for it.
There's a convenience base class CalendarSerializer that you can use the get strongly-typed experience.
Custom calendar and serializer
[Serializable]
class CustomCalendar : BaseCalendar
{
public CustomCalendar()
{
}
// binary serialization support
protected CustomCalendar(SerializationInfo info, StreamingContext context) : base(info, context)
{
SomeCustomProperty = info?.GetBoolean("SomeCustomProperty") ?? true;
}
public bool SomeCustomProperty { get; set; } = true;
// binary serialization support
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info?.AddValue("SomeCustomProperty", SomeCustomProperty);
}
}
// JSON serialization support
class CustomCalendarSerializer : CalendarSerializer<CustomCalendar>
{
protected override CustomCalendar Create(JObject source)
{
return new CustomCalendar();
}
protected override void SerializeFields(JsonWriter writer, CustomCalendar calendar)
{
writer.WritePropertyName("SomeCustomProperty");
writer.WriteValue(calendar.SomeCustomProperty);
}
protected override void DeserializeFields(CustomCalendar calendar, JObject source)
{
calendar.SomeCustomProperty = source["SomeCustomProperty"]!.Value<bool>();
}
}
A serializer can optionally override CalendarTypeName to give the calendar a serializer-neutral
name — the same discriminator the System.Text.Json package would use for it. The registry then finds
the serializer under that name as well as under the calendar's assembly-qualified type name, so a
payload written by either package resolves. Leave it unset and the serializer answers only to the
assembly-qualified name, which is what payloads written by 3.x carry.
Configuring custom calendar serializer
builder.Services.AddQuartz(q => q.UsePersistentStore(store =>
{
store.UseNewtonsoftJsonSerializer(json =>
{
json.AddCalendarSerializer<CustomCalendar>(new CustomCalendarSerializer());
});
}));
::: warning Changed in 4.0
NewtonsoftJsonObjectSerializer.AddCalendarSerializer and AddTriggerSerializer were static in 3.x, so
every scheduler in the process shared one set of custom serializers and registration order silently
decided which one won. They have been removed. Register through the UseNewtonsoftJsonSerializer
callback as above: what the callback registers belongs to that scheduler alone, so two schedulers in one
container can serialize different custom types.
:::
If you build a serializer yourself rather than through the store builder, hand it a
NewtonsoftJsonSerializerRegistry. A new registry already knows every built-in trigger and calendar type,
so registering a custom one adds to that set:
NewtonsoftJsonSerializerRegistry registry = new NewtonsoftJsonSerializerRegistry()
.AddCalendarSerializer<CustomCalendar>(new CustomCalendarSerializer())
.AddTriggerSerializer<CustomTrigger>(new CustomTriggerSerializer());
NewtonsoftJsonObjectSerializer serializer = new(registry);
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.11)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.11)
- Microsoft.Extensions.Logging (>= 10.0.11)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.11)
- Newtonsoft.Json (>= 13.0.4)
- Quartz (>= 4.0.0-alpha.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Quartz.Serialization.Newtonsoft:
| Package | Downloads |
|---|---|
|
Quartz.Serialization.Json
Renamed to Quartz.Serialization.Newtonsoft in 4.0. This package is empty and exists only so a grouped dependency update can move to 4.x - reference Quartz.Serialization.Newtonsoft instead, and see the migration guide. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.1.0 | 2,094 | 9/13/2026 |
| 4.0.1 | 1,708 | 9/8/2026 |
| 4.0.0 | 584 | 9/3/2026 |
| 4.0.0-rc.2 | 67 | 9/3/2026 |
| 4.0.0-rc.1 | 69 | 9/3/2026 |
| 4.0.0-beta.1 | 69 | 9/2/2026 |
| 4.0.0-alpha.5 | 70 | 8/31/2026 |
| 4.0.0-alpha.4 | 66 | 8/31/2026 |
| 4.0.0-alpha.3 | 67 | 8/27/2026 |
| 4.0.0-alpha.2 | 76 | 8/25/2026 |
| 4.0.0-alpha.1 | 86 | 8/22/2026 |