Telerik blogs

In this fourth article, we’ll work through the steps needed to create an AWS backend that serves up our dataset via an HTTP API.


Welcome to this fourth article in a series demonstrating how to create a Blazor client application that incorporates a Telerik UI For Blazor Chart component.

If you haven’t already read the second article, that should be your starting point.

One objective of this series is to demonstrate how we can combine our client application with simple serverless function backend applications.

In this article, we’ll be exploring how to use an AWS Lambda Function. This is AWS’s version of the increasingly popular “serverless computing paradigm.”

If you’re new to “serverless computing” and more accustomed to working with traditional websites/services where code is published to a host server, it’s useful to understand that with AWS Lambda:

  • Code is published as a package to a “storage account.”
  • When a Lambda Function is triggered, code is loaded into worker instances as demand requires. This is all managed transparently.
  • CLI tooling simplifies this publication process, creating the illusion that we are simply publishing directly to a Lambda Function “service.”

AWS Lambda differs slightly from Azure and Google Cloud in that, by default, the underlying storage is not exposed as a distinct resource. This may help to simplify our mental image of a Lambda Function as being a “self-contained compute service” (and arguably helps to declutter the list of separate resources that are presented to cloud customers in the Console).

Note: AWS Lambda Functions support deployments of both file-based packages and container images. In this article, we’ll be demonstrating using a basic file-based deployment.

Note: AWS: Lambda deployment packages identify that “if your deployment package is larger than 50 MB, we recommend uploading your function code and dependencies to an Amazon S3 bucket.” This may sound like an optional recommendation, but it’s not—AWS Lambda has various different usage quotas, which include a deployment package limit of 50 MB.

Series Contents

If you’re planning to follow along with this series, you will need to create a Blazor client application, following the instructions in Part 2 (using Telerik Blazor Chart). Having completed that step, we’ll then look at creating a backend API—in this article, we’ll be looking at creating that API using AWS Lambda Functions.

If you’re interested to learn how the experience compares between the cloud providers, a succinct comparison is in Part 1, and you may further be interested in reading all three of the platform-specific articles in this series.

What Are We Doing in This Article?

In this article, we’ll use AWS Lambda to create a simple serverless HTTP API backend that responds to a request with a JSON dataset.

AWS Lambda supports a number of languages including Node and Python. However, in this article, we will continue using .NET with C#, as we have previously with our Blazor client.

AWS Lambda Functions are event-driven, meaning that their code is triggered in response to various different types of “bound events,” such as a change to a DynamoDB database.

For our purposes, we’re interested in something generally referred to as an “HTTP-triggered function,” which is driven by an event originating from the AWS API Gateway service.

Note: AWS architects HTTP-triggered functions in a way that is similar to Azure Functions—we write our code using an “API Gateway” proxy class, specifically Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse. In contrast, Google Cloud Functions (GCF) simply uses the conventional ASP.NET HttpContext class.

In this article, we’re going to:

  • Create a templated project using .NET Core 3.1.
  • Test our AWS Lambda Function locally, using a simulator tool.
  • Create code for an HTTP-triggered function that will respond to an HTTP-GET request:

    » The code will return a payload of JSON data.
    » For continuity with other articles in this series, that JSON payload will be exactly the same dataset.
    » We’ll retrieve the dataset from a remote source in GitHub.

  • Create resources and publish our function to AWS.
  • Reconfigure our Blazor+Telerik client application and re-test for a final result.

Requirements for This Article

We’re going to expand upon the solution that we developed in the second article of this series.

In addition to those previous requirements, we should now include the following:

A Helpful Steer With AWS Lambda Official Documentation

Specific to .NET developers, the AWS official docs about Lambda Functions can be found here:

The above documentation identifies that AWS Lambda provides several .NET libraries as NuGet packages. Strangely, no further explanation or onward reference seems to be provided.

Therefore, readers of this article will find it useful to know that there is a swath of additional material to be found over on AWS’s GitHub repo—particularly within the various “README” files:

A Solution That Supports Dependency Injection in AWS Lambda Functions

An objective of this series of articles is to present solutions implemented using the “big three” cloud providers, in a way that aligns each solution as closely as possible.

For .NET developers, it’s a common practice to use dependency injection (DI) patterns in our code. Because of this, each of the sample solutions presented in this series includes examples of basic DI usage.

