aws / aws-sdk-net

The official AWS SDK for .NET. For more information on the AWS SDK for .NET, see our web site:
http://aws.amazon.com/sdkfornet/
Apache License 2.0
2.05k stars 852 forks source link

Pinpoint SDK C# is Not working as described #2465

Open digital-build opened 1 year ago

digital-build commented 1 year ago

Describe the bug

Hi team,

Pinpoint C# SDK is NOT working as described.

I was trying to send push notification for iOS with FCM configurations. It is successfully delivered to my iPhone within Pinpoint Console 'and' AWS CLI, however with dot.net SDK it seems not properly translate the request, so it is NOT delivered to the actual devices.

✅ When it runs with AWS CLI (working fine)

run the following command will deliver the Push message to the iOS devices without issues

% cat rawcontent.json
{
    "Addresses": {
        "*** put your own iOS device GCM token ***": {
            "ChannelType": "GCM"
        }
    },
    "MessageConfiguration": {
        "GCMMessage": {
            "RawContent": "{\"notification\": {\"title\": \"Hello Android World!\",\"body\":\"From PinPoint CLI\"},\"data\":{\"custom\":\"123 Penny Lane\"}}"
        }
    }
}

% aws pinpoint send-messages --application-id {*** your pinpoint project Id ***} --message-request file://rawcontent.json

✅ When it runs Amazon Pinpoint Console

(working fine with the same rawcontent into the Amazon Pinpoint Console 'Raw message')

  1. AWS login -> Pinpoint -> select (or create) a project -> Test messaging (in the left side menu)
  2. Choose the following options:

    Channel : choose 'Push notifications' Destinations :

    • choose 'Device tokens' and enter your own Google Firebase registered GCM token with an iOS device
    • choose 'Push notifications service' as 'FCM' Message :
    • choose 'Raw message' and enter the following content JSON payload (which is the same as 'rawcontent.json' in the CLI used earlier).
      {
      "Addresses": {
      "*** put your own iOS device GCM token ***": {
      "ChannelType": "GCM"
      }
      },
      "MessageConfiguration": {
      "GCMMessage": {
      "RawContent": "{\"notification\": {\"title\": \"Hello Android World!\",\"body\":\"From PinPoint CLI\"},\"data\":{\"custom\":\"123 Penny Lane\"}}"
      }
      }
      }
  3. click 'Send message'

🙁 Now, using the Pinpoint SDK:

Questions:

  1. How to deliver FCM Push Notification Message with Pinpoint DOT.NET SDK to iOS devices?
  2. How to send customized push message payload to iOS devices?
  3. As SDK described for ‘RawContent’ field, why does SDK won’t override all other fields values to use the 'real' raw content values?

Please refer to the attached PDF as well. Pinpoint.SDK.wont.deliver.FCM.raw.content.to.iOS.pdf

  1. How to reproduce: here is console app source code to reproduce
