├── .DS_Store ├── .gitignore ├── Application ├── Final │ ├── .dockerignore │ ├── ServerlessTODOList.Common │ │ ├── ServerlessTODOList.Common.csproj │ │ ├── TODOList.cs │ │ └── TODOListItem.cs │ ├── ServerlessTODOList.DataAccess │ │ ├── ITODOListDataAccess.cs │ │ ├── ServerlessTODOList.DataAccess.csproj │ │ ├── TODOListDataAccess.cs │ │ └── TODOListDataAccessException.cs │ ├── ServerlessTODOList.Frontend │ │ ├── Areas │ │ │ └── Identity │ │ │ │ ├── IdentityHostingStartup.cs │ │ │ │ └── Pages │ │ │ │ ├── Account │ │ │ │ ├── ChangePassword.cshtml │ │ │ │ ├── ChangePassword.cshtml.cs │ │ │ │ ├── ConfirmAccount.cshtml │ │ │ │ ├── ConfirmAccount.cshtml.cs │ │ │ │ ├── Login.cshtml │ │ │ │ ├── Login.cshtml.cs │ │ │ │ ├── LoginWith2fa.cshtml │ │ │ │ ├── LoginWith2fa.cshtml.cs │ │ │ │ ├── Logout.cshtml │ │ │ │ ├── Logout.cshtml.cs │ │ │ │ ├── Register.cshtml │ │ │ │ ├── Register.cshtml.cs │ │ │ │ ├── ResetPassword.cshtml │ │ │ │ ├── ResetPassword.cshtml.cs │ │ │ │ └── _ViewImports.cshtml │ │ │ │ ├── _ValidationScriptsPartial.cshtml │ │ │ │ ├── _ViewImports.cshtml │ │ │ │ └── _ViewStart.cshtml │ │ ├── Dockerfile │ │ ├── LambdaEntryPoint.cs │ │ ├── Pages │ │ │ ├── CreateList.cshtml │ │ │ ├── CreateList.cshtml.cs │ │ │ ├── EditList.cshtml │ │ │ ├── EditList.cshtml.cs │ │ │ ├── Error.cshtml │ │ │ ├── Error.cshtml.cs │ │ │ ├── Index.cshtml │ │ │ ├── Index.cshtml.cs │ │ │ ├── MyLists.cshtml │ │ │ ├── MyLists.cshtml.cs │ │ │ ├── Privacy.cshtml │ │ │ ├── Privacy.cshtml.cs │ │ │ ├── Shared │ │ │ │ ├── _CookieConsentPartial.cshtml │ │ │ │ ├── _Layout.cshtml │ │ │ │ ├── _LoginPartial.cshtml │ │ │ │ └── _ValidationScriptsPartial.cshtml │ │ │ ├── _ViewImports.cshtml │ │ │ └── _ViewStart.cshtml │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── ServerlessTODOList.Frontend.csproj │ │ ├── Startup.cs │ │ ├── appsettings.Development.json │ │ ├── appsettings.json │ │ ├── buildspec.yml │ │ ├── serverless.template │ │ └── wwwroot │ │ │ ├── css │ │ │ ├── site.css │ │ │ └── site.min.css │ │ │ ├── favicon.ico │ │ │ ├── images │ │ │ ├── banner1.svg │ │ │ ├── banner2.svg │ │ │ └── banner3.svg │ │ │ ├── js │ │ │ ├── site.js │ │ │ └── site.min.js │ │ │ └── lib │ │ │ ├── bootstrap │ │ │ ├── .bower.json │ │ │ ├── LICENSE │ │ │ └── dist │ │ │ │ ├── css │ │ │ │ ├── bootstrap-theme.css │ │ │ │ ├── bootstrap-theme.css.map │ │ │ │ ├── bootstrap-theme.min.css │ │ │ │ ├── bootstrap-theme.min.css.map │ │ │ │ ├── bootstrap.css │ │ │ │ ├── bootstrap.css.map │ │ │ │ ├── bootstrap.min.css │ │ │ │ └── bootstrap.min.css.map │ │ │ │ ├── fonts │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ │ └── js │ │ │ │ ├── bootstrap.js │ │ │ │ ├── bootstrap.min.js │ │ │ │ └── npm.js │ │ │ ├── jquery-validation-unobtrusive │ │ │ ├── .bower.json │ │ │ ├── LICENSE.txt │ │ │ ├── jquery.validate.unobtrusive.js │ │ │ └── jquery.validate.unobtrusive.min.js │ │ │ ├── jquery-validation │ │ │ ├── .bower.json │ │ │ ├── LICENSE │ │ │ └── dist │ │ │ │ ├── additional-methods.js │ │ │ │ ├── additional-methods.min.js │ │ │ │ ├── jquery.validate.js │ │ │ │ └── jquery.validate.min.js │ │ │ └── jquery │ │ │ ├── .bower.json │ │ │ ├── LICENSE.txt │ │ │ └── dist │ │ │ ├── jquery.js │ │ │ ├── jquery.min.js │ │ │ └── jquery.min.map │ ├── ServerlessTODOList.StreamProcessor │ │ ├── .lambda-test-tool │ │ │ └── SavedRequests │ │ │ │ └── ddb-tasks.json │ │ ├── Function.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── ServerlessTODOList.StreamProcessor.csproj │ │ └── aws-lambda-tools-defaults.json │ └── ServerlessTODOList.sln ├── IdentityScaffolding │ └── Areas │ │ └── Identity │ │ ├── IdentityHostingStartup.cs │ │ └── Pages │ │ ├── Account │ │ ├── ChangePassword.cshtml │ │ ├── ChangePassword.cshtml.cs │ │ ├── ConfirmAccount.cshtml │ │ ├── ConfirmAccount.cshtml.cs │ │ ├── Login.cshtml │ │ ├── Login.cshtml.cs │ │ ├── LoginWith2fa.cshtml │ │ ├── LoginWith2fa.cshtml.cs │ │ ├── Logout.cshtml │ │ ├── Logout.cshtml.cs │ │ ├── Register.cshtml │ │ ├── Register.cshtml.cs │ │ ├── ResetPassword.cshtml │ │ ├── ResetPassword.cshtml.cs │ │ └── _ViewImports.cshtml │ │ ├── _ValidationScriptsPartial.cshtml │ │ ├── _ViewImports.cshtml │ │ └── _ViewStart.cshtml └── Start │ ├── ServerlessTODOList.Common │ ├── ServerlessTODOList.Common.csproj │ ├── TODOList.cs │ └── TODOListItem.cs │ ├── ServerlessTODOList.DataAccess │ ├── ITODOListDataAccess.cs │ ├── ServerlessTODOList.DataAccess.csproj │ ├── TODOListDataAccess.cs │ └── TODOListDataAccessException.cs │ ├── ServerlessTODOList.Frontend │ ├── Areas │ │ └── Identity │ │ │ └── Pages │ │ │ └── _ViewStart.cshtml │ ├── Data │ │ ├── ApplicationDbContext.cs │ │ └── Migrations │ │ │ ├── 00000000000000_CreateIdentitySchema.Designer.cs │ │ │ ├── 00000000000000_CreateIdentitySchema.cs │ │ │ └── ApplicationDbContextModelSnapshot.cs │ ├── Pages │ │ ├── CreateList.cshtml │ │ ├── CreateList.cshtml.cs │ │ ├── EditList.cshtml │ │ ├── EditList.cshtml.cs │ │ ├── Error.cshtml │ │ ├── Error.cshtml.cs │ │ ├── Index.cshtml │ │ ├── Index.cshtml.cs │ │ ├── MyLists.cshtml │ │ ├── MyLists.cshtml.cs │ │ ├── Privacy.cshtml │ │ ├── Privacy.cshtml.cs │ │ ├── Shared │ │ │ ├── _CookieConsentPartial.cshtml │ │ │ ├── _Layout.cshtml │ │ │ ├── _LoginPartial.cshtml │ │ │ └── _ValidationScriptsPartial.cshtml │ │ ├── _ViewImports.cshtml │ │ └── _ViewStart.cshtml │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── ServerlessTODOList.Frontend.csproj │ ├── Startup.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ │ ├── css │ │ ├── site.css │ │ └── site.min.css │ │ ├── favicon.ico │ │ ├── images │ │ ├── banner1.svg │ │ ├── banner2.svg │ │ └── banner3.svg │ │ ├── js │ │ ├── site.js │ │ └── site.min.js │ │ └── lib │ │ ├── bootstrap │ │ ├── .bower.json │ │ ├── LICENSE │ │ └── dist │ │ │ ├── css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap-theme.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ └── npm.js │ │ ├── jquery-validation-unobtrusive │ │ ├── .bower.json │ │ ├── LICENSE.txt │ │ ├── jquery.validate.unobtrusive.js │ │ └── jquery.validate.unobtrusive.min.js │ │ ├── jquery-validation │ │ ├── .bower.json │ │ ├── LICENSE │ │ └── dist │ │ │ ├── additional-methods.js │ │ │ ├── additional-methods.min.js │ │ │ ├── jquery.validate.js │ │ │ └── jquery.validate.min.js │ │ └── jquery │ │ ├── .bower.json │ │ ├── LICENSE.txt │ │ └── dist │ │ ├── jquery.js │ │ ├── jquery.min.js │ │ └── jquery.min.map │ ├── ServerlessTODOList.StreamProcessor │ ├── .lambda-test-tool │ │ └── SavedRequests │ │ │ └── ddb-tasks.json │ ├── Function.cs │ ├── Properties │ │ └── launchSettings.json │ ├── ServerlessTODOList.StreamProcessor.csproj │ └── aws-lambda-tools-defaults.json │ └── ServerlessTODOList.sln ├── Cdk ├── add-project.hook.d.ts ├── cdk.json └── src │ ├── ServerlessTodoListPipelineCdk.sln │ └── ServerlessTodoListPipelineCdk │ ├── Program.cs │ ├── ServerlessTodoListPipelineCdk.csproj │ └── ServerlessTodoListPipelineCdkStack.cs ├── DotnetTryMaterial ├── .DS_Store ├── ASP.NETCoreFrontend │ ├── DependencyInjection.md │ ├── FrontendWrapup.md │ ├── ParameterStoreConfigurationProvider.md │ ├── ParameterStoreDataProtection.md │ ├── TheFrontend.md │ ├── WebIdentity.md │ └── images │ │ ├── AntiForgeryToken.png │ │ ├── CreateUserPool.gif │ │ ├── CreateUserPoolAppClient.gif │ │ └── KeyStoredInParameterStore.png ├── CommonServerlessServices.md ├── DeployingFrontend │ ├── AspNetCoreAsLambda.md │ ├── DeployingFrontend.md │ ├── FargateDeploy.md │ ├── LambdaDeploy.md │ ├── LambdaPrepare.md │ ├── WhatIsFargate.md │ └── images │ │ ├── DeployServerless.gif │ │ ├── ServerlessWizard.gif │ │ ├── add-docker.png │ │ ├── cloudformation-view.png │ │ ├── ecs-view.png │ │ ├── ecs-wizard-page1.png │ │ ├── ecs-wizard-page2.png │ │ ├── ecs-wizard-page3.png │ │ ├── ecs-wizard-page4.png │ │ ├── ecs-wizard-page5.png │ │ ├── example-rest-api.png │ │ ├── lambda-wizard-page1.png │ │ ├── request-normal-flow.png │ │ ├── request-serverless-flow.png │ │ ├── solution-explorer-container.png │ │ └── solution-explorer.png ├── DotnetTryMaterial.sln ├── DynamoDBModule │ ├── CreateTable.md │ ├── DDBServiceClientAPI.md │ ├── DotNetDynamoDBAPIs.md │ ├── DotNetDynamoDBDataModel.md │ ├── DotNetDynamoDBDocumentModel.md │ ├── DynamoDBWrapUp.md │ └── WhatIsDynamoDB.md ├── FinalWrapup.md ├── GettingStarted.md ├── Snippets │ ├── ConfigureEventSourceMapping.cs │ ├── CreateTable.cs │ ├── DDBServiceClientAPI.cs │ ├── DataModelTypes.cs │ ├── DynamoDBDataModel.cs │ ├── DynamoDBDocumentModel.cs │ ├── EnableDynamoDBStream.cs │ ├── IAMRoleSetups.cs │ ├── ParameterStoreSetup.cs │ ├── SESSnippets.cs │ ├── SetConfiguration.cs │ ├── Snippets.cs │ ├── Snippets.csproj │ ├── TearDown.cs │ └── TestDynamoDBLambdaFunction.cs ├── StreamProcessing │ ├── ConfigureLambdaEventSource.md │ ├── DeployLambdaFunction.md │ ├── EnableDynamoDBStream.md │ ├── LookAtLambdaFunction.md │ ├── ServiceEvents.md │ ├── SettingUpSES.md │ ├── StreamProcessingWrapup.md │ ├── TODOTaskListAssignment.md │ ├── TestingLambdaFunction.md │ ├── TroubleshootingLambda.md │ └── images │ │ ├── DDBStreamCommandLineDeployment.gif │ │ ├── LambdaWizardPage1.png │ │ ├── LambdaWizardPage2.png │ │ ├── SolutionExplorerPublishToLambda.png │ │ ├── ToolkitAddEventSource.png │ │ └── ToolkitViewLogs.png ├── TOC.json ├── TOCBuilder │ ├── Program.cs │ └── TOCBuilder.csproj ├── TODOListServices.md ├── TearDown.md ├── WhatAreWeBuilding.md ├── WhatIsServerless.md └── images │ ├── AppInAction.gif │ ├── TutorialSetup.gif │ ├── delete-service.png │ └── serverlessapp.png ├── LICENSE └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cdk.staging 2 | cdk.out 3 | 4 | *.suo 5 | *.user 6 | 7 | **/.vs/ 8 | **/bin/ 9 | **/obj/ 10 | 11 | **/*.binlog 12 | 13 | **/.idea 14 | **/*.trydotnet-builderror 15 | 16 | .vscode/* 17 | **/.ionide/* 18 | -------------------------------------------------------------------------------- /Application/Final/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.dockerignore 2 | **/.env 3 | **/.git 4 | **/.gitignore 5 | **/.vs 6 | **/.vscode 7 | **/*.*proj.user 8 | **/azds.yaml 9 | **/charts 10 | **/bin 11 | **/obj 12 | **/Dockerfile 13 | **/Dockerfile.develop 14 | **/docker-compose.yml 15 | **/docker-compose.*.yml 16 | **/*.dbmdl 17 | **/*.jfm 18 | **/secrets.dev.yaml 19 | **/values.dev.yaml 20 | **/.toolstarget -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Common/ServerlessTODOList.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Common/TODOList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ServerlessTODOList.Common 6 | { 7 | public class TODOList 8 | { 9 | public string User { get; set; } 10 | 11 | public string ListId { get; set; } 12 | 13 | public string Name { get; set; } 14 | 15 | public List Items { get; set; } 16 | 17 | public bool Complete { get; set; } 18 | 19 | public DateTime CreateDate { get; set; } 20 | 21 | public DateTime UpdateDate { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Common/TODOListItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ServerlessTODOList.Common 6 | { 7 | public class TODOListItem 8 | { 9 | public string Description { get; set; } 10 | 11 | public string AssignedEmail { get; set; } 12 | 13 | public bool Complete { get; set; } 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.DataAccess/ITODOListDataAccess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | using ServerlessTODOList.Common; 6 | 7 | namespace ServerlessTODOList.DataAccess 8 | { 9 | public interface ITODOListDataAccess 10 | { 11 | Task> GetTODOListsForUserAsync(string user); 12 | 13 | Task GetTODOListAsync(string user, string listId); 14 | 15 | Task SaveTODOListAsync(TODOList list); 16 | 17 | Task DeleteTODOList(string user, string listId); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.DataAccess/ServerlessTODOList.DataAccess.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.DataAccess/TODOListDataAccess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | using Amazon.DynamoDBv2; 6 | using Amazon.DynamoDBv2.DataModel; 7 | 8 | using ServerlessTODOList.Common; 9 | 10 | 11 | namespace ServerlessTODOList.DataAccess 12 | { 13 | public class TODOListDataAccess : ITODOListDataAccess 14 | { 15 | DynamoDBContext Context { get; set; } 16 | 17 | public TODOListDataAccess(IAmazonDynamoDB ddbClient) 18 | { 19 | var config = new DynamoDBContextConfig 20 | { 21 | Conversion = DynamoDBEntryConversion.V2, 22 | ConsistentRead = true 23 | }; 24 | this.Context = new DynamoDBContext(ddbClient); 25 | } 26 | 27 | public async Task> GetTODOListsForUserAsync(string user) 28 | { 29 | try 30 | { 31 | var lists = await this.Context.QueryAsync(user).GetRemainingAsync(); 32 | return lists; 33 | } 34 | catch (Exception e) 35 | { 36 | throw new TODOListDataAccessException("Error getting TODO lists for user", e); 37 | } 38 | } 39 | 40 | public async Task GetTODOListAsync(string user, string listId) 41 | { 42 | try 43 | { 44 | var todoList = await this.Context.LoadAsync(user, listId); 45 | return todoList; 46 | } 47 | catch(Exception e) 48 | { 49 | throw new TODOListDataAccessException("Error getting TODO list", e); 50 | } 51 | } 52 | 53 | public async Task SaveTODOListAsync(TODOList list) 54 | { 55 | try 56 | { 57 | if (string.IsNullOrEmpty(list.ListId)) 58 | list.ListId = Guid.NewGuid().ToString(); 59 | 60 | if (list.CreateDate == DateTime.MinValue) 61 | list.CreateDate = DateTime.UtcNow; 62 | 63 | list.UpdateDate = DateTime.UtcNow; 64 | 65 | await this.Context.SaveAsync(list); 66 | } 67 | catch (Exception e) 68 | { 69 | throw new TODOListDataAccessException("Error saving TODO list", e); 70 | } 71 | } 72 | 73 | public async Task DeleteTODOList(string user, string listId) 74 | { 75 | try 76 | { 77 | await this.Context.DeleteAsync(user, listId); 78 | } 79 | catch (Exception e) 80 | { 81 | throw new TODOListDataAccessException("Error deleting TODO list", e); 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.DataAccess/TODOListDataAccessException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ServerlessTODOList.DataAccess 6 | { 7 | public class TODOListDataAccessException : Exception 8 | { 9 | public TODOListDataAccessException(string message) : base(message) { } 10 | 11 | public TODOListDataAccessException(string message, Exception innerException) : base(message, innerException) { } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/IdentityHostingStartup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | 7 | [assembly: HostingStartup(typeof(ServerlessTODOList.Frontend.Identity.IdentityHostingStartup))] 8 | namespace ServerlessTODOList.Frontend.Identity 9 | { 10 | public class IdentityHostingStartup : IHostingStartup 11 | { 12 | public void Configure(IWebHostBuilder builder) 13 | { 14 | builder.ConfigureServices((context, services) => { 15 | }); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/Account/ChangePassword.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ChangePasswordModel 3 | @{ 4 | ViewData["Title"] = "Change password"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |
9 |
10 |
11 |
12 |

Change your password.

13 |
14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 |
35 | 36 |
37 |
38 |
39 | 40 | @section Scripts { 41 | 42 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/Account/ConfirmAccount.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ConfirmAccountModel 3 | @{ 4 | ViewData["Title"] = "Confirm Account"; 5 | } 6 | 7 |

@ViewData["Title"]

8 | 9 |
10 |
11 |
12 |

Confirm your new account.

13 |
14 |
15 |
16 | 17 | 18 | 19 |
20 | 21 |
22 |
23 |
24 | 25 | @section Scripts { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/Account/ConfirmAccount.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.Linq; 4 | using System.Security.Claims; 5 | using System.Threading.Tasks; 6 | using Amazon.AspNetCore.Identity.Cognito; 7 | using Amazon.Extensions.CognitoAuthentication; 8 | using Microsoft.AspNetCore.Authorization; 9 | using Microsoft.AspNetCore.Identity; 10 | using Microsoft.AspNetCore.Mvc; 11 | using Microsoft.AspNetCore.Mvc.RazorPages; 12 | 13 | namespace ServerlessTODOList.Frontend.Identity.Pages.Account 14 | { 15 | [AllowAnonymous] 16 | public class ConfirmAccountModel : PageModel 17 | { 18 | private readonly CognitoUserManager _userManager; 19 | 20 | public ConfirmAccountModel(UserManager userManager) 21 | { 22 | _userManager = userManager as CognitoUserManager; 23 | } 24 | 25 | [BindProperty] 26 | public InputModel Input { get; set; } 27 | 28 | public string ReturnUrl { get; set; } 29 | 30 | public class InputModel 31 | { 32 | [Required] 33 | [Display(Name = "Code")] 34 | public string Code { get; set; } 35 | } 36 | 37 | public void OnGet(string returnUrl = null) 38 | { 39 | ReturnUrl = returnUrl; 40 | } 41 | 42 | public async Task OnPostAsync(string returnUrl = null) 43 | { 44 | returnUrl = returnUrl ?? Url.Content("~/"); 45 | if (ModelState.IsValid) 46 | { 47 | var userId = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name).Value; 48 | 49 | var user = await _userManager.FindByIdAsync(userId); 50 | if (user == null) 51 | { 52 | return NotFound($"Unable to load user with ID '{userId}'."); 53 | } 54 | 55 | var result = await _userManager.ConfirmSignUpAsync(user, Input.Code, true); 56 | if (!result.Succeeded) 57 | { 58 | throw new InvalidOperationException($"Error confirming account for user with ID '{userId}':"); 59 | } 60 | else 61 | { 62 | return returnUrl != null ? LocalRedirect(returnUrl) : Page() as IActionResult; 63 | } 64 | } 65 | 66 | // If we got this far, something failed, redisplay form 67 | return Page(); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/Account/LoginWith2fa.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model LoginWith2faModel 3 | @{ 4 | ViewData["Title"] = "Two-factor authentication"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |
9 |

Your login is protected by an SMS 2FA code. Enter your code below.

10 |
11 |
12 |
13 | 14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 |
22 | 26 |
27 |
28 |
29 | 30 |
31 |
32 |
33 |
34 | 35 | @section Scripts { 36 | 37 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/Account/Logout.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model LogoutModel 3 | @{ 4 | ViewData["Title"] = "Log out"; 5 | } 6 | 7 |
8 |

@ViewData["Title"]

9 |

You have successfully logged out of the application.

10 |
-------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/Account/Logout.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Amazon.Extensions.CognitoAuthentication; 2 | using Microsoft.AspNetCore.Authorization; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.Mvc.RazorPages; 6 | using Microsoft.Extensions.Logging; 7 | using System.Threading.Tasks; 8 | 9 | namespace ServerlessTODOList.Frontend.Identity.Pages.Account 10 | { 11 | [AllowAnonymous] 12 | public class LogoutModel : PageModel 13 | { 14 | private readonly SignInManager _signInManager; 15 | private readonly ILogger _logger; 16 | 17 | public LogoutModel(SignInManager signInManager, ILogger logger) 18 | { 19 | _signInManager = signInManager; 20 | _logger = logger; 21 | } 22 | 23 | public void OnGet() 24 | { 25 | } 26 | 27 | public async Task OnPost(string returnUrl = null) 28 | { 29 | await _signInManager.SignOutAsync(); 30 | _logger.LogInformation("User logged out."); 31 | if (returnUrl != null) 32 | { 33 | return LocalRedirect(returnUrl); 34 | } 35 | else 36 | { 37 | return Page(); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/Account/Register.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model RegisterModel 3 | @{ 4 | ViewData["Title"] = "Register"; 5 | } 6 | 7 |

@ViewData["Title"]

8 | 9 |
10 |
11 |
12 |

Create a new account.

13 |
14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 |
35 | 36 |
37 |
38 |
39 | 40 | @section Scripts { 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/Account/ResetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ResetPasswordModel 3 | @{ 4 | ViewData["Title"] = "Reset password"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |
9 |
10 |
11 |
12 |

Reset your password.

13 |
14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 |
35 | 36 |
37 |
38 |
39 | 40 | @section Scripts { 41 | 42 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/Account/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using ServerlessTODOList.Frontend.Identity.Pages.Account -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using ServerlessTODOList.Frontend.Identity 3 | @namespace ServerlessTODOList.Frontend.Identity.Pages 4 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 5 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Areas/Identity/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "/Pages/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/aspnet:2.1-stretch-slim AS base 2 | WORKDIR /app 3 | EXPOSE 80 4 | EXPOSE 443 5 | 6 | FROM mcr.microsoft.com/dotnet/core/sdk:2.1-stretch AS build 7 | WORKDIR /src 8 | COPY ["ServerlessTODOList.Frontend/ServerlessTODOList.Frontend.csproj", "ServerlessTODOList.Frontend/"] 9 | COPY ["ServerlessTODOList.Common/ServerlessTODOList.Common.csproj", "ServerlessTODOList.Common/"] 10 | COPY ["ServerlessTODOList.DataAccess/ServerlessTODOList.DataAccess.csproj", "ServerlessTODOList.DataAccess/"] 11 | RUN dotnet restore "ServerlessTODOList.Frontend/ServerlessTODOList.Frontend.csproj" 12 | COPY . . 13 | WORKDIR "/src/ServerlessTODOList.Frontend" 14 | RUN dotnet build "ServerlessTODOList.Frontend.csproj" -c Release -o /app 15 | 16 | FROM build AS publish 17 | RUN dotnet publish "ServerlessTODOList.Frontend.csproj" -c Release -o /app 18 | 19 | FROM base AS final 20 | WORKDIR /app 21 | COPY --from=publish /app . 22 | ENTRYPOINT ["dotnet", "ServerlessTODOList.Frontend.dll"] -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/LambdaEntryPoint.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Configuration; 3 | 4 | namespace ServerlessTODOList.Frontend 5 | { 6 | public class LambdaEntryPoint : Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction 7 | { 8 | protected override void Init(IWebHostBuilder builder) 9 | { 10 | builder 11 | .ConfigureAppConfiguration(configBuilder => 12 | { 13 | configBuilder.AddSystemsManager("/ServerlessTODOList/"); 14 | }) 15 | .UseStartup(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/CreateList.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ServerlessTODOList.Frontend.Pages.CreateListModel 3 | @{ 4 | ViewData["Title"] = "Create List"; 5 | } 6 | 7 |

Create List

8 | 9 |
10 |
11 |
12 | 13 | 14 |
15 |
16 | 17 |
-------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/CreateList.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | using ServerlessTODOList.Common; 9 | using ServerlessTODOList.DataAccess; 10 | 11 | namespace ServerlessTODOList.Frontend.Pages 12 | { 13 | public class CreateListModel : PageModel 14 | { 15 | ITODOListDataAccess DataAccess { get; set; } 16 | 17 | [BindProperty] 18 | public string Name { get; set; } 19 | 20 | 21 | public CreateListModel(ITODOListDataAccess dataAccess) 22 | { 23 | this.DataAccess = dataAccess; 24 | } 25 | 26 | public void OnGet() 27 | { 28 | 29 | } 30 | 31 | public async Task OnPost() 32 | { 33 | var list = new TODOList 34 | { 35 | User = this.User.Identity.Name, 36 | Name = this.Name 37 | }; 38 | 39 | await this.DataAccess.SaveTODOListAsync(list); 40 | return RedirectToPage("EditList", new { Id = list.ListId }); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/EditList.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ServerlessTODOList.Frontend.Pages.EditListModel 3 | @{ 4 | ViewData["Title"] = "EditList"; 5 | } 6 | 7 |

@this.Model.TODOList?.Name

8 | 9 |
10 |
11 |
12 | Add Task 13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | @if (this.Model?.TODOList?.Items != null) 30 | { 31 | @foreach (var item in this.Model.TODOList.Items) 32 | { 33 | 34 | 35 | 36 | 37 | 38 | 39 | } 40 | } 41 | 42 |
TaskAssigned EmailComplete
43 | 44 | 45 |
46 | 47 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/EditList.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | using ServerlessTODOList.Common; 9 | using ServerlessTODOList.DataAccess; 10 | 11 | namespace ServerlessTODOList.Frontend.Pages 12 | { 13 | public class EditListModel : PageModel 14 | { 15 | ITODOListDataAccess DataAccess { get; set; } 16 | 17 | public TODOList TODOList { get; set; } 18 | 19 | public EditListModel(ITODOListDataAccess dataAccess) 20 | { 21 | this.DataAccess = dataAccess; 22 | } 23 | 24 | public async Task OnGet(string id) 25 | { 26 | this.TODOList = await this.DataAccess.GetTODOListAsync(this.User.Identity.Name, id); 27 | } 28 | 29 | public async Task OnPost(string listId, string tasks) 30 | { 31 | this.TODOList = await this.DataAccess.GetTODOListAsync(this.User.Identity.Name, listId); 32 | this.TODOList.Items = Newtonsoft.Json.JsonConvert.DeserializeObject>(tasks); 33 | await this.DataAccess.SaveTODOListAsync(this.TODOList); 34 | 35 | return RedirectToPage("MyLists"); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/Error.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ErrorModel 3 | @{ 4 | ViewData["Title"] = "Error"; 5 | } 6 | 7 |

Error.

8 |

An error occurred while processing your request.

9 | 10 | @if (Model.ShowRequestId) 11 | { 12 |

13 | Request ID: @Model.RequestId 14 |

15 | } 16 | 17 |

Development Mode

18 |

19 | Swapping to Development environment will display more detailed information about the error that occurred. 20 |

21 |

22 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. 23 |

24 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | 9 | namespace ServerlessTODOList.Frontend.Pages 10 | { 11 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 12 | public class ErrorModel : PageModel 13 | { 14 | public string RequestId { get; set; } 15 | 16 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 17 | 18 | public void OnGet() 19 | { 20 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model IndexModel 3 | @{ 4 | ViewData["Title"] = "Home page"; 5 | } 6 | 7 |
8 |

9 | This is a teaching app to show how to integrate AWS services with an ASP.NET Core application. 10 |

11 |
12 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/Index.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | namespace ServerlessTODOList.Frontend.Pages 9 | { 10 | public class IndexModel : PageModel 11 | { 12 | public void OnGet() 13 | { 14 | 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/MyLists.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ServerlessTODOList.Frontend.Pages.MyListsModel 3 | @{ 4 | ViewData["Title"] = "My Lists"; 5 | } 6 | 7 |

TODO Lists

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | @if (this.Model?.TODOLists != null) 21 | { 22 | @foreach (var list in this.Model.TODOLists.OrderBy(x => x.Name)) 23 | { 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | } 32 | } 33 | 34 |
NameCreatedUpdatedTask Completed
@list.Name@list.CreateDate@list.UpdateDate@MyListsModel.FormattedCompleteCount(list)
35 | 36 | 37 |
38 |
39 | Create New List 40 |
41 |
42 | 43 |
44 | 45 |
46 | 47 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/MyLists.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | 9 | using ServerlessTODOList.Common; 10 | using ServerlessTODOList.DataAccess; 11 | 12 | namespace ServerlessTODOList.Frontend.Pages 13 | { 14 | [Authorize] 15 | public class MyListsModel : PageModel 16 | { 17 | ITODOListDataAccess DataAccess { get; set; } 18 | 19 | public IList TODOLists { get; set; } 20 | 21 | public MyListsModel(ITODOListDataAccess dataAccess) 22 | { 23 | this.DataAccess = dataAccess; 24 | } 25 | 26 | public async Task OnGet() 27 | { 28 | this.TODOLists = await this.DataAccess.GetTODOListsForUserAsync(this.User.Identity.Name); 29 | } 30 | 31 | 32 | public async Task OnPostDeleteAsync(string listIdToDelete) 33 | { 34 | await this.DataAccess.DeleteTODOList(this.User.Identity.Name, listIdToDelete); 35 | this.TODOLists = await this.DataAccess.GetTODOListsForUserAsync(this.User.Identity.Name); 36 | } 37 | 38 | 39 | public static string FormattedCompleteCount(TODOList list) 40 | { 41 | if (list.Items == null) 42 | return "0/0"; 43 | 44 | return list.Items.Where(x => x.Complete).Count() + "/" + list.Items.Count; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model PrivacyModel 3 | @{ 4 | ViewData["Title"] = "Privacy Policy"; 5 | } 6 |

@ViewData["Title"]

7 | 8 |

Use this page to detail your site's privacy policy.

-------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/Privacy.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | namespace ServerlessTODOList.Frontend.Pages 9 | { 10 | public class PrivacyModel : PageModel 11 | { 12 | public void OnGet() 13 | { 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/Shared/_CookieConsentPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Http.Features 2 | 3 | @{ 4 | var consentFeature = Context.Features.Get(); 5 | var showBanner = !consentFeature?.CanTrack ?? false; 6 | var cookieString = consentFeature?.CreateConsentCookie(); 7 | } 8 | 9 | @if (showBanner) 10 | { 11 | 33 | 41 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - ServerlessTODOList.Frontend 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 39 | 40 | 41 | 42 |
43 | @RenderBody() 44 |
45 |
46 |

© 2019 - Serverless TODO List

47 |
48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 62 | 68 | 69 | 70 | 71 | @RenderSection("Scripts", required: false) 72 | 73 | 74 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using Amazon.Extensions.CognitoAuthentication 3 | 4 | @inject SignInManager SignInManager 5 | @inject UserManager UserManager 6 | 7 | @if (SignInManager.IsSignedIn(User)) 8 | { 9 | 19 | } 20 | else 21 | { 22 | 26 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using ServerlessTODOList.Frontend 3 | @namespace ServerlessTODOList.Frontend.Pages 4 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 5 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace ServerlessTODOList.Frontend 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .ConfigureAppConfiguration(builder => 23 | { 24 | builder.AddSystemsManager("/ServerlessTODOList/"); 25 | }) 26 | .UseStartup(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:63209", 7 | "sslPort": 44335 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "ServerlessTODOList.Frontend": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | }, 26 | "Mock Lambda Test Tool": { 27 | "commandName": "Executable", 28 | "commandLineArgs": "--port 5050", 29 | "workingDirectory": ".\\bin\\Debug\\netcoreapp2.1", 30 | "executablePath": "C:\\Users\\%USERNAME%\\.dotnet\\tools\\dotnet-lambda-test-tool-2.1.exe" 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/ServerlessTODOList.Frontend.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | aspnet-ServerlessTODOList.Frontend-A9210003-C0BD-41B7-BE19-A4F5B45C1A97 6 | Lambda 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Identity; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.AspNetCore.HttpsPolicy; 10 | using Microsoft.AspNetCore.Mvc; 11 | using Microsoft.Extensions.Configuration; 12 | using Microsoft.Extensions.DependencyInjection; 13 | using Microsoft.Extensions.Hosting; 14 | using ServerlessTODOList.DataAccess; 15 | 16 | namespace ServerlessTODOList.Frontend 17 | { 18 | public class Startup 19 | { 20 | public Startup(IConfiguration configuration) 21 | { 22 | Configuration = configuration; 23 | } 24 | 25 | public IConfiguration Configuration { get; } 26 | 27 | // This method gets called by the runtime. Use this method to add services to the container. 28 | public void ConfigureServices(IServiceCollection services) 29 | { 30 | services.Configure(options => 31 | { 32 | // This lambda determines whether user consent for non-essential cookies is needed for a given request. 33 | options.CheckConsentNeeded = context => true; 34 | options.MinimumSameSitePolicy = SameSiteMode.None; 35 | }); 36 | 37 | services.AddRazorPages(); 38 | 39 | // AddAWSService is provided by the AWSSDK.Extensions.NETCore.Setup NuGet package. 40 | services.AddAWSService(); 41 | services.AddSingleton(typeof(ITODOListDataAccess), typeof(TODOListDataAccess)); 42 | 43 | // Register Cognito Identity services. 44 | services.AddCognitoIdentity(); 45 | 46 | // Register AWS System Manager's parameter store as the persistence for data protection keys. 47 | services.AddDataProtection() 48 | .PersistKeysToAWSSystemsManager("/ServerlessTODOList/DataProtection"); 49 | } 50 | 51 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 52 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 53 | { 54 | if (env.IsDevelopment()) 55 | { 56 | app.UseDeveloperExceptionPage(); 57 | } 58 | else 59 | { 60 | app.UseExceptionHandler("/Error"); 61 | app.UseHsts(); 62 | } 63 | 64 | app.UseHttpsRedirection(); 65 | app.UseStaticFiles(); 66 | 67 | app.UseRouting(); 68 | 69 | app.UseAuthentication(); 70 | app.UseAuthorization(); 71 | 72 | app.UseEndpoints(endpoints => 73 | { 74 | endpoints.MapRazorPages(); 75 | }); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | }, 4 | "Logging": { 5 | "LogLevel": { 6 | "Default": "Debug", 7 | "System": "Information", 8 | "Microsoft": "Information" 9 | } 10 | }, 11 | "AWS": { 12 | "Region": "us-west-2", 13 | "Profile": "default", 14 | "UserPoolId": "us-west-2_5orfSdaKO", 15 | "UserPoolClientId": "37i0f6pqigjtk83pcfsbovaoje", 16 | "UserPoolClientSecret": "1r31lbel1j4c04btsn216qf1g6ls0o7tpr8aqhn53onbi1tace4m" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-ServerlessTODOList.Frontend-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Warning" 8 | } 9 | }, 10 | "AllowedHosts": "*" 11 | } 12 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | env: 4 | variables: 5 | S3_BUCKET: "normj-east1" 6 | phases: 7 | install: 8 | runtime-versions: 9 | dotnet: 2.2 10 | commands: 11 | - dotnet tool install -g Amazon.Lambda.Tools 12 | build: 13 | commands: 14 | - cd ./Application/Final/ServerlessTODOList.Frontend 15 | - dotnet lambda package-ci --template serverless.template --output-template updated.template --s3-bucket $S3_BUCKET --s3-prefix ServerlessTODOList.Frontend 16 | artifacts: 17 | files: 18 | - ./Application/Final/ServerlessTODOList.Frontend/updated.template 19 | discard-paths: yes 20 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/serverless.template: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion" : "2010-09-09", 3 | "Transform" : "AWS::Serverless-2016-10-31", 4 | "Description" : "Template to deploy ASP.NET Core application for the Serverless TODO List application", 5 | 6 | "Parameters" : { 7 | }, 8 | 9 | "Conditions" : { 10 | }, 11 | 12 | "Resources" : { 13 | 14 | "AspNetCoreFunction" : { 15 | "Type" : "AWS::Serverless::Function", 16 | "Properties": { 17 | "Handler": "ServerlessTODOList.Frontend::ServerlessTODOList.Frontend.LambdaEntryPoint::FunctionHandlerAsync", 18 | "Runtime": "dotnetcore3.1", 19 | "CodeUri": "", 20 | "MemorySize": 512, 21 | "Timeout": 30, 22 | "Role": null, 23 | "Policies": [ 24 | "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", 25 | "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess", 26 | "arn:aws:iam::aws:policy/AmazonSSMFullAccess", 27 | "arn:aws:iam::aws:policy/AmazonCognitoPowerUser" 28 | ], 29 | "Environment" : { 30 | "Variables" : { 31 | } 32 | }, 33 | "Events": { 34 | "ProxyResource": { 35 | "Type": "Api", 36 | "Properties": { 37 | "Path": "/{proxy+}", 38 | "Method": "ANY" 39 | } 40 | }, 41 | "RootResource": { 42 | "Type": "Api", 43 | "Properties": { 44 | "Path": "/", 45 | "Method": "ANY" 46 | } 47 | } 48 | } 49 | } 50 | } 51 | }, 52 | 53 | "Outputs" : { 54 | "ApiURL" : { 55 | "Description" : "API endpoint URL for Prod environment", 56 | "Value" : { "Fn::Sub" : "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | body { 4 | padding-top: 50px; 5 | padding-bottom: 20px; 6 | } 7 | 8 | /* Wrapping element */ 9 | /* Set some basic padding to keep content from hitting the edges */ 10 | .body-content { 11 | padding-left: 15px; 12 | padding-right: 15px; 13 | } 14 | 15 | /* Carousel */ 16 | .carousel-caption p { 17 | font-size: 20px; 18 | line-height: 1.4; 19 | } 20 | 21 | /* Make .svg files in the carousel display properly in older browsers */ 22 | .carousel-inner .item img[src$=".svg"] { 23 | width: 100%; 24 | } 25 | 26 | /* QR code generator */ 27 | #qrCode { 28 | margin: 15px; 29 | } 30 | 31 | /* Hide/rearrange for smaller screens */ 32 | @media screen and (max-width: 767px) { 33 | /* Hide captions */ 34 | .carousel-caption { 35 | display: none; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/css/site.min.css: -------------------------------------------------------------------------------- 1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}#qrCode{margin:15px}@media screen and (max-width:767px){.carousel-caption{display:none}} -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Final/ServerlessTODOList.Frontend/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your Javascript code. 5 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/js/site.min.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Final/ServerlessTODOList.Frontend/wwwroot/js/site.min.js -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap", 3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 4 | "keywords": [ 5 | "css", 6 | "js", 7 | "less", 8 | "mobile-first", 9 | "responsive", 10 | "front-end", 11 | "framework", 12 | "web" 13 | ], 14 | "homepage": "http://getbootstrap.com", 15 | "license": "MIT", 16 | "moduleType": "globals", 17 | "main": [ 18 | "less/bootstrap.less", 19 | "dist/js/bootstrap.js" 20 | ], 21 | "ignore": [ 22 | "/.*", 23 | "_config.yml", 24 | "CNAME", 25 | "composer.json", 26 | "CONTRIBUTING.md", 27 | "docs", 28 | "js/tests", 29 | "test-infra" 30 | ], 31 | "dependencies": { 32 | "jquery": "1.9.1 - 3" 33 | }, 34 | "version": "3.3.7", 35 | "_release": "3.3.7", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.3.7", 39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86" 40 | }, 41 | "_source": "https://github.com/twbs/bootstrap.git", 42 | "_target": "v3.3.7", 43 | "_originalSource": "bootstrap", 44 | "_direct": true 45 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2016 Twitter, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/jquery-validation-unobtrusive/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation-unobtrusive", 3 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive", 4 | "version": "3.2.9", 5 | "_release": "3.2.9", 6 | "_resolution": { 7 | "type": "version", 8 | "tag": "v3.2.9", 9 | "commit": "a91f5401898e125f10771c5f5f0909d8c4c82396" 10 | }, 11 | "_source": "https://github.com/aspnet/jquery-validation-unobtrusive.git", 12 | "_target": "^3.2.9", 13 | "_originalSource": "jquery-validation-unobtrusive", 14 | "_direct": true 15 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | these files except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/jquery-validation/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation", 3 | "homepage": "https://jqueryvalidation.org/", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/jquery-validation/jquery-validation.git" 7 | }, 8 | "authors": [ 9 | "Jörn Zaefferer " 10 | ], 11 | "description": "Form validation made easy", 12 | "main": "dist/jquery.validate.js", 13 | "keywords": [ 14 | "forms", 15 | "validation", 16 | "validate" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "demo", 25 | "lib" 26 | ], 27 | "dependencies": { 28 | "jquery": ">= 1.7.2" 29 | }, 30 | "version": "1.17.0", 31 | "_release": "1.17.0", 32 | "_resolution": { 33 | "type": "version", 34 | "tag": "1.17.0", 35 | "commit": "fc9b12d3bfaa2d0c04605855b896edb2934c0772" 36 | }, 37 | "_source": "https://github.com/jzaefferer/jquery-validation.git", 38 | "_target": "^1.17.0", 39 | "_originalSource": "jquery-validation", 40 | "_direct": true 41 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/jquery-validation/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "main": "dist/jquery.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "package.json" 7 | ], 8 | "keywords": [ 9 | "jquery", 10 | "javascript", 11 | "browser", 12 | "library" 13 | ], 14 | "homepage": "https://github.com/jquery/jquery-dist", 15 | "version": "3.3.1", 16 | "_release": "3.3.1", 17 | "_resolution": { 18 | "type": "version", 19 | "tag": "3.3.1", 20 | "commit": "9e8ec3d10fad04748176144f108d7355662ae75e" 21 | }, 22 | "_source": "https://github.com/jquery/jquery-dist.git", 23 | "_target": "^3.3.1", 24 | "_originalSource": "jquery", 25 | "_direct": true 26 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.Frontend/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors, https://js.foundation/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.StreamProcessor/.lambda-test-tool/SavedRequests/ddb-tasks.json: -------------------------------------------------------------------------------- 1 | {"Records":[{"eventID":"de6437361cedca4bd5462d92d2c36a37","eventName":"MODIFY","eventVersion":"1.1","eventSource":"aws:dynamodb","awsRegion":"us-east-2","dynamodb":{"ApproximateCreationDateTime":1.559879276E9,"Keys":{"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"}},"NewImage":{"UpdateDate":{"S":"6/7/2019 3:47:55 AM"},"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"},"Complete":{"BOOL":false},"Items":{"L":[{"S":"TODO Task1"},{"S":"TODO Task2"}]},"CreateDate":{"S":"6/7/2019 3:47:55 AM"},"Name":{"S":"Test List"}},"OldImage":{"UpdateDate":{"S":"2019-06-07T01:26:44.661Z"},"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"},"Complete":{"N":"0"},"Items":{"L":[{"M":{"Description":{"S":"Task1"},"Complete":{"N":"1"}}},{"M":{"Description":{"S":"Task2"},"Complete":{"N":"0"}}}]},"CreateDate":{"S":"2019-06-07T01:26:44.661Z"},"Name":{"S":"List from DataModel"}},"SequenceNumber":"1278400000000001681088925","SizeBytes":386,"StreamViewType":"NEW_AND_OLD_IMAGES"},"eventSourceARN":"arn:aws:dynamodb:us-east-2:626492997873:table/TODOList/stream/2019-06-07T03:46:43.395"},{"eventID":"622e4c7769418554794f8f64b6048f57","eventName":"MODIFY","eventVersion":"1.1","eventSource":"aws:dynamodb","awsRegion":"us-east-2","dynamodb":{"ApproximateCreationDateTime":1.559879545E9,"Keys":{"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"}},"NewImage":{"UpdateDate":{"S":"6/7/2019 3:52:24 AM"},"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"},"Complete":{"BOOL":false},"Items":{"L":[{"S":"TODO Task1"},{"S":"TODO Task2"}]},"CreateDate":{"S":"6/7/2019 3:52:24 AM"},"Name":{"S":"Test List"}},"OldImage":{"UpdateDate":{"S":"6/7/2019 3:47:55 AM"},"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"},"Complete":{"BOOL":false},"Items":{"L":[{"S":"TODO Task1"},{"S":"TODO Task2"}]},"CreateDate":{"S":"6/7/2019 3:47:55 AM"},"Name":{"S":"Test List"}},"SequenceNumber":"1278500000000001681097628","SizeBytes":325,"StreamViewType":"NEW_AND_OLD_IMAGES"},"eventSourceARN":"arn:aws:dynamodb:us-east-2:626492997873:table/TODOList/stream/2019-06-07T03:46:43.395"}]} -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.StreamProcessor/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\Debug\\netcoreapp2.1", 7 | "executablePath": "C:\\Users\\%USERNAME%\\.dotnet\\tools\\dotnet-lambda-test-tool-2.1.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.StreamProcessor/ServerlessTODOList.StreamProcessor.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netcoreapp3.1 4 | true 5 | Lambda 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.StreamProcessor/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "Information" : [ 4 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 5 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 6 | "dotnet lambda help", 7 | "All the command line options for the Lambda command can be specified in this file." 8 | ], 9 | "profile" : "", 10 | "region" : "", 11 | "configuration" : "Release", 12 | "framework" : "netcoreapp3.1", 13 | "function-runtime" : "dotnetcore3.1", 14 | "function-memory-size" : 256, 15 | "function-timeout" : 30, 16 | "function-handler" : "ServerlessTODOList.StreamProcessor::ServerlessTODOList.StreamProcessor.Function::FunctionHandler", 17 | "function-name" : "ServerlessTODOListStreamProcessor", 18 | "function-role" : "", 19 | "tracing-mode" : "PassThrough", 20 | "environment-variables" : "" 21 | } -------------------------------------------------------------------------------- /Application/Final/ServerlessTODOList.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29001.49 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerlessTODOList.DataAccess", "ServerlessTODOList.DataAccess\ServerlessTODOList.DataAccess.csproj", "{5F5BCE1D-27B3-45B2-8AC6-B5E3A38E8398}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerlessTODOList.Common", "ServerlessTODOList.Common\ServerlessTODOList.Common.csproj", "{3BF67B62-D085-415E-80FB-E0E067A41C8F}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerlessTODOList.Frontend", "ServerlessTODOList.Frontend\ServerlessTODOList.Frontend.csproj", "{BB61C43E-D521-4294-914B-44DBDD90FABC}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerlessTODOList.StreamProcessor", "ServerlessTODOList.StreamProcessor\ServerlessTODOList.StreamProcessor.csproj", "{E0B6B0BC-E375-4992-8F73-E8CA8AD3A96C}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {5F5BCE1D-27B3-45B2-8AC6-B5E3A38E8398}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {5F5BCE1D-27B3-45B2-8AC6-B5E3A38E8398}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {5F5BCE1D-27B3-45B2-8AC6-B5E3A38E8398}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {5F5BCE1D-27B3-45B2-8AC6-B5E3A38E8398}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {3BF67B62-D085-415E-80FB-E0E067A41C8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {3BF67B62-D085-415E-80FB-E0E067A41C8F}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {3BF67B62-D085-415E-80FB-E0E067A41C8F}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {3BF67B62-D085-415E-80FB-E0E067A41C8F}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {BB61C43E-D521-4294-914B-44DBDD90FABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {BB61C43E-D521-4294-914B-44DBDD90FABC}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {BB61C43E-D521-4294-914B-44DBDD90FABC}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {BB61C43E-D521-4294-914B-44DBDD90FABC}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {E0B6B0BC-E375-4992-8F73-E8CA8AD3A96C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {E0B6B0BC-E375-4992-8F73-E8CA8AD3A96C}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {E0B6B0BC-E375-4992-8F73-E8CA8AD3A96C}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {E0B6B0BC-E375-4992-8F73-E8CA8AD3A96C}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {BD47897A-A4B8-4621-BCE4-74AEFF1B7E03} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/IdentityHostingStartup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.AspNetCore.Identity.UI; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.DependencyInjection; 8 | 9 | [assembly: HostingStartup(typeof(ServerlessTODOList.Frontend.Identity.IdentityHostingStartup))] 10 | namespace ServerlessTODOList.Frontend.Identity 11 | { 12 | public class IdentityHostingStartup : IHostingStartup 13 | { 14 | public void Configure(IWebHostBuilder builder) 15 | { 16 | builder.ConfigureServices((context, services) => { 17 | }); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/Account/ChangePassword.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ChangePasswordModel 3 | @{ 4 | ViewData["Title"] = "Change password"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |
9 |
10 |
11 |
12 |

Change your password.

13 |
14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 |
35 | 36 |
37 |
38 |
39 | 40 | @section Scripts { 41 | 42 | } -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/Account/ConfirmAccount.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ConfirmAccountModel 3 | @{ 4 | ViewData["Title"] = "Confirm Account"; 5 | } 6 | 7 |

@ViewData["Title"]

8 | 9 |
10 |
11 |
12 |

Confirm your new account.

13 |
14 |
15 |
16 | 17 | 18 | 19 |
20 | 21 |
22 |
23 |
24 | 25 | @section Scripts { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/Account/ConfirmAccount.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.Linq; 4 | using System.Security.Claims; 5 | using System.Threading.Tasks; 6 | using Amazon.AspNetCore.Identity.Cognito; 7 | using Amazon.Extensions.CognitoAuthentication; 8 | using Microsoft.AspNetCore.Authorization; 9 | using Microsoft.AspNetCore.Identity; 10 | using Microsoft.AspNetCore.Mvc; 11 | using Microsoft.AspNetCore.Mvc.RazorPages; 12 | 13 | namespace ServerlessTODOList.Frontend.Identity.Pages.Account 14 | { 15 | [AllowAnonymous] 16 | public class ConfirmAccountModel : PageModel 17 | { 18 | private readonly CognitoUserManager _userManager; 19 | 20 | public ConfirmAccountModel(UserManager userManager) 21 | { 22 | _userManager = userManager as CognitoUserManager; 23 | } 24 | 25 | [BindProperty] 26 | public InputModel Input { get; set; } 27 | 28 | public string ReturnUrl { get; set; } 29 | 30 | public class InputModel 31 | { 32 | [Required] 33 | [Display(Name = "Code")] 34 | public string Code { get; set; } 35 | } 36 | 37 | public void OnGet(string returnUrl = null) 38 | { 39 | ReturnUrl = returnUrl; 40 | } 41 | 42 | public async Task OnPostAsync(string returnUrl = null) 43 | { 44 | returnUrl = returnUrl ?? Url.Content("~/"); 45 | if (ModelState.IsValid) 46 | { 47 | var userId = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name).Value; 48 | 49 | var user = await _userManager.FindByIdAsync(userId); 50 | if (user == null) 51 | { 52 | return NotFound($"Unable to load user with ID '{userId}'."); 53 | } 54 | 55 | var result = await _userManager.ConfirmSignUpAsync(user, Input.Code, true); 56 | if (!result.Succeeded) 57 | { 58 | throw new InvalidOperationException($"Error confirming account for user with ID '{userId}':"); 59 | } 60 | else 61 | { 62 | return returnUrl != null ? LocalRedirect(returnUrl) : Page() as IActionResult; 63 | } 64 | } 65 | 66 | // If we got this far, something failed, redisplay form 67 | return Page(); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/Account/LoginWith2fa.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model LoginWith2faModel 3 | @{ 4 | ViewData["Title"] = "Two-factor authentication"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |
9 |

Your login is protected by an SMS 2FA code. Enter your code below.

10 |
11 |
12 |
13 | 14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 |
22 | 26 |
27 |
28 |
29 | 30 |
31 |
32 |
33 |
34 | 35 | @section Scripts { 36 | 37 | } -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/Account/Logout.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model LogoutModel 3 | @{ 4 | ViewData["Title"] = "Log out"; 5 | } 6 | 7 |
8 |

@ViewData["Title"]

9 |

You have successfully logged out of the application.

10 |
-------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/Account/Logout.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Amazon.Extensions.CognitoAuthentication; 2 | using Microsoft.AspNetCore.Authorization; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.Mvc.RazorPages; 6 | using Microsoft.Extensions.Logging; 7 | using System.Threading.Tasks; 8 | 9 | namespace ServerlessTODOList.Frontend.Identity.Pages.Account 10 | { 11 | [AllowAnonymous] 12 | public class LogoutModel : PageModel 13 | { 14 | private readonly SignInManager _signInManager; 15 | private readonly ILogger _logger; 16 | 17 | public LogoutModel(SignInManager signInManager, ILogger logger) 18 | { 19 | _signInManager = signInManager; 20 | _logger = logger; 21 | } 22 | 23 | public void OnGet() 24 | { 25 | } 26 | 27 | public async Task OnPost(string returnUrl = null) 28 | { 29 | await _signInManager.SignOutAsync(); 30 | _logger.LogInformation("User logged out."); 31 | if (returnUrl != null) 32 | { 33 | return LocalRedirect(returnUrl); 34 | } 35 | else 36 | { 37 | return Page(); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/Account/Register.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model RegisterModel 3 | @{ 4 | ViewData["Title"] = "Register"; 5 | } 6 | 7 |

@ViewData["Title"]

8 | 9 |
10 |
11 |
12 |

Create a new account.

13 |
14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 |
35 | 36 |
37 |
38 |
39 | 40 | @section Scripts { 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/Account/ResetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ResetPasswordModel 3 | @{ 4 | ViewData["Title"] = "Reset password"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |
9 |
10 |
11 |
12 |

Reset your password.

13 |
14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 |
35 | 36 |
37 |
38 |
39 | 40 | @section Scripts { 41 | 42 | } -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/Account/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using ServerlessTODOList.Frontend.Identity.Pages.Account -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using ServerlessTODOList.Frontend.Identity 3 | @using Microsoft.AspNetCore.Identity 4 | @namespace ServerlessTODOList.Frontend.Identity.Pages 5 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 6 | -------------------------------------------------------------------------------- /Application/IdentityScaffolding/Areas/Identity/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "/Pages/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Common/ServerlessTODOList.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Common/TODOList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ServerlessTODOList.Common 6 | { 7 | public class TODOList 8 | { 9 | public string User { get; set; } 10 | 11 | public string ListId { get; set; } 12 | 13 | public string Name { get; set; } 14 | 15 | public List Items { get; set; } 16 | 17 | public bool Complete { get; set; } 18 | 19 | public DateTime CreateDate { get; set; } 20 | 21 | public DateTime UpdateDate { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Common/TODOListItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ServerlessTODOList.Common 6 | { 7 | public class TODOListItem 8 | { 9 | public string Description { get; set; } 10 | 11 | public string AssignedEmail { get; set; } 12 | 13 | public bool Complete { get; set; } 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.DataAccess/ITODOListDataAccess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | using ServerlessTODOList.Common; 6 | 7 | namespace ServerlessTODOList.DataAccess 8 | { 9 | public interface ITODOListDataAccess 10 | { 11 | Task> GetTODOListsForUserAsync(string user); 12 | 13 | Task GetTODOListAsync(string user, string listId); 14 | 15 | Task SaveTODOListAsync(TODOList list); 16 | 17 | Task DeleteTODOList(string user, string listId); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.DataAccess/ServerlessTODOList.DataAccess.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.DataAccess/TODOListDataAccess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | using Amazon.DynamoDBv2; 6 | using Amazon.DynamoDBv2.DataModel; 7 | 8 | using ServerlessTODOList.Common; 9 | 10 | 11 | namespace ServerlessTODOList.DataAccess 12 | { 13 | public class TODOListDataAccess : ITODOListDataAccess 14 | { 15 | DynamoDBContext Context { get; set; } 16 | 17 | public TODOListDataAccess(IAmazonDynamoDB ddbClient) 18 | { 19 | var config = new DynamoDBContextConfig 20 | { 21 | Conversion = DynamoDBEntryConversion.V2, 22 | ConsistentRead = true 23 | }; 24 | this.Context = new DynamoDBContext(ddbClient); 25 | } 26 | 27 | public async Task> GetTODOListsForUserAsync(string user) 28 | { 29 | try 30 | { 31 | var lists = await this.Context.QueryAsync(user).GetRemainingAsync(); 32 | return lists; 33 | } 34 | catch (Exception e) 35 | { 36 | throw new TODOListDataAccessException("Error getting TODO lists for user", e); 37 | } 38 | } 39 | 40 | public async Task GetTODOListAsync(string user, string listId) 41 | { 42 | try 43 | { 44 | var todoList = await this.Context.LoadAsync(user, listId); 45 | return todoList; 46 | } 47 | catch(Exception e) 48 | { 49 | throw new TODOListDataAccessException("Error getting TODO list", e); 50 | } 51 | } 52 | 53 | public async Task SaveTODOListAsync(TODOList list) 54 | { 55 | try 56 | { 57 | if (string.IsNullOrEmpty(list.ListId)) 58 | list.ListId = Guid.NewGuid().ToString(); 59 | 60 | if (list.CreateDate == DateTime.MinValue) 61 | list.CreateDate = DateTime.UtcNow; 62 | 63 | list.UpdateDate = DateTime.UtcNow; 64 | 65 | await this.Context.SaveAsync(list); 66 | } 67 | catch (Exception e) 68 | { 69 | throw new TODOListDataAccessException("Error saving TODO list", e); 70 | } 71 | } 72 | 73 | public async Task DeleteTODOList(string user, string listId) 74 | { 75 | try 76 | { 77 | await this.Context.DeleteAsync(user, listId); 78 | } 79 | catch (Exception e) 80 | { 81 | throw new TODOListDataAccessException("Error deleting TODO list", e); 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.DataAccess/TODOListDataAccessException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ServerlessTODOList.DataAccess 6 | { 7 | public class TODOListDataAccessException : Exception 8 | { 9 | public TODOListDataAccessException(string message) : base(message) { } 10 | 11 | public TODOListDataAccessException(string message, Exception innerException) : base(message, innerException) { } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Areas/Identity/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "/Pages/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Data/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace ServerlessTODOList.Frontend.Data 8 | { 9 | public class ApplicationDbContext : IdentityDbContext 10 | { 11 | public ApplicationDbContext(DbContextOptions options) 12 | : base(options) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/CreateList.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ServerlessTODOList.Frontend.Pages.CreateListModel 3 | @{ 4 | ViewData["Title"] = "Create List"; 5 | } 6 | 7 |

Create List

8 | 9 |
10 |
11 |
12 | 13 | 14 |
15 |
16 | 17 |
-------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/CreateList.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | using ServerlessTODOList.Common; 9 | using ServerlessTODOList.DataAccess; 10 | 11 | namespace ServerlessTODOList.Frontend.Pages 12 | { 13 | public class CreateListModel : PageModel 14 | { 15 | ITODOListDataAccess DataAccess { get; set; } 16 | 17 | [BindProperty] 18 | public string Name { get; set; } 19 | 20 | 21 | public CreateListModel(ITODOListDataAccess dataAccess) 22 | { 23 | this.DataAccess = dataAccess; 24 | } 25 | 26 | public void OnGet() 27 | { 28 | 29 | } 30 | 31 | public async Task OnPost() 32 | { 33 | var list = new TODOList 34 | { 35 | User = this.User.Identity.Name, 36 | Name = this.Name 37 | }; 38 | 39 | await this.DataAccess.SaveTODOListAsync(list); 40 | return RedirectToPage("EditList", new { Id = list.ListId }); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/EditList.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ServerlessTODOList.Frontend.Pages.EditListModel 3 | @{ 4 | ViewData["Title"] = "EditList"; 5 | } 6 | 7 |

@this.Model.TODOList?.Name

8 | 9 |
10 |
11 |
12 | Add Task 13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | @if (this.Model?.TODOList?.Items != null) 30 | { 31 | @foreach (var item in this.Model.TODOList.Items) 32 | { 33 | 34 | 35 | 36 | 37 | 38 | 39 | } 40 | } 41 | 42 |
TaskAssigned EmailComplete
43 | 44 | 45 |
46 | 47 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/EditList.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | using ServerlessTODOList.Common; 9 | using ServerlessTODOList.DataAccess; 10 | 11 | namespace ServerlessTODOList.Frontend.Pages 12 | { 13 | public class EditListModel : PageModel 14 | { 15 | ITODOListDataAccess DataAccess { get; set; } 16 | 17 | public TODOList TODOList { get; set; } 18 | 19 | public EditListModel(ITODOListDataAccess dataAccess) 20 | { 21 | this.DataAccess = dataAccess; 22 | } 23 | 24 | public async Task OnGet(string id) 25 | { 26 | this.TODOList = await this.DataAccess.GetTODOListAsync(this.User.Identity.Name, id); 27 | } 28 | 29 | public async Task OnPost(string listId, string tasks) 30 | { 31 | this.TODOList = await this.DataAccess.GetTODOListAsync(this.User.Identity.Name, listId); 32 | this.TODOList.Items = Newtonsoft.Json.JsonConvert.DeserializeObject>(tasks); 33 | await this.DataAccess.SaveTODOListAsync(this.TODOList); 34 | 35 | return RedirectToPage("MyLists"); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/Error.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ErrorModel 3 | @{ 4 | ViewData["Title"] = "Error"; 5 | } 6 | 7 |

Error.

8 |

An error occurred while processing your request.

9 | 10 | @if (Model.ShowRequestId) 11 | { 12 |

13 | Request ID: @Model.RequestId 14 |

15 | } 16 | 17 |

Development Mode

18 |

19 | Swapping to Development environment will display more detailed information about the error that occurred. 20 |

21 |

22 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. 23 |

24 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | 9 | namespace ServerlessTODOList.Frontend.Pages 10 | { 11 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 12 | public class ErrorModel : PageModel 13 | { 14 | public string RequestId { get; set; } 15 | 16 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 17 | 18 | public void OnGet() 19 | { 20 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model IndexModel 3 | @{ 4 | ViewData["Title"] = "Home page"; 5 | } 6 | 7 |
8 |

9 | This is a teaching app to show how to integrate AWS services with an ASP.NET Core application. 10 |

11 |
12 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/Index.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | namespace ServerlessTODOList.Frontend.Pages 9 | { 10 | public class IndexModel : PageModel 11 | { 12 | public void OnGet() 13 | { 14 | 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/MyLists.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ServerlessTODOList.Frontend.Pages.MyListsModel 3 | @{ 4 | ViewData["Title"] = "My Lists"; 5 | } 6 | 7 |

TODO Lists

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | @if (this.Model?.TODOLists != null) 21 | { 22 | @foreach (var list in this.Model.TODOLists.OrderBy(x => x.Name)) 23 | { 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | } 32 | } 33 | 34 |
NameCreatedUpdatedTask Completed
@list.Name@list.CreateDate@list.UpdateDate@MyListsModel.FormattedCompleteCount(list)
35 | 36 | 37 |
38 |
39 | Create New List 40 |
41 |
42 | 43 |
44 | 45 |
46 | 47 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/MyLists.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | 9 | using ServerlessTODOList.Common; 10 | using ServerlessTODOList.DataAccess; 11 | 12 | namespace ServerlessTODOList.Frontend.Pages 13 | { 14 | [Authorize] 15 | public class MyListsModel : PageModel 16 | { 17 | ITODOListDataAccess DataAccess { get; set; } 18 | 19 | public IList TODOLists { get; set; } 20 | 21 | public MyListsModel(ITODOListDataAccess dataAccess) 22 | { 23 | this.DataAccess = dataAccess; 24 | } 25 | 26 | public async Task OnGet() 27 | { 28 | this.TODOLists = await this.DataAccess.GetTODOListsForUserAsync(this.User.Identity.Name); 29 | } 30 | 31 | 32 | public async Task OnPostDeleteAsync(string listIdToDelete) 33 | { 34 | await this.DataAccess.DeleteTODOList(this.User.Identity.Name, listIdToDelete); 35 | this.TODOLists = await this.DataAccess.GetTODOListsForUserAsync(this.User.Identity.Name); 36 | } 37 | 38 | 39 | public static string FormattedCompleteCount(TODOList list) 40 | { 41 | if (list.Items == null) 42 | return "0/0"; 43 | 44 | return list.Items.Where(x => x.Complete).Count() + "/" + list.Items.Count; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model PrivacyModel 3 | @{ 4 | ViewData["Title"] = "Privacy Policy"; 5 | } 6 |

@ViewData["Title"]

7 | 8 |

Use this page to detail your site's privacy policy.

-------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/Privacy.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | 8 | namespace ServerlessTODOList.Frontend.Pages 9 | { 10 | public class PrivacyModel : PageModel 11 | { 12 | public void OnGet() 13 | { 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/Shared/_CookieConsentPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Http.Features 2 | 3 | @{ 4 | var consentFeature = Context.Features.Get(); 5 | var showBanner = !consentFeature?.CanTrack ?? false; 6 | var cookieString = consentFeature?.CreateConsentCookie(); 7 | } 8 | 9 | @if (showBanner) 10 | { 11 | 33 | 41 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - ServerlessTODOList.Frontend 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 39 | 40 | 41 | 42 |
43 | @RenderBody() 44 |
45 |
46 |

© 2019 - Serverless TODO List

47 |
48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 62 | 68 | 69 | 70 | 71 | @RenderSection("Scripts", required: false) 72 | 73 | 74 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | 3 | @inject SignInManager SignInManager 4 | @inject UserManager UserManager 5 | 6 | @if (SignInManager.IsSignedIn(User)) 7 | { 8 | 18 | } 19 | else 20 | { 21 | 25 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using ServerlessTODOList.Frontend 3 | @namespace ServerlessTODOList.Frontend.Pages 4 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 5 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace ServerlessTODOList.Frontend 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:63209", 7 | "sslPort": 44335 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "ServerlessTODOList.Frontend": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/ServerlessTODOList.Frontend.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | aspnet-ServerlessTODOList.Frontend-A9210003-C0BD-41B7-BE19-A4F5B45C1A97 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Identity; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.AspNetCore.HttpsPolicy; 10 | using Microsoft.AspNetCore.Mvc; 11 | using Microsoft.EntityFrameworkCore; 12 | using Microsoft.Extensions.Configuration; 13 | using Microsoft.Extensions.DependencyInjection; 14 | using Microsoft.Extensions.Hosting; 15 | 16 | using ServerlessTODOList.DataAccess; 17 | using ServerlessTODOList.Frontend.Data; 18 | 19 | namespace ServerlessTODOList.Frontend 20 | { 21 | public class Startup 22 | { 23 | public Startup(IConfiguration configuration) 24 | { 25 | Configuration = configuration; 26 | } 27 | 28 | public IConfiguration Configuration { get; } 29 | 30 | // This method gets called by the runtime. Use this method to add services to the container. 31 | public void ConfigureServices(IServiceCollection services) 32 | { 33 | services.Configure(options => 34 | { 35 | // This lambda determines whether user consent for non-essential cookies is needed for a given request. 36 | options.CheckConsentNeeded = context => true; 37 | options.MinimumSameSitePolicy = SameSiteMode.None; 38 | }); 39 | 40 | services.AddRazorPages(); 41 | 42 | // AddAWSService is provided by the AWSSDK.Extensions.NETCore.Setup NuGet package. 43 | services.AddAWSService(); 44 | services.AddSingleton(typeof(ITODOListDataAccess), typeof(TODOListDataAccess)); 45 | 46 | 47 | // Default SQL Server Entity Framework Identity setup 48 | services.AddDbContext(options => 49 | options.UseSqlServer( 50 | Configuration.GetConnectionString("DefaultConnection"))); 51 | services.AddDefaultIdentity() 52 | .AddEntityFrameworkStores(); 53 | 54 | } 55 | 56 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 57 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 58 | { 59 | if (env.IsDevelopment()) 60 | { 61 | app.UseDeveloperExceptionPage(); 62 | app.UseDatabaseErrorPage(); 63 | } 64 | else 65 | { 66 | app.UseExceptionHandler("/Error"); 67 | app.UseHsts(); 68 | } 69 | 70 | app.UseHttpsRedirection(); 71 | app.UseStaticFiles(); 72 | 73 | app.UseRouting(); 74 | 75 | app.UseAuthentication(); 76 | app.UseAuthorization(); 77 | 78 | app.UseEndpoints(endpoints => 79 | { 80 | endpoints.MapRazorPages(); 81 | }); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-ServerlessTODOList-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Debug", 8 | "System": "Information", 9 | "Microsoft": "Information" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-ServerlessTODOList.Frontend-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Warning" 8 | } 9 | }, 10 | "AllowedHosts": "*" 11 | } 12 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | body { 4 | padding-top: 50px; 5 | padding-bottom: 20px; 6 | } 7 | 8 | /* Wrapping element */ 9 | /* Set some basic padding to keep content from hitting the edges */ 10 | .body-content { 11 | padding-left: 15px; 12 | padding-right: 15px; 13 | } 14 | 15 | /* Carousel */ 16 | .carousel-caption p { 17 | font-size: 20px; 18 | line-height: 1.4; 19 | } 20 | 21 | /* Make .svg files in the carousel display properly in older browsers */ 22 | .carousel-inner .item img[src$=".svg"] { 23 | width: 100%; 24 | } 25 | 26 | /* QR code generator */ 27 | #qrCode { 28 | margin: 15px; 29 | } 30 | 31 | /* Hide/rearrange for smaller screens */ 32 | @media screen and (max-width: 767px) { 33 | /* Hide captions */ 34 | .carousel-caption { 35 | display: none; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/css/site.min.css: -------------------------------------------------------------------------------- 1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}#qrCode{margin:15px}@media screen and (max-width:767px){.carousel-caption{display:none}} -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Start/ServerlessTODOList.Frontend/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your Javascript code. 5 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/js/site.min.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Start/ServerlessTODOList.Frontend/wwwroot/js/site.min.js -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap", 3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 4 | "keywords": [ 5 | "css", 6 | "js", 7 | "less", 8 | "mobile-first", 9 | "responsive", 10 | "front-end", 11 | "framework", 12 | "web" 13 | ], 14 | "homepage": "http://getbootstrap.com", 15 | "license": "MIT", 16 | "moduleType": "globals", 17 | "main": [ 18 | "less/bootstrap.less", 19 | "dist/js/bootstrap.js" 20 | ], 21 | "ignore": [ 22 | "/.*", 23 | "_config.yml", 24 | "CNAME", 25 | "composer.json", 26 | "CONTRIBUTING.md", 27 | "docs", 28 | "js/tests", 29 | "test-infra" 30 | ], 31 | "dependencies": { 32 | "jquery": "1.9.1 - 3" 33 | }, 34 | "version": "3.3.7", 35 | "_release": "3.3.7", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.3.7", 39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86" 40 | }, 41 | "_source": "https://github.com/twbs/bootstrap.git", 42 | "_target": "v3.3.7", 43 | "_originalSource": "bootstrap", 44 | "_direct": true 45 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2016 Twitter, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/bootstrap/dist/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/jquery-validation-unobtrusive/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation-unobtrusive", 3 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive", 4 | "version": "3.2.9", 5 | "_release": "3.2.9", 6 | "_resolution": { 7 | "type": "version", 8 | "tag": "v3.2.9", 9 | "commit": "a91f5401898e125f10771c5f5f0909d8c4c82396" 10 | }, 11 | "_source": "https://github.com/aspnet/jquery-validation-unobtrusive.git", 12 | "_target": "^3.2.9", 13 | "_originalSource": "jquery-validation-unobtrusive", 14 | "_direct": true 15 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | these files except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/jquery-validation/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation", 3 | "homepage": "https://jqueryvalidation.org/", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/jquery-validation/jquery-validation.git" 7 | }, 8 | "authors": [ 9 | "Jörn Zaefferer " 10 | ], 11 | "description": "Form validation made easy", 12 | "main": "dist/jquery.validate.js", 13 | "keywords": [ 14 | "forms", 15 | "validation", 16 | "validate" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "demo", 25 | "lib" 26 | ], 27 | "dependencies": { 28 | "jquery": ">= 1.7.2" 29 | }, 30 | "version": "1.17.0", 31 | "_release": "1.17.0", 32 | "_resolution": { 33 | "type": "version", 34 | "tag": "1.17.0", 35 | "commit": "fc9b12d3bfaa2d0c04605855b896edb2934c0772" 36 | }, 37 | "_source": "https://github.com/jzaefferer/jquery-validation.git", 38 | "_target": "^1.17.0", 39 | "_originalSource": "jquery-validation", 40 | "_direct": true 41 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/jquery-validation/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "main": "dist/jquery.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "package.json" 7 | ], 8 | "keywords": [ 9 | "jquery", 10 | "javascript", 11 | "browser", 12 | "library" 13 | ], 14 | "homepage": "https://github.com/jquery/jquery-dist", 15 | "version": "3.3.1", 16 | "_release": "3.3.1", 17 | "_resolution": { 18 | "type": "version", 19 | "tag": "3.3.1", 20 | "commit": "9e8ec3d10fad04748176144f108d7355662ae75e" 21 | }, 22 | "_source": "https://github.com/jquery/jquery-dist.git", 23 | "_target": "^3.3.1", 24 | "_originalSource": "jquery", 25 | "_direct": true 26 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.Frontend/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors, https://js.foundation/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.StreamProcessor/.lambda-test-tool/SavedRequests/ddb-tasks.json: -------------------------------------------------------------------------------- 1 | {"Records":[{"eventID":"de6437361cedca4bd5462d92d2c36a37","eventName":"MODIFY","eventVersion":"1.1","eventSource":"aws:dynamodb","awsRegion":"us-east-2","dynamodb":{"ApproximateCreationDateTime":1.559879276E9,"Keys":{"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"}},"NewImage":{"UpdateDate":{"S":"6/7/2019 3:47:55 AM"},"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"},"Complete":{"BOOL":false},"Items":{"L":[{"S":"TODO Task1"},{"S":"TODO Task2"}]},"CreateDate":{"S":"6/7/2019 3:47:55 AM"},"Name":{"S":"Test List"}},"OldImage":{"UpdateDate":{"S":"2019-06-07T01:26:44.661Z"},"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"},"Complete":{"N":"0"},"Items":{"L":[{"M":{"Description":{"S":"Task1"},"Complete":{"N":"1"}}},{"M":{"Description":{"S":"Task2"},"Complete":{"N":"0"}}}]},"CreateDate":{"S":"2019-06-07T01:26:44.661Z"},"Name":{"S":"List from DataModel"}},"SequenceNumber":"1278400000000001681088925","SizeBytes":386,"StreamViewType":"NEW_AND_OLD_IMAGES"},"eventSourceARN":"arn:aws:dynamodb:us-east-2:626492997873:table/TODOList/stream/2019-06-07T03:46:43.395"},{"eventID":"622e4c7769418554794f8f64b6048f57","eventName":"MODIFY","eventVersion":"1.1","eventSource":"aws:dynamodb","awsRegion":"us-east-2","dynamodb":{"ApproximateCreationDateTime":1.559879545E9,"Keys":{"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"}},"NewImage":{"UpdateDate":{"S":"6/7/2019 3:52:24 AM"},"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"},"Complete":{"BOOL":false},"Items":{"L":[{"S":"TODO Task1"},{"S":"TODO Task2"}]},"CreateDate":{"S":"6/7/2019 3:52:24 AM"},"Name":{"S":"Test List"}},"OldImage":{"UpdateDate":{"S":"6/7/2019 3:47:55 AM"},"User":{"S":"testuser"},"ListId":{"S":"generated-list-id"},"Complete":{"BOOL":false},"Items":{"L":[{"S":"TODO Task1"},{"S":"TODO Task2"}]},"CreateDate":{"S":"6/7/2019 3:47:55 AM"},"Name":{"S":"Test List"}},"SequenceNumber":"1278500000000001681097628","SizeBytes":325,"StreamViewType":"NEW_AND_OLD_IMAGES"},"eventSourceARN":"arn:aws:dynamodb:us-east-2:626492997873:table/TODOList/stream/2019-06-07T03:46:43.395"}]} -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.StreamProcessor/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Mock Lambda Test Tool": { 4 | "commandName": "Executable", 5 | "commandLineArgs": "--port 5050", 6 | "workingDirectory": ".\\bin\\Debug\\netcoreapp2.1", 7 | "executablePath": "C:\\Users\\%USERNAME%\\.dotnet\\tools\\dotnet-lambda-test-tool-2.1.exe" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.StreamProcessor/ServerlessTODOList.StreamProcessor.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netcoreapp3.1 4 | true 5 | Lambda 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.StreamProcessor/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "Information" : [ 4 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 5 | "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", 6 | "dotnet lambda help", 7 | "All the command line options for the Lambda command can be specified in this file." 8 | ], 9 | "profile" : "default", 10 | "region" : "us-east-1", 11 | "configuration" : "Release", 12 | "framework" : "netcoreapp3.1", 13 | "function-runtime" : "dotnetcore3.1", 14 | "function-memory-size" : 256, 15 | "function-timeout" : 30, 16 | "function-handler" : "ServerlessTODOList.StreamProcessor::ServerlessTODOList.StreamProcessor.Function::FunctionHandler", 17 | "function-name" : "ServerlessTODOListStreamProcessor", 18 | "function-role" : "", 19 | "tracing-mode" : "PassThrough", 20 | "environment-variables" : "" 21 | } -------------------------------------------------------------------------------- /Application/Start/ServerlessTODOList.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29001.49 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerlessTODOList.DataAccess", "ServerlessTODOList.DataAccess\ServerlessTODOList.DataAccess.csproj", "{5F5BCE1D-27B3-45B2-8AC6-B5E3A38E8398}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerlessTODOList.Common", "ServerlessTODOList.Common\ServerlessTODOList.Common.csproj", "{3BF67B62-D085-415E-80FB-E0E067A41C8F}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerlessTODOList.Frontend", "ServerlessTODOList.Frontend\ServerlessTODOList.Frontend.csproj", "{BB61C43E-D521-4294-914B-44DBDD90FABC}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerlessTODOList.StreamProcessor", "ServerlessTODOList.StreamProcessor\ServerlessTODOList.StreamProcessor.csproj", "{E0B6B0BC-E375-4992-8F73-E8CA8AD3A96C}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {5F5BCE1D-27B3-45B2-8AC6-B5E3A38E8398}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {5F5BCE1D-27B3-45B2-8AC6-B5E3A38E8398}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {5F5BCE1D-27B3-45B2-8AC6-B5E3A38E8398}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {5F5BCE1D-27B3-45B2-8AC6-B5E3A38E8398}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {3BF67B62-D085-415E-80FB-E0E067A41C8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {3BF67B62-D085-415E-80FB-E0E067A41C8F}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {3BF67B62-D085-415E-80FB-E0E067A41C8F}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {3BF67B62-D085-415E-80FB-E0E067A41C8F}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {BB61C43E-D521-4294-914B-44DBDD90FABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {BB61C43E-D521-4294-914B-44DBDD90FABC}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {BB61C43E-D521-4294-914B-44DBDD90FABC}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {BB61C43E-D521-4294-914B-44DBDD90FABC}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {E0B6B0BC-E375-4992-8F73-E8CA8AD3A96C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {E0B6B0BC-E375-4992-8F73-E8CA8AD3A96C}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {E0B6B0BC-E375-4992-8F73-E8CA8AD3A96C}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {E0B6B0BC-E375-4992-8F73-E8CA8AD3A96C}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {BD47897A-A4B8-4621-BCE4-74AEFF1B7E03} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /Cdk/add-project.hook.d.ts: -------------------------------------------------------------------------------- 1 | import { InvokeHook } from '../../../init'; 2 | export declare const invoke: InvokeHook; 3 | -------------------------------------------------------------------------------- /Cdk/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "dotnet run --project ./src/ServerlessTodoListPipelineCdk/ServerlessTodoListPipelineCdk.csproj" 3 | } 4 | -------------------------------------------------------------------------------- /Cdk/src/ServerlessTodoListPipelineCdk.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerlessTodoListPipelineCdk", "ServerlessTodoListPipelineCdk\ServerlessTodoListPipelineCdk.csproj", "{63168FBA-D421-4F38-93B4-666138A13A6F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Debug|x86 = Debug|x86 13 | Release|Any CPU = Release|Any CPU 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Debug|x64.ActiveCfg = Debug|Any CPU 24 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Debug|x64.Build.0 = Debug|Any CPU 25 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Debug|x86.ActiveCfg = Debug|Any CPU 26 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Debug|x86.Build.0 = Debug|Any CPU 27 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Release|x64.ActiveCfg = Release|Any CPU 30 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Release|x64.Build.0 = Release|Any CPU 31 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Release|x86.ActiveCfg = Release|Any CPU 32 | {63168FBA-D421-4F38-93B4-666138A13A6F}.Release|x86.Build.0 = Release|Any CPU 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /Cdk/src/ServerlessTodoListPipelineCdk/Program.cs: -------------------------------------------------------------------------------- 1 | using Amazon.CDK; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace ServerlessTodoListPipelineCdk 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | var app = new App(null); 13 | new ServerlessTodoListPipelineCdkStack(app, "ServerlessTodoListPipelineCdkStack", new StackProps()); 14 | app.Synth(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Cdk/src/ServerlessTodoListPipelineCdk/ServerlessTodoListPipelineCdk.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /DotnetTryMaterial/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/.DS_Store -------------------------------------------------------------------------------- /DotnetTryMaterial/ASP.NETCoreFrontend/FrontendWrapup.md: -------------------------------------------------------------------------------- 1 | # ASP.NET Core wrap up 2 | 3 | At this point we have an ASP.NET Core application running locally that has removed its dependency on SQL Server and local configuration files. 4 | We are only using AWS serverless technologies like Cognito and Parameter Store reducing our overhead of what we have to manage and making it 5 | easy to scale based on our usage. 6 | 7 | 8 | --- 9 | 10 | * [Getting Started](../GettingStarted.md) 11 | * [What is a serverless application?](../WhatIsServerless.md) 12 | * [Common AWS Serverless Services](../CommonServerlessServices.md) 13 | * [What are we going to build in this tutorial?](../WhatAreWeBuilding.md) 14 | * [TODO List AWS Services Used](../TODOListServices.md) 15 | * [Using DynamoDB to store TODO Lists](../DynamoDBModule/WhatIsDynamoDB.md) 16 | * [Handling service events with Lambda](../StreamProcessing/ServiceEvents.md) 17 | * [Getting ASP.NET Core ready for Serverless](../ASP.NETCoreFrontend/TheFrontend.md) 18 | * [Dependency Injection](../ASP.NETCoreFrontend/DependencyInjection.md) 19 | * [Using Amazon Cognito for Identity](../ASP.NETCoreFrontend/WebIdentity.md) 20 | * [Persisting ASP.NET Core Data Protection Keys](../ASP.NETCoreFrontend/ParameterStoreDataProtection.md) 21 | * [AWS Systems Manager Parameter Store for Managing Configuration](../ASP.NETCoreFrontend/ParameterStoreConfigurationProvider.md) 22 | * **ASP.NET Core wrap up** 23 | * [Deploying ASP.NET Core as a Serverless Application](../DeployingFrontend/DeployingFrontend.md) 24 | * [Tear Down](../TearDown.md) 25 | * [Final Wrap Up](../FinalWrapup.md) 26 | 27 | Continue on to next page: [Deploying ASP.NET Core as a Serverless Application](../DeployingFrontend/DeployingFrontend.md) 28 | 29 | -------------------------------------------------------------------------------- /DotnetTryMaterial/ASP.NETCoreFrontend/images/AntiForgeryToken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/ASP.NETCoreFrontend/images/AntiForgeryToken.png -------------------------------------------------------------------------------- /DotnetTryMaterial/ASP.NETCoreFrontend/images/CreateUserPool.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/ASP.NETCoreFrontend/images/CreateUserPool.gif -------------------------------------------------------------------------------- /DotnetTryMaterial/ASP.NETCoreFrontend/images/CreateUserPoolAppClient.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/ASP.NETCoreFrontend/images/CreateUserPoolAppClient.gif -------------------------------------------------------------------------------- /DotnetTryMaterial/ASP.NETCoreFrontend/images/KeyStoredInParameterStore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/ASP.NETCoreFrontend/images/KeyStoredInParameterStore.png -------------------------------------------------------------------------------- /DotnetTryMaterial/CommonServerlessServices.md: -------------------------------------------------------------------------------- 1 | # Common AWS Serverless Services 2 | 3 | There are many AWS services that can be considered serverless. Here are some of the most 4 | common AWS services used that provide the foundational building blocks for a serverless application. 5 | 6 | ## Data Services 7 | 8 | |Service|Description| 9 | |----|---| 10 | | Amazon S3 | Object storage | 11 | | Amazon DynamoDB | Managed NoSQL | 12 | | Amazon Aurora Serverless | On-Demand relational database | 13 | 14 | ## Communication / Messaging 15 | |Service|Description| 16 | |---|---| 17 | | Amazon Simple Notification Service (SNS) |A pub/sub messaging service| 18 | | Amazon Simple Queue Service (SQS) |Fully managed message queuing| 19 | | Amazon Simple Email Service (SES) |SES is a cloud-based email sending service| 20 | 21 | ## Compute 22 | |Service|Description| 23 | |-|-| 24 | | AWS Lambda | Event driven continuous scaling serverless platform | 25 | | AWS Fargate | Fully managed containers within Amazon Elastic Container Service (ECS) | 26 | 27 | ## Networking 28 | |Service|Description| 29 | |-|-| 30 | | Amazon API Gateway | Fully managed API creation service | 31 | | Application Load Balancer | Load Balancer to distribute traffic and can target Lambdas | 32 | 33 | ## Authentication & Authorization 34 | |Service|Description| 35 | |-|-| 36 | | Amazon Cognito | Serverless authentication and authorization | 37 | 38 | 39 | --- 40 | 41 | * [Getting Started](./GettingStarted.md) 42 | * [What is a serverless application?](./WhatIsServerless.md) 43 | * **Common AWS Serverless Services** 44 | * [What are we going to build in this tutorial?](./WhatAreWeBuilding.md) 45 | * [TODO List AWS Services Used](./TODOListServices.md) 46 | * [Using DynamoDB to store TODO Lists](./DynamoDBModule/WhatIsDynamoDB.md) 47 | * [Handling service events with Lambda](./StreamProcessing/ServiceEvents.md) 48 | * [Getting ASP.NET Core ready for Serverless](./ASP.NETCoreFrontend/TheFrontend.md) 49 | * [Deploying ASP.NET Core as a Serverless Application](./DeployingFrontend/DeployingFrontend.md) 50 | * [Tear Down](./TearDown.md) 51 | * [Final Wrap Up](./FinalWrapup.md) 52 | 53 | Continue on to next page: [What are we going to build in this tutorial?](./WhatAreWeBuilding.md) 54 | 55 | -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/DeployingFrontend.md: -------------------------------------------------------------------------------- 1 | # Deploying ASP.NET Core as a Serverless Application 2 | 3 | Now that our application is all coded and only using serverless services for its data storage and configuration it is time 4 | to look into deploying our application. 5 | 6 | For serverless compute options for our an ASP.NET Core application we have 2 options to pick from. The first is using **AWS Lambda** running 7 | the ASP.NET Core application as a Lambda function. The second is using **AWS Fargate** running the application as a docker container. 8 | 9 | ## Lambda vs Fargate 10 | 11 | Both options allow us to focus on building and deploying applications without maintaining and patching any servers. They also 12 | have many differences in their application lifecycle and how you scale them. 13 | 14 | | | Lambda | Fargate 15 | | - | - | - | 16 | | Cost | Cost per request, no charge for idle time. | Cost for the time the container is running, including idle time | 17 | | Scaling | Horizonal scaling by concurrent events
Vertical scaling by memory settings
Single request per execution environment | Horizonal scaling using AWS Auto Scaling
Vertical scaling by memory and cpu settings
Multiple request handled at a time by docker container | 18 | | Performance | Occasional cold start during horizonal scaling | No cold starts as docker containers is always on | 19 | | Programming Model | Restrictions on request and response payload size
No direct connection to the client | Runs as a regular ASP.NET Core application hosted by Kestrel the ASP.NET Core web server. | 20 | 21 | My advice is investigate if Lambda will work for your requirements to take advantage of the easy scaling and pay per request model. If 22 | your application does not fit the Lambda model then fallback to Fargate. 23 | 24 | 25 | ## Upcoming sections 26 | 27 | Ahead in this tutorial are steps for both Lambda and Fargate. You can choose to follow either or both depending on what you want to learn. 28 | 29 | 30 | --- 31 | 32 | * [Getting Started](../GettingStarted.md) 33 | * [What is a serverless application?](../WhatIsServerless.md) 34 | * [Common AWS Serverless Services](../CommonServerlessServices.md) 35 | * [What are we going to build in this tutorial?](../WhatAreWeBuilding.md) 36 | * [TODO List AWS Services Used](../TODOListServices.md) 37 | * [Using DynamoDB to store TODO Lists](../DynamoDBModule/WhatIsDynamoDB.md) 38 | * [Handling service events with Lambda](../StreamProcessing/ServiceEvents.md) 39 | * [Getting ASP.NET Core ready for Serverless](../ASP.NETCoreFrontend/TheFrontend.md) 40 | * **Deploying ASP.NET Core as a Serverless Application** 41 | * [ASP.NET Core as a Lambda Function?](../DeployingFrontend/AspNetCoreAsLambda.md) 42 | * [Preparing for Lambda Deployment](../DeployingFrontend/LambdaPrepare.md) 43 | * [Deploy to Lambda using CloudFormation](../DeployingFrontend/LambdaDeploy.md) 44 | * [What is for Fargate](../DeployingFrontend/WhatIsFargate.md) 45 | * [Deploying to Fargate](../DeployingFrontend/FargateDeploy.md) 46 | * [Tear Down](../TearDown.md) 47 | * [Final Wrap Up](../FinalWrapup.md) 48 | 49 | Continue on to next page: [ASP.NET Core as a Lambda Function?](../DeployingFrontend/AspNetCoreAsLambda.md) 50 | 51 | -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/WhatIsFargate.md: -------------------------------------------------------------------------------- 1 | # What is for Fargate 2 | 3 | Fargate is a compute type for Elastic Container Service (ECS) that allows you to deploy Docker containers without 4 | managing any EC2 instances. When you deploy to ECS with Fargate you will specify the amount of CPU and Memory needed 5 | and Fargate will ensure the compute resources are made available and then run your docker container. 6 | 7 | 8 | ## ECS Tasks vs Services 9 | 10 | ECS runs containers either as a task or a service inside an ECS cluster. A task is for container applications that are meant to startup, do 11 | their work and then shutdown. Batch processing is a common example of when to use a task. A service is for 12 | containers like web servers that are meant to run indefinitely. A service is made up of a collection tasks and 13 | the service monitors the tasks. If any of the tasks stop running the service will start a new task. 14 | 15 | ## Load Balancer 16 | 17 | Tasks for an ECS service will get unique IP address and public DNS when they are started. Because we will potentially have 18 | more then one task supporting our application and the HTTP endpoints are unique for each task we will need 19 | a load balancer from the Elastic Load Balancing service to provide a single consistent HTTP/HTTPS endpoint. 20 | The ECS service managing the tasks for the service will also ensure the tasks are registered to the load balancer 21 | when they are started. 22 | 23 | 24 | --- 25 | 26 | * [Getting Started](../GettingStarted.md) 27 | * [What is a serverless application?](../WhatIsServerless.md) 28 | * [Common AWS Serverless Services](../CommonServerlessServices.md) 29 | * [What are we going to build in this tutorial?](../WhatAreWeBuilding.md) 30 | * [TODO List AWS Services Used](../TODOListServices.md) 31 | * [Using DynamoDB to store TODO Lists](../DynamoDBModule/WhatIsDynamoDB.md) 32 | * [Handling service events with Lambda](../StreamProcessing/ServiceEvents.md) 33 | * [Getting ASP.NET Core ready for Serverless](../ASP.NETCoreFrontend/TheFrontend.md) 34 | * [Deploying ASP.NET Core as a Serverless Application](../DeployingFrontend/DeployingFrontend.md) 35 | * [ASP.NET Core as a Lambda Function?](../DeployingFrontend/AspNetCoreAsLambda.md) 36 | * [Preparing for Lambda Deployment](../DeployingFrontend/LambdaPrepare.md) 37 | * [Deploy to Lambda using CloudFormation](../DeployingFrontend/LambdaDeploy.md) 38 | * **What is for Fargate** 39 | * [Deploying to Fargate](../DeployingFrontend/FargateDeploy.md) 40 | * [Tear Down](../TearDown.md) 41 | * [Final Wrap Up](../FinalWrapup.md) 42 | 43 | Continue on to next page: [Deploying to Fargate](../DeployingFrontend/FargateDeploy.md) 44 | 45 | -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/DeployServerless.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/DeployServerless.gif -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/ServerlessWizard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/ServerlessWizard.gif -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/add-docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/add-docker.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/cloudformation-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/cloudformation-view.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/ecs-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/ecs-view.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/ecs-wizard-page1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/ecs-wizard-page1.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/ecs-wizard-page2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/ecs-wizard-page2.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/ecs-wizard-page3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/ecs-wizard-page3.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/ecs-wizard-page4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/ecs-wizard-page4.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/ecs-wizard-page5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/ecs-wizard-page5.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/example-rest-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/example-rest-api.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/lambda-wizard-page1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/lambda-wizard-page1.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/request-normal-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/request-normal-flow.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/request-serverless-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/request-serverless-flow.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/solution-explorer-container.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/solution-explorer-container.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DeployingFrontend/images/solution-explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/DeployingFrontend/images/solution-explorer.png -------------------------------------------------------------------------------- /DotnetTryMaterial/DynamoDBModule/DotNetDynamoDBAPIs.md: -------------------------------------------------------------------------------- 1 | # Accessing DynamoDB items with the AWS SDK for .NET 2 | 3 | The NuGet package AWSSDK.DynamoDBv2 contains 3 different APIs save and get items from tables. In our TODO list application we will use the Data Model API but we will briefly cover each of the 3 API to get an understanding what is available. 4 | 5 | 6 | | Name | Namespace | Description| 7 | |----------------|-----------|------------| 8 | | Service Client |
  • Amazon.DynamoDBv2
  • Amazon.DynamoDBv2.Model
| The **AmazonDynamoDBClient** service client provides a 1 to 1 mapping with the service APIs. | 9 | | Document Model |
  • Amazon.DynamoDBv2.DocumentModel
| Represents an item as a Document which is similar to dictionary. Recommended when the data stored for each item varies with different attributes. | 10 | | Data Model |
  • Amazon.DynamoDBv2.DataModel
| Model your data as .NET objects and use **DynamoDBContext** object to serialize and deserialize the .NET objects into DynamoDB. | 11 | 12 | 13 | --- 14 | 15 | * [Getting Started](../GettingStarted.md) 16 | * [What is a serverless application?](../WhatIsServerless.md) 17 | * [Common AWS Serverless Services](../CommonServerlessServices.md) 18 | * [What are we going to build in this tutorial?](../WhatAreWeBuilding.md) 19 | * [TODO List AWS Services Used](../TODOListServices.md) 20 | * [Using DynamoDB to store TODO Lists](../DynamoDBModule/WhatIsDynamoDB.md) 21 | * [Creating DynamoDB table](../DynamoDBModule/CreateTable.md) 22 | * **Accessing DynamoDB items with the AWS SDK for .NET** 23 | * [CRUD operations with Amazon DynamoDB Service Client](../DynamoDBModule/DDBServiceClientAPI.md) 24 | * [CRUD operations with Document Model API](../DynamoDBModule/DotNetDynamoDBDocumentModel.md) 25 | * [CRUD operations with Data Model API](../DynamoDBModule/DotNetDynamoDBDataModel.md) 26 | * [Amazon DynamoDB wrap up](../DynamoDBModule/DynamoDBWrapUp.md) 27 | * [Handling service events with Lambda](../StreamProcessing/ServiceEvents.md) 28 | * [Getting ASP.NET Core ready for Serverless](../ASP.NETCoreFrontend/TheFrontend.md) 29 | * [Deploying ASP.NET Core as a Serverless Application](../DeployingFrontend/DeployingFrontend.md) 30 | * [Tear Down](../TearDown.md) 31 | * [Final Wrap Up](../FinalWrapup.md) 32 | 33 | Continue on to next page: [CRUD operations with Amazon DynamoDB Service Client](../DynamoDBModule/DDBServiceClientAPI.md) 34 | 35 | -------------------------------------------------------------------------------- /DotnetTryMaterial/DynamoDBModule/WhatIsDynamoDB.md: -------------------------------------------------------------------------------- 1 | # Using DynamoDB to store TODO Lists 2 | 3 | As we mentioned before we are going to use DynamoDB to store our TODO lists. DynamoDB was chosen because it provides 4 | fast access to our data, it simplifies our development with its schemaless design and provisioning because we don't have to manage database servers. 5 | 6 | ## Fully managed NoSQL datastore 7 | * Define Key and Indexes 8 | * Provisioning 9 | * Write / Read capacity units 10 | * Pay per request 11 | * On Demand 12 | 13 | ## Fast performance 14 | * Provides single-digit millisecond performance 15 | * Amazon DynamoDB Accelerator (DAX) for even faster performance. It's in-memory cache for your Dynamo Tables. 16 | * .NET NuGet package: AWSSDK.DAX.Client 17 | 18 | ## Support multi region 19 | * Multi region replication 20 | * Multi master 21 | 22 | ## AWS SDK for .NET Access 23 | 24 | To access DynamoDB with .NET the NuGet package AWSSDK.DynamoDBv2 is used to access all of the operations the DynamoDB service provides. This includes both the control plane API like creating tables as well as the data plane API for putting and getting items from tables. 25 | 26 | 27 | --- 28 | 29 | * [Getting Started](../GettingStarted.md) 30 | * [What is a serverless application?](../WhatIsServerless.md) 31 | * [Common AWS Serverless Services](../CommonServerlessServices.md) 32 | * [What are we going to build in this tutorial?](../WhatAreWeBuilding.md) 33 | * [TODO List AWS Services Used](../TODOListServices.md) 34 | * **Using DynamoDB to store TODO Lists** 35 | * [Creating DynamoDB table](../DynamoDBModule/CreateTable.md) 36 | * [Accessing DynamoDB items with the AWS SDK for .NET](../DynamoDBModule/DotNetDynamoDBAPIs.md) 37 | * [CRUD operations with Amazon DynamoDB Service Client](../DynamoDBModule/DDBServiceClientAPI.md) 38 | * [CRUD operations with Document Model API](../DynamoDBModule/DotNetDynamoDBDocumentModel.md) 39 | * [CRUD operations with Data Model API](../DynamoDBModule/DotNetDynamoDBDataModel.md) 40 | * [Amazon DynamoDB wrap up](../DynamoDBModule/DynamoDBWrapUp.md) 41 | * [Handling service events with Lambda](../StreamProcessing/ServiceEvents.md) 42 | * [Getting ASP.NET Core ready for Serverless](../ASP.NETCoreFrontend/TheFrontend.md) 43 | * [Deploying ASP.NET Core as a Serverless Application](../DeployingFrontend/DeployingFrontend.md) 44 | * [Tear Down](../TearDown.md) 45 | * [Final Wrap Up](../FinalWrapup.md) 46 | 47 | Continue on to next page: [Creating DynamoDB table](../DynamoDBModule/CreateTable.md) 48 | 49 | -------------------------------------------------------------------------------- /DotnetTryMaterial/Snippets/ConfigureEventSourceMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using System.Text; 7 | 8 | using Amazon; 9 | using Amazon.DynamoDBv2; 10 | using Amazon.DynamoDBv2.Model; 11 | using Amazon.Lambda; 12 | using Amazon.Lambda.Model; 13 | 14 | namespace Snippets 15 | { 16 | public class ConfigureEventSourceMapping 17 | { 18 | public static async Task AddEventSourceAsync() 19 | { 20 | #region add_dynamodb_event_source 21 | using (var streamClient = new AmazonDynamoDBStreamsClient()) 22 | using (var lambdaClient = new AmazonLambdaClient()) 23 | { 24 | // TODO: Enter Lambda function name, this is most likely: ServerlessTODOListStreamProcessor 25 | var functionName = ""; 26 | if(string.IsNullOrEmpty(functionName)) 27 | { 28 | Console.Error.WriteLine("You must set the name of the Lambda function you deployed to the \"functionName\" variable"); 29 | return; 30 | } 31 | 32 | var listRequest = new ListStreamsRequest 33 | { 34 | TableName = "TODOList" 35 | }; 36 | 37 | var listResponse = await streamClient.ListStreamsAsync(listRequest); 38 | if(listResponse.Streams.Count == 0) 39 | { 40 | Console.Error.WriteLine($"A stream is not enabled for the table {listRequest.TableName}"); 41 | return; 42 | } 43 | 44 | var streamArn = listResponse.Streams[0].StreamArn; 45 | Console.WriteLine($"Stream ARN is {streamArn}"); 46 | 47 | var request = new CreateEventSourceMappingRequest 48 | { 49 | FunctionName = functionName, 50 | EventSourceArn = streamArn, 51 | StartingPosition = EventSourcePosition.LATEST, 52 | BatchSize = 100 53 | }; 54 | 55 | await lambdaClient.CreateEventSourceMappingAsync(request); 56 | Console.WriteLine($"Event source mapping made between stream {streamArn} and function {functionName}"); 57 | } 58 | #endregion 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /DotnetTryMaterial/Snippets/DataModelTypes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Snippets 6 | { 7 | #region data_model_classes 8 | public class TODOList 9 | { 10 | public string User { get; set; } 11 | 12 | public string ListId { get; set; } 13 | 14 | public string Name { get; set; } 15 | 16 | public List Items { get; set; } 17 | 18 | public bool Complete { get; set; } 19 | 20 | public DateTime CreateDate { get; set; } 21 | 22 | public DateTime UpdateDate { get; set; } 23 | } 24 | 25 | public class TODOListItem 26 | { 27 | public string Description { get; set; } 28 | 29 | public string AssignedEmail { get; set; } 30 | 31 | public bool Complete { get; set; } 32 | } 33 | #endregion 34 | 35 | } 36 | -------------------------------------------------------------------------------- /DotnetTryMaterial/Snippets/SESSnippets.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | using Amazon; 7 | using Amazon.SimpleEmail; 8 | using Amazon.SimpleEmail.Model; 9 | 10 | namespace Snippets 11 | { 12 | public class SESSnippets 13 | { 14 | public static async Task SendVerificationAsync() 15 | { 16 | #region send_verification_email 17 | using (var sesClient = new AmazonSimpleEmailServiceClient(RegionEndpoint.USEast1)) 18 | { 19 | var request = new VerifyEmailAddressRequest 20 | { 21 | EmailAddress = "" 22 | }; 23 | 24 | if(!string.IsNullOrEmpty(request.EmailAddress)) 25 | { 26 | await sesClient.VerifyEmailAddressAsync(request); 27 | Console.WriteLine("Email send, check your email to verify the email address"); 28 | } 29 | else 30 | { 31 | Console.Error.WriteLine("You must set an email in the request to send the verification email"); 32 | } 33 | } 34 | #endregion 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /DotnetTryMaterial/Snippets/SetConfiguration.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.IO; 5 | using System.Text; 6 | 7 | 8 | namespace Snippets 9 | { 10 | public class SetConfiguration 11 | { 12 | public static string GetAWSProfile() 13 | { 14 | string AWS_PROFILE; 15 | 16 | #region current_aws_profile 17 | AWS_PROFILE = "default"; 18 | #endregion 19 | 20 | return AWS_PROFILE; 21 | } 22 | 23 | public static void SetAWSProfile() 24 | { 25 | Console.WriteLine("Profile set to " + GetAWSProfile()); 26 | SetConfigurationRegion("current_aws_profile", "AWS_PROFILE", GetAWSProfile()); 27 | } 28 | 29 | 30 | public static string GetAWSRegion() 31 | { 32 | string AWS_REGION; 33 | 34 | #region current_aws_region 35 | AWS_REGION = "us-east-1"; 36 | #endregion 37 | 38 | return AWS_REGION; 39 | } 40 | 41 | public static void SetAWSRegion() 42 | { 43 | Console.WriteLine("AWS region to " + GetAWSRegion()); 44 | SetConfigurationRegion("current_aws_region","AWS_REGION", GetAWSRegion()); 45 | } 46 | 47 | private static void SetConfigurationRegion(string region, string property, string value) 48 | { 49 | const string FILE_NAME = "SetConfiguration.cs"; 50 | 51 | var directory = Directory.GetCurrentDirectory(); 52 | do 53 | { 54 | if (File.Exists(Path.Combine(directory, FILE_NAME))) 55 | { 56 | break; 57 | } 58 | else 59 | { 60 | directory = Directory.GetParent(directory).FullName; 61 | } 62 | }while(!string.IsNullOrEmpty(directory)); 63 | 64 | var fullPath = Path.Combine(directory, FILE_NAME); 65 | 66 | var content = File.ReadAllText(fullPath); 67 | 68 | var sb = new StringBuilder(); 69 | 70 | var reader = new StringReader(content); 71 | string line; 72 | bool inRegion = false; 73 | while ((line = reader.ReadLine()) != null) 74 | { 75 | if (!inRegion && line.Contains("#region") && line.Contains(region)) 76 | { 77 | inRegion = true; 78 | } 79 | else if (line.Contains("#endregion")) 80 | { 81 | inRegion = false; 82 | } 83 | if (inRegion && line.Contains(property)) 84 | { 85 | var startPos = line.IndexOf("\"") + 1; 86 | line = line.Substring(0, startPos) + value + "\";"; 87 | } 88 | 89 | sb.AppendLine(line); 90 | } 91 | 92 | File.WriteAllText(fullPath, sb.ToString()); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /DotnetTryMaterial/Snippets/Snippets.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 1701;1702;1591 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /DotnetTryMaterial/Snippets/TestDynamoDBLambdaFunction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | using Amazon; 7 | using Amazon.DynamoDBv2; 8 | using Amazon.DynamoDBv2.DataModel; 9 | 10 | namespace Snippets 11 | { 12 | public class TestDynamoDBLambdaFunction 13 | { 14 | public static async Task SaveTODOListAsync() 15 | { 16 | var config = new DynamoDBContextConfig 17 | { 18 | Conversion = DynamoDBEntryConversion.V2, 19 | ConsistentRead = true 20 | }; 21 | var Context = new DynamoDBContext(new AmazonDynamoDBClient()); 22 | 23 | #region test_save_lambda_todo 24 | 25 | var assignedEmail = ""; 26 | if (string.IsNullOrEmpty(assignedEmail)) 27 | { 28 | Console.Error.WriteLine("You must set the email to the \"assignedEmail\" variable"); 29 | return; 30 | } 31 | 32 | var list = new TODOList 33 | { 34 | User = "testuser", 35 | ListId = Guid.NewGuid().ToString(), 36 | Complete = false, 37 | Name = "ExampleList", 38 | CreateDate = DateTime.UtcNow, 39 | UpdateDate = DateTime.UtcNow, 40 | Items = new List 41 | { 42 | new TODOListItem 43 | { 44 | Description = "Assigned Task", 45 | Complete = false, 46 | AssignedEmail = assignedEmail 47 | } 48 | } 49 | }; 50 | 51 | await Context.SaveAsync(list); 52 | Console.WriteLine("List saved, check your email to see if you get the assignment"); 53 | #endregion 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /DotnetTryMaterial/StreamProcessing/ServiceEvents.md: -------------------------------------------------------------------------------- 1 | # Handling service events with Lambda 2 | 3 | Many AWS services can trigger events when something changes. For example with Amazon S3 when a new object is uploaded 4 | to an S3 bucket an event can be triggered. 5 | 6 | A Lambda function can be configured to respond to the event. Here are some examples of AWS services that can be 7 | configured to trigger Lambda functions for their events. 8 | 9 | * Amazon S3 10 | * Amazon SNS 11 | * Amazon SQS 12 | * AWS Step Functions 13 | * Amazon Kinesis 14 | * Amazon DynamoDB 15 | * Amazon Eventbridge 16 | * Others 17 | 18 | 19 | --- 20 | 21 | * [Getting Started](../GettingStarted.md) 22 | * [What is a serverless application?](../WhatIsServerless.md) 23 | * [Common AWS Serverless Services](../CommonServerlessServices.md) 24 | * [What are we going to build in this tutorial?](../WhatAreWeBuilding.md) 25 | * [TODO List AWS Services Used](../TODOListServices.md) 26 | * [Using DynamoDB to store TODO Lists](../DynamoDBModule/WhatIsDynamoDB.md) 27 | * **Handling service events with Lambda** 28 | * [TODO List Task Assignments](../StreamProcessing/TODOTaskListAssignment.md) 29 | * [Enable DynamoDB Stream](../StreamProcessing/EnableDynamoDBStream.md) 30 | * [Assign Task Lambda Function](../StreamProcessing/LookAtLambdaFunction.md) 31 | * [Deploy Lambda Function](../StreamProcessing/DeployLambdaFunction.md) 32 | * [Configuring DynamoDB as an event source](../StreamProcessing/ConfigureLambdaEventSource.md) 33 | * [Setting up Amazon Simple Email Service (SES)](../StreamProcessing/SettingUpSES.md) 34 | * [Testing Lambda Function](../StreamProcessing/TestingLambdaFunction.md) 35 | * [Tips for troubleshooting Lambda functions](../StreamProcessing/TroubleshootingLambda.md) 36 | * [Stream processing wrap up](../StreamProcessing/StreamProcessingWrapup.md) 37 | * [Getting ASP.NET Core ready for Serverless](../ASP.NETCoreFrontend/TheFrontend.md) 38 | * [Deploying ASP.NET Core as a Serverless Application](../DeployingFrontend/DeployingFrontend.md) 39 | * [Tear Down](../TearDown.md) 40 | * [Final Wrap Up](../FinalWrapup.md) 41 | 42 | Continue on to next page: [TODO List Task Assignments](../StreamProcessing/TODOTaskListAssignment.md) 43 | 44 | -------------------------------------------------------------------------------- /DotnetTryMaterial/StreamProcessing/SettingUpSES.md: -------------------------------------------------------------------------------- 1 | # Setting up Amazon Simple Email Service (SES) 2 | 3 | SES is a cloud-based email sending service. It designed to handle any size workloads whether that is marketers 4 | sending large amounts of marketing emails or for small applications like ours to send emails to people that 5 | have been assigned a new task. 6 | 7 | AWS accounts that start using SES are initially in what is called sandbox mode, where each mail that is sent has to be 8 | to a verified email address. The sandbox mode is used to help prevent fraud and abuse, and to help protect your reputation 9 | as a sender, SES applies certain restrictions to new Amazon SES accounts. 10 | 11 | Checkout the developer guide about setting up email or moving your account of the sandbox. 12 | 13 | ## Verifing Email Address 14 | 15 | Your account is most likely in the sandbox mode. To see the emails our Lambda function will send, you 16 | need to verify each of the emails you plan on testing with both the From and To addresses. You can verify 17 | emails either through the AWS console or by entering an email in the code snippet below and executing it. 18 | 19 | ```cs --source-file ../Snippets/SESSnippets.cs --project ../Snippets/Snippets.csproj --region send_verification_email 20 | ``` 21 | 22 | 23 | --- 24 | 25 | * [Getting Started](../GettingStarted.md) 26 | * [What is a serverless application?](../WhatIsServerless.md) 27 | * [Common AWS Serverless Services](../CommonServerlessServices.md) 28 | * [What are we going to build in this tutorial?](../WhatAreWeBuilding.md) 29 | * [TODO List AWS Services Used](../TODOListServices.md) 30 | * [Using DynamoDB to store TODO Lists](../DynamoDBModule/WhatIsDynamoDB.md) 31 | * [Handling service events with Lambda](../StreamProcessing/ServiceEvents.md) 32 | * [TODO List Task Assignments](../StreamProcessing/TODOTaskListAssignment.md) 33 | * [Enable DynamoDB Stream](../StreamProcessing/EnableDynamoDBStream.md) 34 | * [Assign Task Lambda Function](../StreamProcessing/LookAtLambdaFunction.md) 35 | * [Deploy Lambda Function](../StreamProcessing/DeployLambdaFunction.md) 36 | * [Configuring DynamoDB as an event source](../StreamProcessing/ConfigureLambdaEventSource.md) 37 | * **Setting up Amazon Simple Email Service (SES)** 38 | * [Testing Lambda Function](../StreamProcessing/TestingLambdaFunction.md) 39 | * [Tips for troubleshooting Lambda functions](../StreamProcessing/TroubleshootingLambda.md) 40 | * [Stream processing wrap up](../StreamProcessing/StreamProcessingWrapup.md) 41 | * [Getting ASP.NET Core ready for Serverless](../ASP.NETCoreFrontend/TheFrontend.md) 42 | * [Deploying ASP.NET Core as a Serverless Application](../DeployingFrontend/DeployingFrontend.md) 43 | * [Tear Down](../TearDown.md) 44 | * [Final Wrap Up](../FinalWrapup.md) 45 | 46 | Continue on to next page: [Testing Lambda Function](../StreamProcessing/TestingLambdaFunction.md) 47 | 48 | -------------------------------------------------------------------------------- /DotnetTryMaterial/StreamProcessing/StreamProcessingWrapup.md: -------------------------------------------------------------------------------- 1 | # Stream processing wrap up 2 | 3 | We have completed deploying a Lambda function that handles processing service events. In this example we 4 | handled changes done to our DynamoDB Table but we could have just as easily used Lambda to handle events 5 | from S3 when objects are uploaded or when messages are sent to SQS queues. Lambda takes care of 6 | our scaling needs and we can focus on our business logic. 7 | 8 | To recap in this section we covered: 9 | 10 | * DynamoDB Streams 11 | * Deploying Lambda Functions 12 | * Configuring Event Sources for Lambda Functions 13 | * Testing and Troubleshooting of Lambda functions 14 | 15 | 16 | --- 17 | 18 | * [Getting Started](../GettingStarted.md) 19 | * [What is a serverless application?](../WhatIsServerless.md) 20 | * [Common AWS Serverless Services](../CommonServerlessServices.md) 21 | * [What are we going to build in this tutorial?](../WhatAreWeBuilding.md) 22 | * [TODO List AWS Services Used](../TODOListServices.md) 23 | * [Using DynamoDB to store TODO Lists](../DynamoDBModule/WhatIsDynamoDB.md) 24 | * [Handling service events with Lambda](../StreamProcessing/ServiceEvents.md) 25 | * [TODO List Task Assignments](../StreamProcessing/TODOTaskListAssignment.md) 26 | * [Enable DynamoDB Stream](../StreamProcessing/EnableDynamoDBStream.md) 27 | * [Assign Task Lambda Function](../StreamProcessing/LookAtLambdaFunction.md) 28 | * [Deploy Lambda Function](../StreamProcessing/DeployLambdaFunction.md) 29 | * [Configuring DynamoDB as an event source](../StreamProcessing/ConfigureLambdaEventSource.md) 30 | * [Setting up Amazon Simple Email Service (SES)](../StreamProcessing/SettingUpSES.md) 31 | * [Testing Lambda Function](../StreamProcessing/TestingLambdaFunction.md) 32 | * [Tips for troubleshooting Lambda functions](../StreamProcessing/TroubleshootingLambda.md) 33 | * **Stream processing wrap up** 34 | * [Getting ASP.NET Core ready for Serverless](../ASP.NETCoreFrontend/TheFrontend.md) 35 | * [Deploying ASP.NET Core as a Serverless Application](../DeployingFrontend/DeployingFrontend.md) 36 | * [Tear Down](../TearDown.md) 37 | * [Final Wrap Up](../FinalWrapup.md) 38 | 39 | Continue on to next page: [Getting ASP.NET Core ready for Serverless](../ASP.NETCoreFrontend/TheFrontend.md) 40 | 41 | -------------------------------------------------------------------------------- /DotnetTryMaterial/StreamProcessing/TODOTaskListAssignment.md: -------------------------------------------------------------------------------- 1 | # TODO List Task Assignments 2 | 3 | In our TODO List application each task in a TODO list can be assigned to a user. We want to use a Lambda function 4 | to notifiy users when they have been assigned a task. To implement this we need to implement the following steps. 5 | 6 | * Enable a DynamoDB Stream for our TODOList table 7 | * Write and Deploy a Lambda function 8 | * Configure DynamoDB Stream as an event source for Lambda function 9 | 10 | 11 | --- 12 | 13 | * [Getting Started](../GettingStarted.md) 14 | * [What is a serverless application?](../WhatIsServerless.md) 15 | * [Common AWS Serverless Services](../CommonServerlessServices.md) 16 | * [What are we going to build in this tutorial?](../WhatAreWeBuilding.md) 17 | * [TODO List AWS Services Used](../TODOListServices.md) 18 | * [Using DynamoDB to store TODO Lists](../DynamoDBModule/WhatIsDynamoDB.md) 19 | * [Handling service events with Lambda](../StreamProcessing/ServiceEvents.md) 20 | * **TODO List Task Assignments** 21 | * [Enable DynamoDB Stream](../StreamProcessing/EnableDynamoDBStream.md) 22 | * [Assign Task Lambda Function](../StreamProcessing/LookAtLambdaFunction.md) 23 | * [Deploy Lambda Function](../StreamProcessing/DeployLambdaFunction.md) 24 | * [Configuring DynamoDB as an event source](../StreamProcessing/ConfigureLambdaEventSource.md) 25 | * [Setting up Amazon Simple Email Service (SES)](../StreamProcessing/SettingUpSES.md) 26 | * [Testing Lambda Function](../StreamProcessing/TestingLambdaFunction.md) 27 | * [Tips for troubleshooting Lambda functions](../StreamProcessing/TroubleshootingLambda.md) 28 | * [Stream processing wrap up](../StreamProcessing/StreamProcessingWrapup.md) 29 | * [Getting ASP.NET Core ready for Serverless](../ASP.NETCoreFrontend/TheFrontend.md) 30 | * [Deploying ASP.NET Core as a Serverless Application](../DeployingFrontend/DeployingFrontend.md) 31 | * [Tear Down](../TearDown.md) 32 | * [Final Wrap Up](../FinalWrapup.md) 33 | 34 | Continue on to next page: [Enable DynamoDB Stream](../StreamProcessing/EnableDynamoDBStream.md) 35 | 36 | -------------------------------------------------------------------------------- /DotnetTryMaterial/StreamProcessing/TestingLambdaFunction.md: -------------------------------------------------------------------------------- 1 | # Testing Lambda Function 2 | 3 | Now that everything is deployed and configured let's test our Lambda function. To do that let's save a TODO List to DynamoDB. 4 | 5 | Be sure in the code below to set the **assignedEmail** variable to an email address that you have verified with Amazon Simple Email Service. 6 | 7 | ```cs --source-file ../Snippets/TestDynamoDBLambdaFunction.cs --project ../Snippets/Snippets.csproj --region test_save_lambda_todo 8 | ``` 9 | 10 | 11 | --- 12 | 13 | * [Getting Started](../GettingStarted.md) 14 | * [What is a serverless application?](../WhatIsServerless.md) 15 | * [Common AWS Serverless Services](../CommonServerlessServices.md) 16 | * [What are we going to build in this tutorial?](../WhatAreWeBuilding.md) 17 | * [TODO List AWS Services Used](../TODOListServices.md) 18 | * [Using DynamoDB to store TODO Lists](../DynamoDBModule/WhatIsDynamoDB.md) 19 | * [Handling service events with Lambda](../StreamProcessing/ServiceEvents.md) 20 | * [TODO List Task Assignments](../StreamProcessing/TODOTaskListAssignment.md) 21 | * [Enable DynamoDB Stream](../StreamProcessing/EnableDynamoDBStream.md) 22 | * [Assign Task Lambda Function](../StreamProcessing/LookAtLambdaFunction.md) 23 | * [Deploy Lambda Function](../StreamProcessing/DeployLambdaFunction.md) 24 | * [Configuring DynamoDB as an event source](../StreamProcessing/ConfigureLambdaEventSource.md) 25 | * [Setting up Amazon Simple Email Service (SES)](../StreamProcessing/SettingUpSES.md) 26 | * **Testing Lambda Function** 27 | * [Tips for troubleshooting Lambda functions](../StreamProcessing/TroubleshootingLambda.md) 28 | * [Stream processing wrap up](../StreamProcessing/StreamProcessingWrapup.md) 29 | * [Getting ASP.NET Core ready for Serverless](../ASP.NETCoreFrontend/TheFrontend.md) 30 | * [Deploying ASP.NET Core as a Serverless Application](../DeployingFrontend/DeployingFrontend.md) 31 | * [Tear Down](../TearDown.md) 32 | * [Final Wrap Up](../FinalWrapup.md) 33 | 34 | Continue on to next page: [Tips for troubleshooting Lambda functions](../StreamProcessing/TroubleshootingLambda.md) 35 | 36 | -------------------------------------------------------------------------------- /DotnetTryMaterial/StreamProcessing/images/DDBStreamCommandLineDeployment.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/StreamProcessing/images/DDBStreamCommandLineDeployment.gif -------------------------------------------------------------------------------- /DotnetTryMaterial/StreamProcessing/images/LambdaWizardPage1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/StreamProcessing/images/LambdaWizardPage1.png -------------------------------------------------------------------------------- /DotnetTryMaterial/StreamProcessing/images/LambdaWizardPage2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/StreamProcessing/images/LambdaWizardPage2.png -------------------------------------------------------------------------------- /DotnetTryMaterial/StreamProcessing/images/SolutionExplorerPublishToLambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/StreamProcessing/images/SolutionExplorerPublishToLambda.png -------------------------------------------------------------------------------- /DotnetTryMaterial/StreamProcessing/images/ToolkitAddEventSource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/StreamProcessing/images/ToolkitAddEventSource.png -------------------------------------------------------------------------------- /DotnetTryMaterial/StreamProcessing/images/ToolkitViewLogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/StreamProcessing/images/ToolkitViewLogs.png -------------------------------------------------------------------------------- /DotnetTryMaterial/TOC.json: -------------------------------------------------------------------------------- 1 | [ 2 | "GettingStarted.md", 3 | "WhatIsServerless.md", 4 | "CommonServerlessServices.md", 5 | "WhatAreWeBuilding.md", 6 | "TODOListServices.md", 7 | { 8 | "Name": "Using DynamoDB to store TODO Lists", 9 | "FolderName": "DynamoDBModule", 10 | "RootPage": "WhatIsDynamoDB.md", 11 | "Pages": [ 12 | "CreateTable.md", 13 | "DotNetDynamoDBAPIs.md", 14 | "DDBServiceClientAPI.md", 15 | "DotNetDynamoDBDocumentModel.md", 16 | "DotNetDynamoDBDataModel.md", 17 | "DynamoDBWrapUp.md" 18 | ] 19 | }, 20 | { 21 | "Name": "Handling service events with Lambda", 22 | "FolderName": "StreamProcessing", 23 | "RootPage": "ServiceEvents.md", 24 | "Pages": [ 25 | "TODOTaskListAssignment.md", 26 | "EnableDynamoDBStream.md", 27 | "LookAtLambdaFunction.md", 28 | "DeployLambdaFunction.md", 29 | "ConfigureLambdaEventSource.md", 30 | "SettingUpSES.md", 31 | "TestingLambdaFunction.md", 32 | "TroubleshootingLambda.md", 33 | "StreamProcessingWrapup.md" 34 | ] 35 | }, 36 | { 37 | "Name": "Getting ASP.NET Core ready for Serverless", 38 | "FolderName": "ASP.NETCoreFrontend", 39 | "RootPage": "TheFrontend.md", 40 | "Pages": [ 41 | "DependencyInjection.md", 42 | "WebIdentity.md", 43 | "ParameterStoreDataProtection.md", 44 | "ParameterStoreConfigurationProvider.md", 45 | "FrontendWrapup.md" 46 | ] 47 | }, 48 | { 49 | "Name": "Deploying ASP.NET Core as a Serverless Application", 50 | "FolderName": "DeployingFrontend", 51 | "RootPage": "DeployingFrontend.md", 52 | "Pages": [ 53 | "AspNetCoreAsLambda.md", 54 | "LambdaPrepare.md", 55 | "LambdaDeploy.md", 56 | "WhatIsFargate.md", 57 | "FargateDeploy.md" 58 | ] 59 | }, 60 | "TearDown.md", 61 | "FinalWrapup.md" 62 | 63 | ] -------------------------------------------------------------------------------- /DotnetTryMaterial/TOCBuilder/TOCBuilder.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /DotnetTryMaterial/TODOListServices.md: -------------------------------------------------------------------------------- 1 | # TODO List AWS Services Used 2 | 3 | The TODO list application that we will build and deploy will use the following services. 4 | 5 | | Services | Description | 6 | |-|-| 7 | | Amazon DynamoDB | To store the the TODO Lists | 8 | | Amazon Simple Email Service | Send emails for task assignment | 9 | | Amazon Cognito | Application identity | 10 | | Parameter Store from AWS Systems Manager | Store and retrieve application configuration | 11 | | AWS Lambda | Compute processing | 12 | | Amazon API Gateway | Expose Lambda functions to the web | 13 | 14 | 15 | --- 16 | 17 | * [Getting Started](./GettingStarted.md) 18 | * [What is a serverless application?](./WhatIsServerless.md) 19 | * [Common AWS Serverless Services](./CommonServerlessServices.md) 20 | * [What are we going to build in this tutorial?](./WhatAreWeBuilding.md) 21 | * **TODO List AWS Services Used** 22 | * [Using DynamoDB to store TODO Lists](./DynamoDBModule/WhatIsDynamoDB.md) 23 | * [Handling service events with Lambda](./StreamProcessing/ServiceEvents.md) 24 | * [Getting ASP.NET Core ready for Serverless](./ASP.NETCoreFrontend/TheFrontend.md) 25 | * [Deploying ASP.NET Core as a Serverless Application](./DeployingFrontend/DeployingFrontend.md) 26 | * [Tear Down](./TearDown.md) 27 | * [Final Wrap Up](./FinalWrapup.md) 28 | 29 | Continue on to next page: [Using DynamoDB to store TODO Lists](./DynamoDBModule/WhatIsDynamoDB.md) 30 | 31 | -------------------------------------------------------------------------------- /DotnetTryMaterial/TearDown.md: -------------------------------------------------------------------------------- 1 | # Tear Down 2 | 3 | Before you end this tutorial be sure to tear down the AWS resources created during the tutorial. 4 | This will avoid any unexpected charges for resources left on like the DynamoDB table or Fargate container. 5 | 6 | ## Tear Down Fargate Container 7 | 8 | If you went through the Fargate deployment sections the easiest way to tear down the running containers 9 | and the Application Load Balancer created during the the tutorial is to delete the ECS service in Visual Studio. 10 | To do that open the ECS Cluster view and click the **Delete** button. 11 | 12 | ![alt text](./images/delete-service.png "Delete ECS service") 13 | 14 | ```cs --source-file ./Snippets/TearDown.cs --project ./Snippets/Snippets.csproj --region resources_to_tear_down 15 | ``` 16 | 17 | ## Other resource tear down 18 | 19 | For the other resources if you used the names suggest in the tutorial then running this code box will delete the 20 | resources. If you changed the names then update the properties in the code box and then execute to delete 21 | the resources. 22 | 23 | 24 | --- 25 | 26 | * [Getting Started](./GettingStarted.md) 27 | * [What is a serverless application?](./WhatIsServerless.md) 28 | * [Common AWS Serverless Services](./CommonServerlessServices.md) 29 | * [What are we going to build in this tutorial?](./WhatAreWeBuilding.md) 30 | * [TODO List AWS Services Used](./TODOListServices.md) 31 | * [Using DynamoDB to store TODO Lists](./DynamoDBModule/WhatIsDynamoDB.md) 32 | * [Handling service events with Lambda](./StreamProcessing/ServiceEvents.md) 33 | * [Getting ASP.NET Core ready for Serverless](./ASP.NETCoreFrontend/TheFrontend.md) 34 | * [Deploying ASP.NET Core as a Serverless Application](./DeployingFrontend/DeployingFrontend.md) 35 | * **Tear Down** 36 | * [Final Wrap Up](./FinalWrapup.md) 37 | 38 | Continue on to next page: [Final Wrap Up](./FinalWrapup.md) 39 | 40 | -------------------------------------------------------------------------------- /DotnetTryMaterial/WhatAreWeBuilding.md: -------------------------------------------------------------------------------- 1 | # What are we going to build in this tutorial? 2 | 3 | In this tutorial we are going to be building a very simple serverless application to manage TODO lists. It will have the following features: 4 | 5 | * Register and authenticate users 6 | * Create, update and delete lists with tasks 7 | * Assign tasks from a list to users 8 | 9 | ![alt text](./images/AppInAction.gif "ServerlessTODO List In Action") 10 | 11 | ## The Code 12 | 13 | The code we will work with for this tutorial is under the **Application** directory in this repository. It is recommended you open the **ServerlessTODOList.sln** solution 14 | under the **Application\Start** directory in your IDE of choice. This tutorial will walk you through adding the missing pieces in the application to produce the version in the **Application\Final** 15 | directory. 16 | 17 | ## AWS Toolkit for Visual Studio 18 | 19 | If you following along with Visual Studio it is recommended you have the AWS Toolkit for Visual Studio installed 20 | to make it easy to deploy your code. If you are not using Visual Studio, command line instructions will also be provided for most sections. 21 | 22 | 23 | --- 24 | 25 | * [Getting Started](./GettingStarted.md) 26 | * [What is a serverless application?](./WhatIsServerless.md) 27 | * [Common AWS Serverless Services](./CommonServerlessServices.md) 28 | * **What are we going to build in this tutorial?** 29 | * [TODO List AWS Services Used](./TODOListServices.md) 30 | * [Using DynamoDB to store TODO Lists](./DynamoDBModule/WhatIsDynamoDB.md) 31 | * [Handling service events with Lambda](./StreamProcessing/ServiceEvents.md) 32 | * [Getting ASP.NET Core ready for Serverless](./ASP.NETCoreFrontend/TheFrontend.md) 33 | * [Deploying ASP.NET Core as a Serverless Application](./DeployingFrontend/DeployingFrontend.md) 34 | * [Tear Down](./TearDown.md) 35 | * [Final Wrap Up](./FinalWrapup.md) 36 | 37 | Continue on to next page: [TODO List AWS Services Used](./TODOListServices.md) 38 | 39 | -------------------------------------------------------------------------------- /DotnetTryMaterial/WhatIsServerless.md: -------------------------------------------------------------------------------- 1 | # What is a serverless application? 2 | 3 | I like to define serverless in 3 ways: no servers to manage, only pay for what I use, and no need to predict user traffic as it scales automatically. 4 | 5 | ## No server management 6 | 7 | There is no need to provision or maintain any servers. There is no software or runtime to install, maintain, or administer. This is generally why the word serverless makes more sense if you say "serverless to me", it's not that our solution isn't running on servers, it most definitely is. It's more so I am not touching those servers, it's serverless to me. 8 | 9 | ## Automatic scaling 10 | 11 | Lambdas scale automatically without the need to predict user traffic. AWS does all the scaling work for you! With some of the other services we use in conjunction with Lambda to create serverless applications, you can select for auto-scaling or you can scale simply by changing the provisioning settings. 12 | 13 | ## Pay for what you need 14 | 15 | You only pay for the time your lambda was executing. This means you truly only pay for what you used and nothing more which can be different from a server running all the time or a virtual instance doing the same thing. Fun fact about Lambda is also that you get 1M invocations of a function for free every month indefinitely. 16 | 17 | ## Automated high availability 18 | 19 | Serverless provides built-in availability and fault tolerance. You don't need to architect for these capabilities since the services running the application provide them by default. 20 | 21 | ## Basic overview of a serverless app 22 | 23 | 24 | ![alt text](./images/serverlessapp.png "Serverless Overview") 25 | 26 | 27 | --- 28 | 29 | * [Getting Started](./GettingStarted.md) 30 | * **What is a serverless application?** 31 | * [Common AWS Serverless Services](./CommonServerlessServices.md) 32 | * [What are we going to build in this tutorial?](./WhatAreWeBuilding.md) 33 | * [TODO List AWS Services Used](./TODOListServices.md) 34 | * [Using DynamoDB to store TODO Lists](./DynamoDBModule/WhatIsDynamoDB.md) 35 | * [Handling service events with Lambda](./StreamProcessing/ServiceEvents.md) 36 | * [Getting ASP.NET Core ready for Serverless](./ASP.NETCoreFrontend/TheFrontend.md) 37 | * [Deploying ASP.NET Core as a Serverless Application](./DeployingFrontend/DeployingFrontend.md) 38 | * [Tear Down](./TearDown.md) 39 | * [Final Wrap Up](./FinalWrapup.md) 40 | 41 | Continue on to next page: [Common AWS Serverless Services](./CommonServerlessServices.md) 42 | 43 | -------------------------------------------------------------------------------- /DotnetTryMaterial/images/AppInAction.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/images/AppInAction.gif -------------------------------------------------------------------------------- /DotnetTryMaterial/images/TutorialSetup.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/images/TutorialSetup.gif -------------------------------------------------------------------------------- /DotnetTryMaterial/images/delete-service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/images/delete-service.png -------------------------------------------------------------------------------- /DotnetTryMaterial/images/serverlessapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/normj/ServerlessTODOListTutorial/45168e1c5c22a3b630b0dd00d3b7e5517771e092/DotnetTryMaterial/images/serverlessapp.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Building a AWS Serverless TODO List Application 2 | 3 | This tutorial shows how to build a very simple TODO list application. Along the way you will learn how to use several AWS services like Amazon DynamoDB and AWS Lambda. 4 | I wrote this with the intention of using this as material for giving AWS Talks on .NET serverless but it should be easy enough to follow by yourself. 5 | If not please let me know where I can clarify things. 6 | 7 | 8 | ## dotnet try 9 | 10 | At Microsoft's 2019 Build conference a new .NET Global tool called dotnet try was released which allows the creation of interactive .NET documentation. 11 | 12 | ## Setup 13 | 14 | To get started with this tutorial follow the following steps. 15 | 16 | * Ensure .NET Core 3.1 SDK is installed. The tool dotnet try requires .NET Core 3.1 17 | * https://dotnet.microsoft.com/download/dotnet-core/3.1 18 | * Either the AWS Toolkit for Visual Studio or Amazon.Lambda.Tools .NET Core Global Tool 19 | * AWS Toolkit for Visual Studio Download 20 | * Amazon.Lambda.Tools .NET Core Global Tool - `dotnet tool install -g Amazon.Lambda.Tools` 21 | * **Note:** The AWS Toolkit for Visual Studio is not compatible with Visual Studio for Mac. 22 | * Clone this repository. Be sure to clone the repository in a directory you have write access. 23 | * `git clone https://github.com/normj/ServerlessTODOListTutorial.git` 24 | * Install dotnet try 25 | * The current version publish to NuGet does not currently work for this project. The preview package **Microsoft.dotnet-try** has to be used from its myget feed. 26 | * `dotnet tool install -g --add-source "https://dotnet.myget.org/F/dotnet-try/api/v3/index.json" Microsoft.dotnet-try` 27 | * Start dotnet try in the directory the repo was cloned 28 | * `dotnet try` 29 | 30 | ![alt text](./DotnetTryMaterial/images/TutorialSetup.gif "Setup") 31 | 32 | ## Let's Start 33 | 34 | If you are seeing this page after running `dotnet try` then click [here to get started](./DotnetTryMaterial/GettingStarted.md). --------------------------------------------------------------------------------