Skip to content

Commit 7c5190d

Browse files
Merge pull request #77 from andrei-m-code/feature/system-text-json
Migrated to System.Text.Json with ability to customize serialization
2 parents 2a4ea56 + 55611cc commit 7c5190d

File tree

12 files changed

+135
-134
lines changed

12 files changed

+135
-134
lines changed

CorePush.Tester/AppleNotification.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System;
2-
using Newtonsoft.Json;
2+
using System.Text.Json.Serialization;
33

44
namespace CorePush.Tester
55
{
@@ -9,17 +9,17 @@ public class ApsPayload
99
{
1010
public class Alert
1111
{
12-
[JsonProperty("title")]
12+
[JsonPropertyName("title")]
1313
public string Title { get; set; }
1414

15-
[JsonProperty("body")]
15+
[JsonPropertyName("body")]
1616
public string Body { get; set; }
1717
}
1818

19-
[JsonProperty("alert")]
19+
[JsonPropertyName("alert")]
2020
public Alert AlertBody { get; set; }
2121

22-
[JsonProperty("apns-push-type")]
22+
[JsonPropertyName("apns-push-type")]
2323
public string PushType { get; set; } = "alert";
2424
}
2525

@@ -37,10 +37,10 @@ public AppleNotification(Guid id, string message, string title = "")
3737
};
3838
}
3939

40-
[JsonProperty("aps")]
40+
[JsonPropertyName("aps")]
4141
public ApsPayload Aps { get; set; }
4242

43-
[JsonProperty("id")]
43+
[JsonPropertyName("id")]
4444
public Guid Id { get; set; }
4545
}
4646
}

CorePush.Tester/CorePush.Tester.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFrameworks>net5.0</TargetFrameworks>
5+
<TargetFramework>net6.0</TargetFramework>
66
</PropertyGroup>
77

88
<ItemGroup>

CorePush.Tester/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ private static async Task SendFcmNotificationAsync()
7272
notification = new { body = "Hello World!" }
7373
};
7474

75-
var response = await fcm.SendAsync(fcmReceiverToken, payload);
75+
var response = await fcm.SendAsync(payload);
7676
}
7777
}
7878
}

CorePush/Apple/ApnSender.cs

Lines changed: 51 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using CorePush.Interfaces;
2-
using CorePush.Utils;
3-
using System;
1+
using System;
42
using System.Collections.Concurrent;
53
using System.Collections.Generic;
64
using System.Linq;
@@ -11,15 +9,19 @@
119
using System.Threading;
1210
using System.Threading.Tasks;
1311

