Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
5fc08e1
fix(json,json-cppagent): cache JsonSerializerOptions singletons — plu…
ottobolyos Aug 20, 2026
aae2d32
test(json,json-cppagent): pin thread-safety + cold-path converter + C…
ottobolyos Aug 21, 2026
646eadd
feat(json,json-cppagent): freeze + warm DefaultOptions singletons — d…
ottobolyos Aug 21, 2026
59ec2e5
docs(json,json-cppagent): document CreateOptions/GetOptions helpers —…
ottobolyos Aug 21, 2026
4198e73
chore(json-cppagent,tests): AmE spelling normalization — dime L2
ottobolyos Aug 21, 2026
3c2636e
test(json,json-cppagent): pin warm-up-before-MakeReadOnly static-ctor…
ottobolyos Aug 21, 2026
42c86dd
perf(json,json-cppagent): warm-up traverses MTConnect response graph …
ottobolyos Aug 21, 2026
54587df
chore(json,json-cppagent,tests): AmE tokens amortize+synchronize+flav…
ottobolyos Aug 21, 2026
04e73fb
fix(json,json-cppagent): warm ErrorResponseDocument + WHY-LCG on opti…
ottobolyos Aug 21, 2026
c2ebb3b
test(json,json-cppagent,common,mqttrelay): replace tautological Error…
ottobolyos Aug 21, 2026
a12081b
fix(json,json-cppagent): populate Error warm-up + document JsonAssets…
ottobolyos Aug 21, 2026
e69b8b4
test(json,json-cppagent): pin populated Error-envelope newobjs — cove…
ottobolyos Aug 21, 2026
4b0c112
refactor(json,json-cppagent): warm Version via MTConnectVersions.Vers…
ottobolyos Aug 21, 2026
892f898
test(json,json-cppagent): IL walker accepts ldsfld producers — chase …
ottobolyos Aug 21, 2026
51f3184
chore(json-tests): disambiguate cref on JsonSerializerOptionsSingleto…
ottobolyos Aug 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions libraries/MTConnect.NET-Common/Agents/MTConnectAgentInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ public class MTConnectAgentInformation
/// </summary>
public const string Filename = "agent.information.json";

// Shared across every Save call. See JsonFunctions.cs for the
// rationale — a fresh JsonSerializerOptions per call re-emits
// LCG DynamicMethods into the loader heap, and the GC cannot
// reclaim them.
private static readonly JsonSerializerOptions _saveOptions = new JsonSerializerOptions
{
WriteIndented = true
};


/// <summary>
/// A token regenerated on every save, used to detect when the persisted information has changed.
Expand Down Expand Up @@ -127,12 +136,7 @@ public void Save(string path = null)

try
{
var options = new JsonSerializerOptions
{
WriteIndented = true
};

var json = JsonSerializer.Serialize(this, options);
var json = JsonSerializer.Serialize(this, _saveOptions);
File.WriteAllText(configurationPath, json);
}
catch { }
Expand Down
16 changes: 10 additions & 6 deletions libraries/MTConnect.NET-Common/Buffers/MTConnectAssetFileBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ public class MTConnectAssetFileBuffer : MTConnectAssetBuffer, IDisposable
/// </summary>
public const string DirectoryAssets = "assets";

// Shared across every asset persistence call. See
// JsonFunctions.cs for the rationale — a fresh
// JsonSerializerOptions per call re-emits LCG DynamicMethods
// into the loader heap, and the GC cannot reclaim them.
private static readonly JsonSerializerOptions _writeOptions = new JsonSerializerOptions
{
WriteIndented = true
};

private readonly string _basePath;
private readonly MTConnectAssetQueue _items;
private readonly Regex _regex = new Regex("([0-9]*)_(.*)");
Expand Down Expand Up @@ -432,14 +441,9 @@ private async Task<bool> WriteToFile(uint index, IAsset asset, uint originalInde
}
}

var options = new JsonSerializerOptions
{
WriteIndented = true
};

var assetType = Asset.GetAssetType(asset.Type);

