From 2205d8c13ff01576e54673def3ca43e0821d45f9 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Thu, 22 Apr 2021 11:45:43 -0700 Subject: [PATCH] Modernize and serverlessize the web api! --- webapi/Controllers/AuthorsController.cs | 124 ------------------- webapi/Controllers/BooksController.cs | 37 ++---- webapi/Data/webapiConnectionStringBuilder.cs | 6 +- webapi/Data/webapiContext.cs | 11 +- webapi/Data/webapiInitializer.cs | 24 ---- webapi/LambdaEntryPoint.cs | 24 ++++ webapi/webapi.csproj | 4 + 7 files changed, 45 insertions(+), 185 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..34c20de 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] + 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 9ea3ffc..f47f9fc 100644 --- a/webapi/Data/webapiConnectionStringBuilder.cs +++ b/webapi/Data/webapiConnectionStringBuilder.cs @@ -26,10 +26,8 @@ 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); diff --git a/webapi/Data/webapiContext.cs b/webapi/Data/webapiContext.cs index d292d0a..5427cf3 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,8 @@ 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..77bb24d --- /dev/null +++ b/webapi/LambdaEntryPoint.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.Hosting; + +namespace webapi +{ + /// + /// This class extends from APIGatewayHttpApiV2ProxyFunction 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(); + } + } +} diff --git a/webapi/webapi.csproj b/webapi/webapi.csproj index 2bf6170..d450ffc 100644 --- a/webapi/webapi.csproj +++ b/webapi/webapi.csproj @@ -5,9 +5,13 @@ + + + + \ No newline at end of file