diff --git a/Microsoft.Toolkit.Services/Microsoft.Toolkit.Services.csproj b/Microsoft.Toolkit.Services/Microsoft.Toolkit.Services.csproj index fe8cc6a9931..446db56c7a3 100644 --- a/Microsoft.Toolkit.Services/Microsoft.Toolkit.Services.csproj +++ b/Microsoft.Toolkit.Services/Microsoft.Toolkit.Services.csproj @@ -7,7 +7,7 @@ This .NET standard library enables access to different data sources such as Microsoft Graph, OneDrive, Twitter, Microsoft Translator, and LinkedIn. It is part of the Windows Community Toolkit. UWP Community Toolkit Windows Microsoft Graph OneDrive Twitter Translator LinkedIn service login OAuth - + 8.0 CS8002;CS0618 false @@ -27,7 +27,7 @@ - + @@ -50,4 +50,4 @@ - \ No newline at end of file + diff --git a/Microsoft.Toolkit.Services/Properties/Microsoft.Toolkit.Services.rd.xml b/Microsoft.Toolkit.Services/Properties/Microsoft.Toolkit.Services.rd.xml new file mode 100644 index 00000000000..9f5b9bd9498 --- /dev/null +++ b/Microsoft.Toolkit.Services/Properties/Microsoft.Toolkit.Services.rd.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInDataProvider.cs b/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInDataProvider.cs index 27c7739c333..b7977d0d092 100644 --- a/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInDataProvider.cs +++ b/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInDataProvider.cs @@ -7,9 +7,9 @@ using System.Diagnostics; using System.Net.Http; using System.Text; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.Toolkit.Services.Core; -using Newtonsoft.Json.Linq; #if WINRT using Microsoft.Toolkit.Services.PlatformSpecific.Uwp; @@ -81,7 +81,8 @@ public LinkedInDataProvider(LinkedInOAuthTokens tokens, LinkedInPermissions requ throw new ArgumentException("Missing callback uri"); } - if (!Enum.IsDefined(typeof(LinkedInPermissions), requiredPermissions)) + // Check if its a valid combination of LinkedInPermissions + if ((~(int)LinkedInPermissionsHelpers.AllPermissions & (int)requiredPermissions) != 0) { throw new ArgumentException("Error retrieving required permissions"); } @@ -186,22 +187,18 @@ public async Task> GetDataAsync(LinkedInDataConfig var url = $"{_baseUrl}{config.Query}/~:({fields})?oauth2_access_token={Tokens.AccessToken}&format=json&count={maxRecords}&start={startRecord}"; - using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(url))) - { - request.Headers.Connection.TryParseAdd("Keep-Alive"); - - using (var response = await client.SendAsync(request).ConfigureAwait(false)) - { - var data = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(url)); + request.Headers.Connection.TryParseAdd("Keep-Alive"); - if (response.IsSuccessStatusCode && !string.IsNullOrEmpty(data)) - { - return parser.Parse(data); - } + using var response = await client.SendAsync(request).ConfigureAwait(false); + var data = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new RequestFailedException((System.Net.HttpStatusCode)response.StatusCode, data); - } + if (response.IsSuccessStatusCode && !string.IsNullOrEmpty(data)) + { + return parser.Parse(data); } + + throw new RequestFailedException((System.Net.HttpStatusCode)response.StatusCode, data); } /// @@ -222,22 +219,18 @@ public async Task ShareDataAsync(T dataToShare) var url = $"{_baseUrl}/people/~/shares?oauth2_access_token={Tokens.AccessToken}&format=json"; - using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, new Uri(url))) - { - request.Headers.Add("x-li-format", "json"); - var stringContent = requestParser.Parse(shareRequest); - request.Content = new StringContent(stringContent, Encoding.UTF8, "application/json"); + using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, new Uri(url)); + request.Headers.Add("x-li-format", "json"); + var stringContent = requestParser.Parse(shareRequest); + request.Content = new StringContent(stringContent, Encoding.UTF8, "application/json"); - using (var response = await client.SendAsync(request).ConfigureAwait(false)) - { - var data = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + using var response = await client.SendAsync(request).ConfigureAwait(false); + var data = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var responseParser = new LinkedInParser(); + var responseParser = new LinkedInParser(); - var listResults = responseParser.Parse(data) as List; - return listResults[0]; - } - } + var listResults = responseParser.Parse(data) as List; + return listResults[0]; } return default(U); @@ -263,15 +256,13 @@ private async Task GetAccessTokenAsync(LinkedInOAuthTokens tokens, strin + "&client_id=" + tokens.ClientId + "&client_secret=" + tokens.ClientSecret; - using (var request = new HttpRequestMessage(HttpMethod.Post, new Uri(url))) - { - using (var response = await client.SendAsync(request).ConfigureAwait(false)) - { - var jsonString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var json = JObject.Parse(jsonString); - return json.GetValue("access_token").Value(); - } - } + using var request = new HttpRequestMessage(HttpMethod.Post, new Uri(url)); + using var response = await client.SendAsync(request).ConfigureAwait(false); + using var jsonStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + using var jsonDoc = await JsonDocument.ParseAsync(jsonStream).ConfigureAwait(false); + + var value = jsonDoc.RootElement.GetProperty("access_token"); + return value.GetString(); } private async Task GetAuthorizeCodeAsync(LinkedInOAuthTokens tokens, LinkedInPermissions permissions) diff --git a/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInParser.cs b/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInParser.cs index 583385bd1ee..4e145764452 100644 --- a/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInParser.cs +++ b/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInParser.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json; namespace Microsoft.Toolkit.Services.LinkedIn { @@ -24,11 +24,11 @@ public IEnumerable Parse(string data) try { - results = JsonConvert.DeserializeObject>(data); + results = JsonSerializer.Deserialize>(data); } - catch (JsonSerializationException) + catch (JsonException) { - T linkedInResult = JsonConvert.DeserializeObject(data); + T linkedInResult = JsonSerializer.Deserialize(data); results = new List { linkedInResult }; } @@ -42,7 +42,7 @@ public IEnumerable Parse(string data) /// Returns string data. public string Parse(T dataToShare) { - return JsonConvert.SerializeObject(dataToShare, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + return JsonSerializer.Serialize(dataToShare, typeof(T), new JsonSerializerOptions { IgnoreNullValues = true }); } } } diff --git a/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInPermissions.cs b/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInPermissions.cs index 4042818c797..6d2d2fe756a 100644 --- a/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInPermissions.cs +++ b/Microsoft.Toolkit.Services/Services/LinkedIn/LinkedInPermissions.cs @@ -37,4 +37,18 @@ public enum LinkedInPermissions /// WriteShare = 8 } + +#pragma warning disable SA1649 // File name should match first type name + internal static class LinkedInPermissionsHelpers + { + /// + /// Internal AllPermissions for LinkedInPermissions, so we don't expose it. Keep it in sync with + /// + internal const LinkedInPermissions AllPermissions = + LinkedInPermissions.ReadBasicProfile | + LinkedInPermissions.ReadEmailAddress | + LinkedInPermissions.ReadWriteCompanyAdmin | + LinkedInPermissions.WriteShare; + } +#pragma warning restore SA1649 // File name should match first type name } diff --git a/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/AzureAuthToken.cs b/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/AzureAuthToken.cs index 4ac141da9e0..a2607423256 100644 --- a/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/AzureAuthToken.cs +++ b/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/AzureAuthToken.cs @@ -4,8 +4,8 @@ using System; using System.Net.Http; +using System.Text.Json; using System.Threading.Tasks; -using Newtonsoft.Json; namespace Microsoft.Toolkit.Services.MicrosoftTranslator { @@ -24,6 +24,9 @@ internal class AzureAuthToken /// private static readonly Uri ServiceUrl = new Uri("https://api.cognitive.microsoft.com/sts/v1.0/issueToken"); + // TODO + // private static readonly Uri ServiceUrl = new Uri(THIS SHOULD BE A PARAMETER NOW); + /// /// After obtaining a valid token, this class will cache it for this duration. /// Use a duration of 8 minutes, which is less than the actual token lifetime of 10 minutes. @@ -90,24 +93,22 @@ public async Task GetAccessTokenAsync() return _storedTokenValue; } - using (var request = new HttpRequestMessage(HttpMethod.Post, ServiceUrl)) - { - request.Headers.Add(OcpApimSubscriptionKeyHeader, SubscriptionKey); + using var request = new HttpRequestMessage(HttpMethod.Post, ServiceUrl); + request.Headers.Add(OcpApimSubscriptionKeyHeader, SubscriptionKey); - var response = await client.SendAsync(request).ConfigureAwait(false); - var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var response = await client.SendAsync(request).ConfigureAwait(false); + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - if (!response.IsSuccessStatusCode) - { - var error = JsonConvert.DeserializeObject(content); - throw new TranslatorServiceException(error.Message); - } + if (!response.IsSuccessStatusCode) + { + var error = JsonSerializer.Deserialize(content); + throw new TranslatorServiceException(error?.Error?.Message); + } - _storedTokenTime = DateTime.Now; - _storedTokenValue = $"Bearer {content}"; + _storedTokenTime = DateTime.Now; + _storedTokenValue = $"Bearer {content}"; - return _storedTokenValue; - } + return _storedTokenValue; } } } diff --git a/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/ErrorResponse.cs b/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/ErrorResponse.cs index 3d9e9038495..870ee897f0e 100644 --- a/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/ErrorResponse.cs +++ b/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/ErrorResponse.cs @@ -2,21 +2,27 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Text.Json.Serialization; + namespace Microsoft.Toolkit.Services.MicrosoftTranslator { +#pragma warning disable SA1402 // File may only contain a single type /// /// Holds information about an error occurred while accessing Microsoft Translator Service. /// internal class ErrorResponse + { + [JsonPropertyName("error")] + public Error Error { get; set; } + } + + internal class Error { /// /// Gets or sets the error message. /// + [JsonPropertyName("message")] public string Message { get; set; } - - /// - /// Gets or sets the HTTP status code. - /// - public int StatusCode { get; set; } } +#pragma warning restore SA1402 // File may only contain a single type } diff --git a/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/ServiceLanguage.cs b/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/ServiceLanguage.cs index 6053cebb865..abed597f9bd 100644 --- a/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/ServiceLanguage.cs +++ b/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/ServiceLanguage.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.MicrosoftTranslator { @@ -30,7 +30,7 @@ public class ServiceLanguage /// /// Gets the directionality, which is rtl for right-to-left languages or ltr for left-to-right languages. /// - [JsonProperty("dir")] + [JsonPropertyName("dir")] public string Directionality { get; } /// diff --git a/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/TranslatorService.cs b/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/TranslatorService.cs index ac3680b266a..aec1fb5841e 100644 --- a/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/TranslatorService.cs +++ b/Microsoft.Toolkit.Services/Services/MicrosoftTranslator/TranslatorService.cs @@ -8,9 +8,8 @@ using System.Linq; using System.Net.Http; using System.Net.Http.Headers; +using System.Text.Json; using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.Toolkit.Services.MicrosoftTranslator { @@ -108,14 +107,13 @@ public async Task> DetectLanguagesWithResp await CheckUpdateTokenAsync().ConfigureAwait(false); var uriString = $"{BaseUrl}detect?{ApiVersion}"; - using (var request = CreateHttpRequest(uriString, HttpMethod.Post, input.Select(t => new { Text = t.Substring(0, Math.Min(t.Length, _MaxTextLengthForDetection)) }))) - { - var response = await client.SendAsync(request).ConfigureAwait(false); - var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + using var request = CreateHttpRequest(uriString, HttpMethod.Post, input.Select(t => new { Text = t.Substring(0, Math.Min(t.Length, _MaxTextLengthForDetection)) })); - var responseContent = JsonConvert.DeserializeObject>(content); - return responseContent; - } + var response = await client.SendAsync(request).ConfigureAwait(false); + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + var responseContent = JsonSerializer.Deserialize>(content); + return responseContent; } /// @@ -132,24 +130,23 @@ public async Task> GetLanguageNamesAsync(string lan await CheckUpdateTokenAsync().ConfigureAwait(false); var uriString = $"{BaseUrl}languages?scope=translation&{ApiVersion}"; - using (var request = CreateHttpRequest(uriString)) + using var request = CreateHttpRequest(uriString); + + language = language ?? Language; + if (!string.IsNullOrWhiteSpace(language)) { - language = language ?? Language; - if (!string.IsNullOrWhiteSpace(language)) - { - // If necessary, adds the Accept-Language header in order to get localized language names. - request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(language)); - } + // If necessary, adds the Accept-Language header in order to get localized language names. + request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(language)); + } - var response = await client.SendAsync(request).ConfigureAwait(false); - var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var response = await client.SendAsync(request).ConfigureAwait(false); + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var jsonContent = JToken.Parse(content)["translation"]; - var responseContent = JsonConvert.DeserializeObject>(jsonContent.ToString()).ToList(); - responseContent.ForEach(r => r.Value.Code = r.Key); + var jsonContent = JsonDocument.Parse(content).RootElement.GetProperty("translation"); + var responseContent = JsonSerializer.Deserialize>(jsonContent.ToString()).ToList(); + responseContent.ForEach(r => r.Value.Code = r.Key); - return responseContent.Select(r => r.Value).OrderBy(r => r.Name).ToList(); - } + return responseContent.Select(r => r.Value).OrderBy(r => r.Name).ToList(); } /// @@ -216,14 +213,13 @@ public async Task> TranslateWithResponseAsync(I var toQueryString = string.Join("&", to.Select(t => $"to={t}")); var uriString = (string.IsNullOrWhiteSpace(from) ? $"{BaseUrl}translate?{toQueryString}" : $"{BaseUrl}translate?from={from}&{toQueryString}") + $"&{ApiVersion}"; - using (var request = CreateHttpRequest(uriString, HttpMethod.Post, input.Select(t => new { Text = t }))) - { - var response = await client.SendAsync(request).ConfigureAwait(false); - var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + using var request = CreateHttpRequest(uriString, HttpMethod.Post, input.Select(t => new { Text = t })); - var responseContent = JsonConvert.DeserializeObject>(content); - return responseContent; - } + var response = await client.SendAsync(request).ConfigureAwait(false); + var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + var responseContent = JsonSerializer.Deserialize>(content); + return responseContent; } /// @@ -254,7 +250,7 @@ private HttpRequestMessage CreateHttpRequest(string uriString, HttpMethod method if (content != null) { - var jsonRequest = JsonConvert.SerializeObject(content); + var jsonRequest = JsonSerializer.Serialize(content); var requestContent = new StringContent(jsonRequest, System.Text.Encoding.UTF8, JsonMediaType); request.Content = requestContent; } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/Tweet.cs b/Microsoft.Toolkit.Services/Services/Twitter/Tweet.cs index 97d2613aa02..c0dea2d0092 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/Tweet.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/Tweet.cs @@ -4,7 +4,7 @@ using System; using System.Globalization; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -18,19 +18,19 @@ public class Tweet : Toolkit.Parsers.SchemaBase, ITwitterResult /// /// Gets or sets time item was created. /// - [JsonProperty("created_at")] + [JsonPropertyName("created_at")] public string CreatedAt { get; set; } /// /// Gets or sets item Id. /// - [JsonProperty("id_str")] + [JsonPropertyName("id_str")] public string Id { get; set; } /// /// Gets or sets text of the tweet (handles both 140 and 280 characters) /// - [JsonProperty("text")] + [JsonPropertyName("text")] public string Text { get { return _text ?? FullText; } @@ -40,13 +40,13 @@ public string Text /// /// Gets or sets text of the tweet (280 characters). /// - [JsonProperty("full_text")] + [JsonPropertyName("full_text")] private string FullText { get; set; } /// /// Gets or sets display text range (indexes of tweet text without RT and leading user mentions) /// - [JsonProperty("display_text_range")] + [JsonPropertyName("display_text_range")] public int[] DisplayTextRange { get; set; } /// @@ -54,68 +54,68 @@ public string Text /// (true when tweet is longer than 140 characters) /// This entity may be deprecated - it never seems to be set to true. /// - [JsonProperty("truncated")] + [JsonPropertyName("truncated")] public bool IsTruncated { get; set; } /// /// Gets or sets attached content of the tweet /// - [JsonProperty("entities")] + [JsonPropertyName("entities")] public TwitterEntities Entities { get; set; } /// /// Gets or sets extended attached content of the tweet /// - [JsonProperty("extended_entities")] + [JsonPropertyName("extended_entities")] public TwitterExtendedEntities ExtendedEntities { get; set; } /// /// Gets or sets tweet source (client or website used) /// - [JsonProperty("source")] + [JsonPropertyName("source")] public string Source { get; set; } /// /// Gets or sets in_reply_to_screen_name /// - [JsonProperty("in_reply_to_screen_name")] + [JsonPropertyName("in_reply_to_screen_name")] public string InReplyToScreenName { get; set; } /// /// Gets or sets in_reply_to_status_id_str /// - [JsonProperty("in_reply_to_status_id_str")] + [JsonPropertyName("in_reply_to_status_id_str")] public string InReplyToStatusId { get; set; } /// /// Gets or sets in_reply_to_user_id_str /// - [JsonProperty("in_reply_to_user_id_str")] + [JsonPropertyName("in_reply_to_user_id_str")] public string InReplyToUserId { get; set; } /// /// Gets or sets user who posted the status. /// - [JsonProperty("user")] + [JsonPropertyName("user")] public TwitterUser User { get; set; } /// /// Gets or sets geo coordinates (latitude and longitude) returned by Twitter for some locations /// - [JsonProperty("coordinates")] + [JsonPropertyName("coordinates")] [JsonConverter(typeof(TwitterCoordinatesConverter))] public TwitterCoordinates Coordinates { get; set; } /// /// Gets or sets the Place object returned by Twitter for some locations /// - [JsonProperty("place")] + [JsonPropertyName("place")] public TwitterPlace Place { get; set; } /// /// Gets or sets the Retweeted Tweet /// - [JsonProperty("retweeted_status")] + [JsonPropertyName("retweeted_status")] public Tweet RetweetedStatus { get; set; } /// @@ -138,25 +138,25 @@ public DateTime CreationDate /// /// Gets or sets quoted_status /// - [JsonProperty("quoted_status")] + [JsonPropertyName("quoted_status")] public Tweet QuotedStatus { get; set; } /// /// Gets or sets quoted_status_id_str /// - [JsonProperty("quoted_status_id_str")] + [JsonPropertyName("quoted_status_id_str")] public string QuotedStatusId { get; set; } /// /// Gets or sets quoted_status_permalink /// - [JsonProperty("quoted_status_permalink")] + [JsonPropertyName("quoted_status_permalink")] public TwitterUrl QuotedStatusPermalink { get; set; } /// /// Gets or sets approximate count of tweets quoting tweet /// - [JsonProperty("quote_count")] + [JsonPropertyName("quote_count")] public int QuoteCount { get; set; } /// @@ -165,49 +165,49 @@ public DateTime CreationDate /// /// Premium and Enterprise API access only /// - [JsonProperty("reply_count")] + [JsonPropertyName("reply_count")] public int ReplyCount { get; set; } /// /// Gets or sets number of times tweet has been retweeted /// - [JsonProperty("retweet_count")] + [JsonPropertyName("retweet_count")] public int RetweetCount { get; set; } /// /// Gets or sets number of times tweet has been liked /// - [JsonProperty("favorite_count")] + [JsonPropertyName("favorite_count")] public int FavoriteCount { get; set; } /// /// Gets or sets a value indicating whether or not logged-in user has liked tweet /// - [JsonProperty("favorited")] + [JsonPropertyName("favorited")] public bool Favorited { get; set; } /// /// Gets or sets a value indicating whether or not logged-in user has retweeted tweet /// - [JsonProperty("retweeted")] + [JsonPropertyName("retweeted")] public bool Retweeted { get; set; } /// /// Gets or sets a value indicating whether URL in tweet has been flagged for sensitive content /// - [JsonProperty("possibly_sensitive")] + [JsonPropertyName("possibly_sensitive")] public bool Sensitive { get; set; } /// /// Gets or sets stream filter of tweet /// - [JsonProperty("filter_level")] + [JsonPropertyName("filter_level")] public string FilterLevel { get; set; } /// /// Gets or sets BCP 47 language identifier of tweet content /// - [JsonProperty("lang")] + [JsonPropertyName("lang")] public string Language { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TweetParser.cs b/Microsoft.Toolkit.Services/Services/Twitter/TweetParser.cs index 711e95808f0..26a544cb6f8 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TweetParser.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TweetParser.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json; namespace Microsoft.Toolkit.Services.Twitter { @@ -24,7 +24,7 @@ public IEnumerable Parse(string data) return null; } - return JsonConvert.DeserializeObject>(data); + return JsonSerializer.Deserialize>(data); } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterCoordinatesConverter.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterCoordinatesConverter.cs index 73375d98fab..3e459a1cfee 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterCoordinatesConverter.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterCoordinatesConverter.cs @@ -3,41 +3,97 @@ // See the LICENSE file in the project root for more information. using System; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { - internal class TwitterCoordinatesConverter : JsonConverter + internal class TwitterCoordinatesConverter : JsonConverter { + private readonly JsonEncodedText latitudeName = JsonEncodedText.Encode("Latitude"); + private readonly JsonEncodedText longitudeName = JsonEncodedText.Encode("Longitude"); + public override bool CanConvert(Type objectType) { return false; } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + private readonly JsonConverter doubleConverter; + + public TwitterCoordinatesConverter(JsonSerializerOptions options) + { + doubleConverter = options?.GetConverter(typeof(double)) as JsonConverter ?? throw new InvalidOperationException(); + } + + public override TwitterCoordinates Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { try { - if (reader.TokenType != JsonToken.StartObject) + if (reader.TokenType != JsonTokenType.StartObject) { return null; } - var jObject = JObject.Load(reader); - var jCoordinates = jObject["coordinates"] as JArray; + double latitude = default; + bool latitudeSet = false; + + double longitude = default; + bool longitudeSet = false; - if (jCoordinates.Count != 2) + // Get the first property. + reader.Read(); + if (reader.TokenType != JsonTokenType.PropertyName) { - return null; + throw new JsonException(); + } + + if (reader.ValueTextEquals(latitudeName.EncodedUtf8Bytes)) + { + latitude = ReadProperty(ref reader, options); + latitudeSet = true; + } + else if (reader.ValueTextEquals(longitudeName.EncodedUtf8Bytes)) + { + longitude = ReadProperty(ref reader, options); + longitudeSet = true; + } + else + { + throw new JsonException(); } - var twitterCoordinates = new TwitterCoordinates + // Get the second property. + reader.Read(); + if (reader.TokenType != JsonTokenType.PropertyName) { - Latitude = (double)jCoordinates[0], - Longitude = (double)jCoordinates[1] + throw new JsonException(); + } + + if (latitudeSet && reader.ValueTextEquals(longitudeName.EncodedUtf8Bytes)) + { + longitude = ReadProperty(ref reader, options); + } + else if (longitudeSet && reader.ValueTextEquals(latitudeName.EncodedUtf8Bytes)) + { + latitude = ReadProperty(ref reader, options); + } + else + { + throw new JsonException(); + } + + reader.Read(); + + if (reader.TokenType != JsonTokenType.EndObject) + { + throw new JsonException(); + } + + return new TwitterCoordinates + { + Latitude = latitude, + Longitude = longitude }; - return twitterCoordinates; } catch { @@ -45,9 +101,15 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist } } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + private double ReadProperty(ref Utf8JsonReader reader, JsonSerializerOptions options) + { + reader.Read(); + return doubleConverter.Read(ref reader, typeof(double), options); + } + + public override void Write(Utf8JsonWriter writer, TwitterCoordinates value, JsonSerializerOptions options) { throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterDataProvider.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterDataProvider.cs index 41db01d748b..3ba3d3627c8 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterDataProvider.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterDataProvider.cs @@ -10,9 +10,9 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.Toolkit.Services.Core; -using Newtonsoft.Json; #if WINRT using System.Runtime.InteropServices.WindowsRuntime; @@ -140,7 +140,7 @@ public async Task GetUserAsync(string screenName = null) TwitterOAuthRequest request = new TwitterOAuthRequest(); rawResult = await request.ExecuteGetAsync(uri, _tokens, _signatureManager); - return JsonConvert.DeserializeObject(rawResult); + return JsonSerializer.Deserialize(rawResult); } catch (UserNotFoundException) { @@ -150,7 +150,7 @@ public async Task GetUserAsync(string screenName = null) { if (!string.IsNullOrEmpty(rawResult)) { - var errors = JsonConvert.DeserializeObject(rawResult); + var errors = JsonSerializer.Deserialize(rawResult); throw new TwitterException { Errors = errors }; } @@ -191,7 +191,7 @@ public async Task> GetUserTimeLineAsync(string scr { if (!string.IsNullOrEmpty(rawResult)) { - var errors = JsonConvert.DeserializeObject(rawResult); + var errors = JsonSerializer.Deserialize(rawResult); throw new TwitterException { Errors = errors }; } @@ -581,18 +581,16 @@ private async Task InitializeRequestAccessTokensAsync(string twitterCallba using (var request = new HttpRequestMessage(HttpMethod.Get, new Uri(twitterUrl))) { - using (var response = await _client.SendAsync(request).ConfigureAwait(false)) + using var response = await _client.SendAsync(request).ConfigureAwait(false); + var data = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + if (response.IsSuccessStatusCode) { - var data = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - if (response.IsSuccessStatusCode) - { - getResponse = data; - } - else - { - Debug.WriteLine("HttpHelper call failed trying to retrieve Twitter Request Tokens. Message: {0}", data); - return false; - } + getResponse = data; + } + else + { + Debug.WriteLine("HttpHelper call failed trying to retrieve Twitter Request Tokens. Message: {0}", data); + return false; } } @@ -665,10 +663,8 @@ private async Task ExchangeRequestTokenForAccessTokenAsync(string webAuthR { request.Headers.Authorization = new AuthenticationHeaderValue("OAuth", authorizationHeaderParams); - using (var response = await _client.SendAsync(request).ConfigureAwait(false)) - { - data = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - } + using var response = await _client.SendAsync(request).ConfigureAwait(false); + data = await response.Content.ReadAsStringAsync().ConfigureAwait(false); } var screenName = ExtractTokenFromResponse(data, TwitterOAuthTokenType.ScreenName); diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterDirectMessage.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterDirectMessage.cs index 7ffe9355f1c..803c9b7404d 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterDirectMessage.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterDirectMessage.cs @@ -4,7 +4,7 @@ using System; using System.Globalization; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -17,70 +17,70 @@ public class TwitterDirectMessage : ITwitterResult /// Gets or sets the direct message id. /// /// The direct message id. - [JsonProperty(PropertyName = "id")] + [JsonPropertyName("id")] public decimal Id { get; set; } /// /// Gets or sets the sender id. /// /// The sender id. - [JsonProperty(PropertyName = "sender_id")] + [JsonPropertyName("sender_id")] public decimal SenderId { get; set; } /// /// Gets or sets the direct message text. /// /// The direct message text. - [JsonProperty(PropertyName = "text")] + [JsonPropertyName("text")] public string Text { get; set; } /// /// Gets or sets the recipient id. /// /// The recipient id. - [JsonProperty(PropertyName = "recipient_id")] + [JsonPropertyName("recipient_id")] public decimal RecipientId { get; set; } /// /// Gets or sets the created date. /// /// The created date. - [JsonProperty(PropertyName = "created_at")] + [JsonPropertyName("created_at")] public string CreatedAt { get; set; } /// /// Gets or sets the name of the sender screen. /// /// The name of the sender screen. - [JsonProperty(PropertyName = "sender_screen_name")] + [JsonPropertyName("sender_screen_name")] public string SenderScreenName { get; set; } /// /// Gets or sets the name of the recipient screen. /// /// The name of the recipient screen. - [JsonProperty(PropertyName = "recipient_screen_name")] + [JsonPropertyName("recipient_screen_name")] public string RecipientScreenName { get; set; } /// /// Gets or sets the sender. /// /// The sender. - [JsonProperty(PropertyName = "sender")] + [JsonPropertyName("sender")] public TwitterUser Sender { get; set; } /// /// Gets or sets the recipient. /// /// The recipient. - [JsonProperty(PropertyName = "recipient")] + [JsonPropertyName("recipient")] public TwitterUser Recipient { get; set; } /// /// Gets or sets the entities. /// /// The entities. - [JsonProperty(PropertyName = "entities")] + [JsonPropertyName("entities")] public TwitterEntities Entities { get; set; } /// diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterEntities.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterEntities.cs index 0e489429c48..d4e76c90a12 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterEntities.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterEntities.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -15,35 +15,35 @@ public class TwitterEntities /// Gets or sets Hashtags array of the tweet. /// This array will be empty if no Hashtags are present. /// - [JsonProperty("Hashtags")] + [JsonPropertyName("Hashtags")] public TwitterHashtag[] Hashtags { get; set; } /// /// Gets or sets Symbols array of the tweet. /// This array will be empty if no Symbols are present. /// - [JsonProperty("Symbols")] + [JsonPropertyName("Symbols")] public TwitterSymbol[] Symbols { get; set; } /// /// Gets or sets Media array of the tweet. /// This array will not exist if no media is present. /// - [JsonProperty("media")] + [JsonPropertyName("media")] public TwitterMedia[] Media { get; set; } /// /// Gets or sets Urls array of the tweet. /// This array will be empty if no Urls are present. /// - [JsonProperty("urls")] + [JsonPropertyName("urls")] public TwitterUrl[] Urls { get; set; } /// /// Gets or sets array of usernames mentioned in the tweet. /// This array will be empty if no usernames are mentioned. /// - [JsonProperty("user_mentions")] + [JsonPropertyName("user_mentions")] public TwitterUserMention[] UserMentions { get; set; } /// @@ -51,7 +51,7 @@ public class TwitterEntities /// This array will not exist if no poll is present. /// This array will always have one poll. /// - [JsonProperty("polls")] + [JsonPropertyName("polls")] public TwitterPoll Poll { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterError.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterError.cs index 66e1abf291c..3df83ff3c61 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterError.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterError.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,13 +14,13 @@ public class TwitterError /// /// Gets or sets error code /// - [JsonProperty("code")] + [JsonPropertyName("code")] public int Code { get; set; } /// /// Gets or sets error message /// - [JsonProperty("message")] + [JsonPropertyName("message")] public string Message { get; set; } } } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterErrors.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterErrors.cs index 2ccad80ee64..801c7485bcc 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterErrors.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterErrors.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,7 +14,7 @@ public class TwitterErrors /// /// Gets or sets the list of errors /// - [JsonProperty("errors")] + [JsonPropertyName("errors")] public TwitterError[] Errors { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterExtended.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterExtended.cs index c0bd10a7019..d9cca155f90 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterExtended.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterExtended.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,7 +14,7 @@ public class TwitterExtended /// /// Gets or sets the text of the tweet (280 characters). /// - [JsonProperty("full_text")] + [JsonPropertyName("full_text")] public string FullText { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterExtendedEntities.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterExtendedEntities.cs index 9f912a1f027..6f4ae88d54c 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterExtendedEntities.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterExtendedEntities.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,7 +14,7 @@ public class TwitterExtendedEntities /// /// Gets or sets Media of the tweet. /// - [JsonProperty("media")] + [JsonPropertyName("media")] public TwitterMedia[] Media { get; set; } } } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterGeoData.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterGeoData.cs index 125dc904cc6..977090f6f36 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterGeoData.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterGeoData.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Globalization; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -19,7 +19,7 @@ public class TwitterGeoData /// /// Gets or sets the type of data /// - [JsonProperty("type")] + [JsonPropertyName("type")] public string DataType { get; set; } /// @@ -43,7 +43,7 @@ public string DisplayCoordinates /// /// Gets or sets the coordinates of the geographic data /// - [JsonProperty("coordinates")] + [JsonPropertyName("coordinates")] public string[] Coordinates { get; set; } /// diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterHashtag.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterHashtag.cs index 6dc329569b8..d5350ede07a 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterHashtag.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterHashtag.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,13 +14,13 @@ public class TwitterHashtag /// /// Gets or sets indices of hashtag location in tweet string. /// - [JsonProperty("indices")] + [JsonPropertyName("indices")] public int[] Indices { get; set; } /// /// Gets or sets hashtag text, excluding #. /// - [JsonProperty("text")] + [JsonPropertyName("text")] public string Text { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMedia.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMedia.cs index e6846337bb6..2ebe86dacf7 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMedia.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMedia.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,73 +14,73 @@ public class TwitterMedia /// /// Gets or sets ID as string. /// - [JsonProperty("id_str")] + [JsonPropertyName("id_str")] public string Id { get; set; } /// /// Gets or sets indices array. /// - [JsonProperty("indices")] + [JsonPropertyName("indices")] public int[] Indices { get; set; } /// /// Gets or sets MediaUrl (direct link to image). /// - [JsonProperty("media_url")] + [JsonPropertyName("media_url")] public string MediaUrl { get; set; } /// /// Gets or sets HTTPS MediaUrl. /// - [JsonProperty("media_url_https")] + [JsonPropertyName("media_url_https")] public string MediaUrlHttps { get; set; } /// /// Gets or sets t.co shortened tweet Url. /// - [JsonProperty("url")] + [JsonPropertyName("url")] public string Url { get; set; } /// /// Gets or sets DisplayUrl (pics.twitter.com Url). /// - [JsonProperty("display_url")] + [JsonPropertyName("display_url")] public string DisplayUrl { get; set; } /// /// Gets or sets DisplayUrl (pics.twitter.com Url). /// - [JsonProperty("expanded_url")] + [JsonPropertyName("expanded_url")] public string ExpandedUrl { get; set; } /// /// Gets or sets MediaType - photo, animated_gif, or video /// - [JsonProperty("type")] + [JsonPropertyName("type")] public string MediaType { get; set; } /// /// Gets or sets size array /// - [JsonProperty("sizes")] + [JsonPropertyName("sizes")] public TwitterMediaSizes Sizes { get; set; } /// /// Gets or sets the SourceId - tweet ID of media's original tweet /// - [JsonProperty("source_status_id_str")] + [JsonPropertyName("source_status_id_str")] public string SourceIdStr { get; set; } /// /// Gets or sets metadata for video attached to tweet /// - [JsonProperty("video_info")] + [JsonPropertyName("video_info")] public TwitterMediaVideoInfo VideoInfo { get; set; } /// /// Gets or sets extended metadata for video attached to tweet. /// - [JsonProperty("additional_media_info")] + [JsonPropertyName("additional_media_info")] public TwitterMediaAdditionalInfo AdditionalMediaInfo { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaAdditionalInfo.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaAdditionalInfo.cs index 048844380c0..4ded7817d98 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaAdditionalInfo.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaAdditionalInfo.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,25 +14,25 @@ public class TwitterMediaAdditionalInfo /// /// Gets or sets title of video /// - [JsonProperty("title")] + [JsonPropertyName("title")] public string Title { get; set; } /// /// Gets or sets description of video /// - [JsonProperty("description")] + [JsonPropertyName("description")] public string Description { get; set; } /// /// Gets or sets a value indicating whether video is embeddable /// - [JsonProperty("embeddable")] + [JsonPropertyName("embeddable")] public bool Embeddable { get; set; } /// /// Gets or sets a value indicating whether "monetizable" /// - [JsonProperty("monetizable")] + [JsonPropertyName("monetizable")] public bool Monetizable { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaSizeData.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaSizeData.cs index db91c1502e9..7c787eb4af4 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaSizeData.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaSizeData.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,19 +14,19 @@ public class TwitterMediaSizeData /// /// Gets or sets width integer. /// - [JsonProperty("w")] + [JsonPropertyName("w")] public int Width { get; set; } /// /// Gets or sets height integer. /// - [JsonProperty("h")] + [JsonPropertyName("h")] public int Height { get; set; } /// /// Gets or sets resize string. /// - [JsonProperty("resize")] + [JsonPropertyName("resize")] public string Resize { get; set; } } } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaSizes.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaSizes.cs index d6a4cb73a04..dbffbf70cf2 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaSizes.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaSizes.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,25 +14,25 @@ public class TwitterMediaSizes /// /// Gets or sets small metadata. /// - [JsonProperty("small")] + [JsonPropertyName("small")] public TwitterMediaSizeData Small { get; set; } /// /// Gets or sets thumbnail metadata. /// - [JsonProperty("thumb")] + [JsonPropertyName("thumb")] public TwitterMediaSizeData Thumb { get; set; } /// /// Gets or sets large metadata. /// - [JsonProperty("large")] + [JsonPropertyName("large")] public TwitterMediaSizeData Large { get; set; } /// /// Gets or sets medium metadata. /// - [JsonProperty("medium")] + [JsonPropertyName("medium")] public TwitterMediaSizeData Medium { get; set; } } } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaVideoInfo.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaVideoInfo.cs index 1fde7a7789d..88904902388 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaVideoInfo.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaVideoInfo.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,19 +14,19 @@ public class TwitterMediaVideoInfo /// /// Gets or sets video aspect ratio (width, height) /// - [JsonProperty("aspect_ratio")] + [JsonPropertyName("aspect_ratio")] public int[] AspectRatio { get; set; } /// /// Gets or sets duration of video in milliseconds /// - [JsonProperty("duration_millis")] + [JsonPropertyName("duration_millis")] public int Duration { get; set; } /// /// Gets or sets video variants for different codecs, bitrates, etc. /// - [JsonProperty("variants")] + [JsonPropertyName("variants")] public TwitterMediaVideoVariants[] Variants { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaVideoVariants.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaVideoVariants.cs index ad3b8915450..38301583bd5 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaVideoVariants.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterMediaVideoVariants.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,19 +14,19 @@ public class TwitterMediaVideoVariants /// /// Gets or sets video bitrate in bits-per-second /// - [JsonProperty("bitrate")] + [JsonPropertyName("bitrate")] public int Bitrate { get; set; } /// /// Gets or sets the MIME type of the video /// - [JsonProperty("content_type")] + [JsonPropertyName("content_type")] public string ContentType { get; set; } /// /// Gets or sets the direct URL for the video variant /// - [JsonProperty("url")] + [JsonPropertyName("url")] public string Url { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterOAuthRequest.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterOAuthRequest.cs index 3cab762951d..303cee3de28 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterOAuthRequest.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterOAuthRequest.cs @@ -8,10 +8,9 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.Toolkit.Services.Core; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.Toolkit.Services.Twitter { @@ -46,18 +45,14 @@ public TwitterOAuthRequest() /// String result. public async Task ExecuteGetAsync(Uri requestUri, TwitterOAuthTokens tokens, ISignatureManager signatureManager) { - using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri)) - { - var requestBuilder = new TwitterOAuthRequestBuilder(requestUri, tokens, signatureManager, "GET"); + using var request = new HttpRequestMessage(HttpMethod.Get, requestUri); + var requestBuilder = new TwitterOAuthRequestBuilder(requestUri, tokens, signatureManager, "GET"); - request.Headers.Authorization = AuthenticationHeaderValue.Parse(requestBuilder.AuthorizationHeader); + request.Headers.Authorization = AuthenticationHeaderValue.Parse(requestBuilder.AuthorizationHeader); - using (var response = await client.SendAsync(request).ConfigureAwait(false)) - { - response.ThrowIfNotValid(); - return ProcessErrors(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); - } - } + using var response = await client.SendAsync(request).ConfigureAwait(false); + response.ThrowIfNotValid(); + return ProcessErrors(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); } /// @@ -70,29 +65,22 @@ public async Task ExecuteGetAsync(Uri requestUri, TwitterOAuthTokens tok /// awaitable task public async Task ExecuteGetStreamAsync(Uri requestUri, TwitterOAuthTokens tokens, TwitterStreamCallbacks.RawJsonCallback callback, ISignatureManager signatureManager) { - using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri)) - { - var requestBuilder = new TwitterOAuthRequestBuilder(requestUri, tokens, signatureManager); + using var request = new HttpRequestMessage(HttpMethod.Get, requestUri); + var requestBuilder = new TwitterOAuthRequestBuilder(requestUri, tokens, signatureManager); - request.Headers.Authorization = AuthenticationHeaderValue.Parse(requestBuilder.AuthorizationHeader); + request.Headers.Authorization = AuthenticationHeaderValue.Parse(requestBuilder.AuthorizationHeader); - using (var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false)) + using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false); + response.ThrowIfNotValid(); + using var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + using var reader = new StreamReader(responseStream); + while (!_abort && !reader.EndOfStream) + { + var result = reader.ReadLine(); + + if (!string.IsNullOrEmpty(result)) { - response.ThrowIfNotValid(); - var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - - using (var reader = new StreamReader(responseStream)) - { - while (!_abort && !reader.EndOfStream) - { - var result = reader.ReadLine(); - - if (!string.IsNullOrEmpty(result)) - { - callback?.Invoke(result); - } - } - } + callback?.Invoke(result); } } } @@ -114,18 +102,14 @@ public void Abort() /// String result. public async Task ExecutePostAsync(Uri requestUri, TwitterOAuthTokens tokens, ISignatureManager signatureManager) { - using (var request = new HttpRequestMessage(HttpMethod.Post, requestUri)) - { - var requestBuilder = new TwitterOAuthRequestBuilder(requestUri, tokens, signatureManager, "POST"); + using var request = new HttpRequestMessage(HttpMethod.Post, requestUri); + var requestBuilder = new TwitterOAuthRequestBuilder(requestUri, tokens, signatureManager, "POST"); - request.Headers.Authorization = AuthenticationHeaderValue.Parse(requestBuilder.AuthorizationHeader); + request.Headers.Authorization = AuthenticationHeaderValue.Parse(requestBuilder.AuthorizationHeader); - using (var response = await client.SendAsync(request).ConfigureAwait(false)) - { - response.ThrowIfNotValid(); - return ProcessErrors(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); - } - } + using var response = await client.SendAsync(request).ConfigureAwait(false); + response.ThrowIfNotValid(); + return ProcessErrors(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); } /// @@ -139,35 +123,26 @@ public async Task ExecutePostAsync(Uri requestUri, TwitterOAuthTokens to /// String result. public async Task ExecutePostMultipartAsync(Uri requestUri, TwitterOAuthTokens tokens, string boundary, byte[] content, ISignatureManager signatureManager) { - JToken mediaId = null; + JsonElement mediaId = default; try { - using (var multipartFormDataContent = new MultipartFormDataContent(boundary)) - { - using (var byteContent = new ByteArrayContent(content)) - { - multipartFormDataContent.Add(byteContent, "media"); - - using (var request = new HttpRequestMessage(HttpMethod.Post, requestUri)) - { - var requestBuilder = new TwitterOAuthRequestBuilder(requestUri, tokens, signatureManager, "POST"); + using var multipartFormDataContent = new MultipartFormDataContent(boundary); + using var byteContent = new ByteArrayContent(content); + multipartFormDataContent.Add(byteContent, "media"); - request.Headers.Authorization = AuthenticationHeaderValue.Parse(requestBuilder.AuthorizationHeader); + using var request = new HttpRequestMessage(HttpMethod.Post, requestUri); + var requestBuilder = new TwitterOAuthRequestBuilder(requestUri, tokens, signatureManager, "POST"); - request.Content = multipartFormDataContent; + request.Headers.Authorization = AuthenticationHeaderValue.Parse(requestBuilder.AuthorizationHeader); - using (var response = await client.SendAsync(request).ConfigureAwait(false)) - { - response.ThrowIfNotValid(); - string jsonResult = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + request.Content = multipartFormDataContent; - JObject jObj = JObject.Parse(jsonResult); - mediaId = jObj["media_id_string"]; - } - } - } - } + using var response = await client.SendAsync(request).ConfigureAwait(false); + response.ThrowIfNotValid(); + using var jsonResult = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + var jObj = await JsonDocument.ParseAsync(jsonResult).ConfigureAwait(false); + mediaId = jObj.RootElement.GetProperty("media_id_string"); } catch (ObjectDisposedException) { @@ -182,7 +157,7 @@ private string ProcessErrors(string content) { if (content.StartsWith("{\"errors\":")) { - var errors = JsonConvert.DeserializeObject(content); + var errors = JsonSerializer.Deserialize(content); throw new TwitterException { Errors = errors }; } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterOAuthRequestExtensions.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterOAuthRequestExtensions.cs index 71a29f45145..7d48701f2ea 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterOAuthRequestExtensions.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterOAuthRequestExtensions.cs @@ -2,16 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.IO; -using System.IO.Compression; using System.Net; using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using Microsoft.Toolkit.Services.Core; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.Toolkit.Services.Twitter { diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterParser.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterParser.cs index 1fc118c2c1e..3404467d836 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterParser.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterParser.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json; namespace Microsoft.Toolkit.Services.Twitter { @@ -28,12 +28,12 @@ IEnumerable Toolkit.Parsers.IParser.Parse(string data) try { - return JsonConvert.DeserializeObject>(data); + return JsonSerializer.Deserialize>(data); } - catch (JsonSerializationException) + catch (JsonException) { List items = new List(); - items.Add(JsonConvert.DeserializeObject(data)); + items.Add(JsonSerializer.Deserialize(data)); return items; } } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterPlace.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterPlace.cs index 516e74aa80a..0b5f451130b 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterPlace.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterPlace.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,49 +14,49 @@ public class TwitterPlace /// /// Gets or sets the ID of the place /// - [JsonProperty("id")] + [JsonPropertyName("id")] public string Id { get; set; } /// /// Gets or sets the URL of additional place metadata /// - [JsonProperty("url")] + [JsonPropertyName("url")] public string Url { get; set; } /// /// Gets or sets the place type. /// - [JsonProperty("place_type")] + [JsonPropertyName("place_type")] public string PlaceType { get; set; } /// /// Gets or sets the place name. /// - [JsonProperty("name")] + [JsonPropertyName("name")] public string Name { get; set; } /// /// Gets or sets the full, human-readable place name. /// - [JsonProperty("full_name")] + [JsonPropertyName("full_name")] public string FullName { get; set; } /// /// Gets or sets the shortened country code (e.g. US) for the place. /// - [JsonProperty("country_code")] + [JsonPropertyName("country_code")] public string CountryCode { get; set; } /// /// Gets or sets the name of the country for the place. /// - [JsonProperty("country")] + [JsonPropertyName("country")] public string Country { get; set; } /// /// Gets or sets the bounding box coordinates of a location. /// - [JsonProperty("bounding_box")] + [JsonPropertyName("bounding_box")] public TwitterPlaceBoundingBox BoundingBox { get; set; } } } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterPlaceBoundingBox.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterPlaceBoundingBox.cs index 9e20940bf28..fb39af14c3b 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterPlaceBoundingBox.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterPlaceBoundingBox.cs @@ -3,8 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Globalization; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -16,13 +15,13 @@ public class TwitterPlaceBoundingBox /// /// Gets or sets the bounding box coordinates of the tweet's geolocation data. /// - [JsonProperty("coordinates")] + [JsonPropertyName("coordinates")] public List> Coordinates { get; set; } /// /// Gets or sets the coordinate type. Polygon for a bounding box, Point for an exact coordinate. /// - [JsonProperty("type")] + [JsonPropertyName("type")] public string Type { get; set; } /// diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterPoll.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterPoll.cs index a632d269e38..24f65ee1cbe 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterPoll.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterPoll.cs @@ -4,7 +4,7 @@ using System; using System.Globalization; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -16,19 +16,19 @@ public class TwitterPoll /// /// Gets or sets poll questions. /// - [JsonProperty("options")] + [JsonPropertyName("options")] public TwitterPollOptions[] Options { get; set; } /// /// Gets or sets end timestamp as a string. /// - [JsonProperty("end_datetime")] + [JsonPropertyName("end_datetime")] public string EndDateTime { get; set; } /// /// Gets or sets duration of the poll in minutes. /// - [JsonProperty("duration_minutes")] + [JsonPropertyName("duration_minutes")] public string DurationMinutes { get; set; } /// diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterPollOptions.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterPollOptions.cs index e7d27ab8a8b..af44d214905 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterPollOptions.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterPollOptions.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,13 +14,13 @@ public class TwitterPollOptions /// /// Gets or sets int value of the poll position. /// - [JsonProperty("position")] + [JsonPropertyName("position")] public int Position { get; set; } /// /// Gets or sets text of the poll question. /// - [JsonProperty("text")] + [JsonPropertyName("text")] public string Text { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterSearchParser.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterSearchParser.cs index 7a91992539d..263cddbdf46 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterSearchParser.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterSearchParser.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Linq; -using Newtonsoft.Json; +using System.Text.Json; namespace Microsoft.Toolkit.Services.Twitter { @@ -25,7 +25,7 @@ public IEnumerable Parse(string data) return null; } - var result = JsonConvert.DeserializeObject(data); + var result = JsonSerializer.Deserialize(data); return result.Statuses.ToList(); } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterStreamDeletedEvent.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterStreamDeletedEvent.cs index a0f0c3db63a..fa52090e83d 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterStreamDeletedEvent.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterStreamDeletedEvent.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -15,14 +15,14 @@ public class TwitterStreamDeletedEvent : ITwitterResult /// Gets or sets the user id of the event. This is always the user who initiated the event. /// /// The user Id. - [JsonProperty(PropertyName = "user_id_str")] + [JsonPropertyName("user_id_str")] public string UserId { get; set; } /// /// Gets or sets the id of the event. This is the tweet that was affected. /// /// The tweet Id. - [JsonProperty(PropertyName = "id_str")] + [JsonPropertyName("id_str")] public string Id { get; set; } } } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterStreamEvent.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterStreamEvent.cs index d27be43828a..8bd3b68b2bc 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterStreamEvent.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterStreamEvent.cs @@ -4,8 +4,7 @@ using System; using System.Globalization; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -18,8 +17,8 @@ public class TwitterStreamEvent : ITwitterResult /// Gets or sets the type of the event. /// /// The type of the event. - [JsonProperty(PropertyName = "event")] - [JsonConverter(typeof(StringEnumConverter))] + [JsonPropertyName("event")] + [JsonConverter(typeof(JsonStringEnumConverter))] public TwitterStreamEventType EventType { get; set; } /// @@ -44,7 +43,7 @@ public class TwitterStreamEvent : ITwitterResult /// Gets or sets the creation date. /// /// The creation date. - [JsonProperty(PropertyName = "created_at")] + [JsonPropertyName("created_at")] public string CreatedAt { get; set; } /// diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterSymbol.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterSymbol.cs index 9473ba97fc6..dcac308e6b1 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterSymbol.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterSymbol.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,13 +14,13 @@ public class TwitterSymbol /// /// Gets or sets indices of hashtag location in tweet string. /// - [JsonProperty("indices")] + [JsonPropertyName("indices")] public int[] Indices { get; set; } /// /// Gets or sets hashtag text, excluding #. /// - [JsonProperty("text")] + [JsonPropertyName("text")] public string Text { get; set; } } } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterUrl.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterUrl.cs index dae1bd7b778..ebadd1348bc 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterUrl.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterUrl.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,31 +14,31 @@ public class TwitterUrl /// /// Gets or sets DisplayUrl of the Url. /// - [JsonProperty("display_url")] + [JsonPropertyName("display_url")] public string DisplayUrl { get; set; } /// /// Gets or sets ExpandedUrl of the Url. /// - [JsonProperty("expanded_url")] + [JsonPropertyName("expanded_url")] public string ExpandedUrl { get; set; } /// /// Gets or sets indices position of the tweet. /// - [JsonProperty("indices")] + [JsonPropertyName("indices")] public int[] Indices { get; set; } /// /// Gets or sets unwound Url metadata position of the tweet. /// - [JsonProperty("unwound")] + [JsonPropertyName("unwound")] public TwitterUrlUnwound Unwound { get; set; } /// /// Gets or sets t.co Url of the tweet. /// - [JsonProperty("url")] + [JsonPropertyName("url")] public string Url { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterUrlUnwound.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterUrlUnwound.cs index 63073ed15d1..c862634122e 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterUrlUnwound.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterUrlUnwound.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,25 +14,25 @@ public class TwitterUrlUnwound /// /// Gets or sets fully unwound url. /// - [JsonProperty("url")] + [JsonPropertyName("url")] public string Url { get; set; } /// /// Gets or sets status of unwind; if anything but 200 is bad data. /// - [JsonProperty("status")] + [JsonPropertyName("status")] public int Status { get; set; } /// /// Gets or sets HTML title for url. /// - [JsonProperty("title")] + [JsonPropertyName("title")] public string Title { get; set; } /// /// Gets or sets description of link. /// - [JsonProperty("description")] + [JsonPropertyName("description")] public string Description { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterUser.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterUser.cs index dad92788421..fd458ebebfb 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterUser.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterUser.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,194 +14,194 @@ public class TwitterUser /// /// Gets or sets user Id. /// - [JsonProperty("id_str")] + [JsonPropertyName("id_str")] public string Id { get; set; } /// /// Gets or sets user name. /// - [JsonProperty("name")] + [JsonPropertyName("name")] public string Name { get; set; } /// /// Gets or sets user screen name. /// - [JsonProperty("screen_name")] + [JsonPropertyName("screen_name")] public string ScreenName { get; set; } /// /// Gets or sets profile location. /// - [JsonProperty("location")] + [JsonPropertyName("location")] public string Location { get; set; } /// /// Gets or sets profile url. /// - [JsonProperty("url")] + [JsonPropertyName("url")] public string Url { get; set; } /// /// Gets or sets profile description. /// - [JsonProperty("description")] + [JsonPropertyName("description")] public string Description { get; set; } /// /// Gets or sets a value indicating whether protected status of user. /// - [JsonProperty("protected")] + [JsonPropertyName("protected")] public bool Protected { get; set; } /// /// Gets or sets a value indicating whether account is verified (blue check mark). /// - [JsonProperty("verified")] + [JsonPropertyName("verified")] public bool Verified { get; set; } /// /// Gets or sets followers count. /// - [JsonProperty("followers_count")] + [JsonPropertyName("followers_count")] public int FollowersCount { get; set; } /// /// Gets or sets count of accounts user is following. /// - [JsonProperty("friends_count")] + [JsonPropertyName("friends_count")] public int FriendsCount { get; set; } /// /// Gets or sets count of public lists user is a member of. /// - [JsonProperty("listed_count")] + [JsonPropertyName("listed_count")] public int ListedCount { get; set; } /// /// Gets or sets total count of tweets user has liked. /// - [JsonProperty("favourites_count")] + [JsonPropertyName("favourites_count")] public int FavoritesCount { get; set; } /// /// Gets or sets total count of tweets (including retweets) posted by user. /// - [JsonProperty("statuses_count")] + [JsonPropertyName("statuses_count")] public int StatusesCount { get; set; } /// /// Gets or sets a value indicating whether geotagging is enabled. /// This determines whether or not to geotag the user's posts. /// - [JsonProperty("geo_enabled")] + [JsonPropertyName("geo_enabled")] public bool GeoEnabled { get; set; } /// /// Gets or sets BCP 47 language code according to user's account settings. /// - [JsonProperty("lang")] + [JsonPropertyName("lang")] public string Lang { get; set; } /// /// Gets or sets a value indicating whether contributor mode is enabled. /// - [JsonProperty("contributors_enabled")] + [JsonPropertyName("contributors_enabled")] public bool ContributorsEnabled { get; set; } /// /// Gets or sets profile background color (web hex value). /// - [JsonProperty("profile_background_color")] + [JsonPropertyName("profile_background_color")] public string ProfileBackgroundColor { get; set; } /// /// Gets or sets profile background image url. /// - [JsonProperty("profile_background_image_url")] + [JsonPropertyName("profile_background_image_url")] public string ProfileBackgroundImageUrl { get; set; } /// /// Gets or sets profile background image url using https. /// - [JsonProperty("profile_background_image_url_https")] + [JsonPropertyName("profile_background_image_url_https")] public string ProfileBackgroundImageUrlHttps { get; set; } /// /// Gets or sets a value indicating whether profile background image is tiled. /// - [JsonProperty("profile_background_tile")] + [JsonPropertyName("profile_background_tile")] public bool ProfileBackgroundTile { get; set; } /// /// Gets or sets profile banner url. /// - [JsonProperty("profile_banner_url")] + [JsonPropertyName("profile_banner_url")] public string ProfileBannerUrl { get; set; } /// /// Gets or sets profile image url. /// - [JsonProperty("profile_image_url")] + [JsonPropertyName("profile_image_url")] public string ProfileImageUrl { get; set; } /// /// Gets or sets profile image url using https. /// - [JsonProperty("profile_image_url_https")] + [JsonPropertyName("profile_image_url_https")] public string ProfileImageUrlHttps { get; set; } /// /// Gets or sets profile link color (web hex value). /// - [JsonProperty("profile_link_color")] + [JsonPropertyName("profile_link_color")] public string ProfileLinkColor { get; set; } /// /// Gets or sets profile sidebar border color (web hex value). /// - [JsonProperty("profile_sidebar_border_color")] + [JsonPropertyName("profile_sidebar_border_color")] public string ProfileSidebarBorderColor { get; set; } /// /// Gets or sets profile sidebar fill color (web hex value). /// - [JsonProperty("profile_sidebar_fill_color")] + [JsonPropertyName("profile_sidebar_fill_color")] public string ProfileSidebarFillColor { get; set; } /// /// Gets or sets profile text color (web hex value). /// - [JsonProperty("profile_text_color")] + [JsonPropertyName("profile_text_color")] public string ProfileTextColor { get; set; } /// /// Gets or sets a value indicating whether the user has selected to use their uploaded background image in their profile. /// - [JsonProperty("profile_use_background_image")] + [JsonPropertyName("profile_use_background_image")] public bool ProfileUseBackgroundImage { get; set; } /// /// Gets or sets a value indicating whether or not user is using the default profile theme and background. /// - [JsonProperty("default_profile")] + [JsonPropertyName("default_profile")] public bool DefaultProfile { get; set; } /// /// Gets or sets a value indicating whether or not the user is using the default profile image. /// - [JsonProperty("default_profile_image")] + [JsonPropertyName("default_profile_image")] public bool DefaultProfileImage { get; set; } /// /// Gets or sets "withheld in" countries. /// - [JsonProperty("withheld_in_countries")] + [JsonPropertyName("withheld_in_countries")] public string[] WithheldInCountries { get; set; } /// /// Gets or sets withheld scope (status or profile). /// - [JsonProperty("withheld_scope")] + [JsonPropertyName("withheld_scope")] public string WithheldScope { get; set; } } } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterUserMention.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterUserMention.cs index c8797dd9caa..aa7b6ac861a 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterUserMention.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterUserMention.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Twitter { @@ -14,7 +14,7 @@ public class TwitterUserMention : TwitterUser /// /// Gets or sets the start and end position of the user mention /// - [JsonProperty("indices")] + [JsonPropertyName("indices")] public int[] Indices { get; set; } } } diff --git a/Microsoft.Toolkit.Services/Services/Twitter/TwitterUserStreamParser.cs b/Microsoft.Toolkit.Services/Services/Twitter/TwitterUserStreamParser.cs index d8f036df41f..e8c3af63df4 100644 --- a/Microsoft.Toolkit.Services/Services/Twitter/TwitterUserStreamParser.cs +++ b/Microsoft.Toolkit.Services/Services/Twitter/TwitterUserStreamParser.cs @@ -2,8 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using System.Text.Json; namespace Microsoft.Toolkit.Services.Twitter { @@ -24,55 +23,47 @@ public ITwitterResult Parse(string data) return null; } - var obj = (JObject)JsonConvert.DeserializeObject(data); + var obj = JsonDocument.Parse(data); - var friends = obj.SelectToken("friends", false); - if (friends != null && friends.HasValues) + if (obj.RootElement.TryGetProperty("friends", out var friends) && friends.GetArrayLength() > 0) { return null; } - var delete = obj.SelectToken("delete", false); - if (delete != null) + if (obj.RootElement.TryGetProperty("delete", out var delete)) { - var deletedStatus = delete.SelectToken("status", false); - if (deletedStatus != null && deletedStatus.HasValues) + if (delete.TryGetProperty("status", out var deletedStatus) && deletedStatus.GetArrayLength() > 0) { - return JsonConvert.DeserializeObject(deletedStatus.ToString()); + return JsonSerializer.Deserialize(deletedStatus.ToString()); } - var deletedDirectMessage = delete.SelectToken("direct_message", false); - if (deletedDirectMessage != null && deletedDirectMessage.HasValues) + if (delete.TryGetProperty("direct_message", out var deletedDirectMessage) && deletedDirectMessage.GetArrayLength() > 0) { - return JsonConvert.DeserializeObject(deletedDirectMessage.ToString()); + return JsonSerializer.Deserialize(deletedDirectMessage.ToString()); } } - var events = obj.SelectToken("event", false); - if (events != null) + if (obj.RootElement.TryGetProperty("event", out var events)) { - var targetObject = obj.SelectToken("target_object", false); Tweet endTargetObject = null; - if (targetObject?.SelectToken("user", false) != null) + if (obj.RootElement.TryGetProperty("target_object", out var targetObject) && targetObject.TryGetProperty("user", out _)) { - endTargetObject = JsonConvert.DeserializeObject(targetObject.ToString()); + endTargetObject = JsonSerializer.Deserialize(targetObject.ToString()); } - var endEvent = JsonConvert.DeserializeObject(obj.ToString()); + var endEvent = JsonSerializer.Deserialize(obj.ToString()); endEvent.TargetObject = endTargetObject; return endEvent; } - var user = obj.SelectToken("user", false); - if (user != null && user.HasValues) + if (obj.RootElement.TryGetProperty("user", out var user) && user.GetArrayLength() > 0) { - return JsonConvert.DeserializeObject(obj.ToString()); + return JsonSerializer.Deserialize(obj.ToString()); } - var directMessage = obj.SelectToken("direct_message", false); - if (directMessage != null && directMessage.HasValues) + if (obj.RootElement.TryGetProperty("direct_message", out var directMessage) && directMessage.GetArrayLength() > 0) { - return JsonConvert.DeserializeObject(directMessage.ToString()); + return JsonSerializer.Deserialize(directMessage.ToString()); } return null; diff --git a/Microsoft.Toolkit.Services/Services/Weibo/WeiboDataProvider.cs b/Microsoft.Toolkit.Services/Services/Weibo/WeiboDataProvider.cs index 6975a33d005..ca888d224fe 100644 --- a/Microsoft.Toolkit.Services/Services/Weibo/WeiboDataProvider.cs +++ b/Microsoft.Toolkit.Services/Services/Weibo/WeiboDataProvider.cs @@ -8,12 +8,11 @@ using System.Linq; using System.Net; using System.Net.Http; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.Toolkit.Parsers; using Microsoft.Toolkit.Services.Core; using Microsoft.Toolkit.Services.OAuth; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; #if WINRT using System.Runtime.InteropServices.WindowsRuntime; @@ -224,15 +223,15 @@ private async Task ExchangeRequestTokenForAccessTokenAsync(string webAuthR data = await response.Content.ReadAsStringAsync().ConfigureAwait(false); } - JObject jObject = JObject.Parse(data); + var jObject = JsonDocument.Parse(data); - string accessToken = jObject["access_token"].ToObject(); + string accessToken = jObject.RootElement.GetProperty("access_token").GetString(); if (string.IsNullOrEmpty(accessToken)) { throw new NullReferenceException("The accessToken is null."); } - long uid = jObject["uid"].ToObject(); + long uid = jObject.RootElement.GetProperty("uid").GetInt64(); Uid = uid; _tokens.AccessToken = accessToken; @@ -265,7 +264,7 @@ public async Task GetUserAsync(string screenName = null) WeiboOAuthRequest request = new WeiboOAuthRequest(); rawResult = await request.ExecuteGetAsync(uri, _tokens); - return JsonConvert.DeserializeObject(rawResult); + return JsonSerializer.Deserialize(rawResult); } catch (UserNotFoundException) { @@ -275,7 +274,7 @@ public async Task GetUserAsync(string screenName = null) { if (!string.IsNullOrEmpty(rawResult)) { - var error = JsonConvert.DeserializeObject(rawResult); + var error = JsonSerializer.Deserialize(rawResult); throw new WeiboException { Error = error }; } @@ -316,7 +315,7 @@ public async Task> GetUserTimeLineAsync(string scr { if (!string.IsNullOrEmpty(rawResult)) { - var errors = JsonConvert.DeserializeObject(rawResult); + var errors = JsonSerializer.Deserialize(rawResult); throw new WeiboException { Error = errors }; } diff --git a/Microsoft.Toolkit.Services/Services/Weibo/WeiboError.cs b/Microsoft.Toolkit.Services/Services/Weibo/WeiboError.cs index 8c078b8db10..0a426bc9cb1 100644 --- a/Microsoft.Toolkit.Services/Services/Weibo/WeiboError.cs +++ b/Microsoft.Toolkit.Services/Services/Weibo/WeiboError.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Weibo { @@ -14,13 +14,13 @@ public class WeiboError /// /// Gets or sets error code /// - [JsonProperty("error_code")] + [JsonPropertyName("error_code")] public int Code { get; set; } /// /// Gets or sets error message /// - [JsonProperty("error")] + [JsonPropertyName("error")] public string Message { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Services/Services/Weibo/WeiboGeoInfo.cs b/Microsoft.Toolkit.Services/Services/Weibo/WeiboGeoInfo.cs index e247a2f9da6..d7a19d136ec 100644 --- a/Microsoft.Toolkit.Services/Services/Weibo/WeiboGeoInfo.cs +++ b/Microsoft.Toolkit.Services/Services/Weibo/WeiboGeoInfo.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Services.Weibo { @@ -14,13 +14,13 @@ public class WeiboGeoInfo /// /// Gets the type of geographic information /// - [JsonProperty("type")] + [JsonPropertyName("type")] public string Type { get; internal set; } /// /// Gets the coordinates /// - [JsonProperty("coordinates")] + [JsonPropertyName("coordinates")] public double[] Coordinates { get; internal set; } /// diff --git a/Microsoft.Toolkit.Services/Services/Weibo/WeiboImage.cs b/Microsoft.Toolkit.Services/Services/Weibo/WeiboImage.cs index d8c33c241e2..dcb56e4b04e 100644 --- a/Microsoft.Toolkit.Services/Services/Weibo/WeiboImage.cs +++ b/Microsoft.Toolkit.Services/Services/Weibo/WeiboImage.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Weibo { @@ -14,19 +14,19 @@ public class WeiboImage /// /// Gets or sets the url of the attached image in thumbnail size. /// - [JsonProperty("thumbnail_pic")] + [JsonPropertyName("thumbnail_pic")] public string ThumbnailImageUrl { get; set; } /// /// Gets or sets the url of the attached image in medium size. /// - [JsonProperty("bmiddle_pic")] + [JsonPropertyName("bmiddle_pic")] public string MediumImageUrl { get; set; } /// /// Gets or sets the url of the attached image in original size. /// - [JsonProperty("original_pic")] + [JsonPropertyName("original_pic")] public string OriginalImageUrl { get; set; } } } diff --git a/Microsoft.Toolkit.Services/Services/Weibo/WeiboOAuthRequest.cs b/Microsoft.Toolkit.Services/Services/Weibo/WeiboOAuthRequest.cs index 45ce1d25575..8db8a768507 100644 --- a/Microsoft.Toolkit.Services/Services/Weibo/WeiboOAuthRequest.cs +++ b/Microsoft.Toolkit.Services/Services/Weibo/WeiboOAuthRequest.cs @@ -7,9 +7,9 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.Toolkit.Services.OAuth; -using Newtonsoft.Json; namespace Microsoft.Toolkit.Services.Weibo { @@ -41,26 +41,22 @@ public WeiboOAuthRequest() /// String result. public async Task ExecuteGetAsync(Uri requestUri, WeiboOAuthTokens tokens) { - using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri)) + using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri); + UriBuilder requestUriBuilder = new UriBuilder(request.RequestUri); + if (requestUriBuilder.Query.StartsWith("?")) { - UriBuilder requestUriBuilder = new UriBuilder(request.RequestUri); - if (requestUriBuilder.Query.StartsWith("?")) - { - requestUriBuilder.Query = requestUriBuilder.Query.Substring(1) + "&access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); - } - else - { - requestUriBuilder.Query = requestUriBuilder.Query + "?access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); - } + requestUriBuilder.Query = requestUriBuilder.Query.Substring(1) + "&access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); + } + else + { + requestUriBuilder.Query = requestUriBuilder.Query + "?access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); + } - request.RequestUri = requestUriBuilder.Uri; + request.RequestUri = requestUriBuilder.Uri; - using (HttpResponseMessage response = await _client.SendAsync(request).ConfigureAwait(false)) - { - response.ThrowIfNotValid(); - return ProcessError(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); - } - } + using HttpResponseMessage response = await _client.SendAsync(request).ConfigureAwait(false); + response.ThrowIfNotValid(); + return ProcessError(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); } /// @@ -75,38 +71,33 @@ public async Task ExecutePostAsync(Uri requestUri, WeiboOAuthTokens var contentDict = new Dictionary(); contentDict.Add("status", status); - using (var formUrlEncodedContent = new FormUrlEncodedContent(contentDict)) + using var formUrlEncodedContent = new FormUrlEncodedContent(contentDict); + using var request = new HttpRequestMessage(HttpMethod.Post, requestUri); + UriBuilder requestUriBuilder = new UriBuilder(request.RequestUri); + if (requestUriBuilder.Query.StartsWith("?")) { - using (var request = new HttpRequestMessage(HttpMethod.Post, requestUri)) - { - UriBuilder requestUriBuilder = new UriBuilder(request.RequestUri); - if (requestUriBuilder.Query.StartsWith("?")) - { - requestUriBuilder.Query = requestUriBuilder.Query.Substring(1) + "&access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); - } - else - { - requestUriBuilder.Query = requestUriBuilder.Query + "access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); - } - - request.RequestUri = requestUriBuilder.Uri; - - request.Content = formUrlEncodedContent; - - using (var response = await _client.SendAsync(request).ConfigureAwait(false)) - { - if (response.StatusCode == HttpStatusCode.OK) - { - return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); - } - else - { - response.ThrowIfNotValid(); - ProcessError(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); - return null; - } - } - } + requestUriBuilder.Query = requestUriBuilder.Query.Substring(1) + "&access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); + } + else + { + requestUriBuilder.Query = requestUriBuilder.Query + "access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); + } + + request.RequestUri = requestUriBuilder.Uri; + + request.Content = formUrlEncodedContent; + + using var response = await _client.SendAsync(request).ConfigureAwait(false); + if (response.StatusCode == HttpStatusCode.OK) + { + using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + return await JsonSerializer.DeserializeAsync(stream).ConfigureAwait(false); + } + else + { + response.ThrowIfNotValid(); + ProcessError(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); + return null; } } @@ -122,49 +113,41 @@ public async Task ExecutePostMultipartAsync(Uri requestUri, WeiboOA { try { - using (var multipartFormDataContent = new MultipartFormDataContent()) + using var multipartFormDataContent = new MultipartFormDataContent(); + using var stringContent = new StringContent(status); + multipartFormDataContent.Add(stringContent, "status"); + using var byteContent = new ByteArrayContent(content); + + // Somehow Weibo's backend requires a Filename field to work + byteContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { FileName = "attachment", Name = "pic" }; + multipartFormDataContent.Add(byteContent, "pic"); + + using var request = new HttpRequestMessage(HttpMethod.Post, requestUri); + UriBuilder requestUriBuilder = new UriBuilder(request.RequestUri); + if (requestUriBuilder.Query.StartsWith("?")) + { + requestUriBuilder.Query = requestUriBuilder.Query.Substring(1) + "&access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); + } + else + { + requestUriBuilder.Query = requestUriBuilder.Query + "access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); + } + + request.RequestUri = requestUriBuilder.Uri; + + request.Content = multipartFormDataContent; + + using var response = await _client.SendAsync(request).ConfigureAwait(false); + if (response.StatusCode == HttpStatusCode.OK) + { + using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + return await JsonSerializer.DeserializeAsync(stream).ConfigureAwait(false); + } + else { - using (var stringContent = new StringContent(status)) - { - multipartFormDataContent.Add(stringContent, "status"); - using (var byteContent = new ByteArrayContent(content)) - { - // Somehow Weibo's backend requires a Filename field to work - byteContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { FileName = "attachment", Name = "pic" }; - multipartFormDataContent.Add(byteContent, "pic"); - - using (var request = new HttpRequestMessage(HttpMethod.Post, requestUri)) - { - UriBuilder requestUriBuilder = new UriBuilder(request.RequestUri); - if (requestUriBuilder.Query.StartsWith("?")) - { - requestUriBuilder.Query = requestUriBuilder.Query.Substring(1) + "&access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); - } - else - { - requestUriBuilder.Query = requestUriBuilder.Query + "access_token=" + OAuthEncoder.UrlEncode(tokens.AccessToken); - } - - request.RequestUri = requestUriBuilder.Uri; - - request.Content = multipartFormDataContent; - - using (var response = await _client.SendAsync(request).ConfigureAwait(false)) - { - if (response.StatusCode == HttpStatusCode.OK) - { - return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); - } - else - { - response.ThrowIfNotValid(); - ProcessError(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); - return null; - } - } - } - } - } + response.ThrowIfNotValid(); + ProcessError(await response.Content.ReadAsStringAsync().ConfigureAwait(false)); + return null; } } catch (ObjectDisposedException) @@ -180,10 +163,15 @@ private string ProcessError(string content) { if (content.StartsWith("{\"error\":")) { - WeiboError error = JsonConvert.DeserializeObject(content, new JsonSerializerSettings() + WeiboError error; + try { - Error = (sender, args) => throw new JsonException("Invalid Weibo error response!", args.ErrorContext.Error) - }); + error = JsonSerializer.Deserialize(content); + } + catch (JsonException e) + { + throw new JsonException("Invalid Weibo error response!", e); + } throw new WeiboException { Error = error }; } diff --git a/Microsoft.Toolkit.Services/Services/Weibo/WeiboOAuthRequestExtensions.cs b/Microsoft.Toolkit.Services/Services/Weibo/WeiboOAuthRequestExtensions.cs index 7f7cbb31d76..0a49a6bd2a2 100644 --- a/Microsoft.Toolkit.Services/Services/Weibo/WeiboOAuthRequestExtensions.cs +++ b/Microsoft.Toolkit.Services/Services/Weibo/WeiboOAuthRequestExtensions.cs @@ -2,16 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.IO; -using System.IO.Compression; using System.Net; using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using Microsoft.Toolkit.Services.Core; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.Toolkit.Services.Weibo { diff --git a/Microsoft.Toolkit.Services/Services/Weibo/WeiboParser.cs b/Microsoft.Toolkit.Services/Services/Weibo/WeiboParser.cs index cb3d998308d..7691ea269ad 100644 --- a/Microsoft.Toolkit.Services/Services/Weibo/WeiboParser.cs +++ b/Microsoft.Toolkit.Services/Services/Weibo/WeiboParser.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json; namespace Microsoft.Toolkit.Services.Weibo { @@ -28,12 +28,12 @@ IEnumerable Toolkit.Parsers.IParser.Parse(string data) try { - return JsonConvert.DeserializeObject>(data); + return JsonSerializer.Deserialize>(data); } - catch (JsonSerializationException) + catch (JsonException) { List items = new List(); - items.Add(JsonConvert.DeserializeObject(data)); + items.Add(JsonSerializer.Deserialize(data)); return items; } } diff --git a/Microsoft.Toolkit.Services/Services/Weibo/WeiboStatus.cs b/Microsoft.Toolkit.Services/Services/Weibo/WeiboStatus.cs index a3c26c3de9e..7e8c06a8f7f 100644 --- a/Microsoft.Toolkit.Services/Services/Weibo/WeiboStatus.cs +++ b/Microsoft.Toolkit.Services/Services/Weibo/WeiboStatus.cs @@ -4,8 +4,8 @@ using System; using System.Globalization; +using System.Text.Json.Serialization; using Microsoft.Toolkit.Services.Services.Weibo; -using Newtonsoft.Json; namespace Microsoft.Toolkit.Services.Weibo { @@ -17,7 +17,7 @@ public class WeiboStatus : Toolkit.Parsers.SchemaBase /// /// Gets or sets time item was created. /// - [JsonProperty("created_at")] + [JsonPropertyName("created_at")] public string CreatedAt { get; set; } /// @@ -40,13 +40,13 @@ public DateTime CreationDate /// /// Gets or sets item Id. /// - [JsonProperty("id")] + [JsonPropertyName("id")] public string Id { get; set; } /// /// Gets or sets text of the status (handles both 140 and 280 characters) /// - [JsonProperty("text")] + [JsonPropertyName("text")] public string Text { get; set; } /// @@ -54,85 +54,85 @@ public DateTime CreationDate /// (true when Weibo status is longer than 140 characters) /// This entity may be deprecated - it never seems to be set to true. /// - [JsonProperty("truncated")] + [JsonPropertyName("truncated")] public bool IsTruncated { get; set; } /// /// Gets or sets status source (client or website used) /// - [JsonProperty("source")] + [JsonPropertyName("source")] public string Source { get; set; } /// /// Gets or sets in_reply_to_screen_name /// - [JsonProperty("in_reply_to_screen_name")] + [JsonPropertyName("in_reply_to_screen_name")] public string InReplyToScreenName { get; set; } /// /// Gets or sets in_reply_to_status_id /// - [JsonProperty("in_reply_to_status_id")] + [JsonPropertyName("in_reply_to_status_id")] public string InReplyToStatusId { get; set; } /// /// Gets or sets in_reply_to_user_id /// - [JsonProperty("in_reply_to_user_id")] + [JsonPropertyName("in_reply_to_user_id")] public string InReplyToUserId { get; set; } /// /// Gets or sets user who posted the status. /// - [JsonProperty("user")] + [JsonPropertyName("user")] public WeiboUser User { get; set; } /// /// Gets or sets the Reposted Weibo status /// - [JsonProperty("retweeted_status")] + [JsonPropertyName("retweeted_status")] public WeiboStatus RepostedStatus { get; set; } /// /// Gets or sets the repost count /// - [JsonProperty("reposts_count")] + [JsonPropertyName("reposts_count")] public int RepostCount { get; set; } /// /// Gets or sets the comment count /// - [JsonProperty("comments_count")] + [JsonPropertyName("comments_count")] public int CommentCount { get; set; } /// /// Gets or sets the url of the attached image in thumbnail size. /// - [JsonProperty("thumbnail_pic")] + [JsonPropertyName("thumbnail_pic")] public string ThumbnailImageUrl { get; set; } /// /// Gets or sets the url of the attached image in medium size. /// - [JsonProperty("bmiddle_pic")] + [JsonPropertyName("bmiddle_pic")] public string MediumImageUrl { get; set; } /// /// Gets or sets the url of the attached image in original size. /// - [JsonProperty("original_pic")] + [JsonPropertyName("original_pic")] public string OriginalImageUrl { get; set; } /// /// Gets or sets attached images array of the weibo. /// - [JsonProperty("pic_urls")] + [JsonPropertyName("pic_urls")] public WeiboImage[] AttachedImages { get; set; } /// /// Gets or sets the geographic information. /// - [JsonProperty("geo")] + [JsonPropertyName("geo")] public WeiboGeoInfo GeographicInfo { get; set; } /// diff --git a/Microsoft.Toolkit.Services/Services/Weibo/WeiboStatusParser.cs b/Microsoft.Toolkit.Services/Services/Weibo/WeiboStatusParser.cs index 09f0ae084f9..cdeac82859a 100644 --- a/Microsoft.Toolkit.Services/Services/Weibo/WeiboStatusParser.cs +++ b/Microsoft.Toolkit.Services/Services/Weibo/WeiboStatusParser.cs @@ -2,14 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Toolkit.Services.Weibo; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using System.Text.Json; namespace Microsoft.Toolkit.Services.Weibo { @@ -30,14 +24,14 @@ public IEnumerable Parse(string data) return null; } - JObject rawObject = JObject.Parse(data); + var rawObject = JsonDocument.Parse(data); - IList rawStatuses = rawObject["statuses"].Children().ToList(); + var rawStatuses = rawObject.RootElement.GetProperty("statuses"); IList statuses = new List(); - foreach (JToken result in rawStatuses) + foreach (var rawStatus in rawStatuses.EnumerateArray()) { - WeiboStatus searchResult = result.ToObject(); + WeiboStatus searchResult = JsonSerializer.Deserialize(rawStatus.ToString()); statuses.Add(searchResult); } diff --git a/Microsoft.Toolkit.Services/Services/Weibo/WeiboUser.cs b/Microsoft.Toolkit.Services/Services/Weibo/WeiboUser.cs index f8312087338..c815af4d7d3 100644 --- a/Microsoft.Toolkit.Services/Services/Weibo/WeiboUser.cs +++ b/Microsoft.Toolkit.Services/Services/Weibo/WeiboUser.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Services.Weibo { @@ -14,79 +14,79 @@ public class WeiboUser /// /// Gets or sets user Id. /// - [JsonProperty("id")] + [JsonPropertyName("id")] public string Id { get; set; } /// /// Gets or sets user name. /// - [JsonProperty("name")] + [JsonPropertyName("name")] public string Name { get; set; } /// /// Gets or sets user screen name. /// - [JsonProperty("screen_name")] + [JsonPropertyName("screen_name")] public string ScreenName { get; set; } /// /// Gets or sets profile location. /// - [JsonProperty("location")] + [JsonPropertyName("location")] public string Location { get; set; } /// /// Gets or sets profile url. /// - [JsonProperty("url")] + [JsonPropertyName("url")] public string Url { get; set; } /// /// Gets or sets profile description. /// - [JsonProperty("description")] + [JsonPropertyName("description")] public string Description { get; set; } /// /// Gets or sets profile image url. /// - [JsonProperty("profile_image_url")] + [JsonPropertyName("profile_image_url")] public string ProfileImageUrl { get; set; } /// /// Gets or sets high resolution profile image url. /// - [JsonProperty("avatar_large")] + [JsonPropertyName("avatar_large")] public string HighResolutionProfileImageUrl { get; set; } /// /// Gets or sets followers count. /// - [JsonProperty("followers_count")] + [JsonPropertyName("followers_count")] public int FollowersCount { get; set; } /// /// Gets or sets count of accounts user is following. /// - [JsonProperty("friends_count")] + [JsonPropertyName("friends_count")] public int FriendsCount { get; set; } /// /// Gets or sets total count of statuses user has liked. /// - [JsonProperty("favourites_count")] + [JsonPropertyName("favourites_count")] public int FavoritesCount { get; set; } /// /// Gets or sets total count of Weibo statuses (including reposted statuses) posted by user. /// - [JsonProperty("statuses_count")] + [JsonPropertyName("statuses_count")] public int StatusesCount { get; set; } /// /// Gets or sets a value indicating whether account is verified (blue check mark). /// - [JsonProperty("verified")] + [JsonPropertyName("verified")] public bool Verified { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Data/GitHub.cs b/Microsoft.Toolkit.Uwp.SampleApp/Data/GitHub.cs index d1322f0595d..9a8996727ea 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Data/GitHub.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Data/GitHub.cs @@ -5,8 +5,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; -using Newtonsoft.Json; using Windows.Web.Http; namespace Microsoft.Toolkit.Uwp.SampleApp.Data @@ -31,7 +31,7 @@ public static async Task> GetPublishedReleases() var uri = $"{_root}/repos/{_repoOwner}/{_repoName}/releases"; var result = await client.GetStringAsync(new Uri(uri)); - _releases = JsonConvert.DeserializeObject>(result).Take(5).ToList(); + _releases = JsonSerializer.Deserialize>(result).Take(5).ToList(); } } catch (Exception) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Data/PhotosDataSource.cs b/Microsoft.Toolkit.Uwp.SampleApp/Data/PhotosDataSource.cs index 90eceab697e..a3350c0eca4 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Data/PhotosDataSource.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Data/PhotosDataSource.cs @@ -7,8 +7,8 @@ using System.Collections.ObjectModel; using System.IO; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; -using Newtonsoft.Json; using Windows.Storage; using Windows.Storage.Streams; using Windows.UI.Xaml.Data; @@ -88,7 +88,7 @@ private static async Task> GetPhotosAsync(bool online private static IEnumerable Parse(string jsonData) { - return JsonConvert.DeserializeObject>(jsonData); + return JsonSerializer.Deserialize>(jsonData); } private static void CheckCacheState(bool online) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj index 27d76fc20c0..2933c1f2137 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj +++ b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj @@ -124,8 +124,8 @@ 2.0.1 - - 10.0.3 + + 4.7.2 1.0.5 diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/GitHubRelease.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/GitHubRelease.cs index e96bac72291..a016bccc80d 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/GitHubRelease.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/GitHubRelease.cs @@ -3,30 +3,30 @@ // See the LICENSE file in the project root for more information. using System; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Uwp.SampleApp { public class GitHubRelease { - [JsonProperty("published_at")] + [JsonPropertyName("published_at")] public DateTime Published { get; set; } - [JsonProperty("body")] + [JsonPropertyName("body")] public string Body { get; set; } - [JsonProperty("tag_name")] + [JsonPropertyName("tag_name")] public string Tag { get; set; } - [JsonProperty("name")] + [JsonPropertyName("name")] public string Name { get; set; } public string FullName => $"Version {Name.Replace("v", string.Empty)} notes"; - [JsonProperty("draft")] + [JsonPropertyName("draft")] public bool IsDraft { get; set; } - [JsonProperty("html_url")] + [JsonPropertyName("html_url")] public string Url { get; set; } } } diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageLink.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageLink.cs index c87d92569ba..05090247425 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageLink.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageLink.cs @@ -2,16 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Uwp.SampleApp { public class LandingPageLink { - [JsonProperty("title")] + [JsonPropertyName("title")] public string Title { get; set; } - [JsonProperty("url")] + [JsonPropertyName("url")] public string Url { get; set; } } } diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageLinks.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageLinks.cs index c8fa3afd73f..79297e977ec 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageLinks.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageLinks.cs @@ -2,19 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Uwp.SampleApp { public class LandingPageLinks { - [JsonProperty("new-section-title")] + [JsonPropertyName("new-section-title")] public string NewSectionTitle { get; set; } - [JsonProperty("new-samples")] + [JsonPropertyName("new-samples")] public string[] NewSamples { get; set; } - [JsonProperty("resources")] + [JsonPropertyName("resources")] public LandingPageResource[] Resources { get; set; } } } diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageResource.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageResource.cs index 177044e23c3..64fddf52a8b 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageResource.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/LandingPageResource.cs @@ -2,19 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.Toolkit.Uwp.SampleApp { public class LandingPageResource { - [JsonProperty("title")] + [JsonPropertyName("title")] public string Title { get; set; } - [JsonProperty("id")] + [JsonPropertyName("id")] public string ID { get; set; } - [JsonProperty("links")] + [JsonPropertyName("links")] public LandingPageLink[] Links { get; set; } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs index e89c1a27cfe..d3cffd7038f 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/Sample.cs @@ -12,6 +12,8 @@ using System.Net.Http; using System.Reflection; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.Toolkit.Graph.Converters; @@ -22,7 +24,7 @@ using Microsoft.Toolkit.Uwp.UI.Animations; using Microsoft.Toolkit.Uwp.UI.Controls; using Microsoft.Toolkit.Uwp.UI.Media; -using Newtonsoft.Json; +using Microsoft.UI.Xaml; using Windows.Foundation.Metadata; using Windows.Storage; using Windows.Storage.Streams; @@ -759,7 +761,7 @@ private static async Task GetDocsSHA() { var raw = await response.Content.ReadAsStringAsync(); Debug.WriteLine(raw); - var json = JsonConvert.DeserializeObject(raw); + var json = JsonSerializer.Deserialize(raw); return json?.RefObject?.Sha; } } @@ -774,13 +776,13 @@ private static async Task GetDocsSHA() public class GitRef { - [JsonProperty("object")] + [JsonPropertyName("object")] public GitRefObject RefObject { get; set; } } public class GitRefObject { - [JsonProperty("sha")] + [JsonPropertyName("sha")] public string Sha { get; set; } } } diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs b/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs index 45700de0b3a..901bea050e8 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Models/Samples.cs @@ -4,11 +4,12 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Microsoft.Toolkit.Uwp.Helpers; -using Newtonsoft.Json; namespace Microsoft.Toolkit.Uwp.SampleApp { @@ -56,8 +57,10 @@ public static async Task> GetCategoriesAsync() List allCategories; using (var jsonStream = await StreamHelper.GetPackagedFileStreamAsync("SamplePages/samples.json")) { - var jsonString = await jsonStream.ReadTextAsync(); - allCategories = JsonConvert.DeserializeObject>(jsonString); + allCategories = await JsonSerializer.DeserializeAsync>(jsonStream.AsStream(), new JsonSerializerOptions + { + ReadCommentHandling = JsonCommentHandling.Skip + }); } // Check API diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Pages/About.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/Pages/About.xaml.cs index a36dd63aa1d..2040485db8b 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Pages/About.xaml.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/Pages/About.xaml.cs @@ -5,12 +5,14 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.Toolkit.Uwp.UI.Animations; -using Newtonsoft.Json; using Windows.ApplicationModel; using Windows.UI.Composition; using Windows.UI.Xaml; @@ -202,8 +204,7 @@ private async Task UpdateSections() { using (var jsonStream = await StreamHelper.GetPackagedFileStreamAsync("landingPageLinks.json")) { - var jsonString = await jsonStream.ReadTextAsync(); - var links = JsonConvert.DeserializeObject(jsonString); + var links = await JsonSerializer.DeserializeAsync(jsonStream.AsStream()); var packageVersion = Package.Current.Id.Version; var resource = links.Resources.FirstOrDefault(item => item.ID == "app"); diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MarkdownParser/MarkdownParserPage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MarkdownParser/MarkdownParserPage.xaml.cs index 024053f55fb..c957626067e 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MarkdownParser/MarkdownParserPage.xaml.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/MarkdownParser/MarkdownParserPage.xaml.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Text.Json; +using System.Text.Json.Serialization; using Microsoft.Toolkit.Parsers.Markdown; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; using Windows.UI.Xaml.Controls; namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages @@ -35,7 +35,13 @@ private void UpdateMDResult() var document = new MarkdownDocument(); document.Parse(RawMarkdown.Text); - var json = JsonConvert.SerializeObject(document, Formatting.Indented, new StringEnumConverter()); + var jsonSerializerOptions = new JsonSerializerOptions + { + WriteIndented = true + }; + jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + + var json = JsonSerializer.Serialize(document, typeof(MarkdownDocument), jsonSerializerOptions); MarkdownResult.Text = json; } } diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Microsoft Translator Service/MicrosoftTranslatorPage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Microsoft Translator Service/MicrosoftTranslatorPage.xaml.cs index a6b1d4d492d..d6bedd74ad4 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Microsoft Translator Service/MicrosoftTranslatorPage.xaml.cs +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Microsoft Translator Service/MicrosoftTranslatorPage.xaml.cs @@ -47,13 +47,18 @@ private async void GetLanguages_OnClick(object sender, RoutedEventArgs e) Languages.ItemsSource = null; - _translatorClient.SubscriptionKey = TranslatorServiceKey.Text; - var languages = await _translatorClient.GetLanguageNamesAsync("en"); - - Languages.ItemsSource = languages; - Languages.SelectedIndex = 0; + try + { + _translatorClient.SubscriptionKey = TranslatorServiceKey.Text; + var languages = await _translatorClient.GetLanguageNamesAsync("en"); - SampleController.Current.DisplayWaitRing = false; + Languages.ItemsSource = languages; + Languages.SelectedIndex = 0; + } + finally + { + SampleController.Current.DisplayWaitRing = false; + } } private async void Translate_OnClick(object sender, RoutedEventArgs e) diff --git a/Microsoft.Toolkit.Uwp.SampleApp/landingPageLinks.json b/Microsoft.Toolkit.Uwp.SampleApp/landingPageLinks.json index 611ac435f58..da4679187e2 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/landingPageLinks.json +++ b/Microsoft.Toolkit.Uwp.SampleApp/landingPageLinks.json @@ -84,10 +84,6 @@ "title": "Version", "url": "http://aka.ms/uwptoolkit" }, - { - "title": "Newtonsoft Json (Dependency)", - "url": "http://www.newtonsoft.com/json" - }, { "title": "ColorCode-Universal (Dependency)", "url": "https://github.com/WilliamABradley/ColorCode-Universal" diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Controls/InfiniteCanvasVirtualDrawingSurface.Render.cs b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Controls/InfiniteCanvasVirtualDrawingSurface.Render.cs index 884811d6969..bb9a7648252 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Controls/InfiniteCanvasVirtualDrawingSurface.Render.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Controls/InfiniteCanvasVirtualDrawingSurface.Render.cs @@ -5,11 +5,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.Graphics.Canvas; using Microsoft.Graphics.Canvas.UI.Composition; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Windows.Foundation; using Windows.Graphics; using Windows.Storage; @@ -79,31 +78,49 @@ internal void ClearAll(Rect viewPort) internal string GetSerializedList() { var exportModel = new InkCanvasExportModel { DrawableList = _drawableList, Version = 1 }; - return JsonConvert.SerializeObject(exportModel, Formatting.Indented, new JsonSerializerSettings - { - TypeNameHandling = TypeNameHandling.Auto - }); + return JsonSerializer.Serialize(exportModel, GetJsonSerializerOptions()); } - internal void RenderFromJsonAndDraw(Rect viewPort, string json, float zoom) + private static JsonSerializerOptions GetJsonSerializerOptions() { - _visibleList.Clear(); - _drawableList.Clear(); - _undoCommands.Clear(); - _redoCommands.Clear(); + var jsonSerializerOptions = new JsonSerializerOptions + { + WriteIndented = true + }; + + // This will be needed until These two issues are fixed: + // https://github.com/dotnet/runtime/issues/30083 + // https://github.com/dotnet/runtime/issues/29937 + jsonSerializerOptions.Converters.Add(new IDrawableConverter()); + return jsonSerializerOptions; + } - var token = JToken.Parse(json); + internal static List LoadJson(string json) + { + var token = JsonDocument.Parse(json); List newList; - if (token is JArray) + if (token.RootElement.ValueKind == JsonValueKind.Array) { // first sin, because of creating a file without versioning so we have to be able to import without breaking changes. - newList = JsonConvert.DeserializeObject>(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); + newList = JsonSerializer.Deserialize>(json, GetJsonSerializerOptions()); } else { - newList = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }).DrawableList; + newList = JsonSerializer.Deserialize(json, GetJsonSerializerOptions()).DrawableList; } + return newList; + } + + internal void RenderFromJsonAndDraw(Rect viewPort, string json, float zoom) + { + _visibleList.Clear(); + _drawableList.Clear(); + _undoCommands.Clear(); + _redoCommands.Clear(); + + var newList = LoadJson(json); + foreach (var drawable in newList) { _drawableList.Add(drawable); diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/IDrawable.cs b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/IDrawable.cs index ed9cc2756ea..a20aa9ec18c 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/IDrawable.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/IDrawable.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Text.Json; using Microsoft.Graphics.Canvas; using Windows.Foundation; @@ -13,6 +14,12 @@ internal interface IDrawable bool IsVisible(Rect viewPort); + void WriteJson(Utf8JsonWriter writer); + + void ReadProperty(string propertyName, ref Utf8JsonReader reader); + + void OnDeserialized(); + bool IsActive { get; set; } Rect Bounds { get; set; } diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/InkDrawable.cs b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/InkDrawable.cs index 3a3bc724076..9da83196804 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/InkDrawable.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/InkDrawable.cs @@ -5,9 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; using Microsoft.Graphics.Canvas; -using Newtonsoft.Json; using Windows.Foundation; using Windows.UI.Input.Inking; using Windows.UI.Xaml; @@ -19,6 +19,9 @@ internal class InkDrawable : IDrawable [JsonIgnore] public IReadOnlyList Strokes { get; set; } + [JsonPropertyName("$type")] + public string Type => IDrawableConverter.GetDiscriminator(GetType()); + public List SerializableStrokeList { get; set; } public Rect Bounds { get; set; } @@ -27,6 +30,11 @@ internal class InkDrawable : IDrawable internal static readonly InkStrokeBuilder StrokeBuilder = new InkStrokeBuilder(); + // Don't remove! Used for deserialization. + public InkDrawable() + { + } + public InkDrawable(IReadOnlyList strokes) { if (strokes == null || !strokes.Any()) @@ -83,8 +91,7 @@ private static InkPoint MapPointToToSessionBounds(InkPoint point, Rect sessionBo return new InkPoint(new Point(point.Position.X - sessionBounds.X, point.Position.Y - sessionBounds.Y), point.Pressure, point.TiltX, point.TiltY, point.Timestamp); } - [OnSerializing] - internal void OnSerializingMethod(StreamingContext context) + public void WriteJson(Utf8JsonWriter writer) { SerializableStrokeList = new List(Strokes.Count); foreach (var stroke in Strokes) @@ -103,10 +110,15 @@ internal void OnSerializingMethod(StreamingContext context) serializableStroke.PointTransform = stroke.PointTransform; SerializableStrokeList.Add(serializableStroke); } + + var options = new JsonSerializerOptions(); + options.Converters.Add(new SerializableStrokeConverter()); + JsonSerializer.Serialize(writer, this, options); + + SerializableStrokeList = null; } - [OnDeserialized] - internal void OnDeserializedMethod(StreamingContext context) + public void OnDeserialized() { var finalStrokeList = new List(SerializableStrokeList.Count); @@ -121,10 +133,18 @@ internal void OnDeserializedMethod(StreamingContext context) SerializableStrokeList = null; } - [OnSerialized] - internal void OnSerializedMethod(StreamingContext context) + public void ReadProperty(string propertyName, ref Utf8JsonReader reader) { - SerializableStrokeList = null; + switch (propertyName) + { + case "SerializableStrokeList": + var options = new JsonSerializerOptions(); + options.Converters.Add(new SerializableStrokeConverter()); + SerializableStrokeList = JsonSerializer.Deserialize>(ref reader, options); + break; + default: + break; + } } } } diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/TextDrawable.cs b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/TextDrawable.cs index fbb2450e2ee..7f9604dc12a 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/TextDrawable.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/Drawables/TextDrawable.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Text.Json; +using System.Text.Json.Serialization; using Microsoft.Graphics.Canvas; using Microsoft.Graphics.Canvas.Text; using Windows.Foundation; @@ -13,6 +15,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls { internal class TextDrawable : IDrawable { + [JsonPropertyName("$type")] + public string Type => IDrawableConverter.GetDiscriminator(GetType()); + public string Text { get; set; } public Rect Bounds { get; set; } @@ -27,6 +32,11 @@ internal class TextDrawable : IDrawable public bool IsItalic { get; set; } + // Don't remove! Used for deserialization. + public TextDrawable() + { + } + public TextDrawable(double left, double top, double width, double height, float fontSize, string text, Color textColor, bool isBold, bool isItalic) { Bounds = new Rect(left, top, width, height); @@ -76,5 +86,38 @@ public float HorizontalMarginBasedOnFont return ((100 - FontSize) / 10) + 5; } } + + public void WriteJson(Utf8JsonWriter writer) + { + JsonSerializer.Serialize(writer, this); + } + + public void OnDeserialized() + { + } + + public void ReadProperty(string propertyName, ref Utf8JsonReader reader) + { + switch (propertyName) + { + case "Text": + Text = reader.GetString(); + break; + case "FontSize": + FontSize = reader.GetSingle(); + break; + case "TextColor": + TextColor = JsonSerializer.Deserialize(ref reader); + break; + case "IsBold": + IsBold = reader.GetBoolean(); + break; + case "IsItalic": + IsItalic = reader.GetBoolean(); + break; + default: + break; + } + } } } diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/IDrawableConverter.cs b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/IDrawableConverter.cs new file mode 100644 index 00000000000..19fdc0472b4 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/IDrawableConverter.cs @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Windows.Foundation; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + internal class IDrawableConverter : JsonConverter + { + public override bool CanConvert(Type typeToConvert) => typeof(IDrawable).IsAssignableFrom(typeToConvert); + + public override IDrawable Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(); + } + + reader.Read(); + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException(); + } + + string propertyName = reader.GetString(); + if (propertyName != "$type") + { + throw new JsonException(); + } + + reader.Read(); + if (reader.TokenType != JsonTokenType.String) + { + throw new JsonException(); + } + + var typeDiscriminator = reader.GetString(); + IDrawable drawable; + if (typeDiscriminator == GetDiscriminator(typeof(InkDrawable))) + { + drawable = new InkDrawable(); + } + else if (typeDiscriminator == GetDiscriminator(typeof(TextDrawable))) + { + drawable = new TextDrawable(); + } + else + { + throw new JsonException(); + } + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + drawable.OnDeserialized(); + return drawable; + } + + if (reader.TokenType == JsonTokenType.PropertyName) + { + propertyName = reader.GetString(); + reader.Read(); + switch (propertyName) + { + case "IsActive": + drawable.IsActive = reader.GetBoolean(); + break; + case "Bounds": + drawable.Bounds = JsonSerializer.Deserialize(ref reader); + break; + default: + drawable.ReadProperty(propertyName, ref reader); + break; + } + } + } + + throw new JsonException(); + } + + public override void Write(Utf8JsonWriter writer, IDrawable drawable, JsonSerializerOptions options) + { + drawable.WriteJson(writer); + } + + internal static string GetDiscriminator(Type type) + { + return $"{type.FullName}, {type.Assembly.GetName().Name}"; + } + } +} \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/Matrix3x2Converter.cs b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/Matrix3x2Converter.cs new file mode 100644 index 00000000000..3fbbd9211d9 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/Matrix3x2Converter.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Numerics; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + internal class Matrix3x2Converter : JsonConverter + { + public override Matrix3x2 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(); + } + + string propertyName; + Matrix3x2 matrix = default; + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + return matrix; + } + + if (reader.TokenType == JsonTokenType.PropertyName) + { + propertyName = reader.GetString(); + reader.Read(); + switch (propertyName) + { + case "M11": + matrix.M11 = reader.GetSingle(); + break; + case "M12": + matrix.M12 = reader.GetSingle(); + break; + case "M21": + matrix.M21 = reader.GetSingle(); + break; + case "M22": + matrix.M22 = reader.GetSingle(); + break; + case "M31": + matrix.M31 = reader.GetSingle(); + break; + case "M32": + matrix.M32 = reader.GetSingle(); + break; + case "IsIdentity": + // Ignore, as it is readonly, and from v1 + break; + case "Translation": + var translation = JsonSerializer.Deserialize(ref reader); + matrix.Translation = translation; + break; + } + } + } + + throw new JsonException(); + } + + public override void Write(Utf8JsonWriter writer, Matrix3x2 value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + + writer.WriteNumber("M11", value.M11); + writer.WriteNumber("M12", value.M12); + writer.WriteNumber("M21", value.M21); + writer.WriteNumber("M22", value.M22); + writer.WriteNumber("M31", value.M31); + writer.WriteNumber("M32", value.M32); + + writer.WriteEndObject(); + } + } +} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/SerializableStroke.cs b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/SerializableStroke.cs index dcd0255cb8a..e6869730c39 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/SerializableStroke.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/SerializableStroke.cs @@ -4,8 +4,8 @@ using System.Collections.Generic; using System.Numerics; -using System.Runtime.Serialization; -using Newtonsoft.Json; +using System.Text.Json; +using System.Text.Json.Serialization; using Windows.UI.Input.Inking; namespace Microsoft.Toolkit.Uwp.UI.Controls @@ -29,8 +29,7 @@ internal class SerializableStroke public Matrix3x2 PointTransform { get; set; } - [OnSerializing] - internal void OnSerializingMethod(StreamingContext context) + internal void Write(Utf8JsonWriter writer, JsonSerializerOptions options) { SerializableFinalPointList = new List(FinalPointList.Count); foreach (var point in FinalPointList) @@ -60,10 +59,13 @@ internal void OnSerializingMethod(StreamingContext context) DrawAsHighlighter = DrawingAttributesIgnored.DrawAsHighlighter }; } + + JsonSerializer.Serialize(writer, this, options); + + SerializableFinalPointList = null; } - [OnDeserialized] - internal void OnDeserializedMethod(StreamingContext context) + internal void OnDeserialized() { var finalPointList = new List(SerializableFinalPointList.Count); @@ -108,11 +110,5 @@ internal void OnDeserializedMethod(StreamingContext context) SerializableFinalPointList = null; SerializableDrawingAttributesKind = null; } - - [OnSerialized] - internal void OnSerializedMethod(StreamingContext context) - { - SerializableFinalPointList = null; - } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/SerializableStrokeConverter.cs b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/SerializableStrokeConverter.cs new file mode 100644 index 00000000000..186c7390c3b --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/InfiniteCanvas/JsonConverters/SerializableStrokeConverter.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + internal class SerializableStrokeConverter : JsonConverter + { + public override SerializableStroke Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var matrixOptions = new JsonSerializerOptions(); + matrixOptions.Converters.Add(new Matrix3x2Converter()); + SerializableStroke serializableStroke = JsonSerializer.Deserialize(ref reader, matrixOptions); + + serializableStroke.OnDeserialized(); + + return serializableStroke; + } + + public override void Write(Utf8JsonWriter writer, SerializableStroke value, JsonSerializerOptions options) + { + var matrixOptions = new JsonSerializerOptions(); + matrixOptions.Converters.Add(new Matrix3x2Converter()); + value.Write(writer, matrixOptions); + } + } +} \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Microsoft.Toolkit.Uwp.UI.Controls.csproj b/Microsoft.Toolkit.Uwp.UI.Controls/Microsoft.Toolkit.Uwp.UI.Controls.csproj index 6e77b7b1440..4e3def286e9 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/Microsoft.Toolkit.Uwp.UI.Controls.csproj +++ b/Microsoft.Toolkit.Uwp.UI.Controls/Microsoft.Toolkit.Uwp.UI.Controls.csproj @@ -41,6 +41,7 @@ UWP Toolkit Windows Controls XAML Range WrapPanel Adaptive Markdown BladeView Blade CameraPreview Camera Carousel DockPanel DropShadow Expander GridSplitter HeaderedContent ImageEx InAppNotification InfiniteCanvas Master Details MasterDetails Orbit Radial Gauge RadiaGauge RadialProgressBar Scroll ScrollHeader StaggeredPanel Staggered Tile Tokenizing TextBox UniformGrid Uniform Grid false + 8.0 diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Properties/Microsoft.Windows.Toolkit.UI.Controls.rd.xml b/Microsoft.Toolkit.Uwp.UI.Controls/Properties/Microsoft.Toolkit.Uwp.UI.Controls.rd.xml similarity index 52% rename from Microsoft.Toolkit.Uwp.UI.Controls/Properties/Microsoft.Windows.Toolkit.UI.Controls.rd.xml rename to Microsoft.Toolkit.Uwp.UI.Controls/Properties/Microsoft.Toolkit.Uwp.UI.Controls.rd.xml index 69e67475b53..140de69eea9 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/Properties/Microsoft.Windows.Toolkit.UI.Controls.rd.xml +++ b/Microsoft.Toolkit.Uwp.UI.Controls/Properties/Microsoft.Toolkit.Uwp.UI.Controls.rd.xml @@ -1,5 +1,7 @@ + + diff --git a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/JsonObjectSerializer.cs b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/JsonObjectSerializer.cs index 8ce982ddfc0..3f1d52f6fbd 100644 --- a/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/JsonObjectSerializer.cs +++ b/Microsoft.Toolkit.Uwp/Helpers/ObjectStorage/JsonObjectSerializer.cs @@ -2,14 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Newtonsoft.Json; +using System.Text.Json; namespace Microsoft.Toolkit.Uwp.Helpers { internal class JsonObjectSerializer : IObjectSerializer { - public string Serialize(T value) => JsonConvert.SerializeObject(value); + public string Serialize(T value) => JsonSerializer.Serialize(value); - public T Deserialize(string value) => JsonConvert.DeserializeObject(value); + public T Deserialize(string value) => JsonSerializer.Deserialize(value); } } diff --git a/Microsoft.Toolkit.Uwp/Microsoft.Toolkit.Uwp.csproj b/Microsoft.Toolkit.Uwp/Microsoft.Toolkit.Uwp.csproj index 2a6a6fd40d3..445fb25bbf1 100644 --- a/Microsoft.Toolkit.Uwp/Microsoft.Toolkit.Uwp.csproj +++ b/Microsoft.Toolkit.Uwp/Microsoft.Toolkit.Uwp.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/Microsoft.Toolkit.Uwp/Properties/Microsoft.Toolkit.Uwp.rd.xml b/Microsoft.Toolkit.Uwp/Properties/Microsoft.Toolkit.Uwp.rd.xml new file mode 100644 index 00000000000..c852cb37baa --- /dev/null +++ b/Microsoft.Toolkit.Uwp/Properties/Microsoft.Toolkit.Uwp.rd.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/Microsoft.Toolkit.Uwp/Properties/Microsoft.Windows.Toolkit.rd.xml b/Microsoft.Toolkit.Uwp/Properties/Microsoft.Windows.Toolkit.rd.xml deleted file mode 100644 index 2f2bb20c525..00000000000 --- a/Microsoft.Toolkit.Uwp/Properties/Microsoft.Windows.Toolkit.rd.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - diff --git a/UnitTests/UnitTests.UWP/Assets/Samples/InfiniteCanvasExport.json b/UnitTests/UnitTests.UWP/Assets/Samples/InfiniteCanvasExport.json new file mode 100644 index 00000000000..08a856e87a9 --- /dev/null +++ b/UnitTests/UnitTests.UWP/Assets/Samples/InfiniteCanvasExport.json @@ -0,0 +1,102 @@ +{ + "DrawableList": [ + { + "$type": "Microsoft.Toolkit.Uwp.UI.Controls.InkDrawable, Microsoft.Toolkit.Uwp.UI.Controls", + "SerializableStrokeList": [ + { + "DrawingAttributes": { + "Color": { + "A": 255, + "R": 0, + "G": 0, + "B": 0 + }, + "FitToCurve": true, + "IgnorePressure": false, + "IgnoreTilt": true, + "Size": { + "Width": 4.0, + "Height": 4.0, + "IsEmpty": false + }, + "PenTip": 0, + "PenTipTransform": { + "M11": 1.0, + "M12": 0.0, + "M21": 0.0, + "M22": 1.0, + "M31": 0.0, + "M32": 0.0, + "IsIdentity": true, + "Translation": { + "X": 0.0, + "Y": 0.0 + } + }, + "DrawAsHighlighter": false + }, + "SerializableFinalPointList": [ + { + "Position": { + "X": 103.97531127929688, + "Y": 45.995269775390625 + }, + "Pressure": 0.5, + "TiltX": 0.0, + "TiltY": 0.0, + "Timestamp": 0 + }, + { + "Position": { + "X": 103.80825805664063, + "Y": 45.995269775390625 + }, + "Pressure": 0.5, + "TiltX": 0.0, + "TiltY": 0.0, + "Timestamp": 0 + }, + { + "Position": { + "X": 103.41259002685547, + "Y": 45.995269775390625 + }, + "Pressure": 0.5, + "TiltX": 0.0, + "TiltY": 0.0, + "Timestamp": 0 + } + ], + "SerializableDrawingAttributesKind": 0, + "SerializableDrawingAttributesPencilProperties": null, + "PointTransform": { + "M11": 1.0, + "M12": 0.0, + "M21": 0.0, + "M22": 1.0, + "M31": 0.0, + "M32": 0.0, + "IsIdentity": true, + "Translation": { + "X": 0.0, + "Y": 0.0 + } + } + } + ], + "Bounds": { + "X": 69.949455261230469, + "Y": 28.069997787475586, + "Width": 1668.2589111328125, + "Height": 280.38735961914062, + "Left": 69.949455261230469, + "Top": 28.069997787475586, + "Right": 1738.2083740234375, + "Bottom": 308.45736694335938, + "IsEmpty": false + }, + "IsActive": true + } + ], + "Version": 1 +} \ No newline at end of file diff --git a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs index 71e459be102..0099a77ff49 100644 --- a/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs +++ b/UnitTests/UnitTests.UWP/Helpers/Test_StorageHelper.cs @@ -4,8 +4,8 @@ using Microsoft.Toolkit.Uwp.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Newtonsoft.Json; using System; +using System.Text.Json; using UnitTests.UI; namespace UnitTests.Helpers @@ -24,7 +24,7 @@ public void Test_StorageHelper_LegacyIntTest() int input = 42; // simulate previous version by generating json and manually inserting it as string - string jsonInput = JsonConvert.SerializeObject(input); + string jsonInput = JsonSerializer.Serialize(input); storageHelper.Save(key, jsonInput); @@ -43,7 +43,7 @@ public void Test_StorageHelper_LegacyDateTest() DateTime input = new DateTime(2017, 12, 25); // simulate previous version by generating json and manually inserting it as string - string jsonInput = JsonConvert.SerializeObject(input); + string jsonInput = JsonSerializer.Serialize(input); storageHelper.Save(key, jsonInput); @@ -62,7 +62,7 @@ public void Test_StorageHelper_LegacyPersonTest() Person input = new Person() { Name = "Joe Bloggs", Age = 42 }; // simulate previous version by generating json and manually inserting it as string - string jsonInput = JsonConvert.SerializeObject(input); + string jsonInput = JsonSerializer.Serialize(input); storageHelper.Save(key, jsonInput); diff --git a/UnitTests/UnitTests.UWP/UI/Controls/Test_InfiniteCanvas_Regression.cs b/UnitTests/UnitTests.UWP/UI/Controls/Test_InfiniteCanvas_Regression.cs new file mode 100644 index 00000000000..5c52be75339 --- /dev/null +++ b/UnitTests/UnitTests.UWP/UI/Controls/Test_InfiniteCanvas_Regression.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.Toolkit.Uwp.Helpers; +using Microsoft.Toolkit.Uwp.UI.Controls; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Windows.ApplicationModel.Core; +using Windows.UI.Core; + +namespace UnitTests.UI.Controls +{ + [TestClass] + public class Test_InfiniteCanvas_Regression + { + [TestCategory("InfiniteCanvas")] + [TestMethod] + public async Task Test_InfiniteCanvas_LoadsV1File() + { + var taskSource = new TaskCompletionSource(); + await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync( + CoreDispatcherPriority.Normal, async () => + { + try + { + string json = await StorageFileHelper.ReadTextFromPackagedFileAsync(@"Assets\Samples\InfiniteCanvasExport.json"); + + InfiniteCanvasVirtualDrawingSurface.LoadJson(json).Should().NotBeEmpty(); + + taskSource.SetResult(null); + } + catch (Exception e) + { + taskSource.SetException(e); + } + }); + await taskSource.Task; + } + } +} \ No newline at end of file diff --git a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj index 898608f956f..a9893fa92c0 100644 --- a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj +++ b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj @@ -125,6 +125,9 @@ 4.3.0 + + 4.7.2 + @@ -177,6 +180,7 @@ + @@ -201,6 +205,7 @@ Designer +