JSON/XML/etc object serialization
$ dotnet add package Plinth.SerializationSerialization utilities for JSON and XML
Provides utilities for JSON and XML serialization with sensible defaults and custom converters.
JsonUtil provides a simplified API for JSON serialization with Plinth's default settings:
using Plinth.Serialization;
public class User
{
public Guid Id { get; set; }
public string Name { get; set; }
public string? Email { get; set; }
}
var user = new User { Id = Guid.NewGuid(), Name = "John Doe" };
// Serialize to JSON string
var json = JsonUtil.SerializeObject(user);
// Result: {"Id":"...","Name":"John Doe"}
// Note: Email is null and not included in output
// Deserialize from JSON string
var deserializedUser = JsonUtil.DeserializeObject<User>(json);
// Deserialize from file
var config = JsonUtil.DeserializeObjectFromFile<AppConfig>("config.json");
// Try deserialize with error handling
if (JsonUtil.TryDeserializeObjectFromFile<AppConfig>("config.json", out var result))
{
// Use result
}
else
{
// Handle failure
}
You can customize serialization settings for specific calls:
var json = JsonUtil.SerializeObject(user, settings =>
{
settings.Formatting = Newtonsoft.Json.Formatting.Indented;
settings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Include;
});
// Create a deep clone using JSON serialization
var userCopy = JsonUtil.DeepClone(user);Useful when working with dynamic JSON:
// Convert deserialized object to specific type
var obj = JsonUtil.DeserializeObject<object>(json);
var userId = JsonUtil.ConvertDeserializedObject<Guid>(obj, Guid.Empty);
// Try convert with null check
if (JsonUtil.TryConvertDeserializedObject<Guid>(obj, out var id))
{
// Use id
}XmlUtil provides utilities for XML serialization using .NET's XmlSerializer.
using Plinth.Serialization;
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
public int Year { get; set; }
}
var book = new Book
{
Title = "Sample Book",
Author = "John Doe",
Year = 2024
};
// Serialize to XML string with default settings (includes namespaces, declaration, indented)
var xml = XmlUtil.Serialize(book);
// Serialize with custom settings
var xml = XmlUtil.Serialize(book,
XmlUtil.SerializerSettings.OmitNamespaces |
XmlUtil.SerializerSettings.OmitXmlDeclaration);Available flags:
Default - Includes namespaces, XML declaration, and indentationOmitNamespaces - Excludes XML namespaces from outputOmitXmlDeclaration - Excludes <?xml version="1.0"?> declarationNoIndent - Outputs XML without indentation// Deserialize from XML string
var book = XmlUtil.Deserialize<Book>(xml);
// Deserialize from file
var book = XmlUtil.DeserializeFromFile<Book>("book.xml");
// Deserialize from stream
using var stream = File.OpenRead("book.xml");
var book = XmlUtil.DeserializeFromStream<Book>(stream);// Serialize to stream (useful for large files or network streams)
using var stream = File.Create("output.xml");
XmlUtil.Serialize(book, stream, XmlUtil.SerializerSettings.Default);Validate XML against XSD schemas:
var xml = File.ReadAllText("data.xml");
var errors = XmlUtil.Validate(xml, "schema1.xsd", "schema2.xsd");
if (errors.Count == 0)
{
Console.WriteLine("XML is valid");
}
else
{
foreach (var error in errors)
{
Console.WriteLine($"Validation error: {error}");
}
}Automatically included in JsonUtil, this converter serializes nullable enums as strings instead of integers.
public enum Status { Active, Inactive, Pending }
public class Item
{
public Status? CurrentStatus { get; set; }
}
// Serializes as: {"CurrentStatus":"Active"} instead of {"CurrentStatus":0}CamelCase Property Names:
using Plinth.Serialization.JsonNet;
var settings = new JsonSerializerSettings
{
ContractResolver = new JsonNetCamelCasePropertyNamesContractResolver()
};
// Properties like "FirstName" will serialize as "firstName"Underscore Property Names:
using Plinth.Serialization.JsonNet;
var settings = new JsonSerializerSettings
{
ContractResolver = new JsonNetUnderscorePropertyNamesContractResolver()
};
// Properties like "FirstName" will serialize as "first_name"OmitNamespaces when namespaces aren't required for cleaner XMLTryDeserialize methods for better error handling when reading filesDeepClone for simple objects; complex object graphs may require custom cloning logic