{"id":79821,"date":"2018-07-20T20:27:48","date_gmt":"2018-07-20T20:27:48","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=79821"},"modified":"2021-07-29T19:44:12","modified_gmt":"2021-07-29T19:44:12","slug":"aws-step-function-serverless-applications","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/cloud\/aws\/aws-step-function-serverless-applications\/","title":{"rendered":"AWS Step Function Serverless Applications"},"content":{"rendered":"<p>I am a C# developer in an AWS world. I have been doing C# work in the Microsoft space for over 10 years. I was given a chance to work with colleagues who are redesigning an existing application into C# .NET Core within the Amazon Web Services (AWS) space. I am here to explain some of what I have learned.<\/p>\n<p>I want to talk to you about the structure of AWS Serverless Application (.NET Core) Step Function. (Serverless is crazy, right? Just wait.) This article begins by describing the \u2018Hello world\u2019 Visual Studio template AWS generates for you. Then, it steps through changing the project files to show how to add more functionality. It shows how to leverage an existing C# logic\/assembly into an AWS Lambda and how that Lambda could be treated as a microservice.<\/p>\n<p>Serverless means you do not have to think about managing a server. Wiki has a good <a href=\"https:\/\/en.wikipedia.org\/wiki\/Serverless_computing\">definition<\/a>.<\/p>\n<h2>Installing VS Components<\/h2>\n<p>To follow along with this article, you must have an AWS account and install the AWS Toolkit for Visual Studio. I\u2019m using Visual Studio Community 2017. Visit <a href=\"https:\/\/aws.amazon.com\/\">AWS<\/a> on Amazon to create an AWS account.<\/p>\n<p>You can find the latest AWS Toolkit in the Extension and Updates (Tools =&gt; Extensions and Updates \u2026) . Within the dialog window, select online the section and search for AWS Toolkit. You will see here that I have it installed:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"457\" height=\"102\" class=\"wp-image-79822\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-95.png\" \/><\/p>\n<p>Or visit Visual Studio Marketplace and search for AWS Toolkit. For Visual Studio 2017 it is located <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=AmazonWebServices.AWSToolkitforVisualStudio2017\">here<\/a>. For Visual Studio 2013\/2015, it is located <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=AmazonWebServices.AWSToolkitforVisualStudio2017\">here<\/a>. You can download the AWS SDK for .NET <a href=\"https:\/\/aws.amazon.com\/sdk-for-net\/\">here<\/a>.<\/p>\n<p>The AWS Toolkit installs an AWS Explorer window.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"324\" height=\"379\" class=\"wp-image-79823\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-96.png\" \/><\/p>\n<p>When you choose an AWS template for the first time, Visual Studio will ask you for account information such as your AWS access key, your AWS secret, and in what region you want to work for creating your default profile. As you can see, I chose to use the US West region.<\/p>\n<h2>Navigating AWS<\/h2>\n<p>I will be referencing the <a href=\"https:\/\/aws.amazon.com\/console\/\">AWS Console<\/a> throughout this article. In the upper right hand corner, you will see a button <em>Sign in to the Console<\/em>. Clicking that button takes you to a login screen. After authenticating, you finally end up on the AWS dashboard. In this dashboard you will see several services listed.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"734\" height=\"843\" class=\"wp-image-79824\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-97.png\" \/><\/p>\n<p>This article will visit the consoles for <em>Lambda<\/em>, <em>Step Functions<\/em>, <em>CloudFormation<\/em>, and <em>S3<\/em> as you follow along. The top banner of the console website has a dropdown called <em>Services<\/em>. Chose that dropdown for ease of navigating between console screens.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"894\" height=\"471\" class=\"wp-image-79825\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-98.png\" \/><\/p>\n<h2>Setting up Account Privileges<\/h2>\n<p>To see what your account privileges are when you created your account, you can go to the IAM console for drilling down to the details. There are a couple of tasks you may want to complete. I created a new Group called <em>Develop <\/em>within the<em> Groups <\/em>section.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1299\" height=\"585\" class=\"wp-image-79826\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-99.png\" \/><\/p>\n<p>You will have to assign a name and permissions as you walk through the wizard. I gave Develop the <em>AdministratorAccess <\/em>policy<em>,<\/em> and I assigned myself to that group.<\/p>\n<p>To create a group, click the <em>Create New Group<\/em> button to start the <em>Create New Group Wizard<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"698\" height=\"419\" class=\"wp-image-79827\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-100.png\" \/><\/p>\n<p>Set the <em>Group Name<\/em> to something that will help you remember what it does.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"821\" height=\"218\" class=\"wp-image-79828\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-101.png\" \/><\/p>\n<p>Click the <em>Next Step<\/em> button to advance to <em>Attach Policy<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"222\" height=\"93\" class=\"wp-image-79829\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-102.png\" \/><\/p>\n<p>For the demo, select <em>AdminstratorAccess<\/em> before clicking the Next Step button for reviewing your actions.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1010\" height=\"447\" class=\"wp-image-79830\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-103.png\" \/><\/p>\n<p>After reviewing the group name and the policies, select the <em>Create Group<\/em> button.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1218\" height=\"201\" class=\"wp-image-79831\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-104.png\" \/><\/p>\n<p>Then, on the <em>Groups<\/em> tab and add your account to the group by selecting the <em>Add User<\/em> to Group button. You will be able to select a user. <img loading=\"lazy\" decoding=\"async\" width=\"569\" height=\"200\" class=\"wp-image-79832\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-105.png\" \/><\/p>\n<p>This article doesn\u2019t dive too deep into the Identity and Access Management (IAM) since that could be the topic of a future article.<\/p>\n<h2>Creating the VS Project<\/h2>\n<p>Create a Visual Studio solution\/project by choosing <em>AWS Serverless Application (.NET Core)<\/em> within the <em>New Project<\/em> UI.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"935\" height=\"644\" class=\"wp-image-79833\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-106.png\" \/><\/p>\n<p>On the next screen choose <em>Step Functions Hello World <\/em>and click <em>Finish<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"832\" height=\"548\" class=\"wp-image-79834\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-107.png\" \/><\/p>\n<p>The C# solution created will look something like the following:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"277\" height=\"200\" class=\"wp-image-79835\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/screen-clipping.png\" alt=\"Screen Clipping\" \/><\/p>\n<p>Basically, the <em>GeraldsLambdaApp<\/em> is an AWS Step Functions project similar to a workflow that calls Lambdas. Lambdas are like functions that run as Micro Services. It\u2019s time to dissect the project.<\/p>\n<p>Since I\u2019m a developer I must look at the code. The <em>State.cs<\/em> file contains the <strong>State<\/strong> class which is a vanilla data transfer object.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"776\" height=\"444\" class=\"wp-image-79836\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-108.png\" \/><\/p>\n<p>There is nothing earth shattering in the <em>StepFunctionTasks.cs;<\/em> it contains two methods that take in the <strong>State<\/strong> class and an <strong>ILambdaContext<\/strong> object.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"760\" height=\"775\" class=\"wp-image-79837\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-109.png\" \/><\/p>\n<p>The .NET Core dependencies are pretty straightforward.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"313\" height=\"113\" class=\"wp-image-79838\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-110.png\" \/><\/p>\n<p>Now onto the AWS files.<\/p>\n<p>Take note of the following AWS files because they are instrumental for deploying to AWS via Visual Studio:<\/p>\n<ul>\n<li>aws-lambda-tools-defaults.json<\/li>\n<li>serverless.template<\/li>\n<li>state-machine.json<\/li>\n<\/ul>\n<p>The <em>aws-lambda-tools-defaults.json<\/em> file contains the settings for deploying from Visual Studio to AWS; this is metadata on how to deploy, and it looks like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1144\" height=\"301\" class=\"wp-image-79839\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-111.png\" \/><\/p>\n<p>Take a look at the properties.<\/p>\n<ul>\n<li><strong>profile<\/strong> is the AWS credentials you use to connect to AWS. You need to ensure you have all the proper permissions. This example uses the default profile. The profile is created when you install the AWS tool kit and can be managed in the Visual Studio AWS Explorer. You can add profiles, but that is beyond what I want to talk about with you today.<\/li>\n<li><strong>region<\/strong> is the AWS region you are placing the application into. There are 15 AWS regions (not counting localhost) listed in the AWS Explorer. I chose the US West two region.<\/li>\n<li><strong>configuration<\/strong> is what configuration that is being deployed, for example, Release and Debug.<\/li>\n<li><strong>framework<\/strong> is associated with the .NET framework you are working with. .NET Core 2.0 is supported.<\/li>\n<li><strong>s3-prefix<\/strong> is the value used within the AWS S3 bucket, i.e., folder name.<\/li>\n<li><strong>template<\/strong> is the name of AWS Cloud Formation template to use for deploying the application.<\/li>\n<li><strong>template-parameters<\/strong> are parameters for deployment. This example does not have any.<\/li>\n<li><strong>template-substitutions<\/strong> is for identifying what to replace within the template. The first part is the path within the template and the value to put there after <strong>Fn::Sub=<\/strong>. This example sets the property <strong>DefinionString<\/strong> of the <strong>StateMachine<\/strong> within the <strong>Resources<\/strong> section of the template with the value <strong>state-machine.json<\/strong>.<\/li>\n<li><strong>s3-bucket<\/strong> is the AWS S3 bucket that will be used for placing the assemblies that are within a zip file and a stack template file that contains all the information for deploying your application.<\/li>\n<li><strong>stack-name<\/strong> is the name you will see in within AWS Cloud Formation console.<\/li>\n<\/ul>\n<p>The file <em>serverless.template<\/em> is the Cloud Formation template that defines your application infrastructure. There are several screen shots to walk through.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"543\" height=\"345\" class=\"wp-image-79840\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/screen-clipping-1.png\" alt=\"Screen Clipping\" \/><\/p>\n<p>As you can see, the description describes what your application is doing. <strong>Resources<\/strong> is a collection of stuff that makes up the application. This example has two Lambda tasks: <strong>GreetingTask<\/strong> and <strong>SalutationsTask<\/strong> (C# code). The <strong>StateMachine<\/strong> describes the Step Function (workflow). And, there are two roles listed describing the permission needed to perform the actions.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"665\" height=\"456\" class=\"wp-image-79841\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/screen-clipping-2.png\" alt=\"Screen Clipping\" \/><\/p>\n<p><strong><img loading=\"lazy\" decoding=\"async\" width=\"615\" height=\"372\" class=\"wp-image-79842\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/screen-clipping-3.png\" alt=\"Screen Clipping\" \/><\/strong><\/p>\n<p>The task\u2019s properties handler value is associated with the C# code. The pattern is: <strong>Assembly::Namespace.ClassName::MethodName<\/strong>. This handler value can only be 128 characters long. The properties Role value has <strong>{&#8220;Fn::GetAtt&#8221;: [&#8220;LambdaRole&#8221;, &#8220;Arn&#8221;]}<\/strong> which tells the deployment executable to go read the <strong>LambdaRole<\/strong> section for the specific Arn value(s) \u2013 the <strong>ManagedPolicyArns<\/strong> property.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"595\" height=\"514\" class=\"wp-image-79843\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/screen-clipping-4.png\" alt=\"Screen Clipping\" \/><\/p>\n<p>In this illustration you see <strong>Fn::Sub<\/strong> which is telling the deployment executable to replace the parameter. This parameter is found in the <em>aws-lambda-tools-defaults.json<\/em> file within the <strong>template-substitutions<\/strong> property.<\/p>\n<p>The file <em>state-machine.json<\/em> file describes the AWS Step Function steps.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"409\" height=\"330\" class=\"wp-image-79844\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/screen-clipping-5.png\" alt=\"Screen Clipping\" \/><\/p>\n<p>The properties:<\/p>\n<ul>\n<li><strong>Comment<\/strong> should describe what this state machine is accomplishing.<\/li>\n<li><strong>StartAt<\/strong> is where to begin within the state machine. The value is listed within the States section.<\/li>\n<li><strong>States<\/strong> is the list of work flow activities that are available.\n<ul>\n<li><strong>Greeting<\/strong> and <strong>Salutations<\/strong> are the names of C# methods that are being called.<\/li>\n<li><strong>Type<\/strong> is the state type you are invoking.<\/li>\n<li><strong>Resource<\/strong> is the ARN to be used. In this example, the ARN is parameterized since it\u2019s not known until deployment time.<\/li>\n<li><strong>SecondsPath<\/strong> is a value to wait (i.e., thread sleep) that is a parameter in the C# State class, again parameterized.<\/li>\n<li><strong>Next<\/strong> is the next step in the workflow.<\/li>\n<li><strong>End<\/strong> is saying it\u2019s done.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>The <strong>Type<\/strong> property can have the following values:<\/p>\n<ul>\n<li><strong>Pass<\/strong> \u2013this a pass-through step<\/li>\n<li><strong>Task<\/strong> \u2013 this is the logic you want to invoke<\/li>\n<li><strong>Choice<\/strong> \u2013 decision time here<\/li>\n<li><strong>Wait<\/strong> \u2013wait for a spell<\/li>\n<li><strong>Succeed<\/strong> \u2013 success \u2013 it\u2019s done<\/li>\n<li><strong>Fail<\/strong> \u2013 something happened, and the execution needs to stop<\/li>\n<li><strong>Parallel<\/strong> \u2013 think of this as creating parallel tasks<\/li>\n<\/ul>\n<p>Files <em>StepFunctionTasks.cs<\/em> and <em>State.cs<\/em> are the C# code. You can review the logic on your own.<\/p>\n<p>Now to deploy this to see what you have. Within the solution explorer, right-click on the project to get a context menu. Within that menu, select <em>Publish to AWS Lambda\u2026<\/em> which will display the following form:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"831\" height=\"547\" class=\"wp-image-79845\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-112.png\" \/><\/p>\n<p>This example has the following settings:<\/p>\n<ul>\n<li>Account profile to use: default<\/li>\n<li>Region: <em>US West<\/em><\/li>\n<li><em>Configuration: Debug<\/em><\/li>\n<li>Framework: .NET Core 1.0 (2.0 is also supported)<\/li>\n<li>Stack Name: stack-gerald-lambda (the name of the functions in AWS)<\/li>\n<li>S3 bucket: Gerald-writing (the storage space)<\/li>\n<li>Save settings: True (changes to the <em>aws-lambda-tools-default.json<\/em> file)<\/li>\n<\/ul>\n<p>You can leave the S3 bucket and stack name blank, and AWS will create GUID-like values for you. I prefer to control the name so that I can find what I am looking for. I want to know which S3 bucket is being used because I need to clean up that S3 Bucket over time (AWS won\u2019t do that for me) and I want a handle on my Cloud Formation name to distinguish it from my other templates. Choose <em>Publish<\/em> to push your code to AWS. The next screen shows a deployment log of what is happening. I have not included a screen shot of that nor the last AWS screen within Visual Studio; these last two screens are the Cloud Formation log activities and can also be seen within the AWS console\u2019s Cloud Formation UI.<\/p>\n<p>During deployment, changes are made to the s3-bucket and stack-name properties in the <em>aws-lambda-tools-defaults.json<\/em> file.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1176\" height=\"316\" class=\"wp-image-79846\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-113.png\" \/><\/p>\n<p>There are several screens with the AWS console to discuss. You could find all this within Visual Studio, but I tend to gravitate to the <a href=\"https:\/\/aws.amazon.com\/console\/)\">AWS console<\/a> because I work there often and that is where I do some of my testing<\/p>\n<p>Begin by viewing S3 within the AWS console. Recall in the <em>aws-lambda-tools-defaults.json<\/em> file there is a property <strong>s3-bucket<\/strong> and the example set the value to <strong>Gerald-writing<\/strong>. You can see it in the list of S3 buckets. NOTE: s3-bucket names are unique across AWS.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1087\" height=\"299\" class=\"wp-image-79847\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-114.png\" \/><\/p>\n<p>Navigate into the bucket to see the <strong>s3-prefix<\/strong> property value you assigned in the <em>aws-lambda-tools-defaults.json<\/em> file.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"437\" height=\"277\" class=\"wp-image-79848\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-115.png\" \/><\/p>\n<p>Navigate into this folder to see the zip folder that contains the code and the template file.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1109\" height=\"238\" class=\"wp-image-79849\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-116.png\" \/><\/p>\n<p>If you look at the template, you will see that it is fully filled out with the parameter values. Take a look and compare what you see in Visual Studio bin folder and the template saying what is being deployed.<\/p>\n<p>Navigate within the AWS console to the <em>Lambda Functions<\/em> page. Make sure that the Region (found next to your account name at the top right) matches the region you specified when publishing to AWS. Your functions will look similar to this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"853\" height=\"363\" class=\"wp-image-79850\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-117.png\" \/><\/p>\n<p>Click the Salutations Task lambda, and you will see that the lambda belongs to a Cloud Formation.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"261\" class=\"wp-image-79851\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-118.png\" \/><\/p>\n<p>Search for <em>Step Function<\/em> within the AWS console and you\u2019ll see the following:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1565\" height=\"296\" class=\"wp-image-79852\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-119.png\" \/><\/p>\n<p>Click the StateMachine name to take you to a <em>Details<\/em> screen. You will see detailed information for identifying the state machine (<em>ARN<\/em>), what role is used (<em>IAM role ARN<\/em>), the date created, an <em>Executions<\/em> tab, and a <em>Definition<\/em> tab. The <em>Executions<\/em> tab is where you can test your code by clicking on <em>Start execution. <\/em>This will bring up a modal dialog page where you can place your execution code. In this case it would be the JSON representation of the C# State class.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1720\" height=\"720\" class=\"wp-image-79853\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-120.png\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>Replace the code with the following JSON snippet but add your own name if you wish.<\/p>\n<pre class=\"lang:c# theme:vs2012\">{\r\n  \"name\": \"Gerald\",\r\n  \"message\": \"Hey\",\r\n  \"waitInSeconds\": 5\r\n}<\/pre>\n<p>Click <em>Start Execution<\/em> that you see in the lower right-hand corner to exercise the code. The execution detail page then appears telling you what is happening on the \u201cVisual Workflow\u201d tab. <img loading=\"lazy\" decoding=\"async\" width=\"825\" height=\"496\" class=\"wp-image-79854\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-121.png\" \/><\/p>\n<p>Examine the <em>Code<\/em> tab, and you will see the Visual Studio file <em>state-machine.json<\/em> with filled in values.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"774\" height=\"442\" class=\"wp-image-79855\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-122.png\" \/><\/p>\n<p>On the right side you can examine each step to see what happened. Switch back to the Visual Workflow tab and select the <em>Greeting<\/em> node to see what happened. Notice you have the Input JSON, the Output JSON, and any exception that occurred.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"766\" height=\"689\" class=\"wp-image-79856\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-123.png\" \/><\/p>\n<p>At the bottom of the page you will see the <em>Execution event history<\/em> section which gives you the details of what just happened at each Lambda State.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1534\" height=\"653\" class=\"wp-image-79857\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-124.png\" \/><\/p>\n<p>Expand the step arrows to see the JSON value related with each Lambda State. <img loading=\"lazy\" decoding=\"async\" width=\"1208\" height=\"892\" class=\"wp-image-79858\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-125.png\" \/><\/p>\n<p>Navigate back to the <em>State machines<\/em> page. Select the state machine name and chose the <em>View details<\/em> button.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1102\" height=\"255\" class=\"wp-image-79859\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-126.png\" \/> There are two tabs <em>Executions<\/em> and <em>Definition<\/em>. Click on <em>Definition<\/em>. Notice that the code is what you saw in the <em>state-machine.json<\/em> file with a visualization of what the steps are on the right.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1555\" height=\"728\" class=\"wp-image-79860\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-127.png\" \/><\/p>\n<p>Navigate to the AWS console\u2019s <em>CloudFormation<\/em> page where you will see the following:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1088\" height=\"253\" class=\"wp-image-79861\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-128.png\" \/><\/p>\n<p>Click the hyperlink under <em>Stack Name<\/em> to see the log information that you saw in Visual Studio after publishing.<\/p>\n<p>It\u2019s time to review the power of the AWS Cloud Formation template. Go back to the main Cloud Formation UI. Delete the stack by selecting the checkbox next to the stack name. Select the Actions dropdown button and choose <em>Delete Stack<\/em>. Go back to the <em>Lambda <\/em>and <em>Step Function<\/em> pages. Everything was cleaned up for you. The only exception is the S3 bucket \u2013 the zip file and template are still in place. By having a Cloud Formation template, I can tear down and stand up the system in one deployment. For me with my DevOps hat on, I\u2019m impressed! I have a simple mechanism to deploy an application or piece of a larger ecosystem. I can take this same template, change my configuration, and use it for deploying to another environment for testing or to production.<\/p>\n<p>If you want to re-deploy the functions you just deleted, navigate to the CloudFormation \u2013 Stacks screen. Select <em>Create Change Set For New Stack <\/em>next to the<em> Create Stack<\/em> button.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"434\" height=\"189\" class=\"wp-image-79862\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-129.png\" \/><\/p>\n<p>You will be taken to a new screen that asks where the template resides.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1866\" height=\"643\" class=\"wp-image-79863\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-130.png\" \/><\/p>\n<p>Since the template is already stored in an AWS S3 bucket, select the <em>Specify an Amazon S3 template URL<\/em> and paste in the link of the template. You get the link by navigating to the Amazon S3 bucket, selecting the folder you placed the template in, select checkbox next to the name of the template, and in the details copy the link.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1814\" height=\"891\" class=\"wp-image-79864\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-131.png\" \/><\/p>\n<p>Or click on the name to get the link.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"910\" height=\"649\" class=\"wp-image-79865\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-132.png\" \/><\/p>\n<p>Now that you have pasted into the textbox for <em>Specify an Amazon S3 template URL<\/em>, you can <em>View\/Edit<\/em> the template or choose <em>Next<\/em>. Fill in the information as you move through the wizard screens.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1561\" height=\"587\" class=\"wp-image-79866\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-133.png\" \/><\/p>\n<p>You can explore this process on your own. I want to demonstrate Visual Studio deployments use case.<\/p>\n<h2>Implementing Your Own Code<\/h2>\n<p>Now that you understand the parts, you can make some changes to fully understand what is needed because \u2018Hello World\u2019 apps don\u2019t make it to production. (Well, maybe they do, and they just don\u2019t tell anyone.) The project code can be found at the bottom of the article.<\/p>\n<p>Now it\u2019s time to revisit the C# code in a real-world example. I am assuming you, the reader, is a C# developer that knows how to create solutions, projects, classes, interfaces, enums, and so forth within Visual Studio. My objective is to demonstrate using multiple classes instead of one class that contains your business logic and how that will look in the template and workflow files.<\/p>\n<p>My real world-like example will have a set of validation rules for inputs that I can use when receiving an API call. I will accomplish this using a total of six C# classes: three task classes (workflow), two state classes, and an input class that will be examined. Notice that the state classes and application user information class are basically Data Transfer Objects (DTOs).<\/p>\n<p>I created a project called <em>GeraldLambdaApp <\/em>within my <em>GeraldsDemo<\/em> solution. I then added classes and files for my real-world example.<\/p>\n<p>Here are the C# class parts:<\/p>\n<ul>\n<li>The <strong>AppUserInfo<\/strong> class is a simple DTO that only contains properties that houses the data that will be validated against. I know you may formulate your application user into different objects (one for person, one for address, one for communication) whereas I put them all into one DTO to simplify the object for demonstration purposes. These properties are as follows:\n<ul>\n<li><strong>FirstName<\/strong> \u2013 the first name of the application user, this is a string<\/li>\n<li><strong>LastName<\/strong> \u2013 the last name of the application user, this is a string<\/li>\n<li><strong>AddressLine1<\/strong> \u2013 the first line of an address, this is a string<\/li>\n<li><strong>AddressLine2<\/strong> \u2013 the second line of an address, this is a string<\/li>\n<li><strong>City<\/strong> \u2013 the city associated with the address, this is a string<\/li>\n<li><strong>State<\/strong> \u2013 the state associated with the address, this is a string<\/li>\n<li><strong>Postal<\/strong> \u2013 the postal code, aka zip code, associated with the address, this is a string<\/li>\n<li><strong>Country<\/strong> \u2013 the country associated with the address, this is a string<\/li>\n<li><strong>Email<\/strong> \u2013 an email address for the application user, this is a string<\/li>\n<li><strong>PhoneNumber<\/strong> \u2013 a phone number for the application user<\/li>\n<\/ul>\n<\/li>\n<li>The <strong>ValidationState<\/strong> is a simple DTO that contains properties for holding onto the validation results. Once more, you will formulate your DTO to meet your application needs. The properties are as follows:\n<ul>\n<li><strong>PropertyName<\/strong> \u2013 the property name the validation error is for, this is a string<\/li>\n<li><strong>ValidationMessage<\/strong> \u2013 the validation message you want the consumer of your application to know, this is a string<\/li>\n<li><strong>IsError<\/strong> \u2013 an indicator that there is an error, this is a Boolean<\/li>\n<li><strong>IsWarning<\/strong> \u2013 an indicator that there is a warning, this is a Boolean<\/li>\n<\/ul>\n<\/li>\n<li>The <strong>StepFunctionState<\/strong> is another DTO, but a wrapper around what is being validated and the results. This object is passed between Lambdas. I like to have one object that encompasses the objects I\u2019m working with. Some places may call this their input DTO. Some may not wish to name the class with \u2018State.\u2019 I did so that you can tie it back to the Hello World example. The properties are as follows:\n<ul>\n<li><strong>InputValue<\/strong> \u2013 this is the AppUserInfo class that is being validated<\/li>\n<li><strong>InputValidation<\/strong> \u2013 this is a list of ValidationState objects (some may wish to use <strong>IEnumerable<\/strong>, but I am trying to demonstrate how to reuse the same object between Lambdas)<\/li>\n<li><strong>HasErrors<\/strong> \u2013 an indicator that you have errors associated with the validation, this is a Boolean<\/li>\n<\/ul>\n<\/li>\n<li>The <strong>AddressValidationTasks<\/strong> class is one of the validation business logic that has one public method with multiple private methods. This is a check to see if the address is acceptable. You could have multiple methods for each property of the address. I did not because I wanted to demonstrate that you could have one class be a single Lambda endpoint where a lot of work happens. Here are the methods:\n<ul>\n<li><strong>Address<\/strong> \u2013 public method that takes in the <strong>StepFunctionState<\/strong> class and the <strong>ILambdaContent<\/strong>. This method returns a <strong>StepFunctionState<\/strong> class. This method calls the <strong>Validate<\/strong> method.<\/li>\n<li><strong>Validate<\/strong> \u2013 private method that takes in the <strong>AppUserInfo<\/strong> class and returns a list of ValidationState classes. This method checks to see if there is a value for the specified property and if the length is acceptable. If not, you add a new <strong>ValidationState<\/strong> to or <strong>ValidationState<\/strong> list.<\/li>\n<li><strong>IsThereValue<\/strong> \u2013 private method that takes in a string value and return a Boolean. This method checks to see if the string value is not null or white spaces.<\/li>\n<li><strong>IsLengthValid<\/strong> \u2013 private method that takes in a string value and an integer representing the maximum size of the string. This method checks to see if the string length is less than or equal to the input integer value.<\/li>\n<\/ul>\n<\/li>\n<li>The <strong>NameValidationTasks<\/strong> class is another validation business logic that contains two public methods. I am demonstrating that a single class can have more than one Lambda endpoints. It could have been done it in one Lambda, but I wanted to show that each endpoint can live in a single class. The methods are as follows:\n<ul>\n<li><strong>FirstName<\/strong> \u2013 public method that takes in a <strong>StepFunctionState<\/strong> class and the <strong>ILambdaContent<\/strong>. This method returns a <strong>StepFunctionState<\/strong>. This method validates that the <strong>FirstName<\/strong> property of the <strong>StepFunctionState<\/strong> <strong>InputValue<\/strong> property is valid (not null or white space and length does not exceed 50). If not valid, add a new <strong>ValidationState<\/strong> to the input <strong>StepFunctionState<\/strong> <strong>InputValidation<\/strong> property.<\/li>\n<li><strong>LastName<\/strong> \u2013 public method that takes in a <strong>StepFunctionState<\/strong> class and the <strong>ILambdaContent<\/strong>. This method returns a <strong>StepFunctionState<\/strong>. This method validates that the <strong>LastName<\/strong> property of the <strong>StepFunctionState<\/strong> <strong>InputValue<\/strong> property is valid (not null or white space and length does not exceed 50). If not valid, add a new <strong>ValidationState<\/strong> to the input <strong>StepFunctionState<\/strong> <strong>InputValidation<\/strong> property.<\/li>\n<\/ul>\n<\/li>\n<li>The <strong>DetermineInputValidTask<\/strong> class has a single public method that sets the <strong>StepFunctionState<\/strong> properties <strong>HasErrors<\/strong> and <strong>HasWarnings<\/strong>. The method is\n<ul>\n<li><strong>SetErrorsAndWarnings<\/strong> \u2013 public method that takes in a <strong>StepFunctionState<\/strong> class and the <strong>ILambdaContent<\/strong>. This method returns a <strong>StepFunctionState<\/strong>. This method sets the <strong>StepFunctionState<\/strong> <strong>HasErrors<\/strong> property based upon the <strong>StepFunctionState<\/strong> <strong>InputValidation<\/strong> property when an error is present. This method sets the <strong>StepFunctionState<\/strong> <strong>HasWarnings<\/strong> property based upon the <strong>StepFunctionState<\/strong> <strong>InputValidation<\/strong> property when a warning is present.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>I know some folks just want to see the C# code and not just read about them.<\/p>\n<p>Here is <em>AppUserInfo.cs<\/em><\/p>\n<pre class=\"lang:c# theme:vs2012\">namespace\u00a0GeraldsLambdaApp\r\n{\r\n\u00a0\u00a0\u00a0\u00a0public\u00a0class\u00a0AppUserInfo\r\n\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0FirstName\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0LastName\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0AddressLine1\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0AddressLine2\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0City\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0State\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0Postal\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0Country\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0Email\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0PhoneNumber\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0}\r\n}<\/pre>\n<p><em>ValidateionState.cs<\/em><\/p>\n<pre class=\"lang:c# theme:vs2012\">namespace\u00a0GeraldsLambdaApp\r\n{\r\n\u00a0\u00a0\u00a0\u00a0public\u00a0class\u00a0ValidationState\r\n\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0PropertyName\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0string\u00a0ValidationMessage\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0bool\u00a0IsError\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0bool\u00a0IsWarning\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0}\r\n}<\/pre>\n<p><em>StepFunctionState.cs<\/em><\/p>\n<pre class=\"lang:c# theme:vs2012\">using\u00a0System.Collections.Generic;\r\n \r\nnamespace\u00a0GeraldsLambdaApp\r\n{\r\n\u00a0\u00a0\u00a0\u00a0\/\/\/\u00a0&lt;summary&gt;\r\n\u00a0\u00a0\u00a0\u00a0\/\/\/\u00a0The\u00a0state\u00a0passed\u00a0between\u00a0the\u00a0step\u00a0function\u00a0executions.\r\n\u00a0\u00a0\u00a0\u00a0\/\/\/\u00a0&lt;\/summary&gt;\r\n\u00a0\u00a0\u00a0\u00a0public\u00a0class\u00a0StepFunctionState\r\n\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0AppUserInfo\u00a0InputValue\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0List&lt;ValidationState&gt;\u00a0InputValidation\u00a0{\u00a0get;\u00a0set;\u00a0}\u00a0=\u00a0new\u00a0List&lt;ValidationState&gt;();\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0bool\u00a0HasErrors\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0bool\u00a0HasWarnings\u00a0{\u00a0get;\u00a0set;\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0}\r\n}<\/pre>\n<p><em>AddressValidationTasks.cs<\/em><\/p>\n<pre class=\"lang:c# theme:vs2012\">using\u00a0Amazon.Lambda.Core;\r\nusing\u00a0System.Collections.Generic;\r\nusing\u00a0System.Text.RegularExpressions;\r\n \r\nnamespace\u00a0GeraldsLambdaApp\r\n{\r\n\u00a0\u00a0\u00a0\u00a0public\u00a0class\u00a0AddressValidationTasks\r\n\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0StepFunctionState\u00a0Address(StepFunctionState\u00a0state,\u00a0ILambdaContext\u00a0context)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0state.InputValidation.AddRange(Validate(state.InputValue));\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return\u00a0state;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0private\u00a0List&lt;ValidationState&gt;\u00a0Validate(AppUserInfo\u00a0userInfo)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var\u00a0validationStates\u00a0=\u00a0new\u00a0List&lt;ValidationState&gt;();\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(!IsThereValue(userInfo.AddressLine1))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.AddressLine1),\u00a0ValidationMessage\u00a0=\u00a0\"Address\u00a0line\u00a01\u00a0is\u00a0required.\"\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else\u00a0if\u00a0(!IsLengthValid(userInfo.AddressLine1,\u00a050))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.AddressLine1),\u00a0ValidationMessage\u00a0=\u00a0$\"Address\u00a0line\u00a01\u00a0needs\u00a0to\u00a0less\u00a0than\u00a0{50}\u00a0characters.\"\u00a0});\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(!IsThereValue(userInfo.City))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.City),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.City)}\u00a0is\u00a0required.\"\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else\u00a0if\u00a0(!IsLengthValid(userInfo.City,\u00a020))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.AddressLine1),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.City)}\u00a0cannot\u00a0exceed\u00a0{20}\u00a0characters.\"\u00a0});\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(!IsThereValue(userInfo.State))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.State),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.State)}\u00a0is\u00a0required.\"\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else\u00a0if\u00a0(!IsLengthValid(userInfo.State,\u00a050))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.AddressLine1),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.State)}\u00a0cannot\u00a0exceed\u00a0{20}\u00a0characters.\"\u00a0});\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(!IsThereValue(userInfo.Postal))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.Postal),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.Postal)}\u00a0is\u00a0required.\"\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else\u00a0if\u00a0(!IsLengthValid(userInfo.Postal,\u00a011))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.AddressLine1),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.Postal)}\u00a0cannot\u00a0exceed\u00a0{11}\u00a0characters.\"\u00a0});\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(!IsThereValue(userInfo.Country))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.Country),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.Country)}\u00a0is\u00a0required.\"\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else\u00a0if\u00a0(!IsLengthValid(userInfo.Country,\u00a050))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.AddressLine1),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.Country)}\u00a0cannot\u00a0exceed\u00a0{50}\u00a0characters.\"\u00a0});\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(!IsThereValue(userInfo.Email))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.Email),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.Email)}\u00a0is\u00a0required.\"\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else\u00a0if\u00a0(!IsLengthValid(userInfo.Email,\u00a050))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.AddressLine1),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.Email)}\u00a0cannot\u00a0exceed\u00a0{50}\u00a0characters.\"\u00a0});\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(!IsThereValue(userInfo.PhoneNumber))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.PhoneNumber),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.PhoneNumber)}\u00a0is\u00a0required.\"\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else\u00a0if\u00a0(!IsLengthValid(userInfo.PhoneNumber,\u00a010))\u00a0validationStates.Add(new\u00a0ValidationState\u00a0{\u00a0IsError\u00a0=\u00a0true,\u00a0PropertyName\u00a0=\u00a0nameof(userInfo.AddressLine1),\u00a0ValidationMessage\u00a0=\u00a0$\"{nameof(userInfo.PhoneNumber)}\u00a0cannot\u00a0exceed\u00a0{10}\u00a0characters.\"\u00a0});\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return\u00a0validationStates;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0private\u00a0bool\u00a0IsThereValue(string\u00a0value)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return\u00a0!string.IsNullOrWhiteSpace(value);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0private\u00a0bool\u00a0IsLengthValid(string\u00a0value,\u00a0int\u00a0length)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return\u00a0value.Length\u00a0&lt;=\u00a0length;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0}\r\n}<\/pre>\n<p><em>NameValidationTasks.cs<\/em><\/p>\n<pre class=\"lang:c# theme:vs2012\">using\u00a0Amazon.Lambda.Core;\r\n \r\n\/\/\u00a0Assembly\u00a0attribute\u00a0to\u00a0enable\u00a0the\u00a0Lambda\u00a0function's\u00a0JSON\u00a0input\u00a0to\u00a0be\u00a0converted\u00a0into\u00a0a\u00a0.NET\u00a0class.\r\n[assembly:\u00a0LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]\r\n \r\nnamespace\u00a0GeraldsLambdaApp\r\n{\r\n\u00a0\u00a0\u00a0\u00a0public\u00a0class\u00a0NameValidationTasks\r\n\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\/\u00a0&lt;summary&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\/\u00a0Default\u00a0constructor\u00a0that\u00a0Lambda\u00a0will\u00a0invoke.\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\/\u00a0&lt;\/summary&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0NameValidationTasks()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n \r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0StepFunctionState\u00a0FirstName(StepFunctionState\u00a0state,\u00a0ILambdaContext\u00a0context)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(string.IsNullOrWhiteSpace(state.InputValue.FirstName))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0state.InputValidation.Add(new\u00a0ValidationState\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0IsError\u00a0=\u00a0true,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0PropertyName\u00a0=\u00a0nameof(state.InputValue.FirstName),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ValidationMessage\u00a0=\u00a0\"First\u00a0name\u00a0is\u00a0required.\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else\u00a0if\u00a0(state.InputValue.FirstName.Length\u00a0&gt;\u00a050)\u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0state.InputValidation.Add(new\u00a0ValidationState\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0IsError\u00a0=\u00a0true,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0PropertyName\u00a0=\u00a0nameof(state.InputValue.FirstName),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ValidationMessage\u00a0=\u00a0$\"Address\u00a0line\u00a01\u00a0needs\u00a0to\u00a0less\u00a0than\u00a0{50}\u00a0characters.\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0});\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return\u00a0state;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0StepFunctionState\u00a0LastName(StepFunctionState\u00a0state,\u00a0ILambdaContext\u00a0context)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if\u00a0(string.IsNullOrWhiteSpace(state.InputValue.LastName))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0state.InputValidation.Add(new\u00a0ValidationState\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0IsError\u00a0=\u00a0true,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0PropertyName\u00a0=\u00a0nameof(state.InputValue.LastName),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ValidationMessage\u00a0=\u00a0\"Last\u00a0name\u00a0is\u00a0required.\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0});\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else\u00a0if\u00a0(state.InputValue.LastName.Length\u00a0&gt;\u00a050)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0state.InputValidation.Add(new\u00a0ValidationState\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0IsError\u00a0=\u00a0true,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0PropertyName\u00a0=\u00a0nameof(state.InputValue.LastName),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0ValidationMessage\u00a0=\u00a0$\"Address\u00a0line\u00a01\u00a0needs\u00a0to\u00a0less\u00a0than\u00a0{50}\u00a0characters.\"\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0});\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return\u00a0state;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0}\r\n}<\/pre>\n<p>Within <em>NameValidationTasks.cs<\/em> file you see the code<\/p>\n<pre class=\"lang:c# theme:vs2012\">[assembly:\u00a0LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]<\/pre>\n<p>It resides outside of the <strong>Namespace<\/strong>. It could live in any of your C# files. If you wanted to, you could create just a cs file that contains just this reference. There is no particular reason why it has to be in this file. With that said, I would keep it with code that is not referenced throughout your application, unless everything is with an AWS Lambda. The purpose of this logic is to reference the lambda serializer so that you can reference the objects without casting them when deserializing a JSON input.<\/p>\n<p><em>DetermineInputValidTask.cs<\/em><\/p>\n<pre class=\"lang:c# theme:vs2012\">using\u00a0Amazon.Lambda.Core;\r\nusing\u00a0System.Linq;\r\n \r\nnamespace\u00a0GeraldsLambdaApp\r\n{\r\n\u00a0\u00a0\u00a0\u00a0public\u00a0class\u00a0DetermineInputValidTask\r\n\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0DetermineInputValidTask()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0public\u00a0StepFunctionState\u00a0SetErrorsAndWarnings(StepFunctionState\u00a0state,\u00a0ILambdaContext\u00a0context)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0state.HasErrors\u00a0=\u00a0state.InputValidation.Any(s\u00a0=&gt;\u00a0s.IsError\u00a0==\u00a0true);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0state.HasWarnings\u00a0=\u00a0state.InputValidation.Any(s\u00a0=&gt;\u00a0s.IsWarning\u00a0==\u00a0true);\r\n \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return\u00a0state;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0}\r\n}<\/pre>\n<p>The AWS files needed:<\/p>\n<ul>\n<li>A file named <em>aws-lambda-tools-defaults.json<\/em> that has the metadata for AWS to deploy your application. This was discussed earlier.<\/li>\n<li>A <em>.template<\/em> file. I named mine <em>gerald-lambda-app.template<\/em>. Recall that this template file is a JSON file that describes the application you are deploying.<\/li>\n<li>A state machine JSON file. I called mine <em>state-machine-gerald-lambda-app.json<\/em>. Remember this file defines the workflow process.<\/li>\n<\/ul>\n<p>Now you need to create the Cloud Formation template to register the Lambdas, the access roles, and the state machine. You have four AWS Lambdas (tasks):<\/p>\n<ul>\n<li><strong>FirstNameTask<\/strong> \u2013 found in <em>NameValidationTasks.cs<\/em><\/li>\n<li><strong>LastNameTask<\/strong> \u2013 found in <em>NameValidationTasks.cs<\/em><\/li>\n<li><strong>AddressTask<\/strong> \u2013 found in <em>AddressValidationTasks.cs<\/em><\/li>\n<li><strong>SetErrorsAndWarningsTask<\/strong> \u2013 found in <em>DetermineInputValidTask.cs<\/em><\/li>\n<\/ul>\n<p>Recall the handler within the template is the <strong>Assembly Name::Namespace.Class Name::Method Name<\/strong>.<\/p>\n<p>The temple file <em>gerald-lambda-app.template<\/em>:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"668\" height=\"844\" class=\"wp-image-79867\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-134.png\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"788\" height=\"763\" class=\"wp-image-79868\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-135.png\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"639\" height=\"597\" class=\"wp-image-79869\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-136.png\" \/><\/p>\n<p>Here is the state machine step function JSON (<em>state-machine-gerald-lambda-app.json<\/em>) for the workflow:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"444\" height=\"422\" class=\"wp-image-79870\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-137.png\" \/><\/p>\n<p>Here is what the solution looks like:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"288\" height=\"265\" class=\"wp-image-79871\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-138.png\" \/><\/p>\n<p>I tend to keep the <em>Readme.md<\/em> file more as a reference.<\/p>\n<p>Then publish the application to AWS via Visual Studio as you did earlier in this article with the sample code AWS provided. Within the solution explorer, right-click on the project to get a context menu. Within that menu, select <em>Publish to AWS Lambda\u2026<\/em>Here is a successful deployment within Visual Studio.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1028\" height=\"517\" class=\"wp-image-79872\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-139.png\" \/><\/p>\n<p>Notice this new change within the AWS S3 bucket (using the AWS Console as you did earlier for navigation):<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"547\" height=\"437\" class=\"wp-image-79873\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-140.png\" \/><\/p>\n<p>Navigate to the Cloud Formation UI using AWS Console you\u2019ll see that the new code\/application exists:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"983\" height=\"213\" class=\"wp-image-79874\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-141.png\" \/><\/p>\n<p>If you navigate via AWS console to the AWS Lambda screen, you\u2019ll see the new application\u2019s AWS Lambdas:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"866\" height=\"421\" class=\"wp-image-79875\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-142.png\" \/><\/p>\n<p>Navigate to the <em>Step Functions<\/em> page to see the State Machine.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"760\" height=\"336\" class=\"wp-image-79876\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-143.png\" \/><\/p>\n<p>You can see the details of the state machine by clicking the State Machine name and then choosing the <em>Definition<\/em> tab.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1553\" height=\"695\" class=\"wp-image-79877\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-144.png\" \/><\/p>\n<p>Now it\u2019s time to test the state machine. Select the Executions tab and choose <em>Start execution<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"324\" height=\"321\" class=\"wp-image-79878\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-145.png\" \/><\/p>\n<p>Create a JSON document that represents the inputs and replace the code.<\/p>\n<pre class=\"lang:c# theme:vs2012\">{\r\n  \"InputValue\": {\r\n    \"FirstName\": \"Gerald\",\r\n    \"LastName\": \"Bauer\",\r\n    \"AddressLine1\": \"123 Main Street\",\r\n    \"City\": \"Sometown\",\r\n    \"State\": \"MN\",\r\n    \"Postal\": \"55101\",\r\n    \"Country\": \"USA\",\r\n    \"Email\": \"gb@sometown.com\"\r\n  }\r\n}<\/pre>\n<p>Select Start execution button and watch it work through the workflow.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1554\" height=\"852\" class=\"wp-image-79879\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-146.png\" \/><\/p>\n<p>Once you see that you have successfully walked thru the steps, expand the <em>Output<\/em> arrow over to the right:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"472\" height=\"477\" class=\"wp-image-79880\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-147.png\" \/><\/p>\n<p>Oops! We forgot the phone number \u2013 the validation worked. Recall the validation for user phone number in the <em>AddressValidationTasks.cs<\/em>.<\/p>\n<p>Now you are going to say, this is interesting, but I have existing code that I would like to deploy to AWS Lambdas. You have options. Reference your existing project from the AWS Lambda project or turn that existing C# logic into a NuGet package. These options use the AWS Lambda as a wrapper class to access the exiting logic. The benefits are that, if there is change in architecture platform, you protected yourself from having to rewrite the entire application and your code could use Dependency Injection from what the Lambda creates making it easier for unit tests. I prefer having the AWS Lambda as a wrapper class for my logic.<\/p>\n<p>If you want to move into Microservices or examine the benefits of having Microservices, the AWS Lambdas could help in achieving that goal. I like the Serverless aspect of the Lambdas because of the ease of deployment and not having to think about the Operating System. (Even Azure offers Serverless capabilities.)<\/p>\n<p>In my demo, I have not used environment variables. In the Windows OS these are environment variables at the machine level. The same is true with AWS environment variables. Environment variables can be found within the Lambda UI:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1548\" height=\"246\" class=\"wp-image-79881\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-148.png\" \/><\/p>\n<h2>Summary<\/h2>\n<p>This article examined the \u201cHello World\u201d example AWS provided in the Visual Studio AWS Serverless Application (.NET Core) template. It reviewed the C# project\u2019s AWS parts: the Cloud Formation template that creates Lambdas and a Step Function, the Step Function (state machine) JSON, and investigated the Visual Studio default deployment JSON. Then that that project was transformed into something you can use to meet your needs. It then discussed wrapping existing logic with the AWS Lambda and expose it as Serverless MicroService.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>AWS Serverless Applications allow developers to create apps without needing a server environment. In this article, Gerald Bauer demonstrates how to get started with this technology in C#. He shows how to deploy and test one of the built-in samples and then walks you through how to create your own application. &hellip;<\/p>\n","protected":false},"author":74403,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538,137092],"tags":[],"coauthors":[60579],"class_list":["post-79821","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","category-aws"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/79821","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/74403"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=79821"}],"version-history":[{"count":2,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/79821\/revisions"}],"predecessor-version":[{"id":80049,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/79821\/revisions\/80049"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=79821"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=79821"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=79821"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=79821"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}