var json = JsonSerializer.Serialize(asset, assetType, options);
var json = JsonSerializer.Serialize(asset, assetType, _writeOptions);
if (!string.IsNullOrEmpty(json))
{
if (UseCompression)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ public class MTConnectClientInformation
/// </summary>
public const string FilenameExtension = ".json";

// Shared across every Save call. See JsonFunctions.cs for the
// rationale — a fresh JsonSerializerOptions per call re-emits
// LCG DynamicMethods into the loader heap, and the GC cannot
// reclaim them.
private static readonly JsonSerializerOptions _saveOptions = new JsonSerializerOptions
{
WriteIndented = true
};


/// <summary>
/// A token regenerated on every save, used to detect that the persisted state has changed since it was last loaded.
Expand Down Expand Up @@ -126,12 +135,7 @@ public void Save(string path = null)
var configurationPath = Path.Combine(dir, GenerateFilename(DeviceKey));
if (path != null) configurationPath = path;

var options = new JsonSerializerOptions
{
WriteIndented = true
};

var json = JsonSerializer.Serialize(this, options);
var json = JsonSerializer.Serialize(this, _saveOptions);
File.WriteAllText(configurationPath, json);
}
catch { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ public class AdapterApplicationConfiguration : IAdapterApplicationConfiguration
/// </summary>
public const string DefaultYamlFilename = "adapter.config.default.yaml";

// Shared across every ReadJson call. See JsonFunctions.cs for
// the rationale — a fresh JsonSerializerOptions per call
// re-emits LCG DynamicMethods into the loader heap, and the GC
// cannot reclaim them.
private static readonly JsonSerializerOptions _readOptions = new JsonSerializerOptions()
{
ReadCommentHandling = JsonCommentHandling.Skip
};


/// <summary>
/// An opaque token regenerated each time the configuration is saved, allowing consumers to detect that the configuration has changed.
Expand Down Expand Up @@ -371,12 +380,7 @@ public static T ReadJson<T>(string path = null) where T : AdapterApplicationConf
var text = File.ReadAllText(configurationPath);
if (!string.IsNullOrEmpty(text))
{
var options = new JsonSerializerOptions()
{
ReadCommentHandling = JsonCommentHandling.Skip
};

var configuration = JsonSerializer.Deserialize<T>(text, options);
var configuration = JsonSerializer.Deserialize<T>(text, _readOptions);
configuration.Path = configurationPath;
return configuration;
}
Expand Down Expand Up @@ -411,12 +415,7 @@ public static AdapterApplicationConfiguration ReadJson(Type type, string path =
var text = File.ReadAllText(configurationPath);
if (!string.IsNullOrEmpty(text))
{
var options = new JsonSerializerOptions()
{
ReadCommentHandling = JsonCommentHandling.Skip
};

var configuration = (AdapterApplicationConfiguration)JsonSerializer.Deserialize(text, type, options);
var configuration = (AdapterApplicationConfiguration)JsonSerializer.Deserialize(text, type, _readOptions);
configuration.Path = configurationPath;
return configuration;
}
Expand Down
23 changes: 11 additions & 12 deletions libraries/MTConnect.NET-Common/Configurations/AgentConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ public class AgentConfiguration : IAgentConfiguration
/// </summary>
public const string DefaultYamlFilename = "agent.config.default.yaml";

// Shared across every ReadJson call. See JsonFunctions.cs for
// the rationale — a fresh JsonSerializerOptions per call
// re-emits LCG DynamicMethods into the loader heap, and the GC
// cannot reclaim them.
private static readonly JsonSerializerOptions _readOptions = new JsonSerializerOptions()
{
ReadCommentHandling = JsonCommentHandling.Skip
};


/// <summary>
/// An opaque token regenerated each time the configuration is saved, allowing consumers to detect that the configuration has changed.
Expand Down Expand Up @@ -283,12 +292,7 @@ public static T ReadJson<T>(string path = null) where T : AgentConfiguration
var text = File.ReadAllText(configurationPath);
if (!string.IsNullOrEmpty(text))
{
var options = new JsonSerializerOptions()
{
ReadCommentHandling = JsonCommentHandling.Skip
};

var configuration = JsonSerializer.Deserialize<T>(text, options);
var configuration = JsonSerializer.Deserialize<T>(text, _readOptions);
configuration.Path = configurationPath;
return configuration;
}
Expand Down Expand Up @@ -323,12 +327,7 @@ public static AgentConfiguration ReadJson(Type type, string path = null)
var text = File.ReadAllText(configurationPath);
if (!string.IsNullOrEmpty(text))
{
var options = new JsonSerializerOptions()
{
ReadCommentHandling = JsonCommentHandling.Skip
};

var configuration = (AgentConfiguration)JsonSerializer.Deserialize(text, type, options);
var configuration = (AgentConfiguration)JsonSerializer.Deserialize(text, type, _readOptions);
configuration.Path = configurationPath;
return configuration;
}
Expand Down
Loading