AWS .NET - 1.0

Extension ID

com.castsoftware.awsdotnet

What’s new?

See AWS .NET 1.0 - Release Notes.

In what situation should you install this extension?

The AWS.NET extension is responsible of creating objects describing Amazon Web Service (AWS) Lambda functions but only in the context of dotnet technology. (Similarly, the NodeJS extension is responsible of AWS lambda Functions created for the nodejs runtime). To run fully, this extension requires a Universal Analysis Unit with the HTML5 language switched on. This allows analyzing the .json or .yml configuration files (which are used by deployment frameworks to build aws applications). The supported deployment frameworks are Serverless Framework, CloudFormation, and Serverless Application Model (SAM).

The complementary analysis responsible for creating Java Call to AWS Lambda Function objects is based on the analysis of java files and it will be launched without any further requirement upon installation of the com.castsoftware.awsjava plugin.

Only Serverless Framework, CloudFormation, and Serverless Application Model (SAM) deployment frameworks are supported.

Objects

Icon Description Entry Point (Transaction Configuration) End Point (Transaction Configuration) Data Entity (Transaction Configuration)

DotNet AWS SQS Receiver

(tick) 

(only when not called by other objects)

- -

DotNet AWS SNS Subscriber

(tick)

(only when not called by other objects)

- -

DotNet AWS SQS Publisher -

(tick) 

(only when it is not calling any other object)

-

 DotNet AWS SNS Publisher -

(tick) 

(only when it is not calling any other object)

-

DotNet AWS unknown SQS Receiver (tick) - -

DotNet AWS unknown SNS Subscriber (tick) - -

DotNet AWS unknown SQS Publisher - (tick) -

DotNet AWS unknown SNS Publisher  -

(tick)

-

Dotnet AWS Call to AWS Lambda Function

-

(tick) 

(only when it is not calling any other object)

-

DotNet AWS Call to unknown Lambda -

(tick) 

-

Dotnet AWS Email -

(tick) 

-

Dotnet AWS SMS -

(tick) 

-

Dotnet AWS Post Service -

(tick) 

(only when it is not calling any other object)

-

Dotnet AWS S3 Bucket - - (tick)

Dotnet AWS unknown S3 Bucket - - (tick)

Support for Lambda functions

Lambda services (or functions) allow executing some source code on the cloud. The execution can be set to be triggered by some AWS events.  Lambda functions can be deployed using several deployment frameworks. The supported deployment frameworks are listed on AWS Lambda. When a lambda function is created and its runtime is dotnet, the current extension is responsible for linking the lambda objects and their triggers with the java handler functions.

Example

Let us consider a source code defining a lambda function having a dotnet runtime (for instance dotnetcore3.0) and the handler function is given by the handler function fullname. If the lambda function is deployed using a supported deployment framework (such as CloudFormation), the analysis will create a lambda function.  If the current extension finds a C# method matching the handler fullname a link to that method will be added from the lambda function.

Some applications are using a monolithic pattern: only one handler function is used for many (if not all) API Gateways. That handler function then dispatches the call to sub-handler functions using switches based on the URLs. Ideally, in the modelization, each API Gateway should be linked to its dedicated sub-handler function. However, in our modelization, all API Gateways will be linked to the root handler function. 

Support for SDK

The extension supports only the API for the V3 SDK as the V2 SDK is deprecated and no longer supported.

Support for SNS

The following APIs are supported:

  • Amazon.SimpleNotificationService.AmazonSimpleNotificationServiceClient.Publish
  • Amazon.SimpleNotificationService.AmazonSimpleNotificationServiceClient.PublishAsync
  • Amazon.SimpleNotificationService.AmazonSimpleNotificationServiceClient.Subscribe

For the Publish method, a AWS Dotnet SNS Publisher object is created. Its name is that of the topic. For the Subscribe methods, a AWS Dotnet SNS Subscriber object is created. Its name is that of the topic. Then for each supported protocol, an object is created with a callLink from the subscriber to that object. The supported protocols are the following:

