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 diff --git a/webapi/App_Start/WebApiConfig.cs b/webapi/App_Start/WebApiConfig.cs deleted file mode 100644 index 5f913bb..0000000 --- a/webapi/App_Start/WebApiConfig.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web.Http; - -namespace webapi -{ - public static class WebApiConfig - { - public static void Register(HttpConfiguration config) - { - // Web API configuration and services - - // Web API routes - config.MapHttpAttributeRoutes(); - - config.Routes.MapHttpRoute( - name: "DefaultApi", - routeTemplate: "api/{controller}/{id}", - defaults: new { id = RouteParameter.Optional } - ); - } - } -} diff --git a/webapi/Controllers/AuthorsController.cs b/webapi/Controllers/AuthorsController.cs deleted file mode 100644 index 0c075fb..0000000 --- a/webapi/Controllers/AuthorsController.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Entity; -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; - -namespace webapi.Controllers -{ - public class AuthorsController : ApiController - { - 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 690bf60..c270027 100644 --- a/webapi/Controllers/BooksController.cs +++ b/webapi/Controllers/BooksController.cs @@ -1,33 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Entity; -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 { - public class BooksController : ApiController + [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); + 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) { @@ -53,7 +48,6 @@ public async Task PutBook(int id, Book book) } db.Entry(book).State = EntityState.Modified; - try { await db.SaveChangesAsync(); @@ -70,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) { @@ -84,13 +78,17 @@ public async Task PostBook(Book book) db.Books.Add(book); await db.SaveChangesAsync(); + return CreatedAtRoute("DefaultApi", new + { + id = book.Id + } - return CreatedAtRoute("DefaultApi", new { id = book.Id }, 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) @@ -100,19 +98,9 @@ public async Task DeleteBook(int id) db.Books.Remove(book); await db.SaveChangesAsync(); - 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 d67a294..9492d14 100644 --- a/webapi/Data/webapiConnectionStringBuilder.cs +++ b/webapi/Data/webapiConnectionStringBuilder.cs @@ -2,7 +2,7 @@ using Amazon.SecretsManager.Model; using Newtonsoft.Json; using System; -using System.Data.SqlClient; +using Microsoft.Data.SqlClient; namespace webapi.Data { @@ -15,7 +15,6 @@ private class Credentials } private static string _connectionString; - public static string ConnectionString { get @@ -27,21 +26,10 @@ public static string ConnectionString static webapiConnectionStringBuilder() { var client = new AmazonSecretsManagerClient(); - var response = client.GetSecretValue(new GetSecretValueRequest - { - SecretId = Environment.GetEnvironmentVariable("DB_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("DB_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 b277391..94ea2f0 100644 --- a/webapi/Data/webapiContext.cs +++ b/webapi/Data/webapiContext.cs @@ -1,16 +1,25 @@ -using System.Data.Entity; +using Microsoft.EntityFrameworkCore; namespace webapi.Data { public class webapiContext : DbContext { - public webapiContext() : base(webapiConnectionStringBuilder.ConnectionString) + public DbSet Authors { - Database.SetInitializer(new webapiInitializer()); + get; + set; } - public System.Data.Entity.DbSet Authors { get; set; } + public DbSet Books + { + get; + set; + } - public System.Data.Entity.DbSet Books { get; set; } + 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); + } } -} +} \ No newline at end of file diff --git a/webapi/Data/webapiInitializer.cs b/webapi/Data/webapiInitializer.cs deleted file mode 100644 index 3e846a7..0000000 --- a/webapi/Data/webapiInitializer.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Data.Entity; -using System.Data.Entity.Migrations; -using webapi.Models; - -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); - } - } -} diff --git a/webapi/Global.asax b/webapi/Global.asax deleted file mode 100644 index b87fae1..0000000 --- a/webapi/Global.asax +++ /dev/null @@ -1 +0,0 @@ -<%@ Application Codebehind="Global.asax.cs" Inherits="webapi.WebApiApplication" Language="C#" %> diff --git a/webapi/Global.asax.cs b/webapi/Global.asax.cs deleted file mode 100644 index 679c531..0000000 --- a/webapi/Global.asax.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Http; -using System.Web.Routing; - -namespace webapi -{ - public class WebApiApplication : System.Web.HttpApplication - { - protected void Application_Start() - { - GlobalConfiguration.Configure(WebApiConfig.Register); - } - } -} 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/Program.cs b/webapi/Program.cs new file mode 100644 index 0000000..9be3614 --- /dev/null +++ b/webapi/Program.cs @@ -0,0 +1,30 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace webapi +{ + + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } + + +} diff --git a/webapi/Properties/AssemblyInfo.cs b/webapi/Properties/AssemblyInfo.cs deleted file mode 100644 index 8778422..0000000 --- a/webapi/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("webapi")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("webapi")] -[assembly: AssemblyCopyright("Copyright © 2020")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("647f07a8-81ae-4496-b6ea-fe25cb78b68b")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/webapi/Startup.cs b/webapi/Startup.cs new file mode 100644 index 0000000..6ba7e13 --- /dev/null +++ b/webapi/Startup.cs @@ -0,0 +1,62 @@ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpsPolicy; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace webapi +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + ConfigurationManager.Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + //Added Services + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseHttpsRedirection(); + + //Added Middleware + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } + + public class ConfigurationManager + { + public static IConfiguration Configuration { get; set; } + } +} + diff --git a/webapi/appsettings.json b/webapi/appsettings.json new file mode 100644 index 0000000..d06c703 --- /dev/null +++ b/webapi/appsettings.json @@ -0,0 +1,15 @@ +{ + "ConnectionStrings": [ + { + "LocalSqlServer": "data source=.\\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" + } + ], + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/webapi/packages.config b/webapi/packages.config deleted file mode 100644 index c4defb4..0000000 --- a/webapi/packages.config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/webapi/webapi.csproj b/webapi/webapi.csproj index 714652e..f8d5c55 100644 --- a/webapi/webapi.csproj +++ b/webapi/webapi.csproj @@ -1,178 +1,17 @@ - - - - - - Debug - AnyCPU - - - 2.0 - {647F07A8-81AE-4496-B6EA-FE25CB78B68B} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - webapi - webapi - v4.7.2 - true - false - 44393 - - - - - - - - - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - - - true - pdbonly - true - bin\ - TRACE - prompt - 4 - - - - ..\packages\AWSSDK.Core.3.5.2.10\lib\net45\AWSSDK.Core.dll - - - ..\packages\AWSSDK.SecretsManager.3.5.0.70\lib\net45\AWSSDK.SecretsManager.dll - - - ..\packages\EntityFramework.6.4.0\lib\net45\EntityFramework.dll - - - ..\packages\EntityFramework.6.4.0\lib\net45\EntityFramework.SqlServer.dll - - - ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.1\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll - - - - ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - - - - - - ..\packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll - - - ..\packages\Microsoft.AspNet.WebApi.Core.5.2.7\lib\net45\System.Web.Http.dll - - - ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.7\lib\net45\System.Web.Http.WebHost.dll - - - - - - - - - - - - - - Global.asax - - - - 202002162319195_Initial.cs - - - - - - - - - - Web.config - - - Web.config - - - - - - - - 202002162319195_Initial.cs - - - - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - True - True - 60441 - / - https://localhost:44393/ - False - False - - - False - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - \ No newline at end of file + + + + netcoreapp3.1 + + + + + + + + + + + + + \ No newline at end of file