Fixed json bom handling when serializing/deserializing json

This commit is contained in:
2026-06-01 14:46:03 +02:00
parent ae468e9f19
commit 076504753e
3 changed files with 56 additions and 4 deletions
+2
View File
@@ -82,6 +82,8 @@ Das BizTalk Platform Management Tool unterstützt kontrollierte Wartungsfenster
Bei echten Shutdown- und Restore-Aktionen wird jeder Schritt vor der Ausführung mit Artefakttyp, WMI-Klasse, Schlüsselproperty, Schlüsselwert und Methodenname protokolliert. Die Objektauflösung verwendet eine breite `SELECT * FROM <class>`-Abfrage und filtert danach im Prozess auf den Schlüsselwert. Dadurch können Host-Instance-Namen und andere BizTalk-Namen mit Sonderzeichen keine ungültige WMI-WQL-`WHERE`-Query mehr erzeugen.
Snapshot- und Plan-JSON-Dateien werden als UTF-8 ohne BOM geschrieben. Beim Laden werden vorhandene Dateien mit UTF-8-BOM oder durch Encoding-Konvertierung sichtbar gewordenem BOM-Marker toleriert.
## Status Mapping
- `MSBTS_SendPort.Status`: `1=Bound`, `2=Stopped`, `3=Started`
+2
View File
@@ -65,6 +65,8 @@ Log files are retained for the current day plus the previous four days. Older `B
The Operation Log shows the WMI class, key property, key value and method for real shutdown and restore steps. WMI objects are resolved with a broad `SELECT * FROM <class>` query and a client-side key filter so names containing special characters do not break the WMI query parser.
Snapshot and plan JSON files are written as UTF-8 without BOM. Loading is tolerant of existing files that contain a UTF-8 BOM or a visible BOM marker from previous encoding conversions.
## Build
Open `BizTalkPlatformManagementTool.sln` in Visual Studio on Windows with the .NET Framework 4.6.1 Developer Pack installed, then build the `Release|Any CPU` configuration.
@@ -1,4 +1,5 @@
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
@@ -6,6 +7,8 @@ namespace BizTalkPlatformManagementTool.Services
{
public static class JsonFileStore
{
private static readonly Encoding Utf8NoBom = new UTF8Encoding(false);
public static void Save<T>(string path, T value)
{
Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path)));
@@ -17,8 +20,8 @@ namespace BizTalkPlatformManagementTool.Services
using (var stream = new MemoryStream())
{
serializer.WriteObject(stream, value);
var json = Encoding.UTF8.GetString(stream.ToArray());
File.WriteAllText(path, json, Encoding.UTF8);
var json = Utf8NoBom.GetString(stream.ToArray());
File.WriteAllText(path, json, Utf8NoBom);
}
}
@@ -29,10 +32,55 @@ namespace BizTalkPlatformManagementTool.Services
UseSimpleDictionaryFormat = true
});
using (var stream = File.OpenRead(path))
var json = NormalizeJson(File.ReadAllText(path, Encoding.UTF8));
using (var stream = new MemoryStream(Utf8NoBom.GetBytes(json)))
{
return (T)serializer.ReadObject(stream);
try
{
return (T)serializer.ReadObject(stream);
}
catch (SerializationException ex)
{
throw new InvalidDataException("Failed to load JSON file '" + path + "'. " + DescribeJsonStart(json), ex);
}
}
}
private static string NormalizeJson(string json)
{
if (string.IsNullOrEmpty(json))
{
return json;
}
if (json[0] == '\uFEFF')
{
json = json.Substring(1);
}
if (json.StartsWith("\u00EF\u00BB\u00BF"))
{
json = json.Substring(3);
}
return json;
}
private static string DescribeJsonStart(string json)
{
if (string.IsNullOrWhiteSpace(json))
{
return "The file is empty or contains only whitespace.";
}
var trimmed = json.TrimStart();
var first = trimmed.Length == 0 ? '\0' : trimmed[0];
if (first != '{' && first != '[')
{
return "The first JSON character is '" + first + "' instead of '{' or '['.";
}
return "The file starts with valid JSON syntax but could not be deserialized into the expected model.";
}
}
}