Two primary examples—AWS: .NET Core CLI and GitHub: Amazon.Lambda.APIGatewayEvents—show us most of the building blocks that we’ll be needing. However, there seems to be nothing in the official AWS docs/samples that shine a light on a recommended way to incorporate DI into our project.

This article—StackOverflow: How to use Dependency Injection in AWS Lambda C# implementation?—discusses the topic, including an interesting suggestion that we could:

  • Swap out our implementation code, which would normally be expected to be found in the function entry-point, and instead move this code away into a separate “service class.”
  • In the function entry-point, instead have code that configures a ServiceCollection. This then provides a place to register dependencies, in a way familiar to many .NET developers.

The ideas presented in the StackOverflow solution result in code that looks somewhat “hammered into a different shape, just to support DI.” With that said, the solution works—and does so within a relatively small footprint of code.

Because of this, we’ll adopt a derivative of this approach in this article. Credit to those various contributors on StackOverflow, as they’re the ones that helped to figure this out. We’ll explore the actual code later in this article.

Note: It’s worth noting that AWS Lambda presents the interesting option of hosting an entire ASP.NET Web API application using “serverless” infrastructure. This would offer conventional startup code, including DI configuration and provision for improved local debugging, by virtue of being able to self-host. An example of this approach is detailed in GitHub: Amazon.Lambda.AspNetCoreServer.

However, in our scenario, this approach could be considered to be a somewhat heavyweight solution to a lightweight problem. Furthermore, this approach would also depart from any equivalency with our other “basic function” examples, as found in the other articles of this series—so we won’t explore this option further.

Use the CLI To Generate a New AWS Project

If you haven’t already done so, you need to install and configure the AWS CLI, as identified in the Requirements section above, before progressing.

With that done, we next need to download the .NET project templates specific to AWS Lambda Functions—these have been created by AWS.

  • Enter the following command:
dotnet new -i Amazon.Lambda.Templates

Great—now we’re ready, let’s create some code! Using our command prompt:

  • Navigate to the folder, where previously in the second article of this series we created our .NET solution. If you were following along, we called itBlazorTelerikCloudDemo.
  • Inside this folder, create a new folder and call it LambdaService and navigate to it.
  • As we now have the correct templates installed, we can now use those to scaffold a new project like this:
md LambdaService
cd LambdaService
dotnet new lambda.EmptyFunction

The tooling will create a selection of project files for us. Incidentally, these are organized into src and test subfolders.

  • (Optional) Next, for consistency, we’ll add the Lambda project to the overall .NET solution. Because the AWS Templates scaffold a src subfolder, we’ll additionally use the --in-root parameter to avoid creating unnecessary solution folders (when viewing with Visual Studio):

  • Enter the following:

dotnet sln add LambdaService\src\LambdaService --in-root

Use the AWS Lambda Function Test Tool

Before we progress further, let’s quickly test that our basic templated example system is working.

AWS Lambda Functions differ slightly from solutions provided by Azure and Google Cloud, by not offering the option to fully test/debug our code locally—either by hosting directly or by running from within a locally hosted runtime.

Instead, AWS presents a testing tool that provides a restricted way to test our code. It works by hooking its service into a debug build of our code (i.e., we will need to have compiled the project before using the tool).

Note: Incidentally, the testing tool happens to have been created using Blazor.

  • From the project folder, let’s first make a debug build to test:

    » Note that, although compiling a debug build is the default behavior, using the optional -c debug parameter is a way for us to be certain.

cd  <your repofolder>\BlazorTelerikCloudDemo\LambdaService\src\LambdaService
dotnet build -c debug
  • Install the testing tool:
dotnet tool install -g Amazon.Lambda.TestTool-3.1
  • Run the following from the console (from the same folder as the project):
dotnet lambda-test-tool-3.1
  • Running the above command will start the test tool.

    » A new browser window containing the testing tool UI should also open.

  • In Visual Studio, add a breakpoint to the first line of the FunctionHandler method.
  • Carefully follow the configuration instructions provided by AWS in their guide GitHub: Configure for Visual Studio Code.
  • With the test tool still running, start the Visual Studio debugger. It should attach to the running process of the test tool, using the configuration we just provided. If that doesn’t work, an alternative is to attached the VS Debugger manually, using “Attach to process…” and searching the list for the process with “lambda-test-tool” in its title.
  • In the browser UI, locate the textbox labelled “Function Input.”

    » Enter the value "hello world" (it’s essential to surround the text with quotes, otherwise we’ll see errors).
    » We don’t need to change any of the other settings.

  • If everything has worked, the function should execute and we should hit the breakpoint that we set a moment ago.
  • If we then let the code run to its conclusion, we should see a result appear in the “Response” box of the testing tool.

