Question

I am trying to figure out how to use the AWS .NET SDK to confirm a subscription to a SNS Topic.

The subscription is via HTTP

The endpoint will be in a .net mvc website.

I can't find any .net examples anywhere?

A working example would be fantastic.

I'm trying something like this

 Dim snsclient As New Amazon.SimpleNotificationService.AmazonSimpleNotificationServiceClient(ConfigurationSettings.AppSettings("AWSAccessKey"), ConfigurationSettings.AppSettings("AWSSecretKey"))

    Dim TopicArn As String = "arn:aws:sns:us-east-1:991924819628:post-delivery"


    If Request.Headers("x-amz-sns-message-type") = "SubscriptionConfirmation" Then

        Request.InputStream.Seek(0, 0)
        Dim reader As New System.IO.StreamReader(Request.InputStream)
        Dim inputString As String = reader.ReadToEnd()

        Dim jsSerializer As New System.Web.Script.Serialization.JavaScriptSerializer
        Dim message As Dictionary(Of String, String) = jsSerializer.Deserialize(Of Dictionary(Of String, String))(inputString)

        snsclient.ConfirmSubscription(New Amazon.SimpleNotificationService.Model.ConfirmSubscriptionRequest With {.AuthenticateOnUnsubscribe = False, .Token = message("Token"), .TopicArn = TopicArn})


   End If
Was it helpful?

Solution 5

I ended up getting it working using the code shown. I was having trouble capturing the exception on the development server which turned out was telling me the server's time didn't match the timestamp in the SNS message.

Once the server's time was fixed up (an Amazon server BTW), the confirmation worked.

OTHER TIPS

Here is a working example using MVC WebApi 2 and the latest AWS .NET SDK.

var jsonData = Request.Content.ReadAsStringAsync().Result;
var snsMessage = Amazon.SimpleNotificationService.Util.Message.ParseMessage(jsonData);

//verify the signaure using AWS method
if(!snsMessage.IsMessageSignatureValid())
    throw new Exception("Invalid signature");

if(snsMessage.Type == Amazon.SimpleNotificationService.Util.Message.MESSAGE_TYPE_SUBSCRIPTION_CONFIRMATION)
{
    var subscribeUrl = snsMessage.SubscribeURL;
    var webClient = new WebClient();
    webClient.DownloadString(subscribeUrl);
    return "Successfully subscribed to: " + subscribeUrl;
}

Building on @Craig's answer above (which helped me greatly), the below is an ASP.NET MVC WebAPI controller for consuming and auto-subscribing to SNS topics. #WebHooksFTW

using RestSharp;
using System;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Web.Http;
using System.Web.Http.Description;

namespace sb.web.Controllers.api {
  [System.Web.Mvc.HandleError]
  [AllowAnonymous]
  [ApiExplorerSettings(IgnoreApi = true)]
  public class SnsController : ApiController {
    private static string className = MethodBase.GetCurrentMethod().DeclaringType.Name;

    [HttpPost]
    public HttpResponseMessage Post(string id = "") {
      try {
        var jsonData = Request.Content.ReadAsStringAsync().Result;
        var sm = Amazon.SimpleNotificationService.Util.Message.ParseMessage(jsonData);
        //LogIt.D(jsonData);
        //LogIt.D(sm);

        if (!string.IsNullOrEmpty(sm.SubscribeURL)) {
          var uri = new Uri(sm.SubscribeURL);
          var baseUrl = uri.GetLeftPart(System.UriPartial.Authority);
          var resource = sm.SubscribeURL.Replace(baseUrl, "");
          var response = new RestClient {
            BaseUrl = new Uri(baseUrl),
          }.Execute(new RestRequest {
            Resource = resource,
            Method = Method.GET,
            RequestFormat = RestSharp.DataFormat.Xml
          });
          if (response.StatusCode != System.Net.HttpStatusCode.OK) {
            //LogIt.W(response.StatusCode);
          } else {
            //LogIt.I(response.Content);
          }
        }

        //read for topic: sm.TopicArn
        //read for data: dynamic json = JObject.Parse(sm.MessageText);
        //extract value: var s3OrigUrlSnippet = json.input.key.Value as string;

        //do stuff
        return Request.CreateResponse(HttpStatusCode.OK, new { });
      } catch (Exception ex) {
        //LogIt.E(ex);
        return Request.CreateResponse(HttpStatusCode.InternalServerError, new { status = "unexpected error" });
      }
    }
  }
}

I don't know how recently this has changed, but I've found that AWS SNS now provides a very simply method for subscribing that doesn't involve extracting urls or building requests using RESTSharp.....Here's the simplified WebApi POST method:

    [HttpPost]
    public HttpResponseMessage Post(string id = "")
    {
        try
        {
            var jsonData = Request.Content.ReadAsStringAsync().Result;
            var sm = Amazon.SimpleNotificationService.Util.Message.ParseMessage(jsonData);

            if (sm.IsSubscriptionType)
            {
                sm.SubscribeToTopic(); // CONFIRM THE SUBSCRIPTION
            }
            if (sm.IsNotificationType) // PROCESS NOTIFICATIONS
            {
                //read for topic: sm.TopicArn
                //read for data: dynamic json = JObject.Parse(sm.MessageText);
                //extract value: var s3OrigUrlSnippet = json.input.key.Value as string;
            }

            //do stuff
            return Request.CreateResponse(HttpStatusCode.OK, new { });
        }
        catch (Exception ex)
        {
            //LogIt.E(ex);
            return Request.CreateResponse(HttpStatusCode.InternalServerError, new { status = "unexpected error" });
        }
    }

The following example helped me work with SNS. It goes through all the steps to work with Topics. The subscribe request in this case is an email address, however that can be changed to HTTP.

Pavel's SNS Example
Documentation

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top