Reading and writing
editRead an archive
HarDocument reads JSON from three sources:
| Method | Source |
|---|---|
Parse(string) | A JSON string. |
Parse(Stream) | A UTF-8 stream. |
ParseAsync(Stream, CancellationToken) | A UTF-8 stream, asynchronously. |
Property names are matched case-insensitively. Invalid JSON throws a JsonException, and a document that is the JSON null throws an InvalidOperationException. A stream is not closed.
Create and write an archive
Build the model with object initializers, then write it with WriteTo or WriteToAsync, to any stream:
var document = new HarDocument
{
Log = new HarLog
{
Version = "1.2",
Creator = new HarCreator
{
Name = "MyTool",
Version = "1.0.0",
},
Entries =
[
new HarEntry
{
StartedDateTime = DateTimeOffset.UtcNow,
Request = new HarRequest
{
Method = "GET",
Url = "https://example.com/api/data",
},
Response = new HarResponse
{
Status = 200,
StatusText = "OK",
},
},
],
},
};
using var stream = new MemoryStream();
await document.WriteToAsync(stream, indented: true);To write to a file, pass the FileStream returned by File.Create("output.har"). ToJsonString returns the JSON as a string:
var document = new HarDocument();
document.Log!.Creator = new HarCreator { Name = "MyTool", Version = "1.0" };
document.Log.Entries!.Add(new HarEntry
{
StartedDateTime = new DateTimeOffset(2026, 1, 15, 10, 0, 0, TimeSpan.Zero),
Request = new HarRequest { Method = "GET", Url = "https://example.com/" },
Response = new HarResponse { Status = 204, StatusText = "No Content" },
});
var json = document.ToJsonString(indented: true);
var copy = HarDocument.Parse(json);
Assert.Equal("1.2", copy.Log!.Version);
Assert.Equal(204, Assert.Single(copy.Log.Entries!).Response!.Status);indented: trueformats the JSON on several lines. The default is compact JSON.- A new HarDocument already has a Log with Version
1.2, a Creator and an empty Entries list, so you can add entries to it. - A new HarEntry has empty Request, Response, Cache and Timings objects; set the values you know.
- A property whose value is
nullis not written.
Custom fields
Tools add their own fields to the objects of the format, with names that start with _. The fields the model does not define are kept in the ExtensionData dictionary of each object, and written back:
var document = HarDocument.Parse("""
{
"log": {
"version": "1.2",
"entries": [
{ "_resourceType": "xhr", "request": { "method": "GET", "url": "https://example.com/" } }
]
}
}
""");
var entry = Assert.Single(document.Log!.Entries!);
Assert.Equal("xhr", entry.ExtensionData!["_resourceType"].GetString());
// Custom fields are written back
Assert.Contains("\"_resourceType\":\"xhr\"", document.ToJsonString());The values are JsonElements. To add a field, add an entry to the dictionary; it is null until the object has a field to hold, so create it first.
Values the format uses for unknown data, such as -1 for a timing that does not apply, are read and written as they are.