Amazon Lambda – Part 5 – The Test Application

Source Code – https://github.com/ehelin/AmazonLambdaApi

For the next blog entry in this series, I had planned on creating a web site with the basic Create Read Update Delete (CRUD) functions for the Amazon Lambda Satellite API using Angular JS and the new .NET Core platform.  My thinking (at the time) was I would learn both new technologies and finish out this blog series.  Alas, it was not meant to be…or at least not yet.  Prior to this adventure, I had only created a couple of out of the box .NET Core projects (previously known as ASP .NET 5) to start the next incarnation of my TGIMBA site. I decided to put this on hold when I found out that .NET 4.6.X was the latest my host provider supported.  I never dug into the details and thought it would be another incarnation of .NET with better features.  Boy was I wrong.

I still don’t know all of the differences, but it is not just a complete re-write of .NET as I have known it, but even larger than the Windows 8.X API’s updates.  It is an ambitious (to ambitious?) attempt to go cross platform where (in theory) your .NET Core web/mobile/etc application(s) will run not only on Microsoft Windows technologies, but on Macintosh and other platforms.  If I had realized this scope, I would have stayed with .NET 4.6 for this blog series.

The best overview(s) I have found so far have been with Scott Hansel’s blog.  His series of articles like this (see reference #18) really do a good job of describing the big differences and changes. Long story short, I couldn’t get the libraries like System.Security.Cryptography in .NET Core to use the existing Amazon API Gateway tutorial code.  I was able to replicate parts of it, but it was painful.  I tried keeping the .NET Core web application (better get used to it now :)) and making an API call to a .NET 4.6 web application to use the Amazon sample code.  However, when I was done, 80% of the code was in the .NET 4.6 project.  So, I scrapped the .NET Core application for now and created the this project (see GitHub link at top of this blog entry).

I know that being a software developer means learning new things and I get the concept of a cross-functional version of .NET.  But I would have appreciated a more phased approach.  .Net Core is not just a new version, but a completely new era for Microsoft platforms linked to open source.  This is all good and well.  However, the transition would be easier (in my opinion) if the existing functions of .NET 4.X could have been easily made available as nuget packages in their current forms so the learning curve is not as steep.  They are available, but their installation sometimes broke empty .NET Core projects.  I had some hurdles getting the System.Security.Cryptography.Primitives package to install correctly and build.  Phased approaches (in my opinion) are much better than the completely new approach Microsoft has been taking with the Windows 7 -> Windows 8.X -> Windows 10 leaps.

Stepping off my soapbox 🙂

I will include a couple of things I learned from the .NET Core project effort before going on to this blog entry’s code.  After creating the .NET Core Web application project, I started adding Angular JS.  Going through the process, I discovered I was adding an earlier Angular JavaScript nuget package (see reference #1).  It worked, but none of the Angular.JS files were present. So I uninstalled that package and started reading up on Angular JS for ASP .NET 5 (see reference #2).  I also learned that nuget is no longer the party favorite and tools called Bower and NPM are all the rage.  Following the article’s lead, I used this process:

1) Use NPM (see reference #3) to install Angular

NOTE:

  • According to the document, saving the angular dependency after being added to the npn dependency list should trigger the installation of the angular files in the node_modules directory.  This did not occur for me initially.  I was able to rectify this by moving the production angular reference to the development tag in the Layout.html (see reference #4).
    HelloWorldAngular
  • It took me a moment as I was expecting the console.log to show up in the Visual Studio output and was surprised when it didn’t appear.  However, after seeing this entry, I was able to find it (see reference #5).  Additionally, placing the additional code (see reference #2) in site.js also returned the time.
    • Another interesting item…I was expecting to see an environment value in the appsettings portion of the web.config and was surprised when it was not there.  A subsequent search showed that these values appear to be hosted in a /properties/launchSettings.json file and set in the ‘Startup.cs’ file.  A little different from the traditional configuration 🙂
    • Seems like /wwwroot/js/site.js seems to be the default place to put all your code.

This was as far as I got with .NET Core, so onto this blog entry’s code!

I defined an interface for the API, but only implemented the GET as of this blog post.  I start a new job on Monday, so depending on its requirements, I may stop this series here.

Replicating the earlier blog posts in this series was pretty easy up to the point of the AWS Signature.  Postman made the last blog entry pretty easy because it did all of the calculations for me 🙂  I knew this would be hard to replicate, but I wasn’t prepared for how hard.  Up to the addition of the AWS signature, all of the HTTP GET methods retrieved the Satellite data.  The issues (after adding the AWS signature) I encountered are as follows:

  1. I tend to use HttpClient() as my go to C# object when making web calls.  In the past I have added content type and authorization headers in a slightly different manner than you might expect.  Up until now, this code has always worked for me.  Specifically:

    HttpClient client = new HttpClient();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(“application/json”));
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(“Authorization”, “XXXXXXXX”);

    This time, I kept getting this error:

    {“message”:”‘AWS4-HMAC-SHA256’ not a valid key=value pair (missing equal-sign) in Authorization header: ‘Authorization AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXX/20160707/us-west-2/execute-api/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-api-key, Signature=XXXXXXXXXXXXXXX’.”}

    No matter what I did, I could never get around this error.  I am guessing if I had installed fiddler and watched what was going out, the header was missing the ‘=’ or something.

  2. I have used the WebClient before, so I thought I would try it since the headers are more straight forward.   However, no matter what I did, I kept getting this error – ‘The remote server returned an error: (403) Forbidden.’
  3. I then found out you can add headers without validation. This is the method I have gotten to work.
    1. HttpClient client = new HttpClient();
    2. client.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);

SatelliteHttpGetResult

However, I had a lot of errors before that happened.  I tried keeping notes on all of the errors, but that became to complicated.  So, I will tell you what worked for me and what I found useful.  First, I found on the Amazon document site a detailed process on creating Version 4 Signatures (see reference #15).  Without a doubt (yes, I had to re-read it more than a few times :)), this was the best source.

The second best resource I found was the test suite files (see reference #17).  I used the ‘get-vanilla-empty-query-key’ set of files. Essentially, it allows you to see what your code should be generating for each step.  Many developers commented on missing a new line character or some other small detail.  If this is what you are going through trying to figure it out, the test files are the best approach to see it.  I was missing a space in a multi line entry that I wasn’t seeing and the side by side comparison helped me find it.

  • <file-name>.req—the web request to be signed.
  • <file-name>.creq—the resulting canonical request.
  • <file-name>.sts—the resulting string to sign.
  • <file-name>.authz—the Authorization header.
  • <file-name>.sreq— the signed request.

The third best resource I found was some code that I found on stackoverflow.com (see reference #13).  I borrowed heavily from this post in my implementation.  I had already created a couple of versions, but this code was much more succinct 🙂

Stay tuned!

References

1) http://angularfirst.com/your-first-angular-project-in-visual-studio/
2) https://www.pluralsight.com/blog/software-development/angularjs-for-asp-net-applications
3) https://www.npmjs.com/
4) http://stackoverflow.com/questions/25532770/microsoft-jscript-angular-is-undefined
5) https://blogs.msdn.microsoft.com/cdndevs/2011/05/26/console-log-say-goodbye-to-javascript-alerts-for-debugging/
6) http://stackoverflow.com/questions/34764345/unit-testing-of-class-library-package-net-4-6
7) http://stackoverflow.com/questions/34686403/the-type-or-namespace-name-http-does-not-exist-in-the-namespace-system-net
8) http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
9) https://forums.aws.amazon.com/thread.jspa?threadID=14732
10) http://stackoverflow.com/questions/19689484/amazon-s3-rest-api-403-error-c-sharp/26167524#26167524
11) http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-dotnet
12) http://stackoverflow.com/questions/35363358/computing-sha1-with-asp-net-core
13) http://stackoverflow.com/questions/32906755/aws-api-gateway-signature
14) http://stackoverflow.com/questions/16999604/convert-string-to-hex-string-in-c-sharp
15) http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
16) https://forums.aws.amazon.com/thread.jspa?threadID=14732
17) http://docs.aws.amazon.com/general/latest/gr/signature-v4-test-suite.html
18) http://www.hanselman.com/blog/ASPNET5IsDeadIntroducingASPNETCore10AndNETCore10.aspx

Advertisements

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