12+
using CorePush.Interfaces;
13+
using CorePush.Utils;
14+
using CorePush.Serialization;
15+
1416
namespace CorePush.Apple
1517
{
1618
/// <summary>
1719
/// HTTP2 Apple Push Notification sender
1820
/// </summary>
1921
public class ApnSender : IApnSender
2022
{
21-
private static readonly ConcurrentDictionary<string, Tuple<string, DateTime>> tokens = new ConcurrentDictionary<string, Tuple<string, DateTime>>();
22-
private static readonly Dictionary<ApnServerType, string> servers = new Dictionary<ApnServerType, string>
23+
private static readonly ConcurrentDictionary<string, Tuple<string, DateTime>> tokens = new();
24+
private static readonly Dictionary<ApnServerType, string> servers = new()
2325
{
2426
{ApnServerType.Development, "https://api.development.push.apple.com:443" },
2527
{ApnServerType.Production, "https://api.push.apple.com:443" }
@@ -30,17 +32,24 @@ public class ApnSender : IApnSender
3032

3133
private readonly ApnSettings settings;
3234
private readonly HttpClient http;
35+
private readonly IJsonSerializer serializer;
3336

37+
public ApnSender(ApnSettings settings, HttpClient http) : this(settings, http, new DefaultJsonSerializer())
38+
{
39+
}
40+
3441
/// <summary>
3542
/// Apple push notification sender constructor
3643
/// </summary>
3744
/// <param name="settings">Apple Push Notification settings</param>
3845
/// <param name="http">HTTP client instance</param>
39-
public ApnSender(ApnSettings settings, HttpClient http)
46+
/// <param name="serializer">JSON serializer</param>
47+
public ApnSender(ApnSettings settings, HttpClient http, IJsonSerializer serializer)
4048
{
4149
this.settings = settings ?? throw new ArgumentNullException(nameof(settings));
4250
this.http = http ?? throw new ArgumentNullException(nameof(http));
43-
51+
this.serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
52+
4453
if (http.BaseAddress == null)
4554
{
4655
http.BaseAddress = new Uri(servers[settings.ServerType]);
@@ -65,39 +74,37 @@ public async Task<ApnsResponse> SendAsync(
6574
CancellationToken cancellationToken = default)
6675
{
6776
var path = $"/3/device/{deviceToken}";
68-
var json = JsonHelper.Serialize(notification);
77+
var json = serializer.Serialize(notification);
6978

70-
using (var message = new HttpRequestMessage(HttpMethod.Post, path))
71-
{
72-
message.Version = new Version(2, 0);
73-
message.Content = new StringContent(json);
79+
using var message = new HttpRequestMessage(HttpMethod.Post, path);
80+
81+
message.Version = new Version(2, 0);
82+
message.Content = new StringContent(json);
7483

75-
message.Headers.Authorization = new AuthenticationHeaderValue("bearer", GetJwtToken());
76-
message.Headers.TryAddWithoutValidation(":method", "POST");
77-
message.Headers.TryAddWithoutValidation(":path", path);
78-
message.Headers.Add("apns-topic", settings.AppBundleIdentifier);
79-
message.Headers.Add("apns-expiration", apnsExpiration.ToString());
80-
message.Headers.Add("apns-priority", apnsPriority.ToString());
81-
message.Headers.Add("apns-push-type", apnPushType.ToString().ToLowerInvariant()); // required for iOS 13+
82-
83-
if (!string.IsNullOrWhiteSpace(apnsId))
84-
{
85-
message.Headers.Add(apnIdHeader, apnsId);
86-
}
87-
88-
using (var response = await http.SendAsync(message, cancellationToken))
89-
{
90-
var succeed = response.IsSuccessStatusCode;
91-
var content = await response.Content.ReadAsStringAsync();
92-
var error = JsonHelper.Deserialize<ApnsError>(content);
93-
94-
return new ApnsResponse
95-
{
96-
IsSuccess = succeed,
97-
Error = error
98-
};
99-
}
84+
message.Headers.Authorization = new AuthenticationHeaderValue("bearer", GetJwtToken());
85+
message.Headers.TryAddWithoutValidation(":method", "POST");
86+
message.Headers.TryAddWithoutValidation(":path", path);
87+
message.Headers.Add("apns-topic", settings.AppBundleIdentifier);
88+
message.Headers.Add("apns-expiration", apnsExpiration.ToString());
89+
message.Headers.Add("apns-priority", apnsPriority.ToString());
90+
message.Headers.Add("apns-push-type", apnPushType.ToString().ToLowerInvariant()); // required for iOS 13+
91+
92+
if (!string.IsNullOrWhiteSpace(apnsId))
93+
{
94+
message.Headers.Add(apnIdHeader, apnsId);
10095
}
96+
97+
using var response = await http.SendAsync(message, cancellationToken);
98+
99+
var succeed = response.IsSuccessStatusCode;
100+
var content = await response.Content.ReadAsStringAsync(cancellationToken);
101+
var error = serializer.Deserialize<ApnsError>(content);
102+
103+
return new ApnsResponse
104+
{
105+
IsSuccess = succeed,
106+
Error = error
107+
};
101108
}
102109

103110
private string GetJwtToken()
@@ -114,18 +121,17 @@ private string GetJwtToken()
114121

115122
private string CreateJwtToken()
116123
{
117-
var header = JsonHelper.Serialize(new { alg = "ES256", kid = CleanP8Key(settings.P8PrivateKeyId) });
118-
var payload = JsonHelper.Serialize(new { iss = settings.TeamId, iat = EpochTime() });
124+
var header = serializer.Serialize(new { alg = "ES256", kid = CleanP8Key(settings.P8PrivateKeyId) });
125+
var payload = serializer.Serialize(new { iss = settings.TeamId, iat = EpochTime() });
119126
var headerBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(header));
120127
var payloadBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(payload));
121128
var unsignedJwtData = $"{headerBase64}.{payloadBase64}";
122129
var unsignedJwtBytes = Encoding.UTF8.GetBytes(unsignedJwtData);
123130

124-
using (var dsa = AppleCryptoHelper.GetEllipticCurveAlgorithm(CleanP8Key(settings.P8PrivateKey)))
125-
{
126-
var signature = dsa.SignData(unsignedJwtBytes, 0, unsignedJwtBytes.Length, HashAlgorithmName.SHA256);
127-
return $"{unsignedJwtData}.{Convert.ToBase64String(signature)}";
128-
}
131+
using var dsa = AppleCryptoHelper.GetEllipticCurveAlgorithm(CleanP8Key(settings.P8PrivateKey));
132+
133+
var signature = dsa.SignData(unsignedJwtBytes, 0, unsignedJwtBytes.Length, HashAlgorithmName.SHA256);
134+
return $"{unsignedJwtData}.{Convert.ToBase64String(signature)}";
129135
}
130136

131137
private static int EpochTime()
@@ -149,7 +155,7 @@ private static string CleanP8Key(string p8Key)
149155
lines.RemoveAt(0);
150156
}
151157

152-
if (0 != lines.Count && lines[lines.Count - 1].StartsWith("-----END PRIVATE KEY-----"))
158+
if (0 != lines.Count && lines[^1].StartsWith("-----END PRIVATE KEY-----"))
153159
{
154160
lines.RemoveAt(lines.Count - 1);
155161
}

CorePush/CorePush.csproj

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>netstandard2.0</TargetFramework>
4+
<TargetFramework>net6.0</TargetFramework>
55
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
66

77
<Title>Server Side library for sending ✅Web, ✅Android and ✅iOS Push Notifications</Title>
@@ -10,9 +10,9 @@
1010
<Summary>Server Side library for sending ✅Web, ✅Android and ✅iOS Push Notifications</Summary>
1111
<Authors>andrei-m-code</Authors>
1212

13-
<AssemblyVersion>3.1.1</AssemblyVersion>
14-
<FileVersion>3.1.1</FileVersion>
15-
<Version>3.1.1</Version>
13+
<AssemblyVersion>4.0.0-beta01</AssemblyVersion>
14+
<FileVersion>4.0.0-beta01</FileVersion>
15+
<Version>4.0.0-beta01</Version>
1616

1717
<PackageProjectUrl>https://github.com/andrei-m-code/CorePush</PackageProjectUrl>
1818
<RepositoryUrl>https://github.com/andrei-m-code/CorePush</RepositoryUrl>
@@ -25,6 +25,10 @@
2525
<PackageTags>push-notifications android-push-notifications ios-push-notifications web-push web-push-notifications apn fcm firebase</PackageTags>
2626

2727
<PackageReleaseNotes>
28+
v4.0.0
29+
- Use .NET 6.0 as a target framework
30+
- Use System.Text.Json as a default serializer
31+
2832
v3.1.x
2933
- Memory optimizations
3034
- Ability to change FCM and APN base URL for testing purposes
@@ -62,7 +66,6 @@ v3.0.0
6266
</PropertyGroup>
6367

6468
<ItemGroup>
65-
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
6669
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
6770
</ItemGroup>
6871

CorePush/Google/FcmResponse.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
using Newtonsoft.Json;
2-
using System.Collections.Generic;
1+
using System.Collections.Generic;
2+
using System.Text.Json.Serialization;
33

44
namespace CorePush.Google
55
{
66
public class FcmResponse
77
{
8-
[JsonProperty("multicast_id")]
8+
[JsonPropertyName("multicast_id")]
99
public string MulticastId { get; set; }
1010

11-
[JsonProperty("canonical_ids")]
11+
[JsonPropertyName("canonical_ids")]
1212
public int CanonicalIds { get; set; }
1313

1414
/// <summary>

CorePush/Google/FcmResult.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
using Newtonsoft.Json;
1+
using System.Text.Json.Serialization;
22

33
namespace CorePush.Google
44
{
55
public class FcmResult
66
{
7-
[JsonProperty("message_id")]
7+
[JsonPropertyName("message_id")]
88
public string MessageId { get; set; }
99

10-
[JsonProperty("registration_id")]
10+
[JsonPropertyName("registration_id")]
1111
public string RegistrationId { get; set; }
1212

1313
public string Error { get; set; }

0 commit comments

Comments
 (0)