Push Notification to Apple Wallet Passes failing with WinHttpException exception

I am trying to write some code to send a push notification to a pass on an Apple device using C# .NET and HttpClient over HTTP2 with client certificate authentication.

When I run the code, I am seeing the below exception: InnerException = {"Error 12152 calling WinHttpWriteData, 'The server returned an invalid or unrecognized response'."}

I am trying to find out why this code is failing?

Is it possible to debug/troubleshoot this in some way?

Running this code on Windows 10 OS Build version: 21H2 (19044). The application is built on .Net Framework 4.8 and tried using WinHttpHanlder versions 6 and also 7.

Also, tried using other third party open source libraries like PushSharp and DotApns. PushSharp does not seem to support Http/2 and dotApns does not support certificate authentication for .net framework. We have no plans to migrate to .net Core.

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);
            }
        }

Replies

Hi I'm facing the same issue. Did you find out the solution?