using Amazon;
using Amazon.Pinpoint;
using Amazon.Pinpoint.Model;
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace pinpoint
{
    public class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("main entry");
            await sendPush();
            Console.WriteLine("main exit");
        }

        private static async Task sendPush()
        {
            string region = "us-east-1";
            string accessId = "AKIAX6**********B7";
            string secret = "ioFM2*********************lSVVo";
            string projectId = "b97b7********************bc4fc45";
            string deviceToken = "fkgElT************************6w1eKhToDPBt";
            string rawContent =
                    @"{ 
    ""GCMMessage"": { 
        ""notification"": {
            ""title"": ""title1"", 
            ""collapseKey"": ""ck1"",
            ""body"": {
                ""callInfo"": {
                    ""from"":""+11234567890""
                }
            }
        }
    }
}".ReplaceLineEndings().Replace("    ", "\t");

            var endpoint = RegionEndpoint.GetBySystemName(region);
            using (var pinpoint = new AmazonPinpointClient(accessId, secret, endpoint))
            {
                var req = new SendMessagesRequest
                {
                    ApplicationId = projectId,
                    MessageRequest = new MessageRequest
                    {
                        Addresses = new Dictionary<string, AddressConfiguration>
                        {
                            {
                                deviceToken, new AddressConfiguration
                                {
                                    ChannelType = ChannelType.GCM,
                                    // RawContent = rawContent
                                }
                            }
                        },
                        MessageConfiguration = new DirectMessageConfiguration
                        {
                            GCMMessage = new GCMMessage
                            {
                                RawContent = rawContent,  // <--- expecting raw content 'override' payload as it is described in the method definition comments, but it won't.
                                SilentPush = true,
                                Priority = "high",
                                TimeToLive = 30,
                                Action = new Amazon.Pinpoint.Action("OPEN_APP"),
                            }
                        }
                    }
                };

                Console.WriteLine("request='{0}'", toJson(req));
                var res = await pinpoint!.SendMessagesAsync(req);
                Console.WriteLine("response='{0}'", toJson(res));
            }
        }

        private static string toJson(object obj)
        {
            var options = new JsonSerializerOptions();
            options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
            options.WriteIndented = true;
            options.IgnoreReadOnlyProperties = true;
            options.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;

            return JsonSerializer.Serialize(obj, options);
        }
    }
}

Expected Behavior

Expecting the RawContent would override as it described in the definition of the property (as below)

/// <summary>
/// Gets and sets the property RawContent. 
/// <para>
/// The raw, JSON-formatted string to use as the payload for the notification message.
/// If specified, this value overrides all other content for the message.
/// </para>
/// </summary>
public string RawContent {
    get {
        return _rawContent;
    }
    set {
        _rawContent = value;
    }
}

So, expecting it to be delivered through 'GCM' channel.

Current Behavior

However, unlike the good result of AWS CLI 'and' Amazon Pinpoint Console, Pinpoint SDK is NOT deliver the message to the FCM properly, seems to be occurred by 'empty' channel type which seems to be miss-translated by the SDK to me ("ChannelType": {}).

2022-10-26T20:45:31.849Z 2d678ede-424e-40b8-b922-721af8dc42a3 info
"ApplicationId": "b97b7129ff194636995628957bc4fc45",
"MessageRequest": {
"Addresses": {
" fkgElTKQkkonpDn-wu1KV4:******************************_e7wVe6w1eKhToDPBt ": {
"ChannelType": {},
"Context": {},
"Substitutions": {}
}
},
"Context": {},
"Endpoints": {},
"MessageConfiguration": {
"GCMMessage": {
"Data": {
"k1": "{\n\t\"GCMMessage\": {\n\t\t\"notification\": {\n\t\t\t\"title\": \"title1\",\n\t\t\t\"collapseKey\": \"key1\",\n\t\t\t\"body\": {\n\t\t\t\t\"callInfo\": {\n\t\t\t\t\t\"from\":\"Lambda function (using Pinpoint SDK RawContent in 'notification.body')\" \n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"data\": {\n\t\t\t\"callInfo\": {\n\t\t\t\t\"from\":\"Lambda function (using Pinpoint SDK RawContent in 'data')\" \n\t\t\t}\n\t\t}\n\t}\n}"
},
"RawContent": "{\n\t\"GCMMessage\": {\n\t\t\"notification\": {\n\t\t\t\"title\": \"title1\",\n\t\t\t\"collapseKey\": \"key1\",\n\t\t\t\"body\": {\n\t\t\t\t\"callInfo\": {\n\t\t\t\t\t\"from\":\"Lambda function (using Pinpoint SDK RawContent in 'notification.body')\" \n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"data\": {\n\t\t\t\"callInfo\": {\n\t\t\t\t\"from\":\"Lambda function (using Pinpoint SDK RawContent in 'data')\" \n\t\t\t}\n\t\t}\n\t}\n}",
"SilentPush": true,
"Substitutions": {},
"TimeToLive": 0
}
}
}
}'

Reproduction Steps

How to reproduce: here is console app source code to reproduce

