StructuredClone
The browser's own deep-copy algorithm - and the test that decides whether postMessage, IndexedDB and history.pushState will accept a payload before you hand it to one of them.
@inject Bit.Butil.StructuredClone structuredCloneMDN reference
DateTime arrives
as a string and comes back a string, and the Map, Set and
ArrayBuffer types structured clone preserves have no representation here to
preserve. This is a deep copy and a compatibility check - not a way to smuggle types past the
boundary.
Returns true when the runtime exposes structuredClone. During prerender/SSR the check returns false rather than throwing, so defer it to OnAfterRenderAsync.
@inject Bit.Butil.StructuredClone structuredClone
var supported = await structuredClone.IsSupported();A deep copy with no ICloneable to implement and no copy constructor to keep in sync: the value goes out, a detached copy comes back. Mutating the copy here leaves the original untouched, nested objects and all.
var copy = await structuredClone.Clone(order);
copy!.Lines[0].Quantity = 99; // the original is unaffectedThe same algorithm decides what postMessage, IndexedDB and history.pushState accept - so this answers 'will this payload survive' before you find out from a DataCloneError at the far end. Worth calling once against a representative payload rather than per message.
if (await structuredClone.CanClone(payload) is false)
{
// don't hand it to BroadcastChannel / IndexedDb / History
}API reference
ValueTask<bool> IsSupported()ValueTask<T?> Clone<T>(T value)ValueTask<bool> CanClone<T>(T value)