image of AWS lambda test utility

Note: Earlier we briefly mentioned that AWS supports hosting of an entire ASP.NET application within a Lambda serverless architecture—GitHub: Amazon.Lambda.AspNetCoreServer. This option could represent an alternative way to test code locally.

Modifying the AWS Lambda Function To Return a Dataset

Next, we want our AWS Lambda Function to return some data.

  • We’re going to maintain consistency with the second article in this series by returning a static JSON dataset containing some arbitrary data.
  • We’re going to retrieve the JSON dataset from a GitHub page.

    » If we want, we can view that data directly in our browser:

  • We’re going to request the dataset from GitHub using an HTTPClient … and then pass that dataset back as the response from our API.

Note: The purpose of this is so that we can learn from a really simple system. We can always layer in more complexity later. It’s completely reasonable to assume that we wouldn’t use this approach in a real system. Instead, it’s much more likely that we would use a separate storage account or even query a database.

Introduce an API Implementation Class

Within the top-level files of our newly templated “LambdaService” project, go ahead and create the following:

  • Create a new code file ApiImplementation.cs.
  • Copy and paste the following code into that new file:
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Collections.Generic;

using Amazon.Lambda.APIGatewayEvents;

namespace LambdaFunction
    public class ApiImplementation
        private readonly HttpClient _httpClient;

        public ApiImplementation(HttpClient httpClient)
            _httpClient = httpClient;

        public async Task<APIGatewayHttpApiV2ProxyResponse> Run(APIGatewayHttpApiV2ProxyRequest apiGatewayHttpApiV2ProxyRequest)
            //"APIGatewayHttpApiV2ProxyRequest"  has been passed, to show us how to make it available ...
            //... However, it's not actually used in this example!

            var remoteDatset = "";
            var remoteResponse = await _httpClient.GetAsync(remoteDatset);

            if (remoteResponse.IsSuccessStatusCode)
                return new APIGatewayHttpApiV2ProxyResponse()
                    StatusCode = (int)HttpStatusCode.OK,
                    Body =  await remoteResponse.Content.ReadAsStringAsync(),
                    Headers = new Dictionary<string, string>
                            {"Content-Type", "application/json"}
                return new APIGatewayHttpApiV2ProxyResponse()
                    StatusCode = (int)HttpStatusCode.InternalServerError,
                    Body = string.Empty,
                    Headers = new Dictionary<string, string>
                            {"Content-Type", "application/json"}

If you’ve been following along with the solutions included in the Azure and GCF articles of this series, you’ll notice that this code is very similar to the API implementation in those examples.

What may be unfamiliar is that our implementation code has instead been placed into this separate ApiImplementation class instead of being found directly into the Amazon.Lambda.Core.Function class.

The reason for this relates to a point we highlighted earlier in this article—we need to create a way to support dependency injection.

Specifically in our case, we want to be able to inject an instance of System.Net.Http.HttpClient into the ApiImplementation() constructor.

Let’s inspect the above code more closely:

  • Significantly, we’ve added the class Attribute [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))].

    » This is used to “wire-up” our class, with a serializer provided by AWS that lets our .NET code work with their wider cross-language platform.

  • We’ve introduced the private member _httpClient to the class.

    » This forms part of the code that we use to make HttpClient available through dependency injection.

  • We’ve also introduced a class constructor.

    » This also forms part of the code needed to make HttpClient available through dependency injection.

  • Looking at the main code of the Function—a method named Run—we:

    » defined a hard-coded URL to a demonstration dataset. This is the JSON dataset stored on GitHub.
    » used the HttpClient to retrieve the dataset.
    » returned an HTTP response containing the dataset along with the appropriate response status code.

  • With AWS Lambda we don’t directly work with Microsoft.AspNetCore.Http.HttpContext (as for example, Google Cloud Function does)—instead we work with the AWS API-Gateway proxy-object Amazon.Lambda.APIGatewayEvents.APIGatewayProxyResponse (this is similar to how Azure Functions does it).

    » This maps to JSON message/payload, which, behind the scenes, is passed between the API Gateway service and the Lambda service (at this point the language used to develop the Function itself becomes irrelevant).
    » AWS documents the JSON payload in this article: AWS: Working with AWS Lambda proxy integrations for HTTP APIs.
    » The proxy object gives us the option to customize our HTTP response and its headers (i.e., setting a response body, response-codes, content-types, etc.).

