From 27da0f2b2a050048ad51b15cfed7d4437a3cb2b8 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Fri, 26 Feb 2021 21:22:47 +0000 Subject: [PATCH 1/2] Scaffold modernized infrastructure --- template.yaml | 488 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 488 insertions(+) create mode 100644 template.yaml diff --git a/template.yaml b/template.yaml new file mode 100644 index 0000000..5d69db5 --- /dev/null +++ b/template.yaml @@ -0,0 +1,488 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Resources: + VirtualNetwork: + Type: AWS::EC2::VPC + Properties: + CidrBlock: 10.0.0.0/16 + Tags: + - Key: Name + Value: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Virtual Network ${ResourceName} + - ResourceName: VirtualNetwork + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet1: + Metadata: + StackeryManaged: true + Type: AWS::EC2::Subnet + Properties: + AvailabilityZone: !Select + - 0 + - !GetAZs '' + CidrBlock: !Select + - 0 + - !Cidr + - 10.0.0.0/16 + - 4 + - 14 + Tags: + - Key: Name + Value: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Virtual Network ${ResourceName} Private Subnet 1 + - ResourceName: VirtualNetwork + VpcId: !Ref VirtualNetwork + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet2: + Metadata: + StackeryManaged: true + Type: AWS::EC2::Subnet + Properties: + AvailabilityZone: !Select + - 1 + - !GetAZs '' + CidrBlock: !Select + - 1 + - !Cidr + - 10.0.0.0/16 + - 4 + - 14 + Tags: + - Key: Name + Value: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Virtual Network ${ResourceName} Private Subnet 2 + - ResourceName: VirtualNetwork + VpcId: !Ref VirtualNetwork + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPublicSubnet1: + Metadata: + StackeryManaged: true + Type: AWS::EC2::Subnet + Properties: + AvailabilityZone: !Select + - 0 + - !GetAZs '' + CidrBlock: !Select + - 2 + - !Cidr + - 10.0.0.0/16 + - 4 + - 14 + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Virtual Network ${ResourceName} Public Subnet 1 + - ResourceName: VirtualNetwork + VpcId: !Ref VirtualNetwork + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPublicSubnet2: + Metadata: + StackeryManaged: true + Type: AWS::EC2::Subnet + Properties: + AvailabilityZone: !Select + - 1 + - !GetAZs '' + CidrBlock: !Select + - 3 + - !Cidr + - 10.0.0.0/16 + - 4 + - 14 + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Virtual Network ${ResourceName} Public Subnet 2 + - ResourceName: VirtualNetwork + VpcId: !Ref VirtualNetwork + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet1NatGatewayEIP: + Metadata: + StackeryManaged: true + Type: AWS::EC2::EIP + Properties: + Domain: vpc + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet1NatGateway: + Metadata: + StackeryManaged: true + Type: AWS::EC2::NatGateway + Properties: + AllocationId: !GetAtt VirtualNetworkPrivateSubnet1NatGatewayEIP.AllocationId + SubnetId: !Ref VirtualNetworkPublicSubnet1 + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet1RouteTable: + Metadata: + StackeryManaged: true + Type: AWS::EC2::RouteTable + Properties: + Tags: + - Key: Name + Value: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Virtual Network ${ResourceName} Private Subnet 1 Route Table + - ResourceName: VirtualNetwork + VpcId: !Ref VirtualNetwork + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet1NatGatewayRoute: + Metadata: + StackeryManaged: true + Type: AWS::EC2::Route + Properties: + DestinationCidrBlock: 0.0.0.0/0 + NatGatewayId: !Ref VirtualNetworkPrivateSubnet1NatGateway + RouteTableId: !Ref VirtualNetworkPrivateSubnet1RouteTable + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet1RouteTableAssociation: + Metadata: + StackeryManaged: true + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref VirtualNetworkPrivateSubnet1RouteTable + SubnetId: !Ref VirtualNetworkPrivateSubnet1 + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet2NatGatewayEIP: + Metadata: + StackeryManaged: true + Type: AWS::EC2::EIP + Properties: + Domain: vpc + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet2NatGateway: + Metadata: + StackeryManaged: true + Type: AWS::EC2::NatGateway + Properties: + AllocationId: !GetAtt VirtualNetworkPrivateSubnet2NatGatewayEIP.AllocationId + SubnetId: !Ref VirtualNetworkPublicSubnet2 + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet2RouteTable: + Metadata: + StackeryManaged: true + Type: AWS::EC2::RouteTable + Properties: + Tags: + - Key: Name + Value: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Virtual Network ${ResourceName} Private Subnet 2 Route Table + - ResourceName: VirtualNetwork + VpcId: !Ref VirtualNetwork + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet2NatGatewayRoute: + Metadata: + StackeryManaged: true + Type: AWS::EC2::Route + Properties: + DestinationCidrBlock: 0.0.0.0/0 + NatGatewayId: !Ref VirtualNetworkPrivateSubnet2NatGateway + RouteTableId: !Ref VirtualNetworkPrivateSubnet2RouteTable + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPrivateSubnet2RouteTableAssociation: + Metadata: + StackeryManaged: true + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref VirtualNetworkPrivateSubnet2RouteTable + SubnetId: !Ref VirtualNetworkPrivateSubnet2 + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPublicSubnetsInternetGateway: + Metadata: + StackeryManaged: true + Type: AWS::EC2::InternetGateway + Properties: + Tags: + - Key: Name + Value: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Virtual Network ${ResourceName} Public Subnets Internet Gateway + - ResourceName: VirtualNetwork + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPublicSubnetsInternetGatewayAttachment: + Metadata: + StackeryManaged: true + Type: AWS::EC2::VPCGatewayAttachment + Properties: + InternetGatewayId: !Ref VirtualNetworkPublicSubnetsInternetGateway + VpcId: !Ref VirtualNetwork + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPublicSubnetsRouteTable: + Metadata: + StackeryManaged: true + Type: AWS::EC2::RouteTable + Properties: + Tags: + - Key: Name + Value: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Virtual Network ${ResourceName} Public Subnets Route Table + - ResourceName: VirtualNetwork + VpcId: !Ref VirtualNetwork + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPublicSubnetsInternetGatewayRoute: + Metadata: + StackeryManaged: true + Type: AWS::EC2::Route + Properties: + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: !Ref VirtualNetworkPublicSubnetsInternetGateway + RouteTableId: !Ref VirtualNetworkPublicSubnetsRouteTable + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPublicSubnet1RouteTableAssociation: + Metadata: + StackeryManaged: true + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref VirtualNetworkPublicSubnetsRouteTable + SubnetId: !Ref VirtualNetworkPublicSubnet1 + Condition: VirtualNetworkCreateNewResource + VirtualNetworkPublicSubnet2RouteTableAssociation: + Metadata: + StackeryManaged: true + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref VirtualNetworkPublicSubnetsRouteTable + SubnetId: !Ref VirtualNetworkPublicSubnet2 + Condition: VirtualNetworkCreateNewResource + VirtualNetworkExistingResource: + Type: Custom::StackeryExistingResource + Properties: + ServiceToken: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:stackery-agent-commander + Type: virtualNetwork + Data: !Ref EnvConfigdotnetVirtualNetworkAsString + Condition: VirtualNetworkUseExistingResource + Database: + Type: AWS::RDS::DBInstance + Properties: + BackupRetentionPeriod: '1' + DBSubnetGroupName: !Ref DatabaseSubnetGroup + Engine: sqlserver-ex + MasterUsername: !Sub '{{resolve:secretsmanager:${DatabaseRootUserSecret}:SecretString:username}}' + MasterUserPassword: !Sub '{{resolve:secretsmanager:${DatabaseRootUserSecret}:SecretString:password}}' + AllocatedStorage: '5' + AllowMajorVersionUpgrade: true + AutoMinorVersionUpgrade: true + CopyTagsToSnapshot: true + DBInstanceClass: db.t2.micro + EngineVersion: 14.00.3356.20.v1 + MultiAZ: false + StorageType: gp2 + PubliclyAccessible: false + VPCSecurityGroups: + - !Ref DatabaseSecurityGroup + LicenseModel: license-included + Condition: DatabaseCreateNewResource + DatabaseSubnetGroup: + Type: AWS::RDS::DBSubnetGroup + Properties: + DBSubnetGroupDescription: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Database ${ResourceName} VPC Subnets + - ResourceName: Database + SubnetIds: + - !If + - VirtualNetworkUseExistingResource + - !GetAtt VirtualNetworkExistingResource.PrivateSubnet1 + - !Ref VirtualNetworkPrivateSubnet1 + - !If + - VirtualNetworkUseExistingResource + - !GetAtt VirtualNetworkExistingResource.PrivateSubnet2 + - !Ref VirtualNetworkPrivateSubnet2 + Tags: + - Key: Name + Value: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Database ${ResourceName} VPC Subnets + - ResourceName: Database + Condition: DatabaseCreateNewResource + DatabaseSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Database Security Group + SecurityGroupIngress: + CidrIp: 0.0.0.0/0 + FromPort: 1433 + IpProtocol: tcp + ToPort: 1433 + Tags: + - Key: Name + Value: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Database ${ResourceName} VPC Security Group + - ResourceName: Database + VpcId: !If + - VirtualNetworkUseExistingResource + - !Ref VirtualNetworkExistingResource + - !Ref VirtualNetwork + Condition: DatabaseCreateNewResource + DatabaseRootUserSecret: + Type: AWS::SecretsManager::Secret + Properties: + Description: !Sub + - Root user login info for Stack ${StackTagName} Environment ${EnvironmentTagName} Database ${ResourceName} + - ResourceName: Database + GenerateSecretString: + SecretStringTemplate: '{"username": "root"}' + GenerateStringKey: password + PasswordLength: 16 + ExcludeCharacters: '"@/\' + Name: !Sub /${EnvironmentTagName}/${StackTagName}/Database/RootUser + Condition: DatabaseCreateNewResource + DatabaseRootUserSecretAttachment: + Type: AWS::SecretsManager::SecretTargetAttachment + Properties: + SecretId: !Ref DatabaseRootUserSecret + TargetId: !Ref Database + TargetType: AWS::RDS::DBInstance + Condition: DatabaseCreateNewResource + DatabaseExistingResource: + Type: Custom::StackeryExistingResource + Properties: + ServiceToken: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:stackery-agent-commander + Type: database + Data: !Ref EnvConfigdotnetDatabaseAsString + Condition: DatabaseUseExistingResource + HttpApi: + Type: AWS::Serverless::HttpApi + Properties: + DefinitionBody: + openapi: '3.0' + info: + title: !Sub ${AWS::StackName}-HttpApi + version: '1.0' + paths: + /$default: + x-amazon-apigateway-any-method: + responses: {} + isDefaultRoute: true + x-amazon-apigateway-integration: + httpMethod: ANY + type: http_proxy + uri: http://54.90.19.60 + payloadFormatVersion: '1.0' + parameters: + - name: proxy + in: path + required: true + schema: + type: string + /api/books: + x-amazon-apigateway-any-method: + responses: {} + /api/books/{proxy+}: + x-amazon-apigateway-any-method: + responses: {} + FailOnWarnings: true + WebApi: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Sub ${AWS::StackName}-WebApi + Description: !Sub + - Stack ${StackTagName} Environment ${EnvironmentTagName} Function ${ResourceName} + - ResourceName: WebApi + CodeUri: webapi + Handler: webapi::webapi.LambdaEntryPoint::FunctionHandlerAsync + Runtime: dotnetcore3.1 + MemorySize: 3008 + Timeout: 30 + Tracing: Active + Policies: + - AWSXrayWriteOnlyAccess + - AWSLambdaENIManagementAccess + - AWSSecretsManagerGetSecretValuePolicy: + SecretArn: !If + - DatabaseUseExistingResource + - !GetAtt DatabaseExistingResource.RootUserSecret + - !Ref DatabaseRootUserSecret + - Statement: + - Effect: Allow + Action: + - rds-data:BatchExecuteStatement + - rds-data:BeginTransaction + - rds-data:CommitTransaction + - rds-data:ExecuteStatement + - rds-data:RollbackTransaction + Resource: + - !If + - DatabaseUseExistingResource + - !Sub arn:aws:rds:${AWS::Region}:${AWS::AccountId}:cluster:${DatabaseExistingResource} + - !Sub arn:aws:rds:${AWS::Region}:${AWS::AccountId}:cluster:${Database} + - AWSSecretsManagerGetSecretValuePolicy: + SecretArn: !Sub arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:/${EnvironmentTagName}/* + VpcConfig: + SecurityGroupIds: + - !If + - VirtualNetworkUseExistingResource + - !GetAtt VirtualNetworkExistingResource.DefaultSecurityGroup + - !GetAtt VirtualNetwork.DefaultSecurityGroup + SubnetIds: + - !If + - VirtualNetworkUseExistingResource + - !GetAtt VirtualNetworkExistingResource.PrivateSubnet1 + - !Ref VirtualNetworkPrivateSubnet1 + - !If + - VirtualNetworkUseExistingResource + - !GetAtt VirtualNetworkExistingResource.PrivateSubnet2 + - !Ref VirtualNetworkPrivateSubnet2 + Environment: + Variables: + DB_ID: !If + - DatabaseUseExistingResource + - !Ref DatabaseExistingResource + - !Ref Database + DB_ADDRESS: !If + - DatabaseUseExistingResource + - !GetAtt DatabaseExistingResource.Endpoint.Address + - !GetAtt Database.Endpoint.Address + DB_PORT: !If + - DatabaseUseExistingResource + - !GetAtt DatabaseExistingResource.Endpoint.Port + - !GetAtt Database.Endpoint.Port + DB_ARN: !If + - DatabaseUseExistingResource + - !Sub arn:aws:rds:${AWS::Region}:${AWS::AccountId}:cluster:${DatabaseExistingResource} + - !Sub arn:aws:rds:${AWS::Region}:${AWS::AccountId}:cluster:${Database} + DB_ROOT_USER_SECRET_ARN: !If + - DatabaseUseExistingResource + - !GetAtt DatabaseExistingResource.RootUserSecret + - !Ref DatabaseRootUserSecret + SECRETS_NAMESPACE: !Sub /${EnvironmentTagName}/ + Events: + HttpApiANYapibooksproxy: + Type: HttpApi + Properties: + Path: /api/books/{proxy+} + Method: ANY + ApiId: !Ref HttpApi + PayloadFormatVersion: '2.0' + TimeoutInMillis: 29000 + HttpApiANYapibooks: + Type: HttpApi + Properties: + Path: /api/books + Method: ANY + ApiId: !Ref HttpApi + PayloadFormatVersion: '2.0' + TimeoutInMillis: 29000 +Parameters: + StackTagName: + Type: String + Description: Stack Name (injected by Stackery at deployment time) + EnvironmentTagName: + Type: String + Description: Environment Name (injected by Stackery at deployment time) + EnvConfigdotnetVirtualNetworkAsString: + Type: AWS::SSM::Parameter::Value + Default: //dotnet/VirtualNetwork + EnvConfigdotnetDatabaseAsString: + Type: AWS::SSM::Parameter::Value + Default: //dotnet/Database +Conditions: + VirtualNetworkCreateNewResource: !Equals + - 'false' + - !Ref EnvConfigdotnetVirtualNetworkAsString + VirtualNetworkUseExistingResource: !Not + - Condition: VirtualNetworkCreateNewResource + DatabaseCreateNewResource: !Equals + - 'false' + - !Ref EnvConfigdotnetDatabaseAsString + DatabaseUseExistingResource: !Not + - Condition: DatabaseCreateNewResource +Metadata: + EnvConfigParameters: + EnvConfigdotnetVirtualNetworkAsString: dotnet.VirtualNetwork + EnvConfigdotnetDatabaseAsString: dotnet.Database \ No newline at end of file From fe150ecfbe3c8dc10947b3e33947e54d3054ade2 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Fri, 26 Feb 2021 14:51:50 -0800 Subject: [PATCH 2/2] Convert to .NET Core 3.1 --- webapi/Controllers/AuthorsController.cs | 124 ------------------- webapi/Controllers/BooksController.cs | 37 ++---- webapi/Data/webapiConnectionStringBuilder.cs | 5 +- webapi/Data/webapiContext.cs | 10 +- webapi/Data/webapiInitializer.cs | 24 ---- webapi/LambdaEntryPoint.cs | 24 ++++ webapi/webapi.csproj | 4 + 7 files changed, 45 insertions(+), 183 deletions(-) delete mode 100644 webapi/Controllers/AuthorsController.cs delete mode 100644 webapi/Data/webapiInitializer.cs create mode 100644 webapi/LambdaEntryPoint.cs diff --git a/webapi/Controllers/AuthorsController.cs b/webapi/Controllers/AuthorsController.cs deleted file mode 100644 index 2015128..0000000 --- a/webapi/Controllers/AuthorsController.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Entity.Infrastructure; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using System.Web.Http; -using System.Web.Http.Description; -using webapi.Data; -using webapi.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.AspNetCore.Mvc; - -namespace webapi.Controllers -{ - [ApiController] - public class AuthorsController : ControllerBase - { - private webapiContext db = new webapiContext(); - // GET: api/Authors - public IQueryable GetAuthors() - { - return db.Authors; - } - - // GET: api/Authors/5 - [ResponseType(typeof(Author))] - public async Task GetAuthor(int id) - { - Author author = await db.Authors.FindAsync(id); - if (author == null) - { - return NotFound(); - } - - return Ok(author); - } - - // PUT: api/Authors/5 - [ResponseType(typeof(void))] - public async Task PutAuthor(int id, Author author) - { - if (!ModelState.IsValid) - { - return BadRequest(ModelState); - } - - if (id != author.Id) - { - return BadRequest(); - } - - db.Entry(author).State = EntityState.Modified; - try - { - await db.SaveChangesAsync(); - } - catch (DbUpdateConcurrencyException) - { - if (!AuthorExists(id)) - { - return NotFound(); - } - else - { - throw; - } - } - - return StatusCode(HttpStatusCode.NoContent); - } - - // POST: api/Authors - [ResponseType(typeof(Author))] - public async Task PostAuthor(Author author) - { - if (!ModelState.IsValid) - { - return BadRequest(ModelState); - } - - db.Authors.Add(author); - await db.SaveChangesAsync(); - return CreatedAtRoute("DefaultApi", new - { - id = author.Id - } - - , author); - } - - // DELETE: api/Authors/5 - [ResponseType(typeof(Author))] - public async Task DeleteAuthor(int id) - { - Author author = await db.Authors.FindAsync(id); - if (author == null) - { - return NotFound(); - } - - db.Authors.Remove(author); - await db.SaveChangesAsync(); - return Ok(author); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - db.Dispose(); - } - - base.Dispose(disposing); - } - - private bool AuthorExists(int id) - { - return db.Authors.Count(e => e.Id == id) > 0; - } - } -} \ No newline at end of file diff --git a/webapi/Controllers/BooksController.cs b/webapi/Controllers/BooksController.cs index e892ddc..c270027 100644 --- a/webapi/Controllers/BooksController.cs +++ b/webapi/Controllers/BooksController.cs @@ -1,13 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Entity.Infrastructure; using System.Linq; using System.Net; -using System.Net.Http; using System.Threading.Tasks; -using System.Web.Http; -using System.Web.Http.Description; using webapi.Data; using webapi.Models; using Microsoft.EntityFrameworkCore; @@ -15,19 +8,21 @@ namespace webapi.Controllers { + [Route("api/[controller]")] [ApiController] public class BooksController : ControllerBase { private webapiContext db = new webapiContext(); // GET: api/Books + [HttpGet] public IQueryable GetBooks() { return db.Books.Include(b => b.Author); } // GET: api/Books/5 - [ResponseType(typeof(Book))] - public async Task GetBook(int id) + [HttpGet("{id}")] + public async Task> GetBook(int id) { Book book = await db.Books.FindAsync(id); if (book == null) @@ -39,8 +34,8 @@ public async Task GetBook(int id) } // PUT: api/Books/5 - [ResponseType(typeof(void))] - public async Task PutBook(int id, Book book) + [HttpPut("{id}")] + public async Task PutBook(int id, Book book) { if (!ModelState.IsValid) { @@ -69,12 +64,12 @@ public async Task PutBook(int id, Book book) } } - return StatusCode(HttpStatusCode.NoContent); + return NoContent(); } // POST: api/Books - [ResponseType(typeof(Book))] - public async Task PostBook(Book book) + [HttpPost("{id}")] + public async Task> PostBook(Book book) { if (!ModelState.IsValid) { @@ -92,8 +87,8 @@ public async Task PostBook(Book book) } // DELETE: api/Books/5 - [ResponseType(typeof(Book))] - public async Task DeleteBook(int id) + [HttpDelete("{id}")] + public async Task> DeleteBook(int id) { Book book = await db.Books.FindAsync(id); if (book == null) @@ -106,16 +101,6 @@ public async Task DeleteBook(int id) return Ok(book); } - protected override void Dispose(bool disposing) - { - if (disposing) - { - db.Dispose(); - } - - base.Dispose(disposing); - } - private bool BookExists(int id) { return db.Books.Count(e => e.Id == id) > 0; diff --git a/webapi/Data/webapiConnectionStringBuilder.cs b/webapi/Data/webapiConnectionStringBuilder.cs index b91b0e6..37a4837 100644 --- a/webapi/Data/webapiConnectionStringBuilder.cs +++ b/webapi/Data/webapiConnectionStringBuilder.cs @@ -26,9 +26,10 @@ public static string ConnectionString static webapiConnectionStringBuilder() { var client = new AmazonSecretsManagerClient(); - var response = client.GetSecretValue(new GetSecretValueRequest{SecretId = Environment.GetEnvironmentVariable("DATABASE_CREDENTIALS_SECRET_ARN")}); + var responseTask = client.GetSecretValueAsync(new GetSecretValueRequest{SecretId = $"{Environment.GetEnvironmentVariable("SECRETS_NAMESPACE")}dotnet/Database/SAUser"}); + var response = responseTask.GetAwaiter().GetResult(); var credentials = JsonConvert.DeserializeObject(response.SecretString); - var builder = new SqlConnectionStringBuilder{DataSource = Environment.GetEnvironmentVariable("DATABASE_ADDRESS"), UserID = credentials.username, Password = credentials.password, InitialCatalog = "books"}; + var builder = new SqlConnectionStringBuilder{DataSource = Environment.GetEnvironmentVariable("DB_ADDRESS"), UserID = credentials.username, Password = credentials.password, InitialCatalog = "books"}; _connectionString = builder.ToString(); } } diff --git a/webapi/Data/webapiContext.cs b/webapi/Data/webapiContext.cs index d292d0a..94ea2f0 100644 --- a/webapi/Data/webapiContext.cs +++ b/webapi/Data/webapiContext.cs @@ -4,18 +4,13 @@ namespace webapi.Data { public class webapiContext : DbContext { - public webapiContext(): base(webapiConnectionStringBuilder.ConnectionString) - { - Database.SetInitializer(new webapiInitializer()); - } - - public System.Data.Entity.DbSet Authors + public DbSet Authors { get; set; } - public System.Data.Entity.DbSet Books + public DbSet Books { get; set; @@ -23,6 +18,7 @@ public System.Data.Entity.DbSet Books protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { /* Use Configuration from static ConfigurationManager to access connection string in appsettings.json. Example below: optionsBuilder.UseSqlServer(ConfigurationManager.Configuration.GetConnectionString("CONNECTIONSTRINGNAME")); */ + optionsBuilder.UseSqlServer(webapiConnectionStringBuilder.ConnectionString); base.OnConfiguring(optionsBuilder); } } diff --git a/webapi/Data/webapiInitializer.cs b/webapi/Data/webapiInitializer.cs deleted file mode 100644 index f1cf392..0000000 --- a/webapi/Data/webapiInitializer.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Data.Entity.Migrations; -using webapi.Models; -using Microsoft.EntityFrameworkCore; - -namespace webapi.Data -{ - public class webapiInitializer : CreateDatabaseIfNotExists - { - protected override void Seed(webapiContext context) - { - context.Authors.AddOrUpdate(x => x.Id, new Author() - {Id = 1, Name = "Jane Austen"}, new Author() - {Id = 2, Name = "Charles Dickens"}, new Author() - {Id = 3, Name = "Miguel de Cervantes"}); - context.Books.AddOrUpdate(x => x.Id, new Book() - {Id = 1, Title = "Pride and Prejudice", Year = 1813, AuthorId = 1, Price = 9.99M, Genre = "Comedy of manners"}, new Book() - {Id = 2, Title = "Northanger Abbey", Year = 1817, AuthorId = 1, Price = 12.95M, Genre = "Gothic parody"}, new Book() - {Id = 3, Title = "David Copperfield", Year = 1850, AuthorId = 2, Price = 15, Genre = "Bildungsroman"}, new Book() - {Id = 4, Title = "Don Quixote", Year = 1617, AuthorId = 3, Price = 8.95M, Genre = "Picaresque"}); - context.SaveChanges(); - base.Seed(context); - } - } -} \ No newline at end of file diff --git a/webapi/LambdaEntryPoint.cs b/webapi/LambdaEntryPoint.cs new file mode 100644 index 0000000..def5726 --- /dev/null +++ b/webapi/LambdaEntryPoint.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.Hosting; + +namespace webapi +{ + /// + /// This class extends from APIGatewayProxyFunction which contains the method FunctionHandlerAsync which is the + /// actual Lambda function entry point. The Lambda handler field should be set to + /// + /// webapi::webapi.LambdaEntryPoint::FunctionHandlerAsync + /// + public class LambdaEntryPoint : Amazon.Lambda.AspNetCoreServer.APIGatewayHttpApiV2ProxyFunction + { + /// + /// The builder has configuration, logging and Amazon API Gateway already configured. The startup class + /// needs to be configured in this method using the UseStartup<>() method. + /// + /// + protected override void Init(IWebHostBuilder builder) + { + builder + .UseStartup(); + } + } +} \ No newline at end of file diff --git a/webapi/webapi.csproj b/webapi/webapi.csproj index 2bf6170..f8d5c55 100644 --- a/webapi/webapi.csproj +++ b/webapi/webapi.csproj @@ -5,9 +5,13 @@ + + + + \ No newline at end of file