云计算
现在阅读
Serverless Architecture using C# and AWS Amazon Gateway Api/Lambda
0

Serverless Architecture using C# and AWS Amazon Gateway Api/Lambda

由 ultracpy2018年1月20日

Introduction

  1. A basic overview of the architecture and what makes it different
    1. This architecture is not new! And has been in production over 2 years
    2. https://www.slideshare.net/mitocgroup/microservices-architecture-for-web-applications-using-amazon-aws-cloud (2015)
    3. It is language agnostic – all lambda functions can be written in node.js, .net core, python etc.
  2. A step by step tutorial of how you could us this yourself! (45 minutes or less!)

Background

What is a Server-less Architecture and why is it important?

Would you be interested in how to do the following?

  • You as a developer have the capability to host a very large number of websites for almost no COST! 
  • What if you and or your company were able to dramatically decrease the cost of your hosting by 80-90% in most cases!
  • What if you were able to do this and actually increase your throughput, scalability, and performance of your website?
  • What if you could concentrate on features/products and marketing instead of spending time effort and thought in creating, maintaining and deploying to this infrastructure?

This is what a server-less architecture can do!

Overview of common current architectures: Standard N-Tier Architecture.

This is a basic picture of an N-Tier architecture.  It has a presentation layer with Web site, Native Applications, Windows Forms with then an integration/orchestration layer and possibly a DAO layer with finally a database layer of some sort either RDS, or Document DB.

You will notice that the number of servers increases in size and scale with the increase of redundancy and load that is required for the application.  In many cases an application can have 10-30 or more servers being used just to host it and its underlying services.  This complexity and the maintenance of it are handled by the company/developer hosting the application.  You will also notice that this entire infrastructure is up and running whether it is being used or not.  Thus waste of resources on servers not even being used!

This is the challengeInstead of focusing on the products and services that we are attempting to sell and market we are spending large amounts of time and effort on the infrastructure and deploying to the infrastructure that hosts these services!

This is one of the main Benefits of a Server less Architecture!

Are there really no servers?

No… there are servers! However, we have abstracted away the infrastructure and let AWS host it for us.  In other words:

A Server less application is one where the server-side logic is still written by application developers, but this code is run in stateless compute containers that are event-triggered, ephemeral (may only last for one invocation), and fully managed by a 3rd party.   Another way of thinking of this is FaaS (Functions as a service Model). AWS Lambda is one of the most popular implementations of FaaS at present, but there are others.

This Model can be shown as follows:

This is a much simpler architecture because the complexity of the required infrastructure is abstracted and controlled by a 3rd party – in this case Amazon Web Services.

This all sounds too good to be true! Should you then decide to migrate all your applications to this architecture?

No! As with any new architecture you need to prove it to yourself and to your company through an iterative process.  Prove the technology with an MVP – validate the performance and scalability of this architecture with a sample portion of your infrastructure before going full board into it. The following could be the basis for your intial testing and setup for this arch.

Sample Architecture – Step by step

  1. Setup your Environment
  2. Create a Server less Application with a Hello World Json result function
  3. Create a Static S3 Hosted Website.
    1. Update your hosted site to call this API Gateway function and render data
  4. Wow… you’re done already? Yep!
    1. Api Versioning – updating and rollback
    2. Api Gateway caching
  1. Setup your environment in Visual Studio – you can skip this if you’ve already installed
    1. Install Visual Studio 2015 with update #3 and Install .net Core https://blogs.msdn.microsoft.com/visualstudio/2016/06/27/visual-studio-2015-update-3-and-net-core-1-0-availab
    2. Install AWS toolkit https://aws.amazon.com/visualstudio/
      1. Setup your toolkit to use a user – login to AWS with your account https://aws.amazon.com/console/
        1. Get your access keys and secret key from IAM https://console.aws.amazon.com/iam/home#/home

Click on Create Access Key

Download this .csv File and record this somewhere safe.You cannot get it ever again.. you would need to create a new key set to get this information.

You can use this information to configure your AWS toolkit into your aws toolkit profile configuration.

Enter the profile name, Access KeyID and secret access key as shown before.

Once you have this configured your visual studio add in will show you many of the features of AWS your account has access to.

  1. Create a Server less Application with a Hello World Json result function

Use an Empty serverless application.  You can at your leisure look at the other templates, and more will be forthcoming!

Confirm the Project.Json files of the projects to be as follows:

Application Project: project.json