Note: A reference to APIGatewayHttpApiV2ProxyRequest has been included in our sample code above. This has been included purely to demonstrate how we could access it (e.g., adapting this example in the future). The inclusion APIGatewayHttpApiV2ProxyRequest adds nothing further to this example!

Modify the Lambda Function Entrypoint

Next, we’ll add code that lets us configure dependency injection.

The AWS templating that we used, created a class named Function—originally, it included sample code for a basic Lambda Function.

  • Go ahead and entirely replace that existing code with the following:
using System.Net.Http;
using System.Threading.Tasks;

using Microsoft.Extensions.DependencyInjection;

using Amazon.Lambda.Core;
using Amazon.Lambda.APIGatewayEvents;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace LambdaFunction
    public class Function
        private ServiceCollection _serviceCollection;

        public Function()

        public async Task<APIGatewayHttpApiV2ProxyResponse> FunctionHandler(APIGatewayHttpApiV2ProxyRequest apiGatewayHttpApiV2ProxyRequest)
            using (ServiceProvider serviceProvider = _serviceCollection.BuildServiceProvider())
                // entry to run app.
                return await serviceProvider.GetService<ApiImplementation>().Run(apiGatewayHttpApiV2ProxyRequest);

        private void ConfigureServices()
            // add dependencies here
            _serviceCollection = new ServiceCollection();

Let’s inspect the above code more closely:

  • We’ve introduced a private instance of a ServiceCollection object that will contain the collection of services that will be registered.
  • We’ve introduced ConfigureServices(), called at startup, where we do the actual service registration.
  • In the FunctionHandler method:

    » We’ve removed code that would normally represent the API implementation.
    » We introduced a mechanism that allows a service provider to be created using BuildServiceProvider().
    » The code that normally represents the API implementation has been moved to the separate class ApiImplementation. We invoke that code using the ApiImplementation.Run() method.

Adding in a CORS Policy to the Function

Later in this article, we’ll be slightly updating our Blazor application that we created in the second article.

The change we’re going to make is that, instead of retrieving the JSON dataset from a local file, we’ll revise the code to request the data from an HTTP endpoint (our new Lambda Function).

If we don’t change anything, a problem we’re about to run into is a CORS policy issue.

Explaining Cross-Origin Resource Sharing (CORS) is outside of the scope of this article, but very briefly: browsers implement security that, by default, prevents an application from just retrieving data from resources other than the immediate host. You can learn more here:

The AWS developer docs don’t seem to explicitly demonstrate how to do this using .NET, but fortunately we’ve already learned about the APIGatewayProxyResponse proxy object—so it’s fairly straightforward for us to adapt.

Let’s make the necessary change to the code:

  • Using VS Code, edit the file ApiImplementation.cs.
  • Within the code, update with the following fragments to include a Access-Control-Allow-Origin header, like this:
Headers = new Dictionary<string, string>
        {"Content-Type", "application/json"},
        {"Access-Control-Allow-Origin", "*"}

In this case, we’ve used a wildcard entry to completely open up access. For security reasons, this is not at all recommended and is absolutely not something we should do in a real system. This step is intended as a convenience while learning.

Note: Hard-coding the setting makes it easier to learn what’s happening, but, looking ahead, we will probably be interested in supplementing this code with some form of environment-specific configuration.

Test: Modify the Blazor Client To Retrieve From the Locally Hosted Lambda Function

… OK, sorry, that title was misleading.

AWS’s support for testing/debugging a locally hosted Lambda Function is frustratingly limited. The Lambda Function Test Tool, which we were introduced to earlier, isn’t intended for much more beyond basic testing. It does support the connection of a debugger, which goes some way to provide a better developer experience.

Although we could use the tool to demonstrate that our API is returning a result, it doesn’t actually host a function-as-a-service.

This means that we can’t connect our client-side Blazor application to it—so we’ll skip this part of the test.

Note: As another reminder, an alternative option to host an entire ASP.NET Core Server within a lambda serverless instance—which could present a solution for running the service locally. However, we’ve chosen not to go down that route.