protocol object created name of the object
email Dotnet  AWS Email an Email   (the email addresses are not evaluated)
sms Dotnet AWS SMS an SMS   (the SMS numbers are not evaluated)
http/https Dotnet  AWS Post Service the url (evaluated from the endpoint)
sqs Dotnet AWS Simple Queue Service Publisher the name of the queue (evaluated from the endpoint)
lambda Dotnet AWS Call to Lambda Function the name of the lambda function (evaluated from the endpoint)

The com.castsoftware.wbslinker will create a callLink between the SNS Publishers and SNS Subscribers which have the same name.

Example

When analyzing the following source code:

        void sendSNSMessage(string[] args)
        {
            AmazonSimpleNotificationServiceClient snsClient = new AmazonSimpleNotificationServiceClient(Amazon.RegionEndpoint.USWest2);

            var topicRequest = new CreateTopicRequest();
            
            topicRequest.Name = "Sport";
                    
            var topicResponse = snsClient.CreateTopic(topicRequest);
            
            var topicAttrRequest = new SetTopicAttributesRequest();
            
            topicAttrRequest.TopicArn = topicResponse.TopicArn;
            topicAttrRequest.AttributeName = "DisplayName";
            topicAttrRequest.AttributeValue = "Coding Test Results";
            

            snsClient.SetTopicAttributes(topicAttrRequest);

            Dictionary<string, MessageAttributeValue> messageAttributes = new Dictionary<string, MessageAttributeValue>();
            MessageAttributeValue v1 = new MessageAttributeValue();
            v1.DataType = "String";
            v1.StringValue = "senderidx";
            messageAttributes.Add("AWS.SNS.SMS.SenderID", v1);
            MessageAttributeValue v2 = new MessageAttributeValue();
            v2.DataType = "String";
            v2.StringValue = "0.50";
            messageAttributes.Add("AWS.SNS.SMS.MaxPrice", v2);
            MessageAttributeValue v3 = new MessageAttributeValue();
            v3.DataType = "String";
            // Options: Promotional, Transactional
            v3.StringValue = "Promotional";
            messageAttributes.Add("AWS.SNS.SMS.SMSType", v3);
            SendLambdaAsync(snsClient, "Hello from AWS SNS!", "+1 XXX YYYYYY", messageAttributes).Wait();
        }


        static async Task SendLambdaAsync(AmazonSimpleNotificationServiceClient snsClient, string message, string phoneNumber,
            Dictionary<string, MessageAttributeValue> messageAttributes)
        {
            PublishRequest publishRequest = new PublishRequest();
            publishRequest.Message = message;
            publishRequest.MessageAttributes = messageAttributes;
            try
            {
                var response = await snsClient.PublishAsync(publishRequest);
                Console.WriteLine(response.MessageId);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
        void SQSLambda(string[] args)
        {
            AmazonSimpleNotificationServiceClient snsClient = new AmazonSimpleNotificationServiceClient(Amazon.RegionEndpoint.USWest2);

            var topicRequest = new CreateTopicRequest
            {
              Name = "Sport"
            };
            
            var topicResponse = snsClient.CreateTopic(topicRequest);

            var topicAttrRequest = new SetTopicAttributesRequest
            {
              TopicArn = topicResponse.TopicArn,
              AttributeName = "DisplayName",
              AttributeValue = "Coding Test Results"
            };
                        
            snsClient.SetTopicAttributes(topicAttrRequest);

            snsClient.Subscribe(new SubscribeRequest
            {
              Endpoint = "arn:aws:lambda:us-east-1:123456789012:function:sns-same-account",
              Protocol = "lambda",
              TopicArn = topicResponse.TopicArn
            });
        }

Alternative example with SQS protocol:

Click to enlarge

Support for SQS

The following APIs are supported:

  • Amazon.SQS.AmazonSQSClient.SendMessage
  • Amazon.SQS.AmazonSQSClient.SendMessageAsync
  • Amazon.SQS.AmazonSQSClient.SendMessageBatch
  • Amazon.SQS.AmazonSQSClient.SendMessageBatchAsync
  • Amazon.SQS.AmazonSQSClient.ReceiveMessage
  • Amazon.SQS.AmazonSQSClient.ReceiveMessageAsync

For the SendMessage methods, a AWS Dotnet SQS Publisher object is created. Its name is that of the topic. For the ReceiveMessage methods, a AWS Dotnet SQS Receiver object is created. Its name is that of the topic. 

Example

When analyzing the following source code:

        public static void MainSQS(string[] args)
        {
            //the url for our queue
            var queueUrl = "https://sqs.eu-west-1.amazonaws.com/[USERID]/[QUEUENAME]";

            Console.WriteLine("Queue Test Starting!");

            Console.WriteLine("Creating Client and request");

            //Create some Credentials with our IAM user
            var awsCreds = new BasicAWSCredentials("[ACCESSKEY]", "[SECRETKEY]");

            //Create a client to talk to SQS
            var amazonSQSClient = new AmazonSQSClient(awsCreds,Amazon.RegionEndpoint.EUWest1);

            //Create the request to send
            var sendRequest = new SendMessageRequest(); 
            sendRequest.QueueUrl = "https://sqs.eu-west-1.amazonaws.com/[USERID]/[QUEUENAME]";//queueUrl;
            sendRequest.MessageBody = "{ 'message' : 'hello world' }";

            //Send the message to the queue and wait for the result
            Console.WriteLine("Sending Message");
            var sendMessageResponse = amazonSQSClient.SendMessageAsync(sendRequest).Result;

            Console.WriteLine("Receiving Message");

            //Create a receive requesdt to see if there are any messages on the queue
            var receiveMessageRequest = new ReceiveMessageRequest();
            receiveMessageRequest.QueueUrl = "https://sqs.eu-west-1.amazonaws.com/[USERID]/[QUEUENAME]"//queueUrl;

            //Send the receive request and wait for the response
            var response = amazonSQSClient.ReceiveMessageAsync(receiveMessageRequest).Result;

            //If we have any messages available
            if(response.Messages.Any())
            {
                foreach(var message in response.Messages)
                {
                    //Spit it out
                    Console.WriteLine(message.Body);

                    //Remove it from the queue as we don't want to see it again
                    var deleteMessageRequest = new DeleteMessageRequest();
                    deleteMessageRequest.QueueUrl = queueUrl;
                    deleteMessageRequest.ReceiptHandle = message.ReceiptHandle;

                    var result = amazonSQSClient.DeleteMessageAsync(deleteMessageRequest).Result;
                }
            }

        }
        public static void MainSQS(string[] args)
        {
            //the url for our queue
            var queueUrl = "https://sqs.eu-west-1.amazonaws.com/[USERID]/[QUEUENAME]";

            Console.WriteLine("Queue Test Starting!");

            Console.WriteLine("Creating Client and request");

            //Create some Credentials with our IAM user
            var awsCreds = new BasicAWSCredentials("[ACCESSKEY]", "[SECRETKEY]");

            //Create a client to talk to SQS
            var amazonSQSClient = new AmazonSQSClient(awsCreds,Amazon.RegionEndpoint.EUWest1);

            //Create the request to send
            var sendRequest = new SendMessageRequest(); 
            sendRequest.QueueUrl = "https://sqs.eu-west-1.amazonaws.com/[USERID]/[QUEUENAME]";//queueUrl;
            sendRequest.MessageBody = "{ 'message' : 'hello world' }";

            //Send the message to the queue and wait for the result
            Console.WriteLine("Sending Message");
            var sendMessageResponse = amazonSQSClient.SendMessageAsync(sendRequest).Result;

            Console.WriteLine("Receiving Message");

            //Create a receive requesdt to see if there are any messages on the queue
            var receiveMessageRequest = new ReceiveMessageRequest();
            receiveMessageRequest.QueueUrl = "https://sqs.eu-west-1.amazonaws.com/[USERID]/[QUEUENAME]"//queueUrl;

            //Send the receive request and wait for the response
            var response = amazonSQSClient.ReceiveMessageAsync(receiveMessageRequest).Result;

            //If we have any messages available
            if(response.Messages.Any())
            {
                foreach(var message in response.Messages)
                {
                    //Spit it out
                    Console.WriteLine(message.Body);

                    //Remove it from the queue as we don't want to see it again
                    var deleteMessageRequest = new DeleteMessageRequest();
                    deleteMessageRequest.QueueUrl = queueUrl;
                    deleteMessageRequest.ReceiptHandle = message.ReceiptHandle;

                    var result = amazonSQSClient.DeleteMessageAsync(deleteMessageRequest).Result;
                }
            }

        }

Support for Lambda Invoke

Lambda invoke with AWS SDK:

          public static void Main(string playerName, Action<string> callback)
        {
            var client = new AmazonLambdaClient();
            
            var sqsEvent = new SQSEvent
            {
                Records = new List<SQSEvent.SQSMessage>
                {
                    new SQSEvent.SQSMessage
                    {
                        Body = "Hello Lambda!"
                    }
                }
            };
            
            var request = new InvokeRequest
            {
                FunctionName = "1-direct-invocation",
                // force sync lambda invocation
                InvocationType = InvocationType.RequestResponse,
                LogType = LogType.Tail,
                Payload = JsonSerializer.Serialize(sqsEvent)
            };
            var result = await client.InvokeAsync(request);
        }

Support for AWS S3

S3 Bucket with AWS SDK

          static string bucketName = "S3WestAsieRegion";
        static string key = $"key-{Guid.NewGuid().ToString("n").Substring(0, 8)}";

        static void Main(string[] args)
        {            
            using (var s3 = new AmazonS3Client(RegionEndpoint.USWest2))
            {
                CreateBucket(s3);
                WriteObject(s3);
                ...
            }
        }

        static void CreateBucket(IAmazonS3 s3)
        {
            Task<PutBucketResponse> res = s3.PutBucketAsync(new PutBucketRequest().WithBucketName(bucketName));
            Task.WaitAll(res);

            if (res.IsCompletedSuccessfully)
            {
                Console.WriteLine("New S3 bucket created: {0}", bucketName);
            }
        }

        static void WriteObject(IAmazonS3 s3)
        {
            // The api call used in this method equates to S3's Put api and is
            // suitable for smaller files. To upload larger files and entire
            // folder hierarchies, with automatic usage of S3's multi-part apis for
            // files over 5MB in size, consider using the TransferUtility class
            // in the Amazon.S3.Transfer namespace.
            // See https://docs.aws.amazon.com/AmazonS3/latest/dev/HLuploadFileDotNet.html.
            var ms = new MemoryStream(Encoding.UTF8.GetBytes("Test S3 data"));
            var req = new PutObjectRequest
            {
                BucketName = bucketName,
                Key = key,
                InputStream = ms
            };

            Task<PutObjectResponse> res = s3.PutObjectAsync(req);
            Task.WaitAll(res);

            if (res.IsCompletedSuccessfully)
            {
                Console.WriteLine("Created object '{0}' in bucket '{1}'", key, bucketName);
            }
        }

Linking

The extension com.castsoftware.wbslinker is responsible for matching these objects during application-level analysis with cross-technology:

  • SNS publisher and SNS subscriber
  • SQS publisher and SQS subscriber
  • AWS Lambda Call and AWS Lambda object
  • AWS Http Post service and operation Post

Data sensitivity

This extension is capable of setting a property on AWS S3 Bucket objects for the following:

  • custom sensitivity
  • GDPR
  • PCI-DSS

See Data Sensitivity for more information.

Known limitations

  • Monolithic pattern for lambda functions is not supported properly
  • The use of access points is not supported.