{
  "version": "1.0.0-*",
  "buildOptions": {
    "emitEntryPoint": false
  },
  "dependencies": {
    "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.0.0"
    },
    "Amazon.Lambda.Core": "1.0.0",
    "Amazon.Lambda.APIGatewayEvents": "1.0.2",
    "Amazon.Lambda.Serialization.Json": "1.0.1",
    "Amazon.Lambda.Tools": {
      "type": "build",
      "version": "1.1.0-preview1"
    }
  },
  "tools": {
    "Amazon.Lambda.Tools": "1.1.0-preview1"
  },
  "frameworks": {
    "netcoreapp1.0": {
      "imports": "dnxcore50"
    }
  }
}

Test Project: project.json – note AWSServerless1 is the name of the project being tested and you may need to adjust this file accordingly.

{
  "version": "1.0.0-*",
  "buildOptions": {
  },
  "dependencies": {
    "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.0.0"
    },
    "Amazon.Lambda.Core": "1.0.0*",
    "Amazon.Lambda.APIGatewayEvents": "1.0.2",
    "Amazon.Lambda.TestUtilities": "1.0.0*",
    "AWSServerless1": "1.0.0",
    "xunit": "2.1.0-*",
    "dotnet-test-xunit": "2.2.0-*"
  },
  "testRunner": "xunit",
  "frameworks": {
    "netcoreapp1.0": {
      "imports": "dnxcore50"
    }
  }
}

Confirm successful build of both projects in solution.

Update Hello Function to include CORS headers.  This will allow this function to process cross domain requests successfully.

AWSServerless1 Project look in the Function.cs class and update it to be the following:

public APIGatewayProxyResponse Get(APIGatewayProxyRequest request, ILambdaContext context)
        {
            context.Logger.LogLine("Get Request\n");

            var response = new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.OK,
                Body = "Hello AWS Serverless",
                Headers = new Dictionary<string, string> { { "Content-Type", "application/json" }, { "Access-Control-Allow-Origin", "*" } }
            };
            return response;
        }

Add the following lines of additional code and confirm usings in the Function.cs class.  This is an additional method GetJsonModel that demonstrates how you can extend the functionality and add additional calls to the default call that has already been created.

//Confirm these usings exist
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Net;

//New Code
public class resultJson
        {
            public string practiceId { get; set; }
            public string myMessage { get; set; }
        }

private string GetParms(IDictionary<string, string> qsParms, string parmName)
        {
            var result = string.Empty;
            if (qsParms != null)
            {
                if (qsParms.ContainsKey(parmName))
                {
                    result = qsParms[parmName];
                }
            }
            return result;
        }
        
        /// <summary>
        /// A Lambda function to respond to HTTP Get methods from API Gateway
        /// </summary>
        /// <param name="request"></param>
        /// <returns>The list of blogs</returns>
        public APIGatewayProxyResponse GetJsonModel(APIGatewayProxyRequest request, ILambdaContext context)
        {
            context.Logger.LogLine("Get Request\n");
            var practiceId = GetParms(request.QueryStringParameters, "practiceId");
            resultJson returnResult = new resultJson()
            {
                practiceId = practiceId,
                myMessage = "Hello There AWS Serverless"
            };

            var response = new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.OK,
                Body = JsonConvert.SerializeObject(returnResult),
                Headers = new Dictionary<string, string> { { "Content-Type", "application/json" }, { "Access-Control-Allow-Origin", "*" } }
            };

            return response;
        }

Add to the serverless.template file to include the newly created function.  The file should look as follows:

 {
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Transform" : "AWS::Serverless-2016-10-31",
  "Description" : "An AWS Serverless Application.",

  "Resources" : {

    "Get" : {
      "Type" : "AWS::Serverless::Function",
      "Properties": {
        "Handler": "AWSServerless1::AWSServerless1.Functions::Get",
        "Runtime": "dotnetcore1.0",
        "CodeUri": "",
        "MemorySize": 256,
        "Timeout": 30,
        "Role": null,
        "Policies": [ "AWSLambdaBasicExecutionRole" ],
        "Events": {
          "PutResource": {
            "Type": "Api",
            "Properties": {
              "Path": "/",
              "Method": "GET"
            }
          }
        }
      }
    }

  },
  "GetJsonModel" : {
      "Type" : "AWS::Serverless::Function",
      "Properties": {
        "Handler": "AWSServerless1::AWSServerless1.Functions::GetJsonModel",
        "Runtime": "dotnetcore1.0",
        "CodeUri": "",
        "MemorySize": 256,
        "Timeout": 30,
        "Role": null,
        "Policies": [ "AWSLambdaBasicExecutionRole" ],
        "Events": {
          "PutResource": {
            "Type": "Api",
            "Properties": {
              "Path": "/GetJsonModel",
              "Method": "GET"
            }
          }
        }
      }
    },
  "Outputs" : {
  }
}

