0

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);
        }
    }
marak
  • 260
  • 3
  • 19

0 Answers0