Create and Configure AWS Resources

image of coloured pens
Image credit: Jessica Lewis Creative on Pexels

Next, we’ll start moving our API service into the cloud. To do that, we first need to create some resources.

Optional: Consider Using Other AWS Regions

When we create any AWS resources, we have a large choice of data centers from around the globe. AWS uses the term “Region” to describe their major data centers.

For the purpose of this article, we’ll show examples that use a region called “eu-west-2” (which happens to be in London).

Normally, we should choose an AWS Region that is nearest to our customers. If we wanted to adapt the example in this article, we’d need to know what choices of “Azure Region” we have.

AWS Lambda is not available in all regions, so check availability using the doc below:

We can set the region as a default choice by adding it to our CLI configuration (along with credentials, etc.) using the CLI command:

aws configure

Alternatively, we can supply the region as an additional argument each time we create resources. We’ll demonstrate this option in subsequent CLI examples.

Tip: The AWS Console only lists resources for a particular region—if this is your first time using AWS, the console may have defaulted to showing a different region, from the one you are publishing to. There is a dropdown in the top-right of the page, next to your user information, that shows the currently selected region.

Create and Configure an Execution Role for Function

Next, we need to define an AWS IAM Execution Role, which is used to give the Function permission to use AWS resources.

This is a subject area that introduces just a bit too much complexity/detail to fit well within this article. Because of this, we need to jointly refer to the following guide:

To successfully create a new role and assign permissions, we will need to use the following commands. Important: The create-role command below is partial—meaning that you will need to supply additional arguments to make this work (as detailed in the above doc).

  • aws iam create-role --role-name lambda-role ..... <additional arguments required>

    » We should name the role as “lambda-role” to fit with subsequent examples.

  • aws iam attach-role-policy --role-name lambda-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

    » We should use the policy “AWSLambdaBasicExecutionRole.”

Note: In this article, we’ll be using the AWS CLI, but, if you prefer, using the web-based interface found in the AWS Console is also a really good option.

Deploy the AWS Lambda Function

  • Use the following console command to publish our app to the cloud:
dotnet lambda deploy-function LambdaFunction --function-role lambda-role --region eu-west-2
  • LambdaFunction is just a name and can be anything.

    » By coincidence it’s the same as the code namespace, but it doesn’t have to be.

  • lambda-role is the name of an AWS IAM Role that we needed to prepare earlier.

    » When the app has finished deploying, the CLI will return some confirmation information. However, unlike solutions provided by Azure Functions or Google Cloud Functions, we don’t expect to find the URL that we can use to invoke the function for testing—that is something we must do separately.

  • However, we can manually test the newly deployed Function by entering the following console command:
dotnet lambda invoke-function LambdaFunction --cli-binary-format raw-in-base64-out

If everything has worked, we should expect to see a JSON dataset returned as output directly in the console.

Get the Function ARN

Every resource in AWS is identified with a unique name called an Amazon Resource Name (ARN).

In a moment, we’re going to connect an “AWS API Gateway” to our Lambda Function, but, to do that, we’ll first need to know the ARN of our Function.

  • Enter the following CLI command:
aws lambda get-function --function-name LambdaFunction

This command will return a chunk of information, but we’re only interested in the FunctionArn value. It will look something very similar to this:


Tip: We should copy + paste the ARN to some form of notepad, as we’ll be wanting this string shortly.

Create AWS API Gateway

AWS API Gateway can be used to create public HTTP endpoints that can trigger the events of various different AWS services.

As already mentioned, unlike other cloud providers, AWS Lambda Functions do not automatically provision an HTTP endpoint—so we need to create one using the AWS API Gateway service and integrate it to our Lambda Function.

We can learn about configuring the AWS API Gateway here:

Go ahead and enter the following command, adapting it to your own specific value of “function ARN” (that we made a note of a few steps earlier):

aws apigatewayv2 create-api --name DemoAPI --protocol-type HTTP --target arn:aws:lambda:eu-west-2:123412341234:function:LambdaFunction
  • DemoAPI is just a name we give the API and can be anything.
  • The expected “ARN” value for --target needs to be that of the “LambdaFunction” that we made a note of, when we created the Function.

When the command has run successfully, it will return various pieces of information that we should make a note of—especially the ApiEndPoint and ApiId values.

Tip: If you prefer to use the AWS Console rather than the CLI, the guide AWS: Getting started with API Gateway may be of interest to you.

Configure AWS API Gateway Integration

AWS is relatively verbose, so in addition to creating resources, we need to associate the Endpoint to the Lambda Function and provide it with permission to execute the Lambda Function.

AWS: Working with HTTP APIs advises us that the “API Gateway must have the required permissions” … but then only provides generic guidance as to how we go about doing that.

Fortunately, a separate AWS support article shows us a way forward:

Below is cut + pasted from the above document, which describes the required format of the CLI command:

aws lambda add-permission   \
--function-name "$YOUR_FUNCTION_ARN"   \
--source-arn "arn:aws:execute-api:$API_GW_REGION:$YOUR_ACCOUNT:$API_GW_ID/*/$METHOD/$RESOURCE"   \
--principal   \
--statement-id $STATEMENT_ID   \
--action lambda:InvokeFunction

The guidance in the above AWS support article takes us most of the way, but because the expected syntax is especially fiddly, we’ve included an additional example using real-world values (that worked successfully). This should help readers to make progress through this process:

  • Go ahead and run the following CLI command, adapting as needed to work with your resources (this example has been split across multiple lines for legibility):
aws lambda add-permission 
 --function-name "arn:aws:lambda:eu-west-2:123412341234:function:LambdaFunction" 
 --source-arn "arn:aws:execute-api:eu-west-2:123412341234:ntrvr685z4/*/$default"
 --statement-id 7744ab49-1b3f-5036-8857-ac65adc352a9 
 --action lambda:InvokeFunction 

Tip: As long as we don’t mind breaking away from the CLI and making use of using the AWS Console—the required permission-command can be found as an auto-generated snippet, buried away within the console. Look at the screenshot below for guidance:

image of AWS APIGateway CommandSnippet utility

Test the API Endpoint

At last, we’re in the final straight—let’s test that the API is working.

Earlier, when we initially created the API Gateway resource, the console responded with various information, including the URI of the endpoint.

If we forgot to make a note of that value when we created the resource, we can still get hold of that information again, using this command:

aws apigatewayv2 get-apis 
  • Go ahead and paste that ApiEndpoint into a browser.

If everything is behaving, we should receive a large payload of JSON as a response.

Tip: We should copy + paste the URL to some form of notepad, as we’ll be wanting this string again shortly.

Test: Modify the Blazor Client To Retrieve From Azure

Finally, let’s test our finished result:

Return back to the Blazor application that we created in the second article of this series:

  • Just like earlier, using VS Code, edit the file /Pages/Index.razor.
  • In the code section, update the OnInitializedAsync() method like this (modifying the URL to include your unique name as appropriate):
protected override async Task OnInitializedAsync()
    //seriesData = await Http.GetFromJsonAsync<SeriesDataModel[]>("sample-data/cloud-searchtrend-data.json");
    seriesData = await Http.GetFromJsonAsync<SeriesDataModel[]>("https://<YOUR_UNIQUE_API_ENDPOINT");

Wrapping Up

How Does the AWS Experience Compare?

If you’re curious to learn how my experience with AWS stacks up against Azure and Google Cloud, I wrote more about this in Part 1. You can also learn more specifics in Part 3 on Azure and Part 5 on Google Cloud.

Useful References

You may find it helpful to have awareness about the following subjects. If you get stuck, here are some useful articles:

Resources for Learning AWS Identity and Access Management (IAM) and Configuring the AWS CLI

Take your time to carefully work through the following documentation provided by AWS:


Thanks to Shawn Vause, an AWS-certified professional, for his AWS-specific technical review.

Thanks to Mandy Mowers & Layla Porter for the overall document review.


I always disclose my position, association or bias at the time of writing. As an author, I received a fee from Progress Telerik in exchange for the content found in this series of articles. I have no association with Microsoft, Amazon nor Google—this series of articles is in no way intended to offer biased opinion nor recommendation as to your eventual choice of cloud provider.

About the Author

Jim McG

A UK-based freelance developer using largely Microsoft technologies, Jim McG has been working with web and backend services since the late ‘90s. Today, he generally gravitates around cloud-based solutions using C#, .NET Core and Azure, with a particular interest in serverless technologies. Most recently, he's been transitioning across to Unity and the amazing tech that is Augmented Reality.

Related Posts


Comments are disabled in preview mode.