Add a test function to confirm the new function:

 [Fact]
        public void TestGetJsonModel()
        {
            TestLambdaContext context;
            APIGatewayProxyRequest request;
            APIGatewayProxyResponse response;

            Functions functions = new Functions();


            request = new APIGatewayProxyRequest();
            Dictionary<string, string> qsParms = new Dictionary<string, string>();
            qsParms["practiceId"] = "MyPractice";
            request.QueryStringParameters = qsParms;
            context = new TestLambdaContext();
            response = functions.GetJsonModel(request, context);            
            Assert.Equal(200, response.StatusCode);
            System.Diagnostics.Debug.WriteLine(response.Body);
        }

Confirm successful build of both projects in solution.

Validate the Unit tests created.

You will note that you can debug these tests and confirm the functionality of your lambda function before/after publishing to AWS.

Publish your Code to AWS and create Gateway API calls!

Right Click on the Solution and Select Publish to AWS.

Give it a Stack Name: The name to which all these functions will be connected – its like a grouping of functions into one API.

And create a new bucket for this stack of lambda functions.

Click Publish! And wow… your done – you have a new api gateway call using the lambda functions you just tested!!

Login to your amazon account and go to the Api Gateway service. You will now see an API Gateway that has been created for you based upon this publish.

 

This should already be deployed to prod but this is howyou can update your Prod stage by redeploying the resource.

Once deployed you can get the URL for use as shown in the Prod stage:

This is the URL we will use in the next step of the process. Actually creating an S3 bucket hosted website and calling these methods.

  1. Create a Static S3 Hosted Website.
    1. Login to AWS and select S3 as your service
    2. Click on the Create button link and put in a uniqu bucketname
    3. (Match the DNS name if your making this a public site)

Make the Bucket into a Website:

 

Add the Following Bucket Policy to this Bucket.  This will make it publicly readable and usable as a website.

change sampletheronbucket to the bucketname you created earlier.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadForGetBucketObjects",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::sampletheronbucket/*"
        }
    ]
}

 

Add the following Cors Policy to this website:

<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

This will allow this bucket to make cross domain calls and have an allowed origin of *.  You may want to adjust this for a produciton environment but for this sample it is fine.

Now All we need to do is to Add an index.html file that actually calls the gateway functions we created earlier and your done! Update this code snippet and replace {yourapikey} with the api key you saw in the api gateway page.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"
            integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
            crossorigin="anonymous"></script>
</head>
<body>
    <div> Hello There this is a sample Static Hosted Page</div>
   
</body>
<script type="text/javascript">
    $(document).ready(function () {
        //Make a call to the api Gateway and render the result
        $.get("https://{yourapikey}.amazonaws.com/Prod/GetJsonModel?practiceId=Hello")
            .done(function (data) {
                console.log(data);
        });
        console.log("ready!");
    });
</script>
</html>

 

Upload this file into your new bucket and name it index.html.

Open up a browser and hit this bucket endpoint – and look in the console.  You will see the data that came from the api gateway call logged to the console!

So What’s so cool about this?

You now have a prototype for creating dynamic websites using Api Gateway and Lambda with C#.  You can extend this with any js based front end framework like Angular, React, etc. that can be used by your new static site, and make ajax calls to the gateway for dynamic processing.

  • The cost of this site is based upon: S3 Bucket storage costs
  • API Gateway costs – first million free
  • Lambda procesing costs – first million free
  • Route 53 or other DNS costs for domain

This means… its basically free hosting!

You can also learn to do the following:

  • Cache the api gateway calls by query string parameter – so that the lambda function isn’t even called!
  • Connect the lambda function to a VPC so that you can call resources internal to the company
  • Create unit tests and tests that call the endpoint to validate it and keep it warm (scheduled Lambda)
  • Create an angular or react front end on the static bucket to render dynamic content
  • Create a server side render through the use of Api Gateway direct and return of html content
  • Enable bucket caching – for S3 downloads
  • Setup Cloudfroot distribution for static site

 

 

出处:https://www.codeproject.com/Articles/1178781/Serverless-Architecture-using-Csharp-and-AWS-Amazo

关于作者
ultracpy
评论

你必须 登录 提交评论