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. 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 ## Status Mapping
- `MSBTS_SendPort.Status`: `1=Bound`, `2=Stopped`, `3=Started` - `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. 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 ## 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. 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.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json; using System.Runtime.Serialization.Json;
using System.Text; using System.Text;
@@ -6,6 +7,8 @@ namespace BizTalkPlatformManagementTool.Services
{ {
public static class JsonFileStore public static class JsonFileStore
{ {
private static readonly Encoding Utf8NoBom = new UTF8Encoding(false);
public static void Save<T>(string path, T value) public static void Save<T>(string path, T value)
{ {
Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))); Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path)));
@@ -17,8 +20,8 @@ namespace BizTalkPlatformManagementTool.Services
using (var stream = new MemoryStream()) using (var stream = new MemoryStream())
{ {
serializer.WriteObject(stream, value); serializer.WriteObject(stream, value);
var json = Encoding.UTF8.GetString(stream.ToArray()); var json = Utf8NoBom.GetString(stream.ToArray());
File.WriteAllText(path, json, Encoding.UTF8); File.WriteAllText(path, json, Utf8NoBom);
} }
} }
@@ -29,10 +32,55 @@ namespace BizTalkPlatformManagementTool.Services
UseSimpleDictionaryFormat = true 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.";
}
} }
} }