Home > Uncategorized > #APNS using HTTP/2 in C# using #AWS Lambda

#APNS using HTTP/2 in C# using #AWS Lambda

By March 31st 2021, all users using the Apple Push Notification Service (APNS) must update to Apple’s new API, which is based on HTTP/2. If you don’t update, then it’s likely that your push notifications won’t get through.

If you are using C#, then you can use the dotAPNS NUGet package, which, from the client perspective is a tiny change, however, it does require .NET Core to run, which if your project is in .NET standard, then this could cause problems.

So, in this case, I decided to create a stand-alone .NET Core app using AWS Lambda and AWS API Gateway, which would be a middleware API between my main app and the APNS API.

My App -> AWS LAMBDA -> APNS

So, I created an AWS Lambda App in Visual Studio, and made sure I could publish to AWS Lambda. Which also gives you an API Gateway URL, in the format;

<ID>.execute-api.<Region>.amazonaws.com/Prod

I also needed to update the serverless.template file as follows

         "Events": {
           "RootGet": {
             "Type": "Api",
             "Properties": {
               "Path": "/",
               "Method": "GET"
             }
           },
           "RootPost": {
             "Type": "Api",
             "Properties": {
               "Path": "/",
               "Method": "POST"
             }
           }

And changed the Handler to

ApnsHttp2Serverless::ApnsHttp2Serverless.Functions::HttpRequest

(Where ApnsHttp2Serverless was the name of my project)

Now, my code to send the push notification is as follows;

private ApnsResponse Send(
             byte[] certificate, 
             string certPassword, 
             string message, 
             string destination)
 {
     var x509 = new X509Certificate2(certificate, certPassword);
     var applePushNotificationService = ApnsClient.CreateUsingCert(x509);
     var push = new ApplePush(ApplePushType.Alert)
     .AddAlert(message)
     .AddToken(destination);
     return applePushNotificationService.Send(push).Result;
 }

Which is called from the lambda as follows;

public APIGatewayProxyResponse HttpRequest(APIGatewayProxyRequest request, ILambdaContext context)
 {
     context.Logger.LogLine(request.Body);
     var jRequest = JObject.Parse(request.Body);
     var certificate = jRequest["certificate"].ToObject();
     var certPassword = jRequest["certPassword"].ToObject();
     var message = jRequest["message"].ToObject();
     var destination = jRequest["destination"].ToObject();
     var sendResult = Send(certificate, certPassword, message, destination);
     var response = new APIGatewayProxyResponse
     {
     StatusCode = (int)HttpStatusCode.OK,
     Body = JsonConvert.SerializeObject(sendResult,Formatting.Indented),
     Headers = new Dictionary { { "Content-Type", "application/json" } }
     };
     return response;
 }

So, I pushed this code to AWS Lambda, and wrote the client as follows:

public static string Push(string destination, string message, string certFile, string certPassword)
 {
     var certificate = File.ReadAllBytes(certFile);
     var oPayload = new
     {
         destination,
         message,
         certificate,
         certPassword
     };
     var strPayload = JsonConvert.SerializeObject(oPayload, Formatting.Indented);
     var wc = new WebClient();
     var response = wc.UploadString("https://....execute-api.eu-west-1.amazonaws.com/Prod", strPayload);
     return response;
 }

So, Assuming you have the destination ID, and your certs set up correctly, this just works!

For anyone who is interested, here is the GitHub Repo of the AWS Lambda function:

https://github.com/infiniteloopltd/ApnsHttp2

And for those who happen to use PHP as the trigger to send push notifications, here is the client code in PHP:

<?php
$data        = file_get_contents('cert.p12');
$cert64      = base64_encode($data);
$destination = "-apns-token-";
$password    = "-cert-password-";
$url         = "https://xxxxxx.execute-api.eu-west-1.amazonaws.com/Prod";
$ch          = curl_init($url);
$oPayload    = array(
    'destination' => $destination,
    'message' => 'hello there!',
    'certificate' => $cert64,
    'certPassword' => $password
);
$payload     = json_encode($oPayload);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$content = curl_exec($ch);
if ($content === false) {
    echo 'Curl error: ' . curl_error($ch);
}
curl_close($ch);
echo $content;
?>

Categories: Uncategorized
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: