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
f4e8624
fix(json,json-cppagent): cache JsonSerializerOptions singletons — plu…
ottobolyos Aug 20, 2026
3dd320d
test(json,json-cppagent): pin thread-safety + cold-path converter + C…
ottobolyos Aug 21, 2026
1b96da3
feat(json,json-cppagent): freeze + warm DefaultOptions singletons — d…
ottobolyos Aug 21, 2026
72ea084
docs(json,json-cppagent): document CreateOptions/GetOptions helpers —…
ottobolyos Aug 21, 2026
691bba4
chore(json-cppagent,tests): AmE spelling normalization — dime L2
ottobolyos Aug 21, 2026
8e124ee
test(json,json-cppagent): pin warm-up-before-MakeReadOnly static-ctor…
ottobolyos Aug 21, 2026
ad5ac2f
perf(json,json-cppagent): warm-up traverses MTConnect response graph …
ottobolyos Aug 21, 2026
b072627
chore(json,json-cppagent,tests): AmE tokens amortize+synchronize+flav…
ottobolyos Aug 21, 2026
dac03ba
fix(json,json-cppagent): warm ErrorResponseDocument + WHY-LCG on opti…
ottobolyos Aug 21, 2026
78a174d
test(json,json-cppagent,common,mqttrelay): replace tautological Error…
ottobolyos Aug 21, 2026
0e3ca95
fix(json,json-cppagent): populate Error warm-up + document JsonAssets…
ottobolyos Aug 21, 2026
c013831
test(json,json-cppagent): pin populated Error-envelope newobjs — cove…
ottobolyos Aug 21, 2026
7c6c4da
refactor(json,json-cppagent): warm Version via MTConnectVersions.Vers…
ottobolyos Aug 21, 2026
5c34a16
test(json,json-cppagent): IL walker accepts ldsfld producers — chase …
ottobolyos Aug 21, 2026
d0f770e
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 @@ -277,12 +286,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 @@ -317,12 +321,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
Loading