using Amazon;
using Amazon.Pinpoint;
using Amazon.Pinpoint.Model;
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace pinpoint
{
    public class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("main entry");
            await sendPush();
            Console.WriteLine("main exit");
        }

        private static async Task sendPush()
        {
            string region = "us-east-1";
            string accessId = "AKIAX6**********B7";
            string secret = "ioFM2*********************lSVVo";
            string projectId = "b97b7********************bc4fc45";
            string deviceToken = "fkgElT************************6w1eKhToDPBt";
            string rawContent =
                    @"{ 
    ""GCMMessage"": { 
        ""notification"": {
            ""title"": ""title1"", 
            ""collapseKey"": ""ck1"",
            ""body"": {
                ""callInfo"": {
                    ""from"":""+11234567890""
                }
            }
        }
    }
}".ReplaceLineEndings().Replace("    ", "\t");

            var endpoint = RegionEndpoint.GetBySystemName(region);
            using (var pinpoint = new AmazonPinpointClient(accessId, secret, endpoint))
            {
                var req = new SendMessagesRequest
                {
                    ApplicationId = projectId,
                    MessageRequest = new MessageRequest
                    {
                        Addresses = new Dictionary<string, AddressConfiguration>
                        {
                            {
                                deviceToken, new AddressConfiguration
                                {
                                    ChannelType = ChannelType.GCM,
                                    // RawContent = rawContent
                                }
                            }
                        },
                        MessageConfiguration = new DirectMessageConfiguration
                        {
                            GCMMessage = new GCMMessage
                            {
                                RawContent = rawContent,  // <--- expecting raw content 'override' payload as it is described in the method definition comments, but it won't.
                                SilentPush = true,
                                Priority = "high",
                                TimeToLive = 30,
                                Action = new Amazon.Pinpoint.Action("OPEN_APP"),
                            }
                        }
                    }
                };

                Console.WriteLine("request='{0}'", toJson(req));
                var res = await pinpoint!.SendMessagesAsync(req);
                Console.WriteLine("response='{0}'", toJson(res));
            }
        }

        private static string toJson(object obj)
        {
            var options = new JsonSerializerOptions();
            options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
            options.WriteIndented = true;
            options.IgnoreReadOnlyProperties = true;
            options.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;

            return JsonSerializer.Serialize(obj, options);
        }
    }
}

Possible Solution

Pinpoint.SDK.wont.deliver.FCM.raw.content.to.iOS.pdf

Additional Information/Context

Pinpoint Project / Application ID: b97b7129ff194636995628957bc4fc45 AWS Region: us-east-1 API/SDK: AWSSDK.Pinpoint 3.7.100.3

AWS .NET SDK and/or Package version used

Pinpoint 3.7.100.3

Targeted .NET Platform

.NET 6

Operating System and version

Windows 10, OSX Monterey, AmazonLinux

ashishdhingra commented 1 year ago

Hi @thomas-mz,

Good afternoon.

The logic for the AWSSDK.Pinpoint package is auto-generated by the service models and the behavior is controlled by the Pinpoint service. The AWS .NET SDK simply relays the message request to the Pinpoint service. Just to clarify, you are asserting, that you are able to send push notifications using ChannelType as GCM. Shouldn't the ChannelType be APNS as per details at https://docs.aws.amazon.com/pinpoint/latest/apireference/apps-application-id-messages.html under APNSMessage?

Also refer the following:

Thanks, Ashish

digital-build commented 1 year ago

Hi @ashishdhingra,

Thanks for your review Ashish,

Regarding your question 'that you are able to send push notifications using ChannelType as GCM. Shouldn't the ChannelType be APNS'

Here are my responses, followed by the questions at the bottom.

% aws pinpoint send-messages --application-id { your pinpoint project Id } --message-request file://rawcontent.json



Questions:
1. How to deliver FCM Push Notification Message with Pinpoint DOT.NET SDK to iOS devices?
2. How to send customized push message payload to iOS devices?
3. As SDK described for ‘RawContent’ field, why does SDK won’t override all other fields values to use the 'real' raw content values?