diff --git a/example/SeqTail/Program.cs b/example/SeqTail/Program.cs index 0122366..18b2947 100644 --- a/example/SeqTail/Program.cs +++ b/example/SeqTail/Program.cs @@ -6,7 +6,7 @@ using System.Reactive.Linq; using Serilog.Formatting.Compact.Reader; using System.Threading; -using Newtonsoft.Json.Linq; +using System.Text.Json; const string usage = @"seq-tail: watch a Seq query from your console. @@ -67,7 +67,7 @@ static async Task Run(string server, string? apiKey, string? filter, Cancellatio strict = converted.StrictExpression; } - using var stream = await connection.Events.StreamAsync(filter: strict); + using var stream = await connection.Events.StreamAsync(filter: strict); var subscription = stream .Select(LogEventReader.ReadFromJObject) .Subscribe(Log.Write, cancel.Cancel); diff --git a/example/SeqTail/SeqTail.csproj b/example/SeqTail/SeqTail.csproj index 9bf2168..a59de6f 100644 --- a/example/SeqTail/SeqTail.csproj +++ b/example/SeqTail/SeqTail.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/Seq.Api/Client/SeqApiClient.cs b/src/Seq.Api/Client/SeqApiClient.cs index 295467b..bb7c809 100644 --- a/src/Seq.Api/Client/SeqApiClient.cs +++ b/src/Seq.Api/Client/SeqApiClient.cs @@ -21,8 +21,8 @@ using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; +using System.Text.Json; +using System.Text.Json.Serialization; using Seq.Api.Model; using Seq.Api.Model.Root; using Seq.Api.Serialization; @@ -45,13 +45,11 @@ public sealed class SeqApiClient : IDisposable const string SeqApiV9MediaType = "application/vnd.datalust.seq.v9+json"; readonly CookieContainer _cookies = new(); - readonly JsonSerializer _serializer = JsonSerializer.Create( - new JsonSerializerSettings - { - Converters = { new StringEnumConverter(), new LinkCollectionConverter() }, - DateParseHandling = DateParseHandling.None, - FloatParseHandling = FloatParseHandling.Decimal - }); + readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions() + { + Converters = { new JsonStringEnumConverter(), new LinkCollectionConverter() }, + NumberHandling = JsonNumberHandling.AllowReadingFromString, + }; /// /// Construct a . @@ -217,7 +215,7 @@ public async Task PostAsync(ILinked entity, strin var linkUri = ResolveLink(entity, link, parameters); var request = new HttpRequestMessage(HttpMethod.Post, linkUri) { Content = MakeJsonContent(content) }; var stream = await HttpSendAsync(request, cancellationToken).ConfigureAwait(false); - return _serializer.Deserialize(new JsonTextReader(new StreamReader(stream))); + return await JsonSerializer.DeserializeAsync(stream, _serializerOptions, cancellationToken); } /// @@ -310,7 +308,7 @@ public async Task DeleteAsync(ILinked entity, str var linkUri = ResolveLink(entity, link, parameters); var request = new HttpRequestMessage(HttpMethod.Delete, linkUri) { Content = MakeJsonContent(content) }; var stream = await HttpSendAsync(request, cancellationToken).ConfigureAwait(false); - return _serializer.Deserialize(new JsonTextReader(new StreamReader(stream))); + return await JsonSerializer.DeserializeAsync(stream, _serializerOptions, cancellationToken); } /// @@ -324,7 +322,8 @@ public async Task DeleteAsync(ILinked entity, str /// A stream of values from the websocket. public async Task> StreamAsync(ILinked entity, string link, IDictionary parameters = null, CancellationToken cancellationToken = default) { - return await WebSocketStreamAsync(entity, link, parameters, reader => _serializer.Deserialize(new JsonTextReader(reader)), cancellationToken); + return await WebSocketStreamAsync(entity, link, parameters, stream => + JsonSerializer.DeserializeAsync(stream, _serializerOptions).AsTask(), cancellationToken); } /// @@ -337,10 +336,10 @@ public async Task> StreamAsync(ILinked entity /// A stream of raw messages from the websocket. public async Task> StreamTextAsync(ILinked entity, string link, IDictionary parameters = null, CancellationToken cancellationToken = default) { - return await WebSocketStreamAsync(entity, link, parameters, reader => reader.ReadToEnd(), cancellationToken); + return await WebSocketStreamAsync(entity, link, parameters, stream => new StreamReader(stream).ReadToEndAsync(), cancellationToken); } - async Task> WebSocketStreamAsync(ILinked entity, string link, IDictionary parameters, Func deserialize, CancellationToken cancellationToken = default) + async Task> WebSocketStreamAsync(ILinked entity, string link, IDictionary parameters, Func> deserialize, CancellationToken cancellationToken = default) { var linkUri = ResolveLink(entity, link, parameters); @@ -358,7 +357,7 @@ async Task HttpGetAsync(string url, CancellationToken cancellationToken = { var request = new HttpRequestMessage(HttpMethod.Get, url); var stream = await HttpSendAsync(request, cancellationToken).ConfigureAwait(false); - return _serializer.Deserialize(new JsonTextReader(new StreamReader(stream))); + return await JsonSerializer.DeserializeAsync(stream, _serializerOptions, cancellationToken); } async Task HttpGetStringAsync(string url, CancellationToken cancellationToken = default) @@ -380,7 +379,7 @@ async Task HttpSendAsync(HttpRequestMessage request, CancellationToken c Dictionary payload = null; try { - payload = _serializer.Deserialize>(new JsonTextReader(new StreamReader(stream))); + payload = await JsonSerializer.DeserializeAsync>(stream, _serializerOptions, cancellationToken); } // ReSharper disable once EmptyGeneralCatchClause catch { } @@ -393,9 +392,8 @@ async Task HttpSendAsync(HttpRequestMessage request, CancellationToken c HttpContent MakeJsonContent(object content) { - var json = new StringWriter(); - _serializer.Serialize(json, content); - return new StringContent(json.ToString(), Encoding.UTF8, "application/json"); + var jsonString = JsonSerializer.Serialize(content, _serializerOptions); + return new StringContent(jsonString, Encoding.UTF8, "application/json"); } static string ResolveLink(ILinked entity, string link, IDictionary parameters = null) diff --git a/src/Seq.Api/Model/AppInstances/AppInstanceEntity.cs b/src/Seq.Api/Model/AppInstances/AppInstanceEntity.cs index e563308..03ceb17 100644 --- a/src/Seq.Api/Model/AppInstances/AppInstanceEntity.cs +++ b/src/Seq.Api/Model/AppInstances/AppInstanceEntity.cs @@ -14,7 +14,7 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; using Seq.Api.Model.Apps; using Seq.Api.Model.Inputs; using Seq.Api.Model.Signals; @@ -122,57 +122,57 @@ public AppInstanceEntity() /// /// Settings that control how events are ingested through the app. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public InputSettingsPart? InputSettings { get; set; } /// /// Metrics describing the state and activity of the app process. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public AppInstanceProcessMetricsPart? ProcessMetrics { get; set; } /// /// Information about ingestion activity through this app. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public InputMetricsPart? InputMetrics { get; set; } /// /// Information about the app's diagnostic input. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public InputMetricsPart? DiagnosticInputMetrics { get; set; } /// /// Information about events output through the app. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public AppInstanceOutputMetricsPart? OutputMetrics { get; set; } /// /// Obsolete. /// [Obsolete("Use !AcceptStreamedEvents instead.")] - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool? IsManualInputOnly { get; set; } /// /// Obsolete. /// [Obsolete("Use !AcceptDirectInvocation instead.")] - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool? DisallowManualInput { get; set; } /// /// The name of the app. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string? AppName { get; set; } /// /// If true, then the app is able to write events to the log. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool? IsInput { get; set; } } } diff --git a/src/Seq.Api/Model/Data/QueryResultPart.cs b/src/Seq.Api/Model/Data/QueryResultPart.cs index 2007a80..ed69b1e 100644 --- a/src/Seq.Api/Model/Data/QueryResultPart.cs +++ b/src/Seq.Api/Model/Data/QueryResultPart.cs @@ -13,7 +13,7 @@ // limitations under the License. using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Seq.Api.Model.Data { @@ -37,49 +37,49 @@ public class QueryResultPart /// /// Result rows. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public object[][] Rows { get; set; } /// /// Result time slices. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public TimeSlicePart[] Slices { get; set; } /// /// Result timeseries. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public TimeseriesPart[] Series { get; set; } /// /// Result variables. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public Dictionary Variables { get; set; } /// /// On error only, a description of the error. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Error { get; set; } /// /// Reasons for the . /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string[] Reasons { get; set; } /// /// A corrected version of the query, if one could be suggested. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string Suggestion { get; set; } /// /// Execution statistics. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public QueryExecutionStatisticsPart Statistics { get; set; } } } \ No newline at end of file diff --git a/src/Seq.Api/Model/Entity.cs b/src/Seq.Api/Model/Entity.cs index 67a9408..eed0782 100644 --- a/src/Seq.Api/Model/Entity.cs +++ b/src/Seq.Api/Model/Entity.cs @@ -14,8 +14,8 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; namespace Seq.Api.Model { @@ -50,8 +50,8 @@ protected Entity() /// /// Facilitates backwards compatibility in the Seq server. Should not be used by consumers/clients. /// - [JsonExtensionData, JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonExtensionData, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] [Obsolete("Facilitates backwards compatibility in the Seq server. Should not be used by consumers/clients.")] - public Dictionary ExtensionData { get; set; } + public Dictionary ExtensionData { get; set; } } } diff --git a/src/Seq.Api/Model/Events/EventEntity.cs b/src/Seq.Api/Model/Events/EventEntity.cs index fa58cca..68dac97 100644 --- a/src/Seq.Api/Model/Events/EventEntity.cs +++ b/src/Seq.Api/Model/Events/EventEntity.cs @@ -13,7 +13,7 @@ // limitations under the License. using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; using Seq.Api.Model.Shared; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -48,38 +48,38 @@ public class EventEntity : Entity /// /// A level associated with an event; null may indicate that the event is informational. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string Level { get; set; } /// /// An exception, stack trace/backtrace associated with the event. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string Exception { get; set; } /// /// If requested, a pre-rendered version of the templated event message. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string RenderedMessage { get; set; } /// /// A trace id associated with the event, if any. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string TraceId { get; set; } /// /// A span id associated with the event, if any. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string SpanId { get; set; } /// /// A collection of properties describing the origin of the event, if any. These correspond to resource /// attributes in the OpenTelemetry spec. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public List Resource { get; set; } } } diff --git a/src/Seq.Api/Model/Events/MessageTemplateTokenPart.cs b/src/Seq.Api/Model/Events/MessageTemplateTokenPart.cs index 707c0a1..102f219 100644 --- a/src/Seq.Api/Model/Events/MessageTemplateTokenPart.cs +++ b/src/Seq.Api/Model/Events/MessageTemplateTokenPart.cs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Seq.Api.Model.Events { @@ -24,25 +24,25 @@ public class MessageTemplateTokenPart /// /// Plain text, if the token is a text token. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string Text { get; set; } /// /// The name of the property to be rendered in place of the token, if a property token. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string PropertyName { get; set; } /// /// The raw source text from the message template (provided for both text and property tokens). /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string RawText { get; set; } /// /// A pre-formatted value, if the token carries language-specific formatting directives. /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string FormattedValue { get; set; } } } diff --git a/src/Seq.Api/Model/Inputs/ApiKeyEntity.cs b/src/Seq.Api/Model/Inputs/ApiKeyEntity.cs index bb0c4a6..7de5b19 100644 --- a/src/Seq.Api/Model/Inputs/ApiKeyEntity.cs +++ b/src/Seq.Api/Model/Inputs/ApiKeyEntity.cs @@ -13,7 +13,7 @@ // limitations under the License. using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; using Seq.Api.Model.Security; namespace Seq.Api.Model.Inputs @@ -68,7 +68,7 @@ public class ApiKeyEntity : Entity /// /// Information about the ingestion activity using this API key. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public InputMetricsPart InputMetrics { get; set; } = new InputMetricsPart(); } } diff --git a/src/Seq.Api/Model/LinkCollection.cs b/src/Seq.Api/Model/LinkCollection.cs index b122b97..0145f7a 100644 --- a/src/Seq.Api/Model/LinkCollection.cs +++ b/src/Seq.Api/Model/LinkCollection.cs @@ -14,7 +14,7 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; using Seq.Api.Serialization; namespace Seq.Api.Model diff --git a/src/Seq.Api/Model/Permalinks/PermalinkEntity.cs b/src/Seq.Api/Model/Permalinks/PermalinkEntity.cs index d2fc667..832941c 100644 --- a/src/Seq.Api/Model/Permalinks/PermalinkEntity.cs +++ b/src/Seq.Api/Model/Permalinks/PermalinkEntity.cs @@ -13,7 +13,7 @@ // limitations under the License. using System; -using Newtonsoft.Json; +using System.Text.Json.Serialization; using Seq.Api.Model.Events; using Seq.Api.ResourceGroups; @@ -49,7 +49,7 @@ public class PermalinkEntity : Entity /// The event itself. Only populated when explicitly requested from the API. /// See . /// - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public EventEntity Event { get; set; } } } diff --git a/src/Seq.Api/Model/Retention/RetentionPolicyEntity.cs b/src/Seq.Api/Model/Retention/RetentionPolicyEntity.cs index 380f850..3342876 100644 --- a/src/Seq.Api/Model/Retention/RetentionPolicyEntity.cs +++ b/src/Seq.Api/Model/Retention/RetentionPolicyEntity.cs @@ -13,7 +13,7 @@ // limitations under the License. using System; -using Newtonsoft.Json; +using System.Text.Json.Serialization; using Seq.Api.Model.Signals; namespace Seq.Api.Model.Retention @@ -40,7 +40,7 @@ public class RetentionPolicyEntity : Entity /// Obsolete. /// [Obsolete("Replaced by RemovedSignalExpression."), - JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string SignalId { get; set; } } } diff --git a/src/Seq.Api/Model/Root/RootEntity.cs b/src/Seq.Api/Model/Root/RootEntity.cs index 8dcb8da..213794c 100644 --- a/src/Seq.Api/Model/Root/RootEntity.cs +++ b/src/Seq.Api/Model/Root/RootEntity.cs @@ -13,7 +13,7 @@ // limitations under the License. using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Seq.Api.Model.Root { @@ -49,7 +49,7 @@ public RootEntity() /// A list of non-default features enabled on this server. Normally, null unless /// an administrator has explicitly opted-into alpha or beta-level features. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public List EnabledFeatures { get; set; } /// diff --git a/src/Seq.Api/Model/Signals/SignalEntity.cs b/src/Seq.Api/Model/Signals/SignalEntity.cs index 9c90ba2..daccc5d 100644 --- a/src/Seq.Api/Model/Signals/SignalEntity.cs +++ b/src/Seq.Api/Model/Signals/SignalEntity.cs @@ -14,7 +14,7 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; using Seq.Api.Model.Security; using Seq.Api.Model.Shared; @@ -60,7 +60,7 @@ public SignalEntity() /// // ReSharper disable once UnusedMember.Global [Obsolete("This member has been renamed `IsProtected` to better reflect its purpose.")] - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool? IsRestricted { get; set; } /// diff --git a/src/Seq.Api/Model/Signals/SignalExpressionPart.cs b/src/Seq.Api/Model/Signals/SignalExpressionPart.cs index 7f31382..0f3770b 100644 --- a/src/Seq.Api/Model/Signals/SignalExpressionPart.cs +++ b/src/Seq.Api/Model/Signals/SignalExpressionPart.cs @@ -15,7 +15,8 @@ using System; using System.Collections.Generic; using System.Linq; -using Newtonsoft.Json; +using System.Text.Json.Serialization; + namespace Seq.Api.Model.Signals { @@ -35,21 +36,21 @@ public class SignalExpressionPart /// When is , the id of the /// signal represented by this expression node. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string SignalId { get; set; } /// /// When is or /// , the left side of the operation. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public SignalExpressionPart Left { get; set; } /// /// When is or /// , the right side of the operation. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public SignalExpressionPart Right { get; set; } /// diff --git a/src/Seq.Api/Model/Users/UserEntity.cs b/src/Seq.Api/Model/Users/UserEntity.cs index 81002f1..c02b24d 100644 --- a/src/Seq.Api/Model/Users/UserEntity.cs +++ b/src/Seq.Api/Model/Users/UserEntity.cs @@ -13,7 +13,7 @@ // limitations under the License. using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; using Seq.Api.Model.Shared; using Seq.Api.Model.Signals; @@ -48,14 +48,14 @@ public class UserEntity : Entity /// /// If changing password, the new password for the user. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string NewPassword { get; set; } /// /// A filter that is applied to searches and queries instigated by /// the user. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public DescriptiveFilterPart ViewFilter { get; set; } /// @@ -63,7 +63,7 @@ public class UserEntity : Entity /// changing their password. Recommended when administratively assigning /// a password for the user. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool MustChangePassword { get; set; } /// @@ -78,14 +78,14 @@ public class UserEntity : Entity /// user may need to be unlinked from an existing provider so that login can proceed through /// the new provider. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string AuthenticationProvider { get; set; } /// /// The unique identifier that links the identity provided by the authentication provider /// with the Seq user. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string AuthenticationProviderUniqueIdentifier { get; set; } } } diff --git a/src/Seq.Api/Seq.Api.csproj b/src/Seq.Api/Seq.Api.csproj index 44227ef..c0e3f0a 100644 --- a/src/Seq.Api/Seq.Api.csproj +++ b/src/Seq.Api/Seq.Api.csproj @@ -19,11 +19,12 @@ - + + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Seq.Api/Serialization/LinkCollectionConverter.cs b/src/Seq.Api/Serialization/LinkCollectionConverter.cs index 6c518d5..8045be2 100644 --- a/src/Seq.Api/Serialization/LinkCollectionConverter.cs +++ b/src/Seq.Api/Serialization/LinkCollectionConverter.cs @@ -15,35 +15,37 @@ using System; using System.Collections.Generic; using System.Linq; -using Newtonsoft.Json; +using System.Text.Json; +using System.Text.Json.Serialization; using Seq.Api.Model; namespace Seq.Api.Serialization { - class LinkCollectionConverter : JsonConverter + class LinkCollectionConverter : JsonConverter { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override bool CanConvert(Type objectType) { - var lc = (LinkCollection)value; - var dictionary = lc.ToDictionary(kv => kv.Key, kv => kv.Value.Template); - serializer.Serialize(writer, dictionary); + return objectType == typeof(LinkCollection); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override LinkCollection Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var hrefs = serializer.Deserialize>(reader); - if (hrefs == null) return existingValue; + var hrefs = JsonSerializer.Deserialize>(ref reader, options); var result = new LinkCollection(); - foreach (var href in hrefs) + if (hrefs != null) { - result.Add(href.Key, new Link(href.Value)); + foreach (var href in hrefs) + { + result.Add(href.Key, new Link(href.Value)); + } } return result; } - public override bool CanConvert(Type objectType) + public override void Write(Utf8JsonWriter writer, LinkCollection value, JsonSerializerOptions options) { - return objectType == typeof(LinkCollection); + var dictionary = value.ToDictionary(kv => kv.Key, kv => kv.Value.Template); + JsonSerializer.Serialize(writer, dictionary, options); } } } \ No newline at end of file diff --git a/src/Seq.Api/Streams/ObservableStream.cs b/src/Seq.Api/Streams/ObservableStream.cs index 00a735e..8bc4222 100644 --- a/src/Seq.Api/Streams/ObservableStream.cs +++ b/src/Seq.Api/Streams/ObservableStream.cs @@ -19,7 +19,6 @@ using System.Net.WebSockets; using System.Threading.Tasks; using System.IO; -using System.Text; using System.Linq; namespace Seq.Api.Streams @@ -36,9 +35,9 @@ public sealed partial class ObservableStream : IObservable, IDisposable Task _run; readonly ClientWebSocket _socket; - readonly Func _deserialize; + readonly Func> _deserialize; - internal ObservableStream(ClientWebSocket socket, Func deserialize) + internal ObservableStream(ClientWebSocket socket, Func> deserialize) { _deserialize = deserialize ?? throw new ArgumentNullException(nameof(deserialize)); _socket = socket ?? throw new ArgumentNullException(nameof(socket)); @@ -86,7 +85,6 @@ async Task Receive() { var buffer = new byte[16 * 1024]; var current = new MemoryStream(); - var reader = new StreamReader(current, new UTF8Encoding(false)); while (_socket.State == WebSocketState.Open) { @@ -106,10 +104,9 @@ async Task Receive() if (received.EndOfMessage) { current.Position = 0; - var value = _deserialize(reader); + var value = await _deserialize(current); current.SetLength(0); - reader.DiscardBufferedData(); Emit(value); }