I am trying to build an application to send push notifications to a pass on an Apple wallet using C# .NET (.net framework 4.8) and I am getting a WinHttpException. I read through several online articles which suggested to use System.Net.Http.WinHttpHandler to let the HttpClient use HTTP2. But, still I Am getting the below exception:
InnerException = {"Error 12152 calling WinHttpWriteData, 'The server returned an invalid or unrecognized response'."}
I am running this application on Windows 10 OS Build version: 21H2 (19044). I tried using WinHttpHanlder versions 6 and also 7.Also, verified the signing pass type certificate and the apple certificate are both valid (not expired). The certificates have the PassTypeIdentifier in its subject name.
I am trying to findout, if I am missing something and is it possible to debug/troubleshoot this issue some way?
Below is my code:
private static string pushToken = "dbc56849<hidden>";
private static string AppleApnServer = "https://api.sandbox.push.apple.com";
public static async Task<PushResult> SendPushNotificationToWalletPass(string notificationContent)
{
byte[] certificateData = LoadCertificate();
X509Certificate2 certificate = new X509Certificate2(certificateData, String.Empty, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
string url = $"{AppleApnServer}:443/3/device/{pushToken}";
StringBuilder payload = new StringBuilder();
payload.Append("{ \"aps\" : ");
if (string.IsNullOrWhiteSpace(notificationContent))
{
payload.Append("\"\" }");
}
else
{
payload.Append(notificationContent);
payload.Append(" }"); // close aps dictionary
}
var handler = new Http2Handler();
handler.ClientCertificates.Add(certificate);
using (var httpClient = new HttpClient(handler))
{
using (var request = new HttpRequestMessage(HttpMethod.Post, url))
{
var messageGuid = Guid.NewGuid().ToString();
request.Content = new StringContent(payload.ToString());
request.Headers.Add("apns-id", messageGuid);
request.Headers.Add("apns-push-type", "alert");
using (var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead))
{
HttpStatusCode statusCode = response.StatusCode;
string reasonPhrase = response.ReasonPhrase;
bool success = response.IsSuccessStatusCode;
Console.WriteLine($"APN {(success ? "Delivered Successfully!" : $"Failed to Send! :: StatusCode [{statusCode}] Reason [{reasonPhrase}]")} :: PushToken [{pushToken}]");
if (!success)
{
switch (statusCode)
{
case HttpStatusCode.Gone:
// The device token is no longer active for the topic.
return PushResult.DeviceNotRegistered;
default:
return PushResult.Failure;
}
}
return PushResult.Success;
}
}
}
}
public enum PushResult
{
Success = 0,
Failure = 100,
DeviceNotRegistered = 200
}
// Apple APNS requires http2 but .Net Framework does not support http2 (only built in support in .net core)
// found this workaround https://stackoverflow.com/questions/32685151/how-to-make-the-net-httpclient-use-http-2-0/43101990#43101990
private class Http2Handler : WinHttpHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
request.Version = new Version("2.0");
return base.SendAsync(request, cancellationToken);
}
}