├── .gitignore ├── README.md ├── my-books-tests ├── PublishersControllerTests.cs ├── PublishersServiceTest.cs └── my-books-tests.csproj ├── my-books.sln └── my-books ├── ActionResults └── CustomActionResult.cs ├── Controllers ├── AuthenticationController.cs ├── AuthorsController.cs ├── BooksController.cs ├── LogsController.cs ├── PublishersController.cs ├── v1 │ └── TestController.cs └── v2 │ └── TestController.cs ├── Data ├── AppDbContext.cs ├── AppDbInitializer.cs ├── Models │ ├── ApplicationUser.cs │ ├── Author.cs │ ├── Book.cs │ ├── Book_Author.cs │ ├── Log.cs │ ├── Publisher.cs │ └── RefreshToken.cs ├── Paging │ └── PaginatedList.cs ├── Services │ ├── AuthorsService.cs │ ├── BooksService.cs │ ├── LogsService.cs │ └── PublishersService.cs └── ViewModels │ ├── Authentication │ ├── AuthResultVM.cs │ ├── LoginVM.cs │ ├── RegisterVM.cs │ └── UserRoles.cs │ ├── AuthorVM.cs │ ├── BookVM.cs │ ├── CustomActionResultVM.cs │ ├── ErrorVM.cs │ └── PublisherVM.cs ├── Exceptions ├── CustomExceptionMiddleware.cs ├── ExceptionMiddlewareExtensions.cs └── PublisherNameException.cs ├── Logs ├── log20210319.txt └── log20210426.txt ├── Migrations ├── 20210127195307_InitialDatabaseMigration.Designer.cs ├── 20210127195307_InitialDatabaseMigration.cs ├── 20210207135018_PublisherAdded.Designer.cs ├── 20210207135018_PublisherAdded.cs ├── 20210207144751_ManyToManyAdded.Designer.cs ├── 20210207144751_ManyToManyAdded.cs ├── 20210207162828_BookAuthorColumnRemoved.Designer.cs ├── 20210207162828_BookAuthorColumnRemoved.cs ├── 20210319135502_LogTableAdded.Designer.cs ├── 20210319135502_LogTableAdded.cs ├── 20210426111014_IdentityAdded.Designer.cs ├── 20210426111014_IdentityAdded.cs ├── 20210426125308_RefreshTokensAdded.Designer.cs ├── 20210426125308_RefreshTokensAdded.cs └── AppDbContextModelSnapshot.cs ├── Program.cs ├── Properties └── launchSettings.json ├── Startup.cs ├── appsettings.Development.json ├── appsettings.json ├── my-books.csproj └── obj ├── Debug └── net5.0 │ ├── .NETCoreApp,Version=v5.0.AssemblyAttributes.cs │ ├── my-books.AssemblyInfo.cs │ ├── my-books.AssemblyInfoInputs.cache │ ├── my-books.GeneratedMSBuildEditorConfig.editorconfig │ ├── my-books.assets.cache │ └── my-books.csprojAssemblyReference.cache ├── my-books.csproj.nuget.dgspec.json ├── my-books.csproj.nuget.g.props ├── my-books.csproj.nuget.g.targets ├── project.assets.json └── project.nuget.cache /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | /my-books/bin/Debug/net5.0 6 | /my-books/obj/Debug/net5.0/staticwebassets 7 | *.user 8 | *.suo 9 | /my-books-tests/bin/Debug/netcoreapp3.1 10 | /my-books-tests/obj 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Complete Guide to Asp.Net Core Web API 2 | 3 | This is the source code of the "Complete Guide to Asp.Net Core Web API" course 4 | 5 | 📌 Course link: https://www.udemy.com/course/the-complete-guide-to-aspnet-web-api/?referralCode=9ABCB407460A099020BD 6 | 7 | # What you will learn? 8 | This course will teach you all you need to know to build personal or commercial applications using Asp.Net Core (.NET 5) Web API as your development framework. You will start from just Visual Studio and build your app from the ground up. 9 | 10 | As data storage, you will use an SQL database and Entity Framework will be used to interact with your data. You will also learn how to update database schema using Entity Framework migrations, how to add data to the database, get data from the database, update data in the database and also delete data from the database. 11 | 12 | You will not only learn about the default features or capabilities that Asp.Net Core 5 Web API has to offer, but you will also create your custom implementations. For example, you will learn how to implement your custom Web API return type, how to build a custom exception, or even a custom middleware exception handler. 13 | 14 | You will learn all these, step by step with hands-on practice. You will also have a lot of quizzes that will help to improve your knowledge of Web API. 15 | 16 | Some of the topics that this course covers are: 17 | 18 | - Introduction to Web API 19 | - Building your first Asp.Net Core (.NET 5) API 20 | - Working with relational data 21 | - Controller Action return types 22 | - Error & Exception handling 23 | - Sorting, Filtering, and Paging 24 | - Web API Versioning 25 | - Unit Testing 26 | - Logging information 27 | - Deploying your app and database to Azure 28 | 29 | and much more... 30 | 31 | You will find a branch for each part/clip with a begin and an end state. 32 | 33 | For example for part 13 you have 2 branches: 34 | - begin-13: this has the initial state of the code 35 | - end-13: this has the end state of the code 36 | 37 | Course link: https://www.udemy.com/course/the-complete-guide-to-aspnet-web-api/?referralCode=9ABCB407460A099020BD 38 | -------------------------------------------------------------------------------- /my-books-tests/PublishersControllerTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Logging.Abstractions; 4 | using my_books.Controllers; 5 | using my_books.Data; 6 | using my_books.Data.Models; 7 | using my_books.Data.Services; 8 | using my_books.Data.ViewModels; 9 | using NUnit.Framework; 10 | using System; 11 | using System.Collections.Generic; 12 | using System.Linq; 13 | using System.Text; 14 | using System.Threading.Tasks; 15 | 16 | namespace my_books_tests 17 | { 18 | public class PublishersControllerTests 19 | { 20 | private static DbContextOptions dbContextOptions = new DbContextOptionsBuilder() 21 | .UseInMemoryDatabase(databaseName: "BookDbControllerTest") 22 | .Options; 23 | 24 | AppDbContext context; 25 | PublishersService publishersService; 26 | PublishersController publishersController; 27 | 28 | [OneTimeSetUp] 29 | public void Setup() 30 | { 31 | context = new AppDbContext(dbContextOptions); 32 | context.Database.EnsureCreated(); 33 | 34 | SeedDatabase(); 35 | 36 | publishersService = new PublishersService(context); 37 | publishersController = new PublishersController(publishersService, new NullLogger()); 38 | } 39 | 40 | [Test, Order(1)] 41 | public void HTTPGET_GetAllPublishers_WithSortBySearchPageNr_ReturnOk_Test() 42 | { 43 | IActionResult actionResult = publishersController.GetAllPublishers("name_desc", "Publisher", 1); 44 | Assert.That(actionResult, Is.TypeOf()); 45 | var actionResultData = (actionResult as OkObjectResult).Value as List; 46 | Assert.That(actionResultData.First().Name, Is.EqualTo("Publisher 6")); 47 | Assert.That(actionResultData.First().Id, Is.EqualTo(6)); 48 | Assert.That(actionResultData.Count, Is.EqualTo(5)); 49 | 50 | IActionResult actionResultSecondPage = publishersController.GetAllPublishers("name_desc", "Publisher", 2); 51 | Assert.That(actionResultSecondPage, Is.TypeOf()); 52 | var actionResultDataSecondPage = (actionResultSecondPage as OkObjectResult).Value as List; 53 | Assert.That(actionResultDataSecondPage.First().Name, Is.EqualTo("Publisher 1")); 54 | Assert.That(actionResultDataSecondPage.First().Id, Is.EqualTo(1)); 55 | Assert.That(actionResultDataSecondPage.Count, Is.EqualTo(1)); 56 | } 57 | 58 | [Test, Order(2)] 59 | public void HTTPGET_GetPublisherById_ReturnsOk_Test() 60 | { 61 | int publisherId = 1; 62 | 63 | IActionResult actionResult = publishersController.GetPublisherById(publisherId); 64 | 65 | Assert.That(actionResult, Is.TypeOf()); 66 | 67 | var publisherData = (actionResult as OkObjectResult).Value as Publisher; 68 | Assert.That(publisherData.Id, Is.EqualTo(1)); 69 | Assert.That(publisherData.Name, Is.EqualTo("publisher 1").IgnoreCase); 70 | } 71 | 72 | [Test, Order(3)] 73 | public void HTTPGET_GetPublisherById_ReturnsNotFound_Test() 74 | { 75 | int publisherId = 99; 76 | 77 | IActionResult actionResult = publishersController.GetPublisherById(publisherId); 78 | 79 | Assert.That(actionResult, Is.TypeOf()); 80 | 81 | } 82 | 83 | [Test, Order(4)] 84 | public void HTTPPOST_AddPublisher_ReturnsCreated_Test() 85 | { 86 | var newPublisherVM = new PublisherVM() 87 | { 88 | Name = "New Publisher" 89 | }; 90 | 91 | IActionResult actionResult = publishersController.AddPublisher(newPublisherVM); 92 | 93 | Assert.That(actionResult, Is.TypeOf()); 94 | } 95 | 96 | [Test, Order(5)] 97 | public void HTTPPOST_AddPublisher_ReturnsBadRequest_Test() 98 | { 99 | var newPublisherVM = new PublisherVM() 100 | { 101 | Name = "123 New Publisher" 102 | }; 103 | 104 | IActionResult actionResult = publishersController.AddPublisher(newPublisherVM); 105 | 106 | Assert.That(actionResult, Is.TypeOf()); 107 | } 108 | 109 | [Test, Order(6)] 110 | public void HTTPDELETE_DeletePublisherById_ReturnsOk_Test() 111 | { 112 | int publisherId = 6; 113 | 114 | IActionResult actionResult = publishersController.DeletePublisherById(publisherId); 115 | 116 | Assert.That(actionResult, Is.TypeOf()); 117 | 118 | } 119 | 120 | 121 | [Test, Order(7)] 122 | public void HTTPDELETE_DeletePublisherById_ReturnsBadRequest_Test() 123 | { 124 | int publisherId = 6; 125 | 126 | IActionResult actionResult = publishersController.DeletePublisherById(publisherId); 127 | 128 | Assert.That(actionResult, Is.TypeOf()); 129 | } 130 | 131 | [OneTimeTearDown] 132 | public void CleanUp() 133 | { 134 | context.Database.EnsureDeleted(); 135 | } 136 | 137 | 138 | 139 | private void SeedDatabase() 140 | { 141 | var publishers = new List 142 | { 143 | new Publisher() { 144 | Id = 1, 145 | Name = "Publisher 1" 146 | }, 147 | new Publisher() { 148 | Id = 2, 149 | Name = "Publisher 2" 150 | }, 151 | new Publisher() { 152 | Id = 3, 153 | Name = "Publisher 3" 154 | }, 155 | new Publisher() { 156 | Id = 4, 157 | Name = "Publisher 4" 158 | }, 159 | new Publisher() { 160 | Id = 5, 161 | Name = "Publisher 5" 162 | }, 163 | new Publisher() { 164 | Id = 6, 165 | Name = "Publisher 6" 166 | }, 167 | }; 168 | context.Publishers.AddRange(publishers); 169 | 170 | 171 | context.SaveChanges(); 172 | } 173 | 174 | 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /my-books-tests/PublishersServiceTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using my_books.Data; 3 | using my_books.Data.Models; 4 | using my_books.Data.Services; 5 | using my_books.Data.ViewModels; 6 | using my_books.Exceptions; 7 | using NUnit.Framework; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | 12 | namespace my_books_tests 13 | { 14 | public class PublishersServiceTest 15 | { 16 | private static DbContextOptions dbContextOptions = new DbContextOptionsBuilder() 17 | .UseInMemoryDatabase(databaseName: "BookDbTest") 18 | .Options; 19 | 20 | AppDbContext context; 21 | PublishersService publishersService; 22 | 23 | [OneTimeSetUp] 24 | public void Setup() 25 | { 26 | context = new AppDbContext(dbContextOptions); 27 | context.Database.EnsureCreated(); 28 | 29 | SeedDatabase(); 30 | 31 | publishersService = new PublishersService(context); 32 | } 33 | 34 | 35 | [Test, Order(1)] 36 | public void GetAllPublishers_WithNoSortBy_WithNoSearchString_WithNoPageNumber_Test() 37 | { 38 | var result = publishersService.GetAllPublishers("", "", null); 39 | 40 | Assert.That(result.Count, Is.EqualTo(5)); 41 | } 42 | 43 | [Test, Order(2)] 44 | public void GetAllPublishers_WithNoSortBy_WithNoSearchString_WithPageNumber_Test() 45 | { 46 | var result = publishersService.GetAllPublishers("", "", 2); 47 | 48 | Assert.That(result.Count, Is.EqualTo(1)); 49 | } 50 | 51 | [Test, Order(3)] 52 | public void GetAllPublishers_WithNoSortBy_WithSearchString_WithNoPageNumber_Test() 53 | { 54 | var result = publishersService.GetAllPublishers("", "3", null); 55 | 56 | Assert.That(result.Count, Is.EqualTo(1)); 57 | Assert.That(result.FirstOrDefault().Name, Is.EqualTo("Publisher 3")); 58 | } 59 | 60 | [Test, Order(4)] 61 | public void GetAllPublishers_WithSortBy_WithNoSearchString_WithNoPageNumber_Test() 62 | { 63 | var result = publishersService.GetAllPublishers("name_desc", "", null); 64 | 65 | Assert.That(result.Count, Is.EqualTo(5)); 66 | Assert.That(result.FirstOrDefault().Name, Is.EqualTo("Publisher 6")); 67 | } 68 | 69 | [Test, Order(5)] 70 | public void GetPublisherById_WithResponse_Test() 71 | { 72 | var result = publishersService.GetPublisherById(1); 73 | 74 | Assert.That(result.Id, Is.EqualTo(1)); 75 | Assert.That(result.Name, Is.EqualTo("Publisher 1")); 76 | } 77 | 78 | [Test, Order(6)] 79 | public void GetPublisherById_WithoutResponse_Test() 80 | { 81 | var result = publishersService.GetPublisherById(99); 82 | 83 | Assert.That(result, Is.Null); 84 | } 85 | 86 | [Test, Order(7)] 87 | public void AddPublisher_WithException_Test() 88 | { 89 | var newPublisher = new PublisherVM() 90 | { 91 | Name = "123 With Exception" 92 | }; 93 | 94 | Assert.That(() => publishersService.AddPublisher(newPublisher), Throws.Exception.TypeOf().With.Message.EqualTo("Name starts with number")); 95 | } 96 | 97 | [Test, Order(8)] 98 | public void AddPublisher_WithoutException_Test() 99 | { 100 | var newPublisher = new PublisherVM() 101 | { 102 | Name = "Without Exception" 103 | }; 104 | 105 | var result = publishersService.AddPublisher(newPublisher); 106 | 107 | Assert.That(result, Is.Not.Null); 108 | Assert.That(result.Name, Does.StartWith("Without")); 109 | Assert.That(result.Id, Is.Not.Null); 110 | } 111 | 112 | [Test, Order(9)] 113 | public void GetPublisherData_Test() 114 | { 115 | var result = publishersService.GetPublisherData(1); 116 | 117 | Assert.That(result.Name, Is.EqualTo("Publisher 1")); 118 | Assert.That(result.BookAuthors, Is.Not.Empty); 119 | Assert.That(result.BookAuthors.Count, Is.GreaterThan(0)); 120 | 121 | var firstBookName = result.BookAuthors.OrderBy(n => n.BookName).FirstOrDefault().BookName; 122 | Assert.That(firstBookName, Is.EqualTo("Book 1 Title")); 123 | } 124 | 125 | [Test, Order(10)] 126 | public void DeletePublisherById_PublisherExists_Test() 127 | { 128 | int publisherId = 6; 129 | 130 | var publisherBefore = publishersService.GetPublisherById(publisherId); 131 | Assert.That(publisherBefore, Is.Not.Null); 132 | Assert.That(publisherBefore.Name, Is.EqualTo("Publisher 6")); 133 | 134 | publishersService.DeletePublisherById(publisherId); 135 | 136 | var publisherAfter = publishersService.GetPublisherById(publisherId); 137 | Assert.That(publisherAfter, Is.Null); 138 | } 139 | 140 | [Test, Order(11)] 141 | public void DeletePublisherById_PublisherDoesNotExists_Test() 142 | { 143 | int publisherId = 6; 144 | 145 | Assert.That(() => publishersService.DeletePublisherById(publisherId), Throws.Exception.TypeOf().With.Message.EqualTo($"The publisher with id: {publisherId} does not exist")); 146 | } 147 | 148 | 149 | [OneTimeTearDown] 150 | public void CleanUp() 151 | { 152 | context.Database.EnsureDeleted(); 153 | } 154 | 155 | private void SeedDatabase() 156 | { 157 | var publishers = new List 158 | { 159 | new Publisher() { 160 | Id = 1, 161 | Name = "Publisher 1" 162 | }, 163 | new Publisher() { 164 | Id = 2, 165 | Name = "Publisher 2" 166 | }, 167 | new Publisher() { 168 | Id = 3, 169 | Name = "Publisher 3" 170 | }, 171 | new Publisher() { 172 | Id = 4, 173 | Name = "Publisher 4" 174 | }, 175 | new Publisher() { 176 | Id = 5, 177 | Name = "Publisher 5" 178 | }, 179 | new Publisher() { 180 | Id = 6, 181 | Name = "Publisher 6" 182 | }, 183 | }; 184 | context.Publishers.AddRange(publishers); 185 | 186 | var authors = new List() 187 | { 188 | new Author() 189 | { 190 | Id = 1, 191 | FullName = "Author 1" 192 | }, 193 | new Author() 194 | { 195 | Id = 2, 196 | FullName = "Author 2" 197 | } 198 | }; 199 | context.Authors.AddRange(authors); 200 | 201 | 202 | var books = new List() 203 | { 204 | new Book() 205 | { 206 | Id = 1, 207 | Title = "Book 1 Title", 208 | Description = "Book 1 Description", 209 | IsRead = false, 210 | Genre = "Genre", 211 | CoverUrl = "https://...", 212 | DateAdded = DateTime.Now.AddDays(-10), 213 | PublisherId = 1 214 | }, 215 | new Book() 216 | { 217 | Id = 2, 218 | Title = "Book 2 Title", 219 | Description = "Book 2 Description", 220 | IsRead = false, 221 | Genre = "Genre", 222 | CoverUrl = "https://...", 223 | DateAdded = DateTime.Now.AddDays(-10), 224 | PublisherId = 1 225 | } 226 | }; 227 | context.Books.AddRange(books); 228 | 229 | var books_authors = new List() 230 | { 231 | new Book_Author() 232 | { 233 | Id = 1, 234 | BookId = 1, 235 | AuthorId = 1 236 | }, 237 | new Book_Author() 238 | { 239 | Id = 2, 240 | BookId = 1, 241 | AuthorId = 2 242 | }, 243 | new Book_Author() 244 | { 245 | Id = 3, 246 | BookId = 2, 247 | AuthorId = 2 248 | }, 249 | }; 250 | context.Books_Authors.AddRange(books_authors); 251 | 252 | 253 | context.SaveChanges(); 254 | } 255 | 256 | } 257 | } -------------------------------------------------------------------------------- /my-books-tests/my-books-tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | my_books_tests 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /my-books.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30804.86 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "my-books", "my-books\my-books.csproj", "{571350E0-9962-41A0-9495-BA44ACF3499C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "my-books-tests", "my-books-tests\my-books-tests.csproj", "{6219646B-8557-4B27-9950-8CF5FE427855}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {571350E0-9962-41A0-9495-BA44ACF3499C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {571350E0-9962-41A0-9495-BA44ACF3499C}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {571350E0-9962-41A0-9495-BA44ACF3499C}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {571350E0-9962-41A0-9495-BA44ACF3499C}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {6219646B-8557-4B27-9950-8CF5FE427855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {6219646B-8557-4B27-9950-8CF5FE427855}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {6219646B-8557-4B27-9950-8CF5FE427855}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {6219646B-8557-4B27-9950-8CF5FE427855}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {D8F8C98E-7F86-48FD-A7C0-3BC314200164} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /my-books/ActionResults/CustomActionResult.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.Mvc; 3 | using my_books.Data.ViewModels; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace my_books.ActionResults 10 | { 11 | public class CustomActionResult : IActionResult 12 | { 13 | private readonly CustomActionResultVM _result; 14 | 15 | public CustomActionResult(CustomActionResultVM result) 16 | { 17 | _result = result; 18 | } 19 | 20 | public async Task ExecuteResultAsync(ActionContext context) 21 | { 22 | var objectResult = new ObjectResult(_result.Exception ?? _result.Publisher as object) 23 | { 24 | StatusCode = _result.Exception != null ? StatusCodes.Status500InternalServerError : StatusCodes.Status200OK 25 | }; 26 | 27 | await objectResult.ExecuteResultAsync(context); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /my-books/Controllers/AuthenticationController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.IdentityModel.Tokens; 7 | using my_books.Data; 8 | using my_books.Data.Models; 9 | using my_books.Data.ViewModels.Authentication; 10 | using System; 11 | using System.Collections.Generic; 12 | using System.IdentityModel.Tokens.Jwt; 13 | using System.Linq; 14 | using System.Security.Claims; 15 | using System.Text; 16 | using System.Threading.Tasks; 17 | 18 | namespace my_books.Controllers 19 | { 20 | [Route("api/[controller]")] 21 | [ApiController] 22 | public class AuthenticationController : ControllerBase 23 | { 24 | private readonly UserManager _userManager; 25 | private readonly RoleManager _roleManager; 26 | private readonly AppDbContext _context; 27 | private readonly IConfiguration _configuration; 28 | 29 | public AuthenticationController(UserManager userManager, 30 | RoleManager roleManager, 31 | AppDbContext context, 32 | IConfiguration configuration) 33 | { 34 | _userManager = userManager; 35 | _roleManager = roleManager; 36 | _context = context; 37 | _configuration = configuration; 38 | } 39 | 40 | [HttpPost("register-user")] 41 | public async Task Register([FromBody]RegisterVM payload) 42 | { 43 | if (!ModelState.IsValid) 44 | { 45 | return BadRequest("Please, provide all required fields"); 46 | } 47 | 48 | var userExists = await _userManager.FindByEmailAsync(payload.Email); 49 | 50 | if(userExists != null) 51 | { 52 | return BadRequest($"User {payload.Email} already exists"); 53 | } 54 | 55 | ApplicationUser newUser = new ApplicationUser() 56 | { 57 | Email = payload.Email, 58 | UserName = payload.UserName, 59 | SecurityStamp = Guid.NewGuid().ToString() 60 | }; 61 | 62 | var result = await _userManager.CreateAsync(newUser, payload.Password); 63 | 64 | if (!result.Succeeded) 65 | { 66 | return BadRequest("User could not be created!"); 67 | } 68 | 69 | switch (payload.Role) 70 | { 71 | case "Admin": 72 | await _userManager.AddToRoleAsync(newUser, UserRoles.Admin); 73 | break; 74 | case "Publisher": 75 | await _userManager.AddToRoleAsync(newUser, UserRoles.Publisher); 76 | break; 77 | case "Author": 78 | await _userManager.AddToRoleAsync(newUser, UserRoles.Author); 79 | break; 80 | default: 81 | await _userManager.AddToRoleAsync(newUser, UserRoles.User); 82 | break; 83 | } 84 | 85 | return Created(nameof(Register), $"User {payload.Email} created"); 86 | } 87 | 88 | [HttpPost("login-user")] 89 | public async Task Login([FromBody]LoginVM payload) 90 | { 91 | if (!ModelState.IsValid) 92 | { 93 | return BadRequest("Please, provide all required fields"); 94 | } 95 | 96 | var user = await _userManager.FindByEmailAsync(payload.Email); 97 | 98 | if(user != null && await _userManager.CheckPasswordAsync(user, payload.Password)) 99 | { 100 | var tokenValue = await GenerateJwtToken(user); 101 | 102 | return Ok(tokenValue); 103 | } 104 | 105 | return Unauthorized(); 106 | } 107 | 108 | 109 | 110 | private async Task GenerateJwtToken(ApplicationUser user) 111 | { 112 | var authClaims = new List() 113 | { 114 | new Claim(ClaimTypes.Name, user.UserName), 115 | new Claim(ClaimTypes.NameIdentifier, user.Id), 116 | new Claim(JwtRegisteredClaimNames.Email, user.Email), 117 | new Claim(JwtRegisteredClaimNames.Sub, user.Email), 118 | new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) 119 | }; 120 | 121 | //Add User Roles 122 | var userRoles = await _userManager.GetRolesAsync(user); 123 | foreach (var userRole in userRoles) 124 | { 125 | authClaims.Add(new Claim(ClaimTypes.Role, userRole)); 126 | } 127 | 128 | 129 | var authSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_configuration["JWT:Secret"])); 130 | 131 | var token = new JwtSecurityToken( 132 | issuer: _configuration["JWT:Issuer"], 133 | audience: _configuration["JWT:Audience"], 134 | expires: DateTime.UtcNow.AddMinutes(10), // 5 - 10mins 135 | claims: authClaims, 136 | signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256) 137 | ); 138 | 139 | var jwtToken = new JwtSecurityTokenHandler().WriteToken(token); 140 | 141 | var refreshToken = new RefreshToken() 142 | { 143 | JwtId = token.Id, 144 | IsRevoked = false, 145 | UserId = user.Id, 146 | DateAdded = DateTime.UtcNow, 147 | DateExpire = DateTime.UtcNow.AddMonths(6), 148 | Token = Guid.NewGuid().ToString() + "-" + Guid.NewGuid().ToString() 149 | }; 150 | await _context.RefreshTokens.AddAsync(refreshToken); 151 | await _context.SaveChangesAsync(); 152 | 153 | var response = new AuthResultVM() 154 | { 155 | Token = jwtToken, 156 | RefreshToken = refreshToken.Token, 157 | ExpiresAt = token.ValidTo 158 | }; 159 | 160 | return response; 161 | } 162 | 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /my-books/Controllers/AuthorsController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.Mvc; 4 | using my_books.Data.Services; 5 | using my_books.Data.ViewModels; 6 | using my_books.Data.ViewModels.Authentication; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Threading.Tasks; 11 | 12 | namespace my_books.Controllers 13 | { 14 | [Authorize(Roles = UserRoles.Author)] 15 | [Route("api/[controller]")] 16 | [ApiController] 17 | public class AuthorsController : ControllerBase 18 | { 19 | private AuthorsService _authorsService; 20 | public AuthorsController(AuthorsService authorsService) 21 | { 22 | _authorsService = authorsService; 23 | } 24 | 25 | [HttpPost("add-author")] 26 | public IActionResult AddBook([FromBody] AuthorVM author) 27 | { 28 | _authorsService.AddAuthor(author); 29 | return Ok(); 30 | } 31 | 32 | [HttpGet("get-author-with-books-by-id/{id}")] 33 | public IActionResult GetAuthorWithBooks(int id) 34 | { 35 | var response = _authorsService.GetAuthorWithBooks(id); 36 | return Ok(response); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /my-books/Controllers/BooksController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.Mvc; 4 | using my_books.Data.Services; 5 | using my_books.Data.ViewModels; 6 | using my_books.Data.ViewModels.Authentication; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Threading.Tasks; 11 | 12 | namespace my_books.Controllers 13 | { 14 | [Route("api/[controller]")] 15 | [ApiController] 16 | public class BooksController : ControllerBase 17 | { 18 | public BooksService _booksService; 19 | public BooksController(BooksService booksService) 20 | { 21 | _booksService = booksService; 22 | } 23 | 24 | [Authorize(Roles = UserRoles.Author)] 25 | [HttpGet("get-all-books")] 26 | public IActionResult GetAllBooks() 27 | { 28 | var allBooks = _booksService.GetAllBooks(); 29 | return Ok(allBooks); 30 | } 31 | 32 | [Authorize(Roles = UserRoles.Admin)] 33 | [HttpGet("get-book-by-id/{id}")] 34 | public IActionResult GetBookById(int id) 35 | { 36 | var book = _booksService.GetBookById(id); 37 | return Ok(book); 38 | } 39 | 40 | [HttpPost("add-book-with-authors")] 41 | public IActionResult AddBook([FromBody]BookVM book) 42 | { 43 | _booksService.AddBookWithAuthors(book); 44 | return Ok(); 45 | } 46 | 47 | [HttpPut("update-book-by-id/{id}")] 48 | public IActionResult UpdateBookById(int id, [FromBody]BookVM book) 49 | { 50 | var updatedBook = _booksService.UpdateBookById(id, book); 51 | return Ok(updatedBook); 52 | } 53 | 54 | [HttpDelete("delete-book-by-id/{id}")] 55 | public IActionResult DeleteBookById(int id) 56 | { 57 | _booksService.DeleteBookById(id); 58 | return Ok(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /my-books/Controllers/LogsController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.Mvc; 4 | using my_books.Data.Services; 5 | using my_books.Data.ViewModels.Authentication; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Threading.Tasks; 10 | 11 | namespace my_books.Controllers 12 | { 13 | [Authorize(Roles = UserRoles.Admin)] 14 | [Route("api/[controller]")] 15 | [ApiController] 16 | public class LogsController : ControllerBase 17 | { 18 | private LogsService _logsService; 19 | public LogsController(LogsService logsService) 20 | { 21 | _logsService = logsService; 22 | } 23 | 24 | [HttpGet("get-all-logs-from-db")] 25 | public IActionResult GetAllLogsFromDB() 26 | { 27 | try 28 | { 29 | var allLogs = _logsService.GetAllLogsFromDB(); 30 | return Ok(allLogs); 31 | } 32 | catch (Exception) 33 | { 34 | return BadRequest("Could not load logs from the database"); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /my-books/Controllers/PublishersController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.Extensions.Logging; 5 | using my_books.ActionResults; 6 | using my_books.Data.Models; 7 | using my_books.Data.Services; 8 | using my_books.Data.ViewModels; 9 | using my_books.Data.ViewModels.Authentication; 10 | using my_books.Exceptions; 11 | using System; 12 | using System.Collections.Generic; 13 | using System.Linq; 14 | using System.Threading.Tasks; 15 | 16 | namespace my_books.Controllers 17 | { 18 | [Authorize(Roles = UserRoles.Publisher+","+UserRoles.Admin)] 19 | [Route("api/[controller]")] 20 | [ApiController] 21 | public class PublishersController : ControllerBase 22 | { 23 | private PublishersService _publishersService; 24 | private readonly ILogger _logger; 25 | public PublishersController(PublishersService publishersService, ILogger logger) 26 | { 27 | _publishersService = publishersService; 28 | _logger = logger; 29 | } 30 | 31 | [HttpGet("get-all-publishers")] 32 | public IActionResult GetAllPublishers(string sortBy, string searchString, int pageNumber) 33 | { 34 | try 35 | { 36 | _logger.LogInformation("This is just a log in GetAllPublishers()"); 37 | var _result = _publishersService.GetAllPublishers(sortBy, searchString, pageNumber); 38 | return Ok(_result); 39 | } 40 | catch (Exception) 41 | { 42 | return BadRequest("Sorry, we could not load the publishers"); 43 | } 44 | } 45 | 46 | [HttpPost("add-publisher")] 47 | public IActionResult AddPublisher([FromBody] PublisherVM publisher) 48 | { 49 | try 50 | { 51 | var newPublisher = _publishersService.AddPublisher(publisher); 52 | return Created(nameof(AddPublisher), newPublisher); 53 | } 54 | catch (PublisherNameException ex) 55 | { 56 | return BadRequest($"{ex.Message}, Publisher name: {ex.PublisherName}"); 57 | } 58 | catch (Exception ex) 59 | { 60 | return BadRequest(ex.Message); 61 | } 62 | 63 | } 64 | 65 | [HttpGet("get-publisher-by-id/{id}")] 66 | public IActionResult GetPublisherById(int id) 67 | { 68 | var _response = _publishersService.GetPublisherById(id); 69 | 70 | if (_response != null) 71 | { 72 | return Ok(_response); 73 | } 74 | else 75 | { 76 | return NotFound(); 77 | } 78 | } 79 | 80 | 81 | [HttpGet("get-publisher-books-with-authors/{id}")] 82 | public IActionResult GetPublisherData(int id) 83 | { 84 | var _response = _publishersService.GetPublisherData(id); 85 | return Ok(_response); 86 | } 87 | 88 | [HttpDelete("delete-publisher-by-id/{id}")] 89 | public IActionResult DeletePublisherById(int id) 90 | { 91 | try 92 | { 93 | _publishersService.DeletePublisherById(id); 94 | return Ok(); 95 | } 96 | catch (Exception ex) 97 | { 98 | return BadRequest(ex.Message); 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /my-books/Controllers/v1/TestController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.Mvc; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace my_books.Controllers.v1 9 | { 10 | [ApiVersion("1.0")] 11 | [ApiVersion("1.2")] 12 | [ApiVersion("1.9")] 13 | [Route("api/[controller]")] 14 | //[Route("api/v{version:apiVersion}/[controller]")] 15 | [ApiController] 16 | public class TestController : ControllerBase 17 | { 18 | [HttpGet("get-test-data")] 19 | public IActionResult GetV1() 20 | { 21 | return Ok("This is version V1.0"); 22 | } 23 | 24 | [HttpGet("get-test-data"), MapToApiVersion("1.2")] 25 | public IActionResult GetV12() 26 | { 27 | return Ok("This is version V1.2"); 28 | } 29 | 30 | [HttpGet("get-test-data"), MapToApiVersion("1.9")] 31 | public IActionResult GetV19() 32 | { 33 | return Ok("This is version V1.9"); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /my-books/Controllers/v2/TestController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.Mvc; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace my_books.Controllers.v2 9 | { 10 | [ApiVersion("2.0")] 11 | [Route("api/[controller]")] 12 | //[Route("api/v{version:apiVersion}/[controller]")] 13 | [ApiController] 14 | public class TestController : ControllerBase 15 | { 16 | [HttpGet("get-test-data")] 17 | public IActionResult Get() 18 | { 19 | return Ok("This is TestController V2"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /my-books/Data/AppDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore; 3 | using my_books.Data.Models; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace my_books.Data 10 | { 11 | public class AppDbContext:IdentityDbContext 12 | { 13 | public AppDbContext(DbContextOptions options):base(options) 14 | { 15 | 16 | } 17 | 18 | protected override void OnModelCreating(ModelBuilder modelBuilder) 19 | { 20 | modelBuilder.Entity() 21 | .HasOne(b => b.Book) 22 | .WithMany(ba => ba.Book_Authors) 23 | .HasForeignKey(bi => bi.BookId); 24 | 25 | modelBuilder.Entity() 26 | .HasOne(b => b.Author) 27 | .WithMany(ba => ba.Book_Authors) 28 | .HasForeignKey(bi => bi.AuthorId); 29 | 30 | modelBuilder.Entity().HasKey(n => n.Id); 31 | 32 | base.OnModelCreating(modelBuilder); 33 | } 34 | 35 | public DbSet Books { get; set; } 36 | public DbSet Authors { get; set; } 37 | public DbSet Books_Authors { get; set; } 38 | public DbSet Publishers { get; set; } 39 | 40 | public DbSet Logs { get; set; } 41 | public DbSet RefreshTokens { get; set; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /my-books/Data/AppDbInitializer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Identity; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using my_books.Data.Models; 5 | using my_books.Data.ViewModels.Authentication; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Threading.Tasks; 10 | 11 | namespace my_books.Data 12 | { 13 | public class AppDbInitializer 14 | { 15 | public static void Seed(IApplicationBuilder applicationBuilder) 16 | { 17 | using (var serviceScope = applicationBuilder.ApplicationServices.CreateScope()) 18 | { 19 | var context = serviceScope.ServiceProvider.GetService(); 20 | 21 | if (!context.Books.Any()) 22 | { 23 | context.Books.AddRange(new Book() 24 | { 25 | Title = "1st Book Title", 26 | Description = "1st Book Description", 27 | IsRead = true, 28 | DateRead = DateTime.Now.AddDays(-10), 29 | Rate = 4, 30 | Genre = "Biography", 31 | CoverUrl = "https....", 32 | DateAdded = DateTime.Now 33 | }, 34 | new Book() 35 | { 36 | Title = "2nd Book Title", 37 | Description = "2nd Book Description", 38 | IsRead = false, 39 | Genre = "Biography", 40 | CoverUrl = "https....", 41 | DateAdded = DateTime.Now 42 | }); 43 | 44 | context.SaveChanges(); 45 | } 46 | } 47 | } 48 | 49 | public static async Task SeedRoles(IApplicationBuilder applicationBuilder) 50 | { 51 | using (var serviceScope = applicationBuilder.ApplicationServices.CreateScope()) 52 | { 53 | var roleManager = serviceScope.ServiceProvider.GetRequiredService>(); 54 | 55 | if (!await roleManager.RoleExistsAsync(UserRoles.Admin)) 56 | await roleManager.CreateAsync(new IdentityRole(UserRoles.Admin)); 57 | 58 | if (!await roleManager.RoleExistsAsync(UserRoles.Publisher)) 59 | await roleManager.CreateAsync(new IdentityRole(UserRoles.Publisher)); 60 | 61 | if (!await roleManager.RoleExistsAsync(UserRoles.Author)) 62 | await roleManager.CreateAsync(new IdentityRole(UserRoles.Author)); 63 | 64 | if (!await roleManager.RoleExistsAsync(UserRoles.User)) 65 | await roleManager.CreateAsync(new IdentityRole(UserRoles.User)); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /my-books/Data/Models/ApplicationUser.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace my_books.Data.Models 8 | { 9 | public class ApplicationUser : IdentityUser 10 | { 11 | public string Custom { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /my-books/Data/Models/Author.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Data.Models 7 | { 8 | public class Author 9 | { 10 | public int Id { get; set; } 11 | public string FullName { get; set; } 12 | 13 | //Navigations Properties 14 | public List Book_Authors { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /my-books/Data/Models/Book.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Data.Models 7 | { 8 | public class Book 9 | { 10 | public int Id { get; set; } 11 | public string Title { get; set; } 12 | public string Description { get; set; } 13 | public bool IsRead { get; set; } 14 | public DateTime? DateRead { get; set; } 15 | public int? Rate { get; set; } 16 | public string Genre { get; set; } 17 | public string CoverUrl { get; set; } 18 | public DateTime DateAdded { get; set; } 19 | 20 | //Navigation Properties 21 | public int PublisherId { get; set; } 22 | public Publisher Publisher { get; set; } 23 | 24 | public List Book_Authors { get; set; } 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /my-books/Data/Models/Book_Author.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Data.Models 7 | { 8 | public class Book_Author 9 | { 10 | public int Id { get; set; } 11 | 12 | public int BookId { get; set; } 13 | public Book Book { get; set; } 14 | 15 | 16 | public int AuthorId { get; set; } 17 | public Author Author { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /my-books/Data/Models/Log.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Data.Models 7 | { 8 | public class Log 9 | { 10 | public int Id { get; set; } 11 | public string Message { get; set; } 12 | public string MessageTemplate { get; set; } 13 | public string Level { get; set; } 14 | 15 | public DateTime TimeStamp { get; set; } 16 | public string Exception { get; set; } 17 | public string Properties { get; set; } //XML properties 18 | public string LogEvent { get; set; } 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /my-books/Data/Models/Publisher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Data.Models 7 | { 8 | public class Publisher 9 | { 10 | public int Id { get; set; } 11 | public string Name { get; set; } 12 | 13 | //Navigation Properties 14 | public List Books { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /my-books/Data/Models/RefreshToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace my_books.Data.Models 8 | { 9 | public class RefreshToken 10 | { 11 | public int Id { get; set; } 12 | 13 | public string UserId { get; set; } 14 | public string Token { get; set; } 15 | public string JwtId { get; set; } 16 | 17 | public bool IsRevoked { get; set; } 18 | public DateTime DateAdded { get; set; } 19 | public DateTime DateExpire { get; set; } 20 | 21 | [ForeignKey(nameof(UserId))] 22 | public ApplicationUser User { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /my-books/Data/Paging/PaginatedList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Data.Paging 7 | { 8 | public class PaginatedList : List 9 | { 10 | public int PageIndex { get; private set; } 11 | public int TotalPages { get; private set; } 12 | 13 | 14 | public PaginatedList(List items, int count, int pageIndex, int pageSize) 15 | { 16 | PageIndex = pageIndex; 17 | TotalPages = (int)Math.Ceiling(count / (double)pageSize); 18 | 19 | this.AddRange(items); 20 | } 21 | 22 | public bool HasPreviousPage 23 | { 24 | get 25 | { 26 | return PageIndex > 1; 27 | } 28 | } 29 | 30 | 31 | public bool HasNextPage 32 | { 33 | get 34 | { 35 | return PageIndex < TotalPages; 36 | } 37 | } 38 | 39 | 40 | public static PaginatedList Create(IQueryable source, int pageIndex, int pageSize) 41 | { 42 | var count = source.Count(); 43 | var items = source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); 44 | return new PaginatedList(items, count, pageIndex, pageSize); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /my-books/Data/Services/AuthorsService.cs: -------------------------------------------------------------------------------- 1 | using my_books.Data.Models; 2 | using my_books.Data.ViewModels; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace my_books.Data.Services 9 | { 10 | public class AuthorsService 11 | { 12 | private AppDbContext _context; 13 | public AuthorsService(AppDbContext context) 14 | { 15 | _context = context; 16 | } 17 | 18 | public void AddAuthor(AuthorVM book) 19 | { 20 | var _author = new Author() 21 | { 22 | FullName = book.FullName 23 | }; 24 | _context.Authors.Add(_author); 25 | _context.SaveChanges(); 26 | } 27 | 28 | public AuthorWithBooksVM GetAuthorWithBooks(int authorId) 29 | { 30 | var _author = _context.Authors.Where(n => n.Id == authorId).Select(n => new AuthorWithBooksVM() 31 | { 32 | FullName = n.FullName, 33 | BookTitles = n.Book_Authors.Select(n => n.Book.Title).ToList() 34 | }).FirstOrDefault(); 35 | 36 | return _author; 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /my-books/Data/Services/BooksService.cs: -------------------------------------------------------------------------------- 1 | using my_books.Data.Models; 2 | using my_books.Data.ViewModels; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace my_books.Data.Services 9 | { 10 | public class BooksService 11 | { 12 | private AppDbContext _context; 13 | public BooksService(AppDbContext context) 14 | { 15 | _context = context; 16 | } 17 | 18 | 19 | public void AddBookWithAuthors(BookVM book) 20 | { 21 | var _book = new Book() 22 | { 23 | Title = book.Title, 24 | Description = book.Description, 25 | IsRead = book.IsRead, 26 | DateRead = book.IsRead ? book.DateRead.Value : null, 27 | Rate = book.IsRead ? book.Rate.Value : null, 28 | Genre = book.Genre, 29 | CoverUrl = book.CoverUrl, 30 | DateAdded = DateTime.Now, 31 | PublisherId = book.PublisherId 32 | }; 33 | _context.Books.Add(_book); 34 | _context.SaveChanges(); 35 | 36 | foreach (var id in book.AuthorIds) 37 | { 38 | var _book_author = new Book_Author() 39 | { 40 | BookId = _book.Id, 41 | AuthorId = id 42 | }; 43 | _context.Books_Authors.Add(_book_author); 44 | _context.SaveChanges(); 45 | } 46 | } 47 | 48 | public List GetAllBooks() => _context.Books.ToList(); 49 | public BookWithAuthorsVM GetBookById(int bookId) 50 | { 51 | var _bookWithAuthors = _context.Books.Where(n => n.Id == bookId).Select(book => new BookWithAuthorsVM() 52 | { 53 | Title = book.Title, 54 | Description = book.Description, 55 | IsRead = book.IsRead, 56 | DateRead = book.IsRead ? book.DateRead.Value : null, 57 | Rate = book.IsRead ? book.Rate.Value : null, 58 | Genre = book.Genre, 59 | CoverUrl = book.CoverUrl, 60 | PublisherName = book.Publisher.Name, 61 | AuthorNames = book.Book_Authors.Select(n => n.Author.FullName).ToList() 62 | }).FirstOrDefault(); 63 | 64 | return _bookWithAuthors; 65 | } 66 | 67 | public Book UpdateBookById(int bookId, BookVM book) 68 | { 69 | var _book = _context.Books.FirstOrDefault(n => n.Id == bookId); 70 | if(_book != null) 71 | { 72 | _book.Title = book.Title; 73 | _book.Description = book.Description; 74 | _book.IsRead = book.IsRead; 75 | _book.DateRead = book.IsRead ? book.DateRead.Value : null; 76 | _book.Rate = book.IsRead ? book.Rate.Value : null; 77 | _book.Genre = book.Genre; 78 | _book.CoverUrl = book.CoverUrl; 79 | 80 | _context.SaveChanges(); 81 | } 82 | 83 | return _book; 84 | } 85 | 86 | public void DeleteBookById(int bookId) 87 | { 88 | var _book = _context.Books.FirstOrDefault(n => n.Id == bookId); 89 | if(_book != null) 90 | { 91 | _context.Books.Remove(_book); 92 | _context.SaveChanges(); 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /my-books/Data/Services/LogsService.cs: -------------------------------------------------------------------------------- 1 | using my_books.Data.Models; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace my_books.Data.Services 8 | { 9 | public class LogsService 10 | { 11 | private AppDbContext _context; 12 | public LogsService(AppDbContext context) 13 | { 14 | _context = context; 15 | } 16 | 17 | public List GetAllLogsFromDB() => _context.Logs.ToList(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /my-books/Data/Services/PublishersService.cs: -------------------------------------------------------------------------------- 1 | using my_books.Data.Models; 2 | using my_books.Data.Paging; 3 | using my_books.Data.ViewModels; 4 | using my_books.Exceptions; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text.RegularExpressions; 9 | using System.Threading.Tasks; 10 | 11 | namespace my_books.Data.Services 12 | { 13 | public class PublishersService 14 | { 15 | private AppDbContext _context; 16 | public PublishersService(AppDbContext context) 17 | { 18 | _context = context; 19 | } 20 | 21 | public List GetAllPublishers(string sortBy, string searchString, int? pageNumber) 22 | { 23 | var allPublishers = _context.Publishers.OrderBy(n => n.Name).ToList(); 24 | 25 | if (!string.IsNullOrEmpty(sortBy)) 26 | { 27 | switch (sortBy) 28 | { 29 | case "name_desc": 30 | allPublishers = allPublishers.OrderByDescending(n => n.Name).ToList(); 31 | break; 32 | default: 33 | break; 34 | } 35 | } 36 | 37 | 38 | if (!string.IsNullOrEmpty(searchString)) 39 | { 40 | allPublishers = allPublishers.Where(n => n.Name.Contains(searchString, StringComparison.CurrentCultureIgnoreCase)).ToList(); 41 | } 42 | 43 | // Paging 44 | int pageSize = 5; 45 | allPublishers = PaginatedList.Create(allPublishers.AsQueryable(), pageNumber ?? 1, pageSize); 46 | 47 | return allPublishers; 48 | } 49 | 50 | public Publisher AddPublisher(PublisherVM publisher) 51 | { 52 | if (StringStartsWithNumber(publisher.Name)) throw new PublisherNameException("Name starts with number", publisher.Name); 53 | 54 | var _publisher = new Publisher() 55 | { 56 | Name = publisher.Name 57 | }; 58 | _context.Publishers.Add(_publisher); 59 | _context.SaveChanges(); 60 | 61 | return _publisher; 62 | } 63 | 64 | public Publisher GetPublisherById(int id) => _context.Publishers.FirstOrDefault(n => n.Id == id); 65 | 66 | public PublisherWithBooksAndAuthorsVM GetPublisherData(int publisherId) 67 | { 68 | var _publisherData = _context.Publishers.Where(n => n.Id == publisherId) 69 | .Select(n => new PublisherWithBooksAndAuthorsVM() 70 | { 71 | Name = n.Name, 72 | BookAuthors = n.Books.Select(n => new BookAuthorVM() 73 | { 74 | BookName = n.Title, 75 | BookAuthors = n.Book_Authors.Select(n => n.Author.FullName).ToList() 76 | }).ToList() 77 | }).FirstOrDefault(); 78 | 79 | return _publisherData; 80 | } 81 | 82 | public void DeletePublisherById(int id) 83 | { 84 | var _publisher = _context.Publishers.FirstOrDefault(n => n.Id == id); 85 | 86 | if(_publisher != null) 87 | { 88 | _context.Publishers.Remove(_publisher); 89 | _context.SaveChanges(); 90 | } else 91 | { 92 | throw new Exception($"The publisher with id: {id} does not exist"); 93 | } 94 | } 95 | 96 | private bool StringStartsWithNumber(string name) => (Regex.IsMatch(name, @"^\d")); 97 | 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /my-books/Data/ViewModels/Authentication/AuthResultVM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Data.ViewModels.Authentication 7 | { 8 | public class AuthResultVM 9 | { 10 | public string Token { get; set; } 11 | public string RefreshToken { get; set; } 12 | public DateTime ExpiresAt { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /my-books/Data/ViewModels/Authentication/LoginVM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace my_books.Data.ViewModels.Authentication 8 | { 9 | public class LoginVM 10 | { 11 | [Required(ErrorMessage = "Email is required")] 12 | public string Email { get; set; } 13 | 14 | [Required(ErrorMessage = "Password is required")] 15 | public string Password { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /my-books/Data/ViewModels/Authentication/RegisterVM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace my_books.Data.ViewModels.Authentication 8 | { 9 | public class RegisterVM 10 | { 11 | [Required(ErrorMessage = "Username is required")] 12 | public string UserName { get; set; } 13 | 14 | [Required(ErrorMessage = "Email is required")] 15 | public string Email { get; set; } 16 | 17 | [Required(ErrorMessage = "Password is required")] 18 | public string Password { get; set; } 19 | 20 | [Required(ErrorMessage = "Role is required")] 21 | public string Role { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /my-books/Data/ViewModels/Authentication/UserRoles.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Data.ViewModels.Authentication 7 | { 8 | public static class UserRoles 9 | { 10 | public const string Admin = "Admin"; 11 | public const string Publisher = "Publisher"; 12 | public const string Author = "Author"; 13 | public const string User = "User"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /my-books/Data/ViewModels/AuthorVM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Data.ViewModels 7 | { 8 | public class AuthorVM 9 | { 10 | public string FullName { get; set; } 11 | } 12 | 13 | public class AuthorWithBooksVM 14 | { 15 | public string FullName { get; set; } 16 | public List BookTitles { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /my-books/Data/ViewModels/BookVM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Data.ViewModels 7 | { 8 | public class BookVM 9 | { 10 | public string Title { get; set; } 11 | public string Description { get; set; } 12 | public bool IsRead { get; set; } 13 | public DateTime? DateRead { get; set; } 14 | public int? Rate { get; set; } 15 | public string Genre { get; set; } 16 | public string CoverUrl { get; set; } 17 | 18 | public int PublisherId { get; set; } 19 | public List AuthorIds { get; set; } 20 | } 21 | 22 | public class BookWithAuthorsVM 23 | { 24 | public string Title { get; set; } 25 | public string Description { get; set; } 26 | public bool IsRead { get; set; } 27 | public DateTime? DateRead { get; set; } 28 | public int? Rate { get; set; } 29 | public string Genre { get; set; } 30 | public string CoverUrl { get; set; } 31 | 32 | public string PublisherName { get; set; } 33 | public List AuthorNames { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /my-books/Data/ViewModels/CustomActionResultVM.cs: -------------------------------------------------------------------------------- 1 | using my_books.Data.Models; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace my_books.Data.ViewModels 8 | { 9 | public class CustomActionResultVM 10 | { 11 | public Exception Exception { get; set; } 12 | public Publisher Publisher { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /my-books/Data/ViewModels/ErrorVM.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace my_books.Data.ViewModels 8 | { 9 | public class ErrorVM 10 | { 11 | public int StatusCode { get; set; } 12 | public string Message { get; set; } 13 | public string Path { get; set; } 14 | 15 | public override string ToString() 16 | { 17 | return JsonConvert.SerializeObject(this); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /my-books/Data/ViewModels/PublisherVM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Data.ViewModels 7 | { 8 | public class PublisherVM 9 | { 10 | public string Name { get; set; } 11 | } 12 | 13 | public class PublisherWithBooksAndAuthorsVM 14 | { 15 | public string Name { get; set; } 16 | 17 | public List BookAuthors { get; set; } 18 | } 19 | 20 | public class BookAuthorVM 21 | { 22 | public string BookName { get; set; } 23 | public List BookAuthors { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /my-books/Exceptions/CustomExceptionMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using my_books.Data.ViewModels; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Threading.Tasks; 8 | 9 | namespace my_books.Exceptions 10 | { 11 | public class CustomExceptionMiddleware 12 | { 13 | private readonly RequestDelegate _next; 14 | 15 | public CustomExceptionMiddleware(RequestDelegate next) 16 | { 17 | _next = next; 18 | } 19 | 20 | public async Task InvokeAsync(HttpContext httpContext) 21 | { 22 | try 23 | { 24 | await _next(httpContext); 25 | } 26 | catch (Exception ex) 27 | { 28 | await HandleExceptionAsync(httpContext, ex); 29 | } 30 | } 31 | 32 | private Task HandleExceptionAsync(HttpContext httpContext, Exception ex) 33 | { 34 | httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; 35 | httpContext.Response.ContentType = "application/json"; 36 | 37 | var response = new ErrorVM() 38 | { 39 | StatusCode = httpContext.Response.StatusCode, 40 | Message = "Internal Server Error from the custom middleware", 41 | Path = "path-goes-here" 42 | }; 43 | 44 | return httpContext.Response.WriteAsync(response.ToString()); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /my-books/Exceptions/ExceptionMiddlewareExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Diagnostics; 3 | using Microsoft.AspNetCore.Http; 4 | using Microsoft.AspNetCore.Http.Features; 5 | using Microsoft.Extensions.Logging; 6 | using my_books.Data.ViewModels; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Net; 11 | using System.Threading.Tasks; 12 | 13 | namespace my_books.Exceptions 14 | { 15 | public static class ExceptionMiddlewareExtensions 16 | { 17 | public static void ConfigureBuildInExceptionHandler(this IApplicationBuilder app, ILoggerFactory loggerFactory) 18 | { 19 | app.UseExceptionHandler(appError => 20 | { 21 | appError.Run(async context => 22 | { 23 | 24 | var logger = loggerFactory.CreateLogger("ConfigureBuildInExceptionHandler"); 25 | 26 | context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; 27 | context.Response.ContentType = "application/json"; 28 | 29 | var contextFeature = context.Features.Get(); 30 | var contextRequest = context.Features.Get(); 31 | 32 | if (contextFeature != null) 33 | { 34 | 35 | var errorVMString = new ErrorVM() 36 | { 37 | StatusCode = context.Response.StatusCode, 38 | Message = contextFeature.Error.Message, 39 | Path = contextRequest.Path 40 | }.ToString(); 41 | 42 | logger.LogError(errorVMString); 43 | 44 | await context.Response.WriteAsync(errorVMString); 45 | } 46 | }); 47 | }); 48 | } 49 | 50 | public static void ConfigureCustomExceptionHandler(this IApplicationBuilder app) 51 | { 52 | app.UseMiddleware(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /my-books/Exceptions/PublisherNameException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace my_books.Exceptions 7 | { 8 | [Serializable] 9 | public class PublisherNameException:Exception 10 | { 11 | public string PublisherName { get; set; } 12 | 13 | public PublisherNameException() 14 | { 15 | 16 | } 17 | 18 | public PublisherNameException(string message) : base(message) 19 | { 20 | 21 | } 22 | 23 | public PublisherNameException(string message, Exception inner): base(message, inner) 24 | { 25 | 26 | } 27 | 28 | public PublisherNameException(string message, string publisherName): this(message) 29 | { 30 | PublisherName = publisherName; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /my-books/Logs/log20210319.txt: -------------------------------------------------------------------------------- 1 | 03/19/2021 14:16:05 +01:00 [] - Message: This is just a log in GetAllPublishers() 2 | 03/19/2021 14:18:53 +01:00 [Information] - Message: This is just a log in GetAllPublishers() 3 | 03/19/2021 15:06:04 +01:00 [Information] - Message: This is just a log in GetAllPublishers() 4 | 03/19/2021 15:13:58 +01:00 [Error] - Message: An unhandled exception has occurred while executing the request. 5 | System.Exception: This is an exception thrown from GetAllPublishers() 6 | at my_books.Controllers.PublishersController.GetAllPublishers(String sortBy, String searchString, Int32 pageNumber) in C:\Users\Author\source\repos\my-books\my-books\Controllers\PublishersController.cs:line 31 7 | at lambda_method2(Closure , Object , Object[] ) 8 | at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) 9 | at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync() 10 | at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) 11 | at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync() 12 | --- End of stack trace from previous location --- 13 | at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) 14 | at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) 15 | at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() 16 | --- End of stack trace from previous location --- 17 | at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) 18 | at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) 19 | at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) 20 | at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task) 21 | 03/19/2021 15:13:58 +01:00 [Error] - Message: {"StatusCode":500,"Message":"This is an exception thrown from GetAllPublishers()","Path":"/api/publishers/get-all-publishers"} 22 | 03/19/2021 15:32:31 +01:00 [Information] - Message: This is just a log in GetAllPublishers() 23 | -------------------------------------------------------------------------------- /my-books/Migrations/20210127195307_InitialDatabaseMigration.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using my_books.Data; 9 | 10 | namespace my_books.Migrations 11 | { 12 | [DbContext(typeof(AppDbContext))] 13 | [Migration("20210127195307_InitialDatabaseMigration")] 14 | partial class InitialDatabaseMigration 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .UseIdentityColumns() 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("ProductVersion", "5.0.2"); 23 | 24 | modelBuilder.Entity("my_books.Data.Models.Book", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int") 29 | .UseIdentityColumn(); 30 | 31 | b.Property("Author") 32 | .HasColumnType("nvarchar(max)"); 33 | 34 | b.Property("CoverUrl") 35 | .HasColumnType("nvarchar(max)"); 36 | 37 | b.Property("DateAdded") 38 | .HasColumnType("datetime2"); 39 | 40 | b.Property("DateRead") 41 | .HasColumnType("datetime2"); 42 | 43 | b.Property("Description") 44 | .HasColumnType("nvarchar(max)"); 45 | 46 | b.Property("Genre") 47 | .HasColumnType("nvarchar(max)"); 48 | 49 | b.Property("IsRead") 50 | .HasColumnType("bit"); 51 | 52 | b.Property("Rate") 53 | .HasColumnType("int"); 54 | 55 | b.Property("Title") 56 | .HasColumnType("nvarchar(max)"); 57 | 58 | b.HasKey("Id"); 59 | 60 | b.ToTable("Books"); 61 | }); 62 | #pragma warning restore 612, 618 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /my-books/Migrations/20210127195307_InitialDatabaseMigration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace my_books.Migrations 5 | { 6 | public partial class InitialDatabaseMigration : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.CreateTable( 11 | name: "Books", 12 | columns: table => new 13 | { 14 | Id = table.Column(type: "int", nullable: false) 15 | .Annotation("SqlServer:Identity", "1, 1"), 16 | Title = table.Column(type: "nvarchar(max)", nullable: true), 17 | Description = table.Column(type: "nvarchar(max)", nullable: true), 18 | IsRead = table.Column(type: "bit", nullable: false), 19 | DateRead = table.Column(type: "datetime2", nullable: true), 20 | Rate = table.Column(type: "int", nullable: true), 21 | Genre = table.Column(type: "nvarchar(max)", nullable: true), 22 | Author = table.Column(type: "nvarchar(max)", nullable: true), 23 | CoverUrl = table.Column(type: "nvarchar(max)", nullable: true), 24 | DateAdded = table.Column(type: "datetime2", nullable: false) 25 | }, 26 | constraints: table => 27 | { 28 | table.PrimaryKey("PK_Books", x => x.Id); 29 | }); 30 | } 31 | 32 | protected override void Down(MigrationBuilder migrationBuilder) 33 | { 34 | migrationBuilder.DropTable( 35 | name: "Books"); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /my-books/Migrations/20210207135018_PublisherAdded.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using my_books.Data; 9 | 10 | namespace my_books.Migrations 11 | { 12 | [DbContext(typeof(AppDbContext))] 13 | [Migration("20210207135018_PublisherAdded")] 14 | partial class PublisherAdded 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .UseIdentityColumns() 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("ProductVersion", "5.0.2"); 23 | 24 | modelBuilder.Entity("my_books.Data.Models.Book", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int") 29 | .UseIdentityColumn(); 30 | 31 | b.Property("Author") 32 | .HasColumnType("nvarchar(max)"); 33 | 34 | b.Property("CoverUrl") 35 | .HasColumnType("nvarchar(max)"); 36 | 37 | b.Property("DateAdded") 38 | .HasColumnType("datetime2"); 39 | 40 | b.Property("DateRead") 41 | .HasColumnType("datetime2"); 42 | 43 | b.Property("Description") 44 | .HasColumnType("nvarchar(max)"); 45 | 46 | b.Property("Genre") 47 | .HasColumnType("nvarchar(max)"); 48 | 49 | b.Property("IsRead") 50 | .HasColumnType("bit"); 51 | 52 | b.Property("PublisherId") 53 | .HasColumnType("int"); 54 | 55 | b.Property("Rate") 56 | .HasColumnType("int"); 57 | 58 | b.Property("Title") 59 | .HasColumnType("nvarchar(max)"); 60 | 61 | b.HasKey("Id"); 62 | 63 | b.HasIndex("PublisherId"); 64 | 65 | b.ToTable("Books"); 66 | }); 67 | 68 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 69 | { 70 | b.Property("Id") 71 | .ValueGeneratedOnAdd() 72 | .HasColumnType("int") 73 | .UseIdentityColumn(); 74 | 75 | b.Property("Name") 76 | .HasColumnType("nvarchar(max)"); 77 | 78 | b.HasKey("Id"); 79 | 80 | b.ToTable("Publisher"); 81 | }); 82 | 83 | modelBuilder.Entity("my_books.Data.Models.Book", b => 84 | { 85 | b.HasOne("my_books.Data.Models.Publisher", "Publisher") 86 | .WithMany("Books") 87 | .HasForeignKey("PublisherId") 88 | .OnDelete(DeleteBehavior.Cascade) 89 | .IsRequired(); 90 | 91 | b.Navigation("Publisher"); 92 | }); 93 | 94 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 95 | { 96 | b.Navigation("Books"); 97 | }); 98 | #pragma warning restore 612, 618 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /my-books/Migrations/20210207135018_PublisherAdded.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace my_books.Migrations 4 | { 5 | public partial class PublisherAdded : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "PublisherId", 11 | table: "Books", 12 | type: "int", 13 | nullable: false, 14 | defaultValue: 0); 15 | 16 | migrationBuilder.CreateTable( 17 | name: "Publisher", 18 | columns: table => new 19 | { 20 | Id = table.Column(type: "int", nullable: false) 21 | .Annotation("SqlServer:Identity", "1, 1"), 22 | Name = table.Column(type: "nvarchar(max)", nullable: true) 23 | }, 24 | constraints: table => 25 | { 26 | table.PrimaryKey("PK_Publisher", x => x.Id); 27 | }); 28 | 29 | migrationBuilder.CreateIndex( 30 | name: "IX_Books_PublisherId", 31 | table: "Books", 32 | column: "PublisherId"); 33 | 34 | migrationBuilder.AddForeignKey( 35 | name: "FK_Books_Publisher_PublisherId", 36 | table: "Books", 37 | column: "PublisherId", 38 | principalTable: "Publisher", 39 | principalColumn: "Id", 40 | onDelete: ReferentialAction.Cascade); 41 | } 42 | 43 | protected override void Down(MigrationBuilder migrationBuilder) 44 | { 45 | migrationBuilder.DropForeignKey( 46 | name: "FK_Books_Publisher_PublisherId", 47 | table: "Books"); 48 | 49 | migrationBuilder.DropTable( 50 | name: "Publisher"); 51 | 52 | migrationBuilder.DropIndex( 53 | name: "IX_Books_PublisherId", 54 | table: "Books"); 55 | 56 | migrationBuilder.DropColumn( 57 | name: "PublisherId", 58 | table: "Books"); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /my-books/Migrations/20210207144751_ManyToManyAdded.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using my_books.Data; 9 | 10 | namespace my_books.Migrations 11 | { 12 | [DbContext(typeof(AppDbContext))] 13 | [Migration("20210207144751_ManyToManyAdded")] 14 | partial class ManyToManyAdded 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .UseIdentityColumns() 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("ProductVersion", "5.0.2"); 23 | 24 | modelBuilder.Entity("my_books.Data.Models.Author", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int") 29 | .UseIdentityColumn(); 30 | 31 | b.Property("FullName") 32 | .HasColumnType("nvarchar(max)"); 33 | 34 | b.HasKey("Id"); 35 | 36 | b.ToTable("Authors"); 37 | }); 38 | 39 | modelBuilder.Entity("my_books.Data.Models.Book", b => 40 | { 41 | b.Property("Id") 42 | .ValueGeneratedOnAdd() 43 | .HasColumnType("int") 44 | .UseIdentityColumn(); 45 | 46 | b.Property("Author") 47 | .HasColumnType("nvarchar(max)"); 48 | 49 | b.Property("CoverUrl") 50 | .HasColumnType("nvarchar(max)"); 51 | 52 | b.Property("DateAdded") 53 | .HasColumnType("datetime2"); 54 | 55 | b.Property("DateRead") 56 | .HasColumnType("datetime2"); 57 | 58 | b.Property("Description") 59 | .HasColumnType("nvarchar(max)"); 60 | 61 | b.Property("Genre") 62 | .HasColumnType("nvarchar(max)"); 63 | 64 | b.Property("IsRead") 65 | .HasColumnType("bit"); 66 | 67 | b.Property("PublisherId") 68 | .HasColumnType("int"); 69 | 70 | b.Property("Rate") 71 | .HasColumnType("int"); 72 | 73 | b.Property("Title") 74 | .HasColumnType("nvarchar(max)"); 75 | 76 | b.HasKey("Id"); 77 | 78 | b.HasIndex("PublisherId"); 79 | 80 | b.ToTable("Books"); 81 | }); 82 | 83 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 84 | { 85 | b.Property("Id") 86 | .ValueGeneratedOnAdd() 87 | .HasColumnType("int") 88 | .UseIdentityColumn(); 89 | 90 | b.Property("AuthorId") 91 | .HasColumnType("int"); 92 | 93 | b.Property("BookId") 94 | .HasColumnType("int"); 95 | 96 | b.HasKey("Id"); 97 | 98 | b.HasIndex("AuthorId"); 99 | 100 | b.HasIndex("BookId"); 101 | 102 | b.ToTable("Books_Authors"); 103 | }); 104 | 105 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 106 | { 107 | b.Property("Id") 108 | .ValueGeneratedOnAdd() 109 | .HasColumnType("int") 110 | .UseIdentityColumn(); 111 | 112 | b.Property("Name") 113 | .HasColumnType("nvarchar(max)"); 114 | 115 | b.HasKey("Id"); 116 | 117 | b.ToTable("Publishers"); 118 | }); 119 | 120 | modelBuilder.Entity("my_books.Data.Models.Book", b => 121 | { 122 | b.HasOne("my_books.Data.Models.Publisher", "Publisher") 123 | .WithMany("Books") 124 | .HasForeignKey("PublisherId") 125 | .OnDelete(DeleteBehavior.Cascade) 126 | .IsRequired(); 127 | 128 | b.Navigation("Publisher"); 129 | }); 130 | 131 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 132 | { 133 | b.HasOne("my_books.Data.Models.Author", "Author") 134 | .WithMany("Book_Authors") 135 | .HasForeignKey("AuthorId") 136 | .OnDelete(DeleteBehavior.Cascade) 137 | .IsRequired(); 138 | 139 | b.HasOne("my_books.Data.Models.Book", "Book") 140 | .WithMany("Book_Authors") 141 | .HasForeignKey("BookId") 142 | .OnDelete(DeleteBehavior.Cascade) 143 | .IsRequired(); 144 | 145 | b.Navigation("Author"); 146 | 147 | b.Navigation("Book"); 148 | }); 149 | 150 | modelBuilder.Entity("my_books.Data.Models.Author", b => 151 | { 152 | b.Navigation("Book_Authors"); 153 | }); 154 | 155 | modelBuilder.Entity("my_books.Data.Models.Book", b => 156 | { 157 | b.Navigation("Book_Authors"); 158 | }); 159 | 160 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 161 | { 162 | b.Navigation("Books"); 163 | }); 164 | #pragma warning restore 612, 618 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /my-books/Migrations/20210207144751_ManyToManyAdded.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace my_books.Migrations 4 | { 5 | public partial class ManyToManyAdded : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.DropForeignKey( 10 | name: "FK_Books_Publisher_PublisherId", 11 | table: "Books"); 12 | 13 | migrationBuilder.DropPrimaryKey( 14 | name: "PK_Publisher", 15 | table: "Publisher"); 16 | 17 | migrationBuilder.RenameTable( 18 | name: "Publisher", 19 | newName: "Publishers"); 20 | 21 | migrationBuilder.AddPrimaryKey( 22 | name: "PK_Publishers", 23 | table: "Publishers", 24 | column: "Id"); 25 | 26 | migrationBuilder.CreateTable( 27 | name: "Authors", 28 | columns: table => new 29 | { 30 | Id = table.Column(type: "int", nullable: false) 31 | .Annotation("SqlServer:Identity", "1, 1"), 32 | FullName = table.Column(type: "nvarchar(max)", nullable: true) 33 | }, 34 | constraints: table => 35 | { 36 | table.PrimaryKey("PK_Authors", x => x.Id); 37 | }); 38 | 39 | migrationBuilder.CreateTable( 40 | name: "Books_Authors", 41 | columns: table => new 42 | { 43 | Id = table.Column(type: "int", nullable: false) 44 | .Annotation("SqlServer:Identity", "1, 1"), 45 | BookId = table.Column(type: "int", nullable: false), 46 | AuthorId = table.Column(type: "int", nullable: false) 47 | }, 48 | constraints: table => 49 | { 50 | table.PrimaryKey("PK_Books_Authors", x => x.Id); 51 | table.ForeignKey( 52 | name: "FK_Books_Authors_Authors_AuthorId", 53 | column: x => x.AuthorId, 54 | principalTable: "Authors", 55 | principalColumn: "Id", 56 | onDelete: ReferentialAction.Cascade); 57 | table.ForeignKey( 58 | name: "FK_Books_Authors_Books_BookId", 59 | column: x => x.BookId, 60 | principalTable: "Books", 61 | principalColumn: "Id", 62 | onDelete: ReferentialAction.Cascade); 63 | }); 64 | 65 | migrationBuilder.CreateIndex( 66 | name: "IX_Books_Authors_AuthorId", 67 | table: "Books_Authors", 68 | column: "AuthorId"); 69 | 70 | migrationBuilder.CreateIndex( 71 | name: "IX_Books_Authors_BookId", 72 | table: "Books_Authors", 73 | column: "BookId"); 74 | 75 | migrationBuilder.AddForeignKey( 76 | name: "FK_Books_Publishers_PublisherId", 77 | table: "Books", 78 | column: "PublisherId", 79 | principalTable: "Publishers", 80 | principalColumn: "Id", 81 | onDelete: ReferentialAction.Cascade); 82 | } 83 | 84 | protected override void Down(MigrationBuilder migrationBuilder) 85 | { 86 | migrationBuilder.DropForeignKey( 87 | name: "FK_Books_Publishers_PublisherId", 88 | table: "Books"); 89 | 90 | migrationBuilder.DropTable( 91 | name: "Books_Authors"); 92 | 93 | migrationBuilder.DropTable( 94 | name: "Authors"); 95 | 96 | migrationBuilder.DropPrimaryKey( 97 | name: "PK_Publishers", 98 | table: "Publishers"); 99 | 100 | migrationBuilder.RenameTable( 101 | name: "Publishers", 102 | newName: "Publisher"); 103 | 104 | migrationBuilder.AddPrimaryKey( 105 | name: "PK_Publisher", 106 | table: "Publisher", 107 | column: "Id"); 108 | 109 | migrationBuilder.AddForeignKey( 110 | name: "FK_Books_Publisher_PublisherId", 111 | table: "Books", 112 | column: "PublisherId", 113 | principalTable: "Publisher", 114 | principalColumn: "Id", 115 | onDelete: ReferentialAction.Cascade); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /my-books/Migrations/20210207162828_BookAuthorColumnRemoved.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using my_books.Data; 9 | 10 | namespace my_books.Migrations 11 | { 12 | [DbContext(typeof(AppDbContext))] 13 | [Migration("20210207162828_BookAuthorColumnRemoved")] 14 | partial class BookAuthorColumnRemoved 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .UseIdentityColumns() 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("ProductVersion", "5.0.2"); 23 | 24 | modelBuilder.Entity("my_books.Data.Models.Author", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int") 29 | .UseIdentityColumn(); 30 | 31 | b.Property("FullName") 32 | .HasColumnType("nvarchar(max)"); 33 | 34 | b.HasKey("Id"); 35 | 36 | b.ToTable("Authors"); 37 | }); 38 | 39 | modelBuilder.Entity("my_books.Data.Models.Book", b => 40 | { 41 | b.Property("Id") 42 | .ValueGeneratedOnAdd() 43 | .HasColumnType("int") 44 | .UseIdentityColumn(); 45 | 46 | b.Property("CoverUrl") 47 | .HasColumnType("nvarchar(max)"); 48 | 49 | b.Property("DateAdded") 50 | .HasColumnType("datetime2"); 51 | 52 | b.Property("DateRead") 53 | .HasColumnType("datetime2"); 54 | 55 | b.Property("Description") 56 | .HasColumnType("nvarchar(max)"); 57 | 58 | b.Property("Genre") 59 | .HasColumnType("nvarchar(max)"); 60 | 61 | b.Property("IsRead") 62 | .HasColumnType("bit"); 63 | 64 | b.Property("PublisherId") 65 | .HasColumnType("int"); 66 | 67 | b.Property("Rate") 68 | .HasColumnType("int"); 69 | 70 | b.Property("Title") 71 | .HasColumnType("nvarchar(max)"); 72 | 73 | b.HasKey("Id"); 74 | 75 | b.HasIndex("PublisherId"); 76 | 77 | b.ToTable("Books"); 78 | }); 79 | 80 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 81 | { 82 | b.Property("Id") 83 | .ValueGeneratedOnAdd() 84 | .HasColumnType("int") 85 | .UseIdentityColumn(); 86 | 87 | b.Property("AuthorId") 88 | .HasColumnType("int"); 89 | 90 | b.Property("BookId") 91 | .HasColumnType("int"); 92 | 93 | b.HasKey("Id"); 94 | 95 | b.HasIndex("AuthorId"); 96 | 97 | b.HasIndex("BookId"); 98 | 99 | b.ToTable("Books_Authors"); 100 | }); 101 | 102 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 103 | { 104 | b.Property("Id") 105 | .ValueGeneratedOnAdd() 106 | .HasColumnType("int") 107 | .UseIdentityColumn(); 108 | 109 | b.Property("Name") 110 | .HasColumnType("nvarchar(max)"); 111 | 112 | b.HasKey("Id"); 113 | 114 | b.ToTable("Publishers"); 115 | }); 116 | 117 | modelBuilder.Entity("my_books.Data.Models.Book", b => 118 | { 119 | b.HasOne("my_books.Data.Models.Publisher", "Publisher") 120 | .WithMany("Books") 121 | .HasForeignKey("PublisherId") 122 | .OnDelete(DeleteBehavior.Cascade) 123 | .IsRequired(); 124 | 125 | b.Navigation("Publisher"); 126 | }); 127 | 128 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 129 | { 130 | b.HasOne("my_books.Data.Models.Author", "Author") 131 | .WithMany("Book_Authors") 132 | .HasForeignKey("AuthorId") 133 | .OnDelete(DeleteBehavior.Cascade) 134 | .IsRequired(); 135 | 136 | b.HasOne("my_books.Data.Models.Book", "Book") 137 | .WithMany("Book_Authors") 138 | .HasForeignKey("BookId") 139 | .OnDelete(DeleteBehavior.Cascade) 140 | .IsRequired(); 141 | 142 | b.Navigation("Author"); 143 | 144 | b.Navigation("Book"); 145 | }); 146 | 147 | modelBuilder.Entity("my_books.Data.Models.Author", b => 148 | { 149 | b.Navigation("Book_Authors"); 150 | }); 151 | 152 | modelBuilder.Entity("my_books.Data.Models.Book", b => 153 | { 154 | b.Navigation("Book_Authors"); 155 | }); 156 | 157 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 158 | { 159 | b.Navigation("Books"); 160 | }); 161 | #pragma warning restore 612, 618 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /my-books/Migrations/20210207162828_BookAuthorColumnRemoved.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace my_books.Migrations 4 | { 5 | public partial class BookAuthorColumnRemoved : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.DropColumn( 10 | name: "Author", 11 | table: "Books"); 12 | } 13 | 14 | protected override void Down(MigrationBuilder migrationBuilder) 15 | { 16 | migrationBuilder.AddColumn( 17 | name: "Author", 18 | table: "Books", 19 | type: "nvarchar(max)", 20 | nullable: true); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /my-books/Migrations/20210319135502_LogTableAdded.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using my_books.Data; 9 | 10 | namespace my_books.Migrations 11 | { 12 | [DbContext(typeof(AppDbContext))] 13 | [Migration("20210319135502_LogTableAdded")] 14 | partial class LogTableAdded 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .UseIdentityColumns() 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("ProductVersion", "5.0.2"); 23 | 24 | modelBuilder.Entity("my_books.Data.Models.Author", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int") 29 | .UseIdentityColumn(); 30 | 31 | b.Property("FullName") 32 | .HasColumnType("nvarchar(max)"); 33 | 34 | b.HasKey("Id"); 35 | 36 | b.ToTable("Authors"); 37 | }); 38 | 39 | modelBuilder.Entity("my_books.Data.Models.Book", b => 40 | { 41 | b.Property("Id") 42 | .ValueGeneratedOnAdd() 43 | .HasColumnType("int") 44 | .UseIdentityColumn(); 45 | 46 | b.Property("CoverUrl") 47 | .HasColumnType("nvarchar(max)"); 48 | 49 | b.Property("DateAdded") 50 | .HasColumnType("datetime2"); 51 | 52 | b.Property("DateRead") 53 | .HasColumnType("datetime2"); 54 | 55 | b.Property("Description") 56 | .HasColumnType("nvarchar(max)"); 57 | 58 | b.Property("Genre") 59 | .HasColumnType("nvarchar(max)"); 60 | 61 | b.Property("IsRead") 62 | .HasColumnType("bit"); 63 | 64 | b.Property("PublisherId") 65 | .HasColumnType("int"); 66 | 67 | b.Property("Rate") 68 | .HasColumnType("int"); 69 | 70 | b.Property("Title") 71 | .HasColumnType("nvarchar(max)"); 72 | 73 | b.HasKey("Id"); 74 | 75 | b.HasIndex("PublisherId"); 76 | 77 | b.ToTable("Books"); 78 | }); 79 | 80 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 81 | { 82 | b.Property("Id") 83 | .ValueGeneratedOnAdd() 84 | .HasColumnType("int") 85 | .UseIdentityColumn(); 86 | 87 | b.Property("AuthorId") 88 | .HasColumnType("int"); 89 | 90 | b.Property("BookId") 91 | .HasColumnType("int"); 92 | 93 | b.HasKey("Id"); 94 | 95 | b.HasIndex("AuthorId"); 96 | 97 | b.HasIndex("BookId"); 98 | 99 | b.ToTable("Books_Authors"); 100 | }); 101 | 102 | modelBuilder.Entity("my_books.Data.Models.Log", b => 103 | { 104 | b.Property("Id") 105 | .ValueGeneratedOnAdd() 106 | .HasColumnType("int") 107 | .UseIdentityColumn(); 108 | 109 | b.Property("Exception") 110 | .HasColumnType("nvarchar(max)"); 111 | 112 | b.Property("Level") 113 | .HasColumnType("nvarchar(max)"); 114 | 115 | b.Property("LogEvent") 116 | .HasColumnType("nvarchar(max)"); 117 | 118 | b.Property("Message") 119 | .HasColumnType("nvarchar(max)"); 120 | 121 | b.Property("MessageTemplate") 122 | .HasColumnType("nvarchar(max)"); 123 | 124 | b.Property("Properties") 125 | .HasColumnType("nvarchar(max)"); 126 | 127 | b.Property("TimeStamp") 128 | .HasColumnType("datetime2"); 129 | 130 | b.HasKey("Id"); 131 | 132 | b.ToTable("Logs"); 133 | }); 134 | 135 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 136 | { 137 | b.Property("Id") 138 | .ValueGeneratedOnAdd() 139 | .HasColumnType("int") 140 | .UseIdentityColumn(); 141 | 142 | b.Property("Name") 143 | .HasColumnType("nvarchar(max)"); 144 | 145 | b.HasKey("Id"); 146 | 147 | b.ToTable("Publishers"); 148 | }); 149 | 150 | modelBuilder.Entity("my_books.Data.Models.Book", b => 151 | { 152 | b.HasOne("my_books.Data.Models.Publisher", "Publisher") 153 | .WithMany("Books") 154 | .HasForeignKey("PublisherId") 155 | .OnDelete(DeleteBehavior.Cascade) 156 | .IsRequired(); 157 | 158 | b.Navigation("Publisher"); 159 | }); 160 | 161 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 162 | { 163 | b.HasOne("my_books.Data.Models.Author", "Author") 164 | .WithMany("Book_Authors") 165 | .HasForeignKey("AuthorId") 166 | .OnDelete(DeleteBehavior.Cascade) 167 | .IsRequired(); 168 | 169 | b.HasOne("my_books.Data.Models.Book", "Book") 170 | .WithMany("Book_Authors") 171 | .HasForeignKey("BookId") 172 | .OnDelete(DeleteBehavior.Cascade) 173 | .IsRequired(); 174 | 175 | b.Navigation("Author"); 176 | 177 | b.Navigation("Book"); 178 | }); 179 | 180 | modelBuilder.Entity("my_books.Data.Models.Author", b => 181 | { 182 | b.Navigation("Book_Authors"); 183 | }); 184 | 185 | modelBuilder.Entity("my_books.Data.Models.Book", b => 186 | { 187 | b.Navigation("Book_Authors"); 188 | }); 189 | 190 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 191 | { 192 | b.Navigation("Books"); 193 | }); 194 | #pragma warning restore 612, 618 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /my-books/Migrations/20210319135502_LogTableAdded.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace my_books.Migrations 5 | { 6 | public partial class LogTableAdded : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.CreateTable( 11 | name: "Logs", 12 | columns: table => new 13 | { 14 | Id = table.Column(type: "int", nullable: false) 15 | .Annotation("SqlServer:Identity", "1, 1"), 16 | Message = table.Column(type: "nvarchar(max)", nullable: true), 17 | MessageTemplate = table.Column(type: "nvarchar(max)", nullable: true), 18 | Level = table.Column(type: "nvarchar(max)", nullable: true), 19 | TimeStamp = table.Column(type: "datetime2", nullable: false), 20 | Exception = table.Column(type: "nvarchar(max)", nullable: true), 21 | Properties = table.Column(type: "nvarchar(max)", nullable: true), 22 | LogEvent = table.Column(type: "nvarchar(max)", nullable: true) 23 | }, 24 | constraints: table => 25 | { 26 | table.PrimaryKey("PK_Logs", x => x.Id); 27 | }); 28 | } 29 | 30 | protected override void Down(MigrationBuilder migrationBuilder) 31 | { 32 | migrationBuilder.DropTable( 33 | name: "Logs"); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /my-books/Migrations/20210426111014_IdentityAdded.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using my_books.Data; 9 | 10 | namespace my_books.Migrations 11 | { 12 | [DbContext(typeof(AppDbContext))] 13 | [Migration("20210426111014_IdentityAdded")] 14 | partial class IdentityAdded 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .UseIdentityColumns() 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("ProductVersion", "5.0.2"); 23 | 24 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 25 | { 26 | b.Property("Id") 27 | .HasColumnType("nvarchar(450)"); 28 | 29 | b.Property("ConcurrencyStamp") 30 | .IsConcurrencyToken() 31 | .HasColumnType("nvarchar(max)"); 32 | 33 | b.Property("Name") 34 | .HasMaxLength(256) 35 | .HasColumnType("nvarchar(256)"); 36 | 37 | b.Property("NormalizedName") 38 | .HasMaxLength(256) 39 | .HasColumnType("nvarchar(256)"); 40 | 41 | b.HasKey("Id"); 42 | 43 | b.HasIndex("NormalizedName") 44 | .IsUnique() 45 | .HasDatabaseName("RoleNameIndex") 46 | .HasFilter("[NormalizedName] IS NOT NULL"); 47 | 48 | b.ToTable("AspNetRoles"); 49 | }); 50 | 51 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 52 | { 53 | b.Property("Id") 54 | .ValueGeneratedOnAdd() 55 | .HasColumnType("int") 56 | .UseIdentityColumn(); 57 | 58 | b.Property("ClaimType") 59 | .HasColumnType("nvarchar(max)"); 60 | 61 | b.Property("ClaimValue") 62 | .HasColumnType("nvarchar(max)"); 63 | 64 | b.Property("RoleId") 65 | .IsRequired() 66 | .HasColumnType("nvarchar(450)"); 67 | 68 | b.HasKey("Id"); 69 | 70 | b.HasIndex("RoleId"); 71 | 72 | b.ToTable("AspNetRoleClaims"); 73 | }); 74 | 75 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 76 | { 77 | b.Property("Id") 78 | .ValueGeneratedOnAdd() 79 | .HasColumnType("int") 80 | .UseIdentityColumn(); 81 | 82 | b.Property("ClaimType") 83 | .HasColumnType("nvarchar(max)"); 84 | 85 | b.Property("ClaimValue") 86 | .HasColumnType("nvarchar(max)"); 87 | 88 | b.Property("UserId") 89 | .IsRequired() 90 | .HasColumnType("nvarchar(450)"); 91 | 92 | b.HasKey("Id"); 93 | 94 | b.HasIndex("UserId"); 95 | 96 | b.ToTable("AspNetUserClaims"); 97 | }); 98 | 99 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 100 | { 101 | b.Property("LoginProvider") 102 | .HasColumnType("nvarchar(450)"); 103 | 104 | b.Property("ProviderKey") 105 | .HasColumnType("nvarchar(450)"); 106 | 107 | b.Property("ProviderDisplayName") 108 | .HasColumnType("nvarchar(max)"); 109 | 110 | b.Property("UserId") 111 | .IsRequired() 112 | .HasColumnType("nvarchar(450)"); 113 | 114 | b.HasKey("LoginProvider", "ProviderKey"); 115 | 116 | b.HasIndex("UserId"); 117 | 118 | b.ToTable("AspNetUserLogins"); 119 | }); 120 | 121 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 122 | { 123 | b.Property("UserId") 124 | .HasColumnType("nvarchar(450)"); 125 | 126 | b.Property("RoleId") 127 | .HasColumnType("nvarchar(450)"); 128 | 129 | b.HasKey("UserId", "RoleId"); 130 | 131 | b.HasIndex("RoleId"); 132 | 133 | b.ToTable("AspNetUserRoles"); 134 | }); 135 | 136 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 137 | { 138 | b.Property("UserId") 139 | .HasColumnType("nvarchar(450)"); 140 | 141 | b.Property("LoginProvider") 142 | .HasColumnType("nvarchar(450)"); 143 | 144 | b.Property("Name") 145 | .HasColumnType("nvarchar(450)"); 146 | 147 | b.Property("Value") 148 | .HasColumnType("nvarchar(max)"); 149 | 150 | b.HasKey("UserId", "LoginProvider", "Name"); 151 | 152 | b.ToTable("AspNetUserTokens"); 153 | }); 154 | 155 | modelBuilder.Entity("my_books.Data.Models.ApplicationUser", b => 156 | { 157 | b.Property("Id") 158 | .HasColumnType("nvarchar(450)"); 159 | 160 | b.Property("AccessFailedCount") 161 | .HasColumnType("int"); 162 | 163 | b.Property("ConcurrencyStamp") 164 | .IsConcurrencyToken() 165 | .HasColumnType("nvarchar(max)"); 166 | 167 | b.Property("Custom") 168 | .HasColumnType("nvarchar(max)"); 169 | 170 | b.Property("Email") 171 | .HasMaxLength(256) 172 | .HasColumnType("nvarchar(256)"); 173 | 174 | b.Property("EmailConfirmed") 175 | .HasColumnType("bit"); 176 | 177 | b.Property("LockoutEnabled") 178 | .HasColumnType("bit"); 179 | 180 | b.Property("LockoutEnd") 181 | .HasColumnType("datetimeoffset"); 182 | 183 | b.Property("NormalizedEmail") 184 | .HasMaxLength(256) 185 | .HasColumnType("nvarchar(256)"); 186 | 187 | b.Property("NormalizedUserName") 188 | .HasMaxLength(256) 189 | .HasColumnType("nvarchar(256)"); 190 | 191 | b.Property("PasswordHash") 192 | .HasColumnType("nvarchar(max)"); 193 | 194 | b.Property("PhoneNumber") 195 | .HasColumnType("nvarchar(max)"); 196 | 197 | b.Property("PhoneNumberConfirmed") 198 | .HasColumnType("bit"); 199 | 200 | b.Property("SecurityStamp") 201 | .HasColumnType("nvarchar(max)"); 202 | 203 | b.Property("TwoFactorEnabled") 204 | .HasColumnType("bit"); 205 | 206 | b.Property("UserName") 207 | .HasMaxLength(256) 208 | .HasColumnType("nvarchar(256)"); 209 | 210 | b.HasKey("Id"); 211 | 212 | b.HasIndex("NormalizedEmail") 213 | .HasDatabaseName("EmailIndex"); 214 | 215 | b.HasIndex("NormalizedUserName") 216 | .IsUnique() 217 | .HasDatabaseName("UserNameIndex") 218 | .HasFilter("[NormalizedUserName] IS NOT NULL"); 219 | 220 | b.ToTable("AspNetUsers"); 221 | }); 222 | 223 | modelBuilder.Entity("my_books.Data.Models.Author", b => 224 | { 225 | b.Property("Id") 226 | .ValueGeneratedOnAdd() 227 | .HasColumnType("int") 228 | .UseIdentityColumn(); 229 | 230 | b.Property("FullName") 231 | .HasColumnType("nvarchar(max)"); 232 | 233 | b.HasKey("Id"); 234 | 235 | b.ToTable("Authors"); 236 | }); 237 | 238 | modelBuilder.Entity("my_books.Data.Models.Book", b => 239 | { 240 | b.Property("Id") 241 | .ValueGeneratedOnAdd() 242 | .HasColumnType("int") 243 | .UseIdentityColumn(); 244 | 245 | b.Property("CoverUrl") 246 | .HasColumnType("nvarchar(max)"); 247 | 248 | b.Property("DateAdded") 249 | .HasColumnType("datetime2"); 250 | 251 | b.Property("DateRead") 252 | .HasColumnType("datetime2"); 253 | 254 | b.Property("Description") 255 | .HasColumnType("nvarchar(max)"); 256 | 257 | b.Property("Genre") 258 | .HasColumnType("nvarchar(max)"); 259 | 260 | b.Property("IsRead") 261 | .HasColumnType("bit"); 262 | 263 | b.Property("PublisherId") 264 | .HasColumnType("int"); 265 | 266 | b.Property("Rate") 267 | .HasColumnType("int"); 268 | 269 | b.Property("Title") 270 | .HasColumnType("nvarchar(max)"); 271 | 272 | b.HasKey("Id"); 273 | 274 | b.HasIndex("PublisherId"); 275 | 276 | b.ToTable("Books"); 277 | }); 278 | 279 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 280 | { 281 | b.Property("Id") 282 | .ValueGeneratedOnAdd() 283 | .HasColumnType("int") 284 | .UseIdentityColumn(); 285 | 286 | b.Property("AuthorId") 287 | .HasColumnType("int"); 288 | 289 | b.Property("BookId") 290 | .HasColumnType("int"); 291 | 292 | b.HasKey("Id"); 293 | 294 | b.HasIndex("AuthorId"); 295 | 296 | b.HasIndex("BookId"); 297 | 298 | b.ToTable("Books_Authors"); 299 | }); 300 | 301 | modelBuilder.Entity("my_books.Data.Models.Log", b => 302 | { 303 | b.Property("Id") 304 | .ValueGeneratedOnAdd() 305 | .HasColumnType("int") 306 | .UseIdentityColumn(); 307 | 308 | b.Property("Exception") 309 | .HasColumnType("nvarchar(max)"); 310 | 311 | b.Property("Level") 312 | .HasColumnType("nvarchar(max)"); 313 | 314 | b.Property("LogEvent") 315 | .HasColumnType("nvarchar(max)"); 316 | 317 | b.Property("Message") 318 | .HasColumnType("nvarchar(max)"); 319 | 320 | b.Property("MessageTemplate") 321 | .HasColumnType("nvarchar(max)"); 322 | 323 | b.Property("Properties") 324 | .HasColumnType("nvarchar(max)"); 325 | 326 | b.Property("TimeStamp") 327 | .HasColumnType("datetime2"); 328 | 329 | b.HasKey("Id"); 330 | 331 | b.ToTable("Logs"); 332 | }); 333 | 334 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 335 | { 336 | b.Property("Id") 337 | .ValueGeneratedOnAdd() 338 | .HasColumnType("int") 339 | .UseIdentityColumn(); 340 | 341 | b.Property("Name") 342 | .HasColumnType("nvarchar(max)"); 343 | 344 | b.HasKey("Id"); 345 | 346 | b.ToTable("Publishers"); 347 | }); 348 | 349 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 350 | { 351 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 352 | .WithMany() 353 | .HasForeignKey("RoleId") 354 | .OnDelete(DeleteBehavior.Cascade) 355 | .IsRequired(); 356 | }); 357 | 358 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 359 | { 360 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 361 | .WithMany() 362 | .HasForeignKey("UserId") 363 | .OnDelete(DeleteBehavior.Cascade) 364 | .IsRequired(); 365 | }); 366 | 367 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 368 | { 369 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 370 | .WithMany() 371 | .HasForeignKey("UserId") 372 | .OnDelete(DeleteBehavior.Cascade) 373 | .IsRequired(); 374 | }); 375 | 376 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 377 | { 378 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 379 | .WithMany() 380 | .HasForeignKey("RoleId") 381 | .OnDelete(DeleteBehavior.Cascade) 382 | .IsRequired(); 383 | 384 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 385 | .WithMany() 386 | .HasForeignKey("UserId") 387 | .OnDelete(DeleteBehavior.Cascade) 388 | .IsRequired(); 389 | }); 390 | 391 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 392 | { 393 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 394 | .WithMany() 395 | .HasForeignKey("UserId") 396 | .OnDelete(DeleteBehavior.Cascade) 397 | .IsRequired(); 398 | }); 399 | 400 | modelBuilder.Entity("my_books.Data.Models.Book", b => 401 | { 402 | b.HasOne("my_books.Data.Models.Publisher", "Publisher") 403 | .WithMany("Books") 404 | .HasForeignKey("PublisherId") 405 | .OnDelete(DeleteBehavior.Cascade) 406 | .IsRequired(); 407 | 408 | b.Navigation("Publisher"); 409 | }); 410 | 411 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 412 | { 413 | b.HasOne("my_books.Data.Models.Author", "Author") 414 | .WithMany("Book_Authors") 415 | .HasForeignKey("AuthorId") 416 | .OnDelete(DeleteBehavior.Cascade) 417 | .IsRequired(); 418 | 419 | b.HasOne("my_books.Data.Models.Book", "Book") 420 | .WithMany("Book_Authors") 421 | .HasForeignKey("BookId") 422 | .OnDelete(DeleteBehavior.Cascade) 423 | .IsRequired(); 424 | 425 | b.Navigation("Author"); 426 | 427 | b.Navigation("Book"); 428 | }); 429 | 430 | modelBuilder.Entity("my_books.Data.Models.Author", b => 431 | { 432 | b.Navigation("Book_Authors"); 433 | }); 434 | 435 | modelBuilder.Entity("my_books.Data.Models.Book", b => 436 | { 437 | b.Navigation("Book_Authors"); 438 | }); 439 | 440 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 441 | { 442 | b.Navigation("Books"); 443 | }); 444 | #pragma warning restore 612, 618 445 | } 446 | } 447 | } 448 | -------------------------------------------------------------------------------- /my-books/Migrations/20210426111014_IdentityAdded.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace my_books.Migrations 5 | { 6 | public partial class IdentityAdded : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.CreateTable( 11 | name: "AspNetRoles", 12 | columns: table => new 13 | { 14 | Id = table.Column(type: "nvarchar(450)", nullable: false), 15 | Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 16 | NormalizedName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 17 | ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true) 18 | }, 19 | constraints: table => 20 | { 21 | table.PrimaryKey("PK_AspNetRoles", x => x.Id); 22 | }); 23 | 24 | migrationBuilder.CreateTable( 25 | name: "AspNetUsers", 26 | columns: table => new 27 | { 28 | Id = table.Column(type: "nvarchar(450)", nullable: false), 29 | Custom = table.Column(type: "nvarchar(max)", nullable: true), 30 | UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 31 | NormalizedUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 32 | Email = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 33 | NormalizedEmail = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 34 | EmailConfirmed = table.Column(type: "bit", nullable: false), 35 | PasswordHash = table.Column(type: "nvarchar(max)", nullable: true), 36 | SecurityStamp = table.Column(type: "nvarchar(max)", nullable: true), 37 | ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true), 38 | PhoneNumber = table.Column(type: "nvarchar(max)", nullable: true), 39 | PhoneNumberConfirmed = table.Column(type: "bit", nullable: false), 40 | TwoFactorEnabled = table.Column(type: "bit", nullable: false), 41 | LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), 42 | LockoutEnabled = table.Column(type: "bit", nullable: false), 43 | AccessFailedCount = table.Column(type: "int", nullable: false) 44 | }, 45 | constraints: table => 46 | { 47 | table.PrimaryKey("PK_AspNetUsers", x => x.Id); 48 | }); 49 | 50 | migrationBuilder.CreateTable( 51 | name: "AspNetRoleClaims", 52 | columns: table => new 53 | { 54 | Id = table.Column(type: "int", nullable: false) 55 | .Annotation("SqlServer:Identity", "1, 1"), 56 | RoleId = table.Column(type: "nvarchar(450)", nullable: false), 57 | ClaimType = table.Column(type: "nvarchar(max)", nullable: true), 58 | ClaimValue = table.Column(type: "nvarchar(max)", nullable: true) 59 | }, 60 | constraints: table => 61 | { 62 | table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); 63 | table.ForeignKey( 64 | name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", 65 | column: x => x.RoleId, 66 | principalTable: "AspNetRoles", 67 | principalColumn: "Id", 68 | onDelete: ReferentialAction.Cascade); 69 | }); 70 | 71 | migrationBuilder.CreateTable( 72 | name: "AspNetUserClaims", 73 | columns: table => new 74 | { 75 | Id = table.Column(type: "int", nullable: false) 76 | .Annotation("SqlServer:Identity", "1, 1"), 77 | UserId = table.Column(type: "nvarchar(450)", nullable: false), 78 | ClaimType = table.Column(type: "nvarchar(max)", nullable: true), 79 | ClaimValue = table.Column(type: "nvarchar(max)", nullable: true) 80 | }, 81 | constraints: table => 82 | { 83 | table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); 84 | table.ForeignKey( 85 | name: "FK_AspNetUserClaims_AspNetUsers_UserId", 86 | column: x => x.UserId, 87 | principalTable: "AspNetUsers", 88 | principalColumn: "Id", 89 | onDelete: ReferentialAction.Cascade); 90 | }); 91 | 92 | migrationBuilder.CreateTable( 93 | name: "AspNetUserLogins", 94 | columns: table => new 95 | { 96 | LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), 97 | ProviderKey = table.Column(type: "nvarchar(450)", nullable: false), 98 | ProviderDisplayName = table.Column(type: "nvarchar(max)", nullable: true), 99 | UserId = table.Column(type: "nvarchar(450)", nullable: false) 100 | }, 101 | constraints: table => 102 | { 103 | table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); 104 | table.ForeignKey( 105 | name: "FK_AspNetUserLogins_AspNetUsers_UserId", 106 | column: x => x.UserId, 107 | principalTable: "AspNetUsers", 108 | principalColumn: "Id", 109 | onDelete: ReferentialAction.Cascade); 110 | }); 111 | 112 | migrationBuilder.CreateTable( 113 | name: "AspNetUserRoles", 114 | columns: table => new 115 | { 116 | UserId = table.Column(type: "nvarchar(450)", nullable: false), 117 | RoleId = table.Column(type: "nvarchar(450)", nullable: false) 118 | }, 119 | constraints: table => 120 | { 121 | table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); 122 | table.ForeignKey( 123 | name: "FK_AspNetUserRoles_AspNetRoles_RoleId", 124 | column: x => x.RoleId, 125 | principalTable: "AspNetRoles", 126 | principalColumn: "Id", 127 | onDelete: ReferentialAction.Cascade); 128 | table.ForeignKey( 129 | name: "FK_AspNetUserRoles_AspNetUsers_UserId", 130 | column: x => x.UserId, 131 | principalTable: "AspNetUsers", 132 | principalColumn: "Id", 133 | onDelete: ReferentialAction.Cascade); 134 | }); 135 | 136 | migrationBuilder.CreateTable( 137 | name: "AspNetUserTokens", 138 | columns: table => new 139 | { 140 | UserId = table.Column(type: "nvarchar(450)", nullable: false), 141 | LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), 142 | Name = table.Column(type: "nvarchar(450)", nullable: false), 143 | Value = table.Column(type: "nvarchar(max)", nullable: true) 144 | }, 145 | constraints: table => 146 | { 147 | table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); 148 | table.ForeignKey( 149 | name: "FK_AspNetUserTokens_AspNetUsers_UserId", 150 | column: x => x.UserId, 151 | principalTable: "AspNetUsers", 152 | principalColumn: "Id", 153 | onDelete: ReferentialAction.Cascade); 154 | }); 155 | 156 | migrationBuilder.CreateIndex( 157 | name: "IX_AspNetRoleClaims_RoleId", 158 | table: "AspNetRoleClaims", 159 | column: "RoleId"); 160 | 161 | migrationBuilder.CreateIndex( 162 | name: "RoleNameIndex", 163 | table: "AspNetRoles", 164 | column: "NormalizedName", 165 | unique: true, 166 | filter: "[NormalizedName] IS NOT NULL"); 167 | 168 | migrationBuilder.CreateIndex( 169 | name: "IX_AspNetUserClaims_UserId", 170 | table: "AspNetUserClaims", 171 | column: "UserId"); 172 | 173 | migrationBuilder.CreateIndex( 174 | name: "IX_AspNetUserLogins_UserId", 175 | table: "AspNetUserLogins", 176 | column: "UserId"); 177 | 178 | migrationBuilder.CreateIndex( 179 | name: "IX_AspNetUserRoles_RoleId", 180 | table: "AspNetUserRoles", 181 | column: "RoleId"); 182 | 183 | migrationBuilder.CreateIndex( 184 | name: "EmailIndex", 185 | table: "AspNetUsers", 186 | column: "NormalizedEmail"); 187 | 188 | migrationBuilder.CreateIndex( 189 | name: "UserNameIndex", 190 | table: "AspNetUsers", 191 | column: "NormalizedUserName", 192 | unique: true, 193 | filter: "[NormalizedUserName] IS NOT NULL"); 194 | } 195 | 196 | protected override void Down(MigrationBuilder migrationBuilder) 197 | { 198 | migrationBuilder.DropTable( 199 | name: "AspNetRoleClaims"); 200 | 201 | migrationBuilder.DropTable( 202 | name: "AspNetUserClaims"); 203 | 204 | migrationBuilder.DropTable( 205 | name: "AspNetUserLogins"); 206 | 207 | migrationBuilder.DropTable( 208 | name: "AspNetUserRoles"); 209 | 210 | migrationBuilder.DropTable( 211 | name: "AspNetUserTokens"); 212 | 213 | migrationBuilder.DropTable( 214 | name: "AspNetRoles"); 215 | 216 | migrationBuilder.DropTable( 217 | name: "AspNetUsers"); 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /my-books/Migrations/20210426125308_RefreshTokensAdded.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using my_books.Data; 9 | 10 | namespace my_books.Migrations 11 | { 12 | [DbContext(typeof(AppDbContext))] 13 | [Migration("20210426125308_RefreshTokensAdded")] 14 | partial class RefreshTokensAdded 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .UseIdentityColumns() 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("ProductVersion", "5.0.2"); 23 | 24 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 25 | { 26 | b.Property("Id") 27 | .HasColumnType("nvarchar(450)"); 28 | 29 | b.Property("ConcurrencyStamp") 30 | .IsConcurrencyToken() 31 | .HasColumnType("nvarchar(max)"); 32 | 33 | b.Property("Name") 34 | .HasMaxLength(256) 35 | .HasColumnType("nvarchar(256)"); 36 | 37 | b.Property("NormalizedName") 38 | .HasMaxLength(256) 39 | .HasColumnType("nvarchar(256)"); 40 | 41 | b.HasKey("Id"); 42 | 43 | b.HasIndex("NormalizedName") 44 | .IsUnique() 45 | .HasDatabaseName("RoleNameIndex") 46 | .HasFilter("[NormalizedName] IS NOT NULL"); 47 | 48 | b.ToTable("AspNetRoles"); 49 | }); 50 | 51 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 52 | { 53 | b.Property("Id") 54 | .ValueGeneratedOnAdd() 55 | .HasColumnType("int") 56 | .UseIdentityColumn(); 57 | 58 | b.Property("ClaimType") 59 | .HasColumnType("nvarchar(max)"); 60 | 61 | b.Property("ClaimValue") 62 | .HasColumnType("nvarchar(max)"); 63 | 64 | b.Property("RoleId") 65 | .IsRequired() 66 | .HasColumnType("nvarchar(450)"); 67 | 68 | b.HasKey("Id"); 69 | 70 | b.HasIndex("RoleId"); 71 | 72 | b.ToTable("AspNetRoleClaims"); 73 | }); 74 | 75 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 76 | { 77 | b.Property("Id") 78 | .ValueGeneratedOnAdd() 79 | .HasColumnType("int") 80 | .UseIdentityColumn(); 81 | 82 | b.Property("ClaimType") 83 | .HasColumnType("nvarchar(max)"); 84 | 85 | b.Property("ClaimValue") 86 | .HasColumnType("nvarchar(max)"); 87 | 88 | b.Property("UserId") 89 | .IsRequired() 90 | .HasColumnType("nvarchar(450)"); 91 | 92 | b.HasKey("Id"); 93 | 94 | b.HasIndex("UserId"); 95 | 96 | b.ToTable("AspNetUserClaims"); 97 | }); 98 | 99 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 100 | { 101 | b.Property("LoginProvider") 102 | .HasColumnType("nvarchar(450)"); 103 | 104 | b.Property("ProviderKey") 105 | .HasColumnType("nvarchar(450)"); 106 | 107 | b.Property("ProviderDisplayName") 108 | .HasColumnType("nvarchar(max)"); 109 | 110 | b.Property("UserId") 111 | .IsRequired() 112 | .HasColumnType("nvarchar(450)"); 113 | 114 | b.HasKey("LoginProvider", "ProviderKey"); 115 | 116 | b.HasIndex("UserId"); 117 | 118 | b.ToTable("AspNetUserLogins"); 119 | }); 120 | 121 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 122 | { 123 | b.Property("UserId") 124 | .HasColumnType("nvarchar(450)"); 125 | 126 | b.Property("RoleId") 127 | .HasColumnType("nvarchar(450)"); 128 | 129 | b.HasKey("UserId", "RoleId"); 130 | 131 | b.HasIndex("RoleId"); 132 | 133 | b.ToTable("AspNetUserRoles"); 134 | }); 135 | 136 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 137 | { 138 | b.Property("UserId") 139 | .HasColumnType("nvarchar(450)"); 140 | 141 | b.Property("LoginProvider") 142 | .HasColumnType("nvarchar(450)"); 143 | 144 | b.Property("Name") 145 | .HasColumnType("nvarchar(450)"); 146 | 147 | b.Property("Value") 148 | .HasColumnType("nvarchar(max)"); 149 | 150 | b.HasKey("UserId", "LoginProvider", "Name"); 151 | 152 | b.ToTable("AspNetUserTokens"); 153 | }); 154 | 155 | modelBuilder.Entity("my_books.Data.Models.ApplicationUser", b => 156 | { 157 | b.Property("Id") 158 | .HasColumnType("nvarchar(450)"); 159 | 160 | b.Property("AccessFailedCount") 161 | .HasColumnType("int"); 162 | 163 | b.Property("ConcurrencyStamp") 164 | .IsConcurrencyToken() 165 | .HasColumnType("nvarchar(max)"); 166 | 167 | b.Property("Custom") 168 | .HasColumnType("nvarchar(max)"); 169 | 170 | b.Property("Email") 171 | .HasMaxLength(256) 172 | .HasColumnType("nvarchar(256)"); 173 | 174 | b.Property("EmailConfirmed") 175 | .HasColumnType("bit"); 176 | 177 | b.Property("LockoutEnabled") 178 | .HasColumnType("bit"); 179 | 180 | b.Property("LockoutEnd") 181 | .HasColumnType("datetimeoffset"); 182 | 183 | b.Property("NormalizedEmail") 184 | .HasMaxLength(256) 185 | .HasColumnType("nvarchar(256)"); 186 | 187 | b.Property("NormalizedUserName") 188 | .HasMaxLength(256) 189 | .HasColumnType("nvarchar(256)"); 190 | 191 | b.Property("PasswordHash") 192 | .HasColumnType("nvarchar(max)"); 193 | 194 | b.Property("PhoneNumber") 195 | .HasColumnType("nvarchar(max)"); 196 | 197 | b.Property("PhoneNumberConfirmed") 198 | .HasColumnType("bit"); 199 | 200 | b.Property("SecurityStamp") 201 | .HasColumnType("nvarchar(max)"); 202 | 203 | b.Property("TwoFactorEnabled") 204 | .HasColumnType("bit"); 205 | 206 | b.Property("UserName") 207 | .HasMaxLength(256) 208 | .HasColumnType("nvarchar(256)"); 209 | 210 | b.HasKey("Id"); 211 | 212 | b.HasIndex("NormalizedEmail") 213 | .HasDatabaseName("EmailIndex"); 214 | 215 | b.HasIndex("NormalizedUserName") 216 | .IsUnique() 217 | .HasDatabaseName("UserNameIndex") 218 | .HasFilter("[NormalizedUserName] IS NOT NULL"); 219 | 220 | b.ToTable("AspNetUsers"); 221 | }); 222 | 223 | modelBuilder.Entity("my_books.Data.Models.Author", b => 224 | { 225 | b.Property("Id") 226 | .ValueGeneratedOnAdd() 227 | .HasColumnType("int") 228 | .UseIdentityColumn(); 229 | 230 | b.Property("FullName") 231 | .HasColumnType("nvarchar(max)"); 232 | 233 | b.HasKey("Id"); 234 | 235 | b.ToTable("Authors"); 236 | }); 237 | 238 | modelBuilder.Entity("my_books.Data.Models.Book", b => 239 | { 240 | b.Property("Id") 241 | .ValueGeneratedOnAdd() 242 | .HasColumnType("int") 243 | .UseIdentityColumn(); 244 | 245 | b.Property("CoverUrl") 246 | .HasColumnType("nvarchar(max)"); 247 | 248 | b.Property("DateAdded") 249 | .HasColumnType("datetime2"); 250 | 251 | b.Property("DateRead") 252 | .HasColumnType("datetime2"); 253 | 254 | b.Property("Description") 255 | .HasColumnType("nvarchar(max)"); 256 | 257 | b.Property("Genre") 258 | .HasColumnType("nvarchar(max)"); 259 | 260 | b.Property("IsRead") 261 | .HasColumnType("bit"); 262 | 263 | b.Property("PublisherId") 264 | .HasColumnType("int"); 265 | 266 | b.Property("Rate") 267 | .HasColumnType("int"); 268 | 269 | b.Property("Title") 270 | .HasColumnType("nvarchar(max)"); 271 | 272 | b.HasKey("Id"); 273 | 274 | b.HasIndex("PublisherId"); 275 | 276 | b.ToTable("Books"); 277 | }); 278 | 279 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 280 | { 281 | b.Property("Id") 282 | .ValueGeneratedOnAdd() 283 | .HasColumnType("int") 284 | .UseIdentityColumn(); 285 | 286 | b.Property("AuthorId") 287 | .HasColumnType("int"); 288 | 289 | b.Property("BookId") 290 | .HasColumnType("int"); 291 | 292 | b.HasKey("Id"); 293 | 294 | b.HasIndex("AuthorId"); 295 | 296 | b.HasIndex("BookId"); 297 | 298 | b.ToTable("Books_Authors"); 299 | }); 300 | 301 | modelBuilder.Entity("my_books.Data.Models.Log", b => 302 | { 303 | b.Property("Id") 304 | .ValueGeneratedOnAdd() 305 | .HasColumnType("int") 306 | .UseIdentityColumn(); 307 | 308 | b.Property("Exception") 309 | .HasColumnType("nvarchar(max)"); 310 | 311 | b.Property("Level") 312 | .HasColumnType("nvarchar(max)"); 313 | 314 | b.Property("LogEvent") 315 | .HasColumnType("nvarchar(max)"); 316 | 317 | b.Property("Message") 318 | .HasColumnType("nvarchar(max)"); 319 | 320 | b.Property("MessageTemplate") 321 | .HasColumnType("nvarchar(max)"); 322 | 323 | b.Property("Properties") 324 | .HasColumnType("nvarchar(max)"); 325 | 326 | b.Property("TimeStamp") 327 | .HasColumnType("datetime2"); 328 | 329 | b.HasKey("Id"); 330 | 331 | b.ToTable("Logs"); 332 | }); 333 | 334 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 335 | { 336 | b.Property("Id") 337 | .ValueGeneratedOnAdd() 338 | .HasColumnType("int") 339 | .UseIdentityColumn(); 340 | 341 | b.Property("Name") 342 | .HasColumnType("nvarchar(max)"); 343 | 344 | b.HasKey("Id"); 345 | 346 | b.ToTable("Publishers"); 347 | }); 348 | 349 | modelBuilder.Entity("my_books.Data.Models.RefreshToken", b => 350 | { 351 | b.Property("Id") 352 | .ValueGeneratedOnAdd() 353 | .HasColumnType("int") 354 | .UseIdentityColumn(); 355 | 356 | b.Property("DateAdded") 357 | .HasColumnType("datetime2"); 358 | 359 | b.Property("DateExpire") 360 | .HasColumnType("datetime2"); 361 | 362 | b.Property("IsRevoked") 363 | .HasColumnType("bit"); 364 | 365 | b.Property("JwtId") 366 | .HasColumnType("nvarchar(max)"); 367 | 368 | b.Property("Token") 369 | .HasColumnType("nvarchar(max)"); 370 | 371 | b.Property("UserId") 372 | .HasColumnType("nvarchar(450)"); 373 | 374 | b.HasKey("Id"); 375 | 376 | b.HasIndex("UserId"); 377 | 378 | b.ToTable("RefreshTokens"); 379 | }); 380 | 381 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 382 | { 383 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 384 | .WithMany() 385 | .HasForeignKey("RoleId") 386 | .OnDelete(DeleteBehavior.Cascade) 387 | .IsRequired(); 388 | }); 389 | 390 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 391 | { 392 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 393 | .WithMany() 394 | .HasForeignKey("UserId") 395 | .OnDelete(DeleteBehavior.Cascade) 396 | .IsRequired(); 397 | }); 398 | 399 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 400 | { 401 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 402 | .WithMany() 403 | .HasForeignKey("UserId") 404 | .OnDelete(DeleteBehavior.Cascade) 405 | .IsRequired(); 406 | }); 407 | 408 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 409 | { 410 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 411 | .WithMany() 412 | .HasForeignKey("RoleId") 413 | .OnDelete(DeleteBehavior.Cascade) 414 | .IsRequired(); 415 | 416 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 417 | .WithMany() 418 | .HasForeignKey("UserId") 419 | .OnDelete(DeleteBehavior.Cascade) 420 | .IsRequired(); 421 | }); 422 | 423 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 424 | { 425 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 426 | .WithMany() 427 | .HasForeignKey("UserId") 428 | .OnDelete(DeleteBehavior.Cascade) 429 | .IsRequired(); 430 | }); 431 | 432 | modelBuilder.Entity("my_books.Data.Models.Book", b => 433 | { 434 | b.HasOne("my_books.Data.Models.Publisher", "Publisher") 435 | .WithMany("Books") 436 | .HasForeignKey("PublisherId") 437 | .OnDelete(DeleteBehavior.Cascade) 438 | .IsRequired(); 439 | 440 | b.Navigation("Publisher"); 441 | }); 442 | 443 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 444 | { 445 | b.HasOne("my_books.Data.Models.Author", "Author") 446 | .WithMany("Book_Authors") 447 | .HasForeignKey("AuthorId") 448 | .OnDelete(DeleteBehavior.Cascade) 449 | .IsRequired(); 450 | 451 | b.HasOne("my_books.Data.Models.Book", "Book") 452 | .WithMany("Book_Authors") 453 | .HasForeignKey("BookId") 454 | .OnDelete(DeleteBehavior.Cascade) 455 | .IsRequired(); 456 | 457 | b.Navigation("Author"); 458 | 459 | b.Navigation("Book"); 460 | }); 461 | 462 | modelBuilder.Entity("my_books.Data.Models.RefreshToken", b => 463 | { 464 | b.HasOne("my_books.Data.Models.ApplicationUser", "User") 465 | .WithMany() 466 | .HasForeignKey("UserId"); 467 | 468 | b.Navigation("User"); 469 | }); 470 | 471 | modelBuilder.Entity("my_books.Data.Models.Author", b => 472 | { 473 | b.Navigation("Book_Authors"); 474 | }); 475 | 476 | modelBuilder.Entity("my_books.Data.Models.Book", b => 477 | { 478 | b.Navigation("Book_Authors"); 479 | }); 480 | 481 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 482 | { 483 | b.Navigation("Books"); 484 | }); 485 | #pragma warning restore 612, 618 486 | } 487 | } 488 | } 489 | -------------------------------------------------------------------------------- /my-books/Migrations/20210426125308_RefreshTokensAdded.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace my_books.Migrations 5 | { 6 | public partial class RefreshTokensAdded : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.CreateTable( 11 | name: "RefreshTokens", 12 | columns: table => new 13 | { 14 | Id = table.Column(type: "int", nullable: false) 15 | .Annotation("SqlServer:Identity", "1, 1"), 16 | UserId = table.Column(type: "nvarchar(450)", nullable: true), 17 | Token = table.Column(type: "nvarchar(max)", nullable: true), 18 | JwtId = table.Column(type: "nvarchar(max)", nullable: true), 19 | IsRevoked = table.Column(type: "bit", nullable: false), 20 | DateAdded = table.Column(type: "datetime2", nullable: false), 21 | DateExpire = table.Column(type: "datetime2", nullable: false) 22 | }, 23 | constraints: table => 24 | { 25 | table.PrimaryKey("PK_RefreshTokens", x => x.Id); 26 | table.ForeignKey( 27 | name: "FK_RefreshTokens_AspNetUsers_UserId", 28 | column: x => x.UserId, 29 | principalTable: "AspNetUsers", 30 | principalColumn: "Id", 31 | onDelete: ReferentialAction.Restrict); 32 | }); 33 | 34 | migrationBuilder.CreateIndex( 35 | name: "IX_RefreshTokens_UserId", 36 | table: "RefreshTokens", 37 | column: "UserId"); 38 | } 39 | 40 | protected override void Down(MigrationBuilder migrationBuilder) 41 | { 42 | migrationBuilder.DropTable( 43 | name: "RefreshTokens"); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /my-books/Migrations/AppDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | using my_books.Data; 8 | 9 | namespace my_books.Migrations 10 | { 11 | [DbContext(typeof(AppDbContext))] 12 | partial class AppDbContextModelSnapshot : ModelSnapshot 13 | { 14 | protected override void BuildModel(ModelBuilder modelBuilder) 15 | { 16 | #pragma warning disable 612, 618 17 | modelBuilder 18 | .UseIdentityColumns() 19 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 20 | .HasAnnotation("ProductVersion", "5.0.2"); 21 | 22 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 23 | { 24 | b.Property("Id") 25 | .HasColumnType("nvarchar(450)"); 26 | 27 | b.Property("ConcurrencyStamp") 28 | .IsConcurrencyToken() 29 | .HasColumnType("nvarchar(max)"); 30 | 31 | b.Property("Name") 32 | .HasMaxLength(256) 33 | .HasColumnType("nvarchar(256)"); 34 | 35 | b.Property("NormalizedName") 36 | .HasMaxLength(256) 37 | .HasColumnType("nvarchar(256)"); 38 | 39 | b.HasKey("Id"); 40 | 41 | b.HasIndex("NormalizedName") 42 | .IsUnique() 43 | .HasDatabaseName("RoleNameIndex") 44 | .HasFilter("[NormalizedName] IS NOT NULL"); 45 | 46 | b.ToTable("AspNetRoles"); 47 | }); 48 | 49 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 50 | { 51 | b.Property("Id") 52 | .ValueGeneratedOnAdd() 53 | .HasColumnType("int") 54 | .UseIdentityColumn(); 55 | 56 | b.Property("ClaimType") 57 | .HasColumnType("nvarchar(max)"); 58 | 59 | b.Property("ClaimValue") 60 | .HasColumnType("nvarchar(max)"); 61 | 62 | b.Property("RoleId") 63 | .IsRequired() 64 | .HasColumnType("nvarchar(450)"); 65 | 66 | b.HasKey("Id"); 67 | 68 | b.HasIndex("RoleId"); 69 | 70 | b.ToTable("AspNetRoleClaims"); 71 | }); 72 | 73 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 74 | { 75 | b.Property("Id") 76 | .ValueGeneratedOnAdd() 77 | .HasColumnType("int") 78 | .UseIdentityColumn(); 79 | 80 | b.Property("ClaimType") 81 | .HasColumnType("nvarchar(max)"); 82 | 83 | b.Property("ClaimValue") 84 | .HasColumnType("nvarchar(max)"); 85 | 86 | b.Property("UserId") 87 | .IsRequired() 88 | .HasColumnType("nvarchar(450)"); 89 | 90 | b.HasKey("Id"); 91 | 92 | b.HasIndex("UserId"); 93 | 94 | b.ToTable("AspNetUserClaims"); 95 | }); 96 | 97 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 98 | { 99 | b.Property("LoginProvider") 100 | .HasColumnType("nvarchar(450)"); 101 | 102 | b.Property("ProviderKey") 103 | .HasColumnType("nvarchar(450)"); 104 | 105 | b.Property("ProviderDisplayName") 106 | .HasColumnType("nvarchar(max)"); 107 | 108 | b.Property("UserId") 109 | .IsRequired() 110 | .HasColumnType("nvarchar(450)"); 111 | 112 | b.HasKey("LoginProvider", "ProviderKey"); 113 | 114 | b.HasIndex("UserId"); 115 | 116 | b.ToTable("AspNetUserLogins"); 117 | }); 118 | 119 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 120 | { 121 | b.Property("UserId") 122 | .HasColumnType("nvarchar(450)"); 123 | 124 | b.Property("RoleId") 125 | .HasColumnType("nvarchar(450)"); 126 | 127 | b.HasKey("UserId", "RoleId"); 128 | 129 | b.HasIndex("RoleId"); 130 | 131 | b.ToTable("AspNetUserRoles"); 132 | }); 133 | 134 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 135 | { 136 | b.Property("UserId") 137 | .HasColumnType("nvarchar(450)"); 138 | 139 | b.Property("LoginProvider") 140 | .HasColumnType("nvarchar(450)"); 141 | 142 | b.Property("Name") 143 | .HasColumnType("nvarchar(450)"); 144 | 145 | b.Property("Value") 146 | .HasColumnType("nvarchar(max)"); 147 | 148 | b.HasKey("UserId", "LoginProvider", "Name"); 149 | 150 | b.ToTable("AspNetUserTokens"); 151 | }); 152 | 153 | modelBuilder.Entity("my_books.Data.Models.ApplicationUser", b => 154 | { 155 | b.Property("Id") 156 | .HasColumnType("nvarchar(450)"); 157 | 158 | b.Property("AccessFailedCount") 159 | .HasColumnType("int"); 160 | 161 | b.Property("ConcurrencyStamp") 162 | .IsConcurrencyToken() 163 | .HasColumnType("nvarchar(max)"); 164 | 165 | b.Property("Custom") 166 | .HasColumnType("nvarchar(max)"); 167 | 168 | b.Property("Email") 169 | .HasMaxLength(256) 170 | .HasColumnType("nvarchar(256)"); 171 | 172 | b.Property("EmailConfirmed") 173 | .HasColumnType("bit"); 174 | 175 | b.Property("LockoutEnabled") 176 | .HasColumnType("bit"); 177 | 178 | b.Property("LockoutEnd") 179 | .HasColumnType("datetimeoffset"); 180 | 181 | b.Property("NormalizedEmail") 182 | .HasMaxLength(256) 183 | .HasColumnType("nvarchar(256)"); 184 | 185 | b.Property("NormalizedUserName") 186 | .HasMaxLength(256) 187 | .HasColumnType("nvarchar(256)"); 188 | 189 | b.Property("PasswordHash") 190 | .HasColumnType("nvarchar(max)"); 191 | 192 | b.Property("PhoneNumber") 193 | .HasColumnType("nvarchar(max)"); 194 | 195 | b.Property("PhoneNumberConfirmed") 196 | .HasColumnType("bit"); 197 | 198 | b.Property("SecurityStamp") 199 | .HasColumnType("nvarchar(max)"); 200 | 201 | b.Property("TwoFactorEnabled") 202 | .HasColumnType("bit"); 203 | 204 | b.Property("UserName") 205 | .HasMaxLength(256) 206 | .HasColumnType("nvarchar(256)"); 207 | 208 | b.HasKey("Id"); 209 | 210 | b.HasIndex("NormalizedEmail") 211 | .HasDatabaseName("EmailIndex"); 212 | 213 | b.HasIndex("NormalizedUserName") 214 | .IsUnique() 215 | .HasDatabaseName("UserNameIndex") 216 | .HasFilter("[NormalizedUserName] IS NOT NULL"); 217 | 218 | b.ToTable("AspNetUsers"); 219 | }); 220 | 221 | modelBuilder.Entity("my_books.Data.Models.Author", b => 222 | { 223 | b.Property("Id") 224 | .ValueGeneratedOnAdd() 225 | .HasColumnType("int") 226 | .UseIdentityColumn(); 227 | 228 | b.Property("FullName") 229 | .HasColumnType("nvarchar(max)"); 230 | 231 | b.HasKey("Id"); 232 | 233 | b.ToTable("Authors"); 234 | }); 235 | 236 | modelBuilder.Entity("my_books.Data.Models.Book", b => 237 | { 238 | b.Property("Id") 239 | .ValueGeneratedOnAdd() 240 | .HasColumnType("int") 241 | .UseIdentityColumn(); 242 | 243 | b.Property("CoverUrl") 244 | .HasColumnType("nvarchar(max)"); 245 | 246 | b.Property("DateAdded") 247 | .HasColumnType("datetime2"); 248 | 249 | b.Property("DateRead") 250 | .HasColumnType("datetime2"); 251 | 252 | b.Property("Description") 253 | .HasColumnType("nvarchar(max)"); 254 | 255 | b.Property("Genre") 256 | .HasColumnType("nvarchar(max)"); 257 | 258 | b.Property("IsRead") 259 | .HasColumnType("bit"); 260 | 261 | b.Property("PublisherId") 262 | .HasColumnType("int"); 263 | 264 | b.Property("Rate") 265 | .HasColumnType("int"); 266 | 267 | b.Property("Title") 268 | .HasColumnType("nvarchar(max)"); 269 | 270 | b.HasKey("Id"); 271 | 272 | b.HasIndex("PublisherId"); 273 | 274 | b.ToTable("Books"); 275 | }); 276 | 277 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 278 | { 279 | b.Property("Id") 280 | .ValueGeneratedOnAdd() 281 | .HasColumnType("int") 282 | .UseIdentityColumn(); 283 | 284 | b.Property("AuthorId") 285 | .HasColumnType("int"); 286 | 287 | b.Property("BookId") 288 | .HasColumnType("int"); 289 | 290 | b.HasKey("Id"); 291 | 292 | b.HasIndex("AuthorId"); 293 | 294 | b.HasIndex("BookId"); 295 | 296 | b.ToTable("Books_Authors"); 297 | }); 298 | 299 | modelBuilder.Entity("my_books.Data.Models.Log", b => 300 | { 301 | b.Property("Id") 302 | .ValueGeneratedOnAdd() 303 | .HasColumnType("int") 304 | .UseIdentityColumn(); 305 | 306 | b.Property("Exception") 307 | .HasColumnType("nvarchar(max)"); 308 | 309 | b.Property("Level") 310 | .HasColumnType("nvarchar(max)"); 311 | 312 | b.Property("LogEvent") 313 | .HasColumnType("nvarchar(max)"); 314 | 315 | b.Property("Message") 316 | .HasColumnType("nvarchar(max)"); 317 | 318 | b.Property("MessageTemplate") 319 | .HasColumnType("nvarchar(max)"); 320 | 321 | b.Property("Properties") 322 | .HasColumnType("nvarchar(max)"); 323 | 324 | b.Property("TimeStamp") 325 | .HasColumnType("datetime2"); 326 | 327 | b.HasKey("Id"); 328 | 329 | b.ToTable("Logs"); 330 | }); 331 | 332 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 333 | { 334 | b.Property("Id") 335 | .ValueGeneratedOnAdd() 336 | .HasColumnType("int") 337 | .UseIdentityColumn(); 338 | 339 | b.Property("Name") 340 | .HasColumnType("nvarchar(max)"); 341 | 342 | b.HasKey("Id"); 343 | 344 | b.ToTable("Publishers"); 345 | }); 346 | 347 | modelBuilder.Entity("my_books.Data.Models.RefreshToken", b => 348 | { 349 | b.Property("Id") 350 | .ValueGeneratedOnAdd() 351 | .HasColumnType("int") 352 | .UseIdentityColumn(); 353 | 354 | b.Property("DateAdded") 355 | .HasColumnType("datetime2"); 356 | 357 | b.Property("DateExpire") 358 | .HasColumnType("datetime2"); 359 | 360 | b.Property("IsRevoked") 361 | .HasColumnType("bit"); 362 | 363 | b.Property("JwtId") 364 | .HasColumnType("nvarchar(max)"); 365 | 366 | b.Property("Token") 367 | .HasColumnType("nvarchar(max)"); 368 | 369 | b.Property("UserId") 370 | .HasColumnType("nvarchar(450)"); 371 | 372 | b.HasKey("Id"); 373 | 374 | b.HasIndex("UserId"); 375 | 376 | b.ToTable("RefreshTokens"); 377 | }); 378 | 379 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 380 | { 381 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 382 | .WithMany() 383 | .HasForeignKey("RoleId") 384 | .OnDelete(DeleteBehavior.Cascade) 385 | .IsRequired(); 386 | }); 387 | 388 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 389 | { 390 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 391 | .WithMany() 392 | .HasForeignKey("UserId") 393 | .OnDelete(DeleteBehavior.Cascade) 394 | .IsRequired(); 395 | }); 396 | 397 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 398 | { 399 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 400 | .WithMany() 401 | .HasForeignKey("UserId") 402 | .OnDelete(DeleteBehavior.Cascade) 403 | .IsRequired(); 404 | }); 405 | 406 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 407 | { 408 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 409 | .WithMany() 410 | .HasForeignKey("RoleId") 411 | .OnDelete(DeleteBehavior.Cascade) 412 | .IsRequired(); 413 | 414 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 415 | .WithMany() 416 | .HasForeignKey("UserId") 417 | .OnDelete(DeleteBehavior.Cascade) 418 | .IsRequired(); 419 | }); 420 | 421 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 422 | { 423 | b.HasOne("my_books.Data.Models.ApplicationUser", null) 424 | .WithMany() 425 | .HasForeignKey("UserId") 426 | .OnDelete(DeleteBehavior.Cascade) 427 | .IsRequired(); 428 | }); 429 | 430 | modelBuilder.Entity("my_books.Data.Models.Book", b => 431 | { 432 | b.HasOne("my_books.Data.Models.Publisher", "Publisher") 433 | .WithMany("Books") 434 | .HasForeignKey("PublisherId") 435 | .OnDelete(DeleteBehavior.Cascade) 436 | .IsRequired(); 437 | 438 | b.Navigation("Publisher"); 439 | }); 440 | 441 | modelBuilder.Entity("my_books.Data.Models.Book_Author", b => 442 | { 443 | b.HasOne("my_books.Data.Models.Author", "Author") 444 | .WithMany("Book_Authors") 445 | .HasForeignKey("AuthorId") 446 | .OnDelete(DeleteBehavior.Cascade) 447 | .IsRequired(); 448 | 449 | b.HasOne("my_books.Data.Models.Book", "Book") 450 | .WithMany("Book_Authors") 451 | .HasForeignKey("BookId") 452 | .OnDelete(DeleteBehavior.Cascade) 453 | .IsRequired(); 454 | 455 | b.Navigation("Author"); 456 | 457 | b.Navigation("Book"); 458 | }); 459 | 460 | modelBuilder.Entity("my_books.Data.Models.RefreshToken", b => 461 | { 462 | b.HasOne("my_books.Data.Models.ApplicationUser", "User") 463 | .WithMany() 464 | .HasForeignKey("UserId"); 465 | 466 | b.Navigation("User"); 467 | }); 468 | 469 | modelBuilder.Entity("my_books.Data.Models.Author", b => 470 | { 471 | b.Navigation("Book_Authors"); 472 | }); 473 | 474 | modelBuilder.Entity("my_books.Data.Models.Book", b => 475 | { 476 | b.Navigation("Book_Authors"); 477 | }); 478 | 479 | modelBuilder.Entity("my_books.Data.Models.Publisher", b => 480 | { 481 | b.Navigation("Books"); 482 | }); 483 | #pragma warning restore 612, 618 484 | } 485 | } 486 | } 487 | -------------------------------------------------------------------------------- /my-books/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.Hosting; 4 | using Microsoft.Extensions.Logging; 5 | using Serilog; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Threading.Tasks; 10 | 11 | namespace my_books 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | try 18 | { 19 | var configuration = new ConfigurationBuilder() 20 | .AddJsonFile("appsettings.json") 21 | .Build(); 22 | 23 | Log.Logger = new LoggerConfiguration() 24 | .ReadFrom.Configuration(configuration) 25 | .CreateLogger(); 26 | 27 | //Log.Logger = new LoggerConfiguration() 28 | // .WriteTo.File("Logs/log.txt", rollingInterval: RollingInterval.Day) 29 | // .CreateLogger(); 30 | 31 | CreateHostBuilder(args).Build().Run(); 32 | } 33 | finally 34 | { 35 | Log.CloseAndFlush(); 36 | } 37 | 38 | } 39 | 40 | public static IHostBuilder CreateHostBuilder(string[] args) => 41 | Host.CreateDefaultBuilder(args) 42 | .UseSerilog() 43 | .ConfigureWebHostDefaults(webBuilder => 44 | { 45 | webBuilder.UseStartup(); 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /my-books/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:55778", 8 | "sslPort": 44382 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "api/publishers/get-all-publishers", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "my_books": { 21 | "commandName": "Project", 22 | "dotnetRunMessages": "true", 23 | "launchBrowser": true, 24 | "launchUrl": "swagger", 25 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /my-books/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication.JwtBearer; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.AspNetCore.HttpsPolicy; 5 | using Microsoft.AspNetCore.Identity; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.Versioning; 8 | using Microsoft.EntityFrameworkCore; 9 | using Microsoft.Extensions.Configuration; 10 | using Microsoft.Extensions.DependencyInjection; 11 | using Microsoft.Extensions.Hosting; 12 | using Microsoft.Extensions.Logging; 13 | using Microsoft.IdentityModel.Tokens; 14 | using Microsoft.OpenApi.Models; 15 | using my_books.Data; 16 | using my_books.Data.Models; 17 | using my_books.Data.Services; 18 | using my_books.Exceptions; 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace my_books 26 | { 27 | public class Startup 28 | { 29 | public string ConnectionString { get; set; } 30 | public Startup(IConfiguration configuration) 31 | { 32 | Configuration = configuration; 33 | ConnectionString = Configuration.GetConnectionString("DefaultConnectionString"); 34 | } 35 | 36 | public IConfiguration Configuration { get; } 37 | 38 | // This method gets called by the runtime. Use this method to add services to the container. 39 | public void ConfigureServices(IServiceCollection services) 40 | { 41 | 42 | services.AddControllers(); 43 | 44 | //Configure DBContext with SQL 45 | services.AddDbContext(options => options.UseSqlServer(ConnectionString)); 46 | 47 | //Configure the Services 48 | services.AddTransient(); 49 | services.AddTransient(); 50 | services.AddTransient(); 51 | services.AddTransient(); 52 | 53 | services.AddApiVersioning(config => 54 | { 55 | config.DefaultApiVersion = new ApiVersion(1, 0); 56 | config.AssumeDefaultVersionWhenUnspecified = true; 57 | 58 | //config.ApiVersionReader = new HeaderApiVersionReader("custom-version-header"); 59 | //config.ApiVersionReader = new MediaTypeApiVersionReader(); 60 | }); 61 | 62 | 63 | //Add Identity 64 | services.AddIdentity() 65 | .AddEntityFrameworkStores() 66 | .AddDefaultTokenProviders(); 67 | 68 | //Add Authentication 69 | services.AddAuthentication(options => 70 | { 71 | options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 72 | options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 73 | options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; 74 | }) 75 | //Add JWT Bearer 76 | .AddJwtBearer(options => 77 | { 78 | options.SaveToken = true; 79 | options.RequireHttpsMetadata = false; 80 | options.TokenValidationParameters = new TokenValidationParameters() 81 | { 82 | ValidateIssuerSigningKey = true, 83 | IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration["JWT:Secret"])), 84 | 85 | ValidateIssuer = true, 86 | ValidIssuer = Configuration["JWT:Issuer"], 87 | 88 | ValidateAudience = true, 89 | ValidAudience = Configuration["JWT:Audience"] 90 | }; 91 | }); 92 | 93 | services.AddSwaggerGen(c => 94 | { 95 | c.SwaggerDoc("v1", new OpenApiInfo { Title = "my_books", Version = "v1" }); 96 | }); 97 | } 98 | 99 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 100 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) 101 | { 102 | if (env.IsDevelopment()) 103 | { 104 | app.UseDeveloperExceptionPage(); 105 | app.UseSwagger(); 106 | app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "my_books v1")); 107 | } 108 | 109 | app.UseHttpsRedirection(); 110 | 111 | app.UseRouting(); 112 | 113 | //Authentication & Authorization 114 | app.UseAuthentication(); 115 | app.UseAuthorization(); 116 | 117 | //Exception Handling 118 | app.ConfigureBuildInExceptionHandler(loggerFactory); 119 | //app.ConfigureCustomExceptionHandler(); 120 | 121 | app.UseEndpoints(endpoints => 122 | { 123 | endpoints.MapControllers(); 124 | }); 125 | 126 | //AppDbInitializer.Seed(app); 127 | AppDbInitializer.SeedRoles(app).Wait(); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /my-books/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /my-books/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Serilog": { 3 | "MinimumLevel": { 4 | "Default": "Information", 5 | "Override": { 6 | "System": "Error", 7 | "Microsoft": "Error" 8 | } 9 | }, 10 | "WriteTo": [ 11 | { 12 | "Name": "File", 13 | "Args": { 14 | "path": "Logs/log.txt", 15 | "rollingInterval": "Day", 16 | "outputTemplate": "{Timestamp} [{Level}] - Message: {Message}{NewLine}{Exception}" 17 | } 18 | }, 19 | { 20 | "Name": "MSSqlServer", 21 | "Args": { 22 | "connectionString": "Data Source=ETR\\sqlserver;Initial Catalog=my-books-db;Integrated Security=True;Pooling=False", 23 | "tableName": "Logs" 24 | } 25 | } 26 | ] 27 | }, 28 | "AllowedHosts": "*", 29 | "ConnectionStrings": { 30 | "DefaultConnectionString": "Data Source=ETR\\sqlserver;Initial Catalog=my-books-db;Integrated Security=True;Pooling=False" 31 | }, 32 | "JWT": { 33 | "Audience": "User", 34 | "Issuer": "https://localhost:44382/", 35 | "Secret": "this-is-just-a-secret-key-here" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /my-books/my-books.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | my_books 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /my-books/obj/Debug/net5.0/.NETCoreApp,Version=v5.0.AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using System.Reflection; 4 | [assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v5.0", FrameworkDisplayName = "")] 5 | -------------------------------------------------------------------------------- /my-books/obj/Debug/net5.0/my-books.AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | using System; 12 | using System.Reflection; 13 | 14 | [assembly: System.Reflection.AssemblyCompanyAttribute("my-books")] 15 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 16 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 17 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] 18 | [assembly: System.Reflection.AssemblyProductAttribute("my-books")] 19 | [assembly: System.Reflection.AssemblyTitleAttribute("my-books")] 20 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] 21 | 22 | // Generated by the MSBuild WriteCodeFragment class. 23 | 24 | -------------------------------------------------------------------------------- /my-books/obj/Debug/net5.0/my-books.AssemblyInfoInputs.cache: -------------------------------------------------------------------------------- 1 | 855ee7ccb2555119c3d4910c42469b412b0b7521 2 | -------------------------------------------------------------------------------- /my-books/obj/Debug/net5.0/my-books.GeneratedMSBuildEditorConfig.editorconfig: -------------------------------------------------------------------------------- 1 | is_global = true 2 | build_property.TargetFramework = net5.0 3 | build_property.TargetPlatformMinVersion = 4 | build_property.UsingMicrosoftNETSdkWeb = true 5 | build_property.ProjectTypeGuids = 6 | build_property.PublishSingleFile = 7 | build_property.IncludeAllContentForSelfExtract = 8 | build_property._SupportedPlatformList = Android,iOS,Linux,macOS,Windows 9 | -------------------------------------------------------------------------------- /my-books/obj/Debug/net5.0/my-books.assets.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/etrupja/complete-guide-to-aspnetcore-web-api/fb3bc2b9ef3162dc0fececba8c178866a3d1d4ca/my-books/obj/Debug/net5.0/my-books.assets.cache -------------------------------------------------------------------------------- /my-books/obj/Debug/net5.0/my-books.csprojAssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/etrupja/complete-guide-to-aspnetcore-web-api/fb3bc2b9ef3162dc0fececba8c178866a3d1d4ca/my-books/obj/Debug/net5.0/my-books.csprojAssemblyReference.cache -------------------------------------------------------------------------------- /my-books/obj/my-books.csproj.nuget.dgspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": 1, 3 | "restore": { 4 | "C:\\Users\\Author\\source\\repos\\my-books\\my-books\\my-books.csproj": {} 5 | }, 6 | "projects": { 7 | "C:\\Users\\Author\\source\\repos\\my-books\\my-books\\my-books.csproj": { 8 | "version": "1.0.0", 9 | "restore": { 10 | "projectUniqueName": "C:\\Users\\Author\\source\\repos\\my-books\\my-books\\my-books.csproj", 11 | "projectName": "my-books", 12 | "projectPath": "C:\\Users\\Author\\source\\repos\\my-books\\my-books\\my-books.csproj", 13 | "packagesPath": "C:\\Users\\Author\\.nuget\\packages\\", 14 | "outputPath": "C:\\Users\\Author\\source\\repos\\my-books\\my-books\\obj\\", 15 | "projectStyle": "PackageReference", 16 | "fallbackFolders": [ 17 | "C:\\Microsoft\\Xamarin\\NuGet\\" 18 | ], 19 | "configFilePaths": [ 20 | "C:\\Users\\Author\\AppData\\Roaming\\NuGet\\NuGet.Config", 21 | "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config", 22 | "C:\\Program Files (x86)\\NuGet\\Config\\Xamarin.Offline.config" 23 | ], 24 | "originalTargetFrameworks": [ 25 | "net5.0" 26 | ], 27 | "sources": { 28 | "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, 29 | "https://api.nuget.org/v3/index.json": {} 30 | }, 31 | "frameworks": { 32 | "net5.0": { 33 | "targetAlias": "net5.0", 34 | "projectReferences": {} 35 | } 36 | }, 37 | "warningProperties": { 38 | "warnAsError": [ 39 | "NU1605" 40 | ] 41 | } 42 | }, 43 | "frameworks": { 44 | "net5.0": { 45 | "targetAlias": "net5.0", 46 | "dependencies": { 47 | "Swashbuckle.AspNetCore": { 48 | "target": "Package", 49 | "version": "[5.6.3, )" 50 | } 51 | }, 52 | "imports": [ 53 | "net461", 54 | "net462", 55 | "net47", 56 | "net471", 57 | "net472", 58 | "net48" 59 | ], 60 | "assetTargetFallback": true, 61 | "warn": true, 62 | "frameworkReferences": { 63 | "Microsoft.AspNetCore.App": { 64 | "privateAssets": "none" 65 | }, 66 | "Microsoft.NETCore.App": { 67 | "privateAssets": "all" 68 | } 69 | }, 70 | "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\5.0.102\\RuntimeIdentifierGraph.json" 71 | } 72 | } 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /my-books/obj/my-books.csproj.nuget.g.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | True 5 | NuGet 6 | $(MSBuildThisFileDirectory)project.assets.json 7 | $(UserProfile)\.nuget\packages\ 8 | C:\Users\Author\.nuget\packages\;C:\Microsoft\Xamarin\NuGet\ 9 | PackageReference 10 | 5.8.0 11 | 12 | 13 | 14 | 15 | 16 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 17 | 18 | 19 | 20 | 21 | 22 | 23 | C:\Users\Author\.nuget\packages\microsoft.extensions.apidescription.server\3.0.0 24 | 25 | -------------------------------------------------------------------------------- /my-books/obj/my-books.csproj.nuget.g.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /my-books/obj/project.assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "targets": { 4 | "net5.0": { 5 | "Microsoft.Extensions.ApiDescription.Server/3.0.0": { 6 | "type": "package", 7 | "build": { 8 | "build/Microsoft.Extensions.ApiDescription.Server.props": {}, 9 | "build/Microsoft.Extensions.ApiDescription.Server.targets": {} 10 | }, 11 | "buildMultiTargeting": { 12 | "buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.props": {}, 13 | "buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.targets": {} 14 | } 15 | }, 16 | "Microsoft.OpenApi/1.2.3": { 17 | "type": "package", 18 | "compile": { 19 | "lib/netstandard2.0/Microsoft.OpenApi.dll": {} 20 | }, 21 | "runtime": { 22 | "lib/netstandard2.0/Microsoft.OpenApi.dll": {} 23 | } 24 | }, 25 | "Swashbuckle.AspNetCore/5.6.3": { 26 | "type": "package", 27 | "dependencies": { 28 | "Microsoft.Extensions.ApiDescription.Server": "3.0.0", 29 | "Swashbuckle.AspNetCore.Swagger": "5.6.3", 30 | "Swashbuckle.AspNetCore.SwaggerGen": "5.6.3", 31 | "Swashbuckle.AspNetCore.SwaggerUI": "5.6.3" 32 | }, 33 | "build": { 34 | "build/Swashbuckle.AspNetCore.props": {} 35 | } 36 | }, 37 | "Swashbuckle.AspNetCore.Swagger/5.6.3": { 38 | "type": "package", 39 | "dependencies": { 40 | "Microsoft.OpenApi": "1.2.3" 41 | }, 42 | "compile": { 43 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.Swagger.dll": {} 44 | }, 45 | "runtime": { 46 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.Swagger.dll": {} 47 | }, 48 | "frameworkReferences": [ 49 | "Microsoft.AspNetCore.App" 50 | ] 51 | }, 52 | "Swashbuckle.AspNetCore.SwaggerGen/5.6.3": { 53 | "type": "package", 54 | "dependencies": { 55 | "Swashbuckle.AspNetCore.Swagger": "5.6.3" 56 | }, 57 | "compile": { 58 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerGen.dll": {} 59 | }, 60 | "runtime": { 61 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerGen.dll": {} 62 | }, 63 | "frameworkReferences": [ 64 | "Microsoft.AspNetCore.App" 65 | ] 66 | }, 67 | "Swashbuckle.AspNetCore.SwaggerUI/5.6.3": { 68 | "type": "package", 69 | "compile": { 70 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerUI.dll": {} 71 | }, 72 | "runtime": { 73 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerUI.dll": {} 74 | }, 75 | "frameworkReferences": [ 76 | "Microsoft.AspNetCore.App" 77 | ] 78 | } 79 | } 80 | }, 81 | "libraries": { 82 | "Microsoft.Extensions.ApiDescription.Server/3.0.0": { 83 | "sha512": "LH4OE/76F6sOCslif7+Xh3fS/wUUrE5ryeXAMcoCnuwOQGT5Smw0p57IgDh/pHgHaGz/e+AmEQb7pRgb++wt0w==", 84 | "type": "package", 85 | "path": "microsoft.extensions.apidescription.server/3.0.0", 86 | "hasTools": true, 87 | "files": [ 88 | ".nupkg.metadata", 89 | ".signature.p7s", 90 | "build/Microsoft.Extensions.ApiDescription.Server.props", 91 | "build/Microsoft.Extensions.ApiDescription.Server.targets", 92 | "buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.props", 93 | "buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.targets", 94 | "microsoft.extensions.apidescription.server.3.0.0.nupkg.sha512", 95 | "microsoft.extensions.apidescription.server.nuspec", 96 | "tools/Newtonsoft.Json.dll", 97 | "tools/dotnet-getdocument.deps.json", 98 | "tools/dotnet-getdocument.dll", 99 | "tools/dotnet-getdocument.runtimeconfig.json", 100 | "tools/net461-x86/GetDocument.Insider.exe", 101 | "tools/net461-x86/GetDocument.Insider.exe.config", 102 | "tools/net461/GetDocument.Insider.exe", 103 | "tools/net461/GetDocument.Insider.exe.config", 104 | "tools/netcoreapp2.1/GetDocument.Insider.deps.json", 105 | "tools/netcoreapp2.1/GetDocument.Insider.dll", 106 | "tools/netcoreapp2.1/GetDocument.Insider.runtimeconfig.json" 107 | ] 108 | }, 109 | "Microsoft.OpenApi/1.2.3": { 110 | "sha512": "Nug3rO+7Kl5/SBAadzSMAVgqDlfGjJZ0GenQrLywJ84XGKO0uRqkunz5Wyl0SDwcR71bAATXvSdbdzPrYRYKGw==", 111 | "type": "package", 112 | "path": "microsoft.openapi/1.2.3", 113 | "files": [ 114 | ".nupkg.metadata", 115 | ".signature.p7s", 116 | "lib/net46/Microsoft.OpenApi.dll", 117 | "lib/net46/Microsoft.OpenApi.pdb", 118 | "lib/net46/Microsoft.OpenApi.xml", 119 | "lib/netstandard2.0/Microsoft.OpenApi.dll", 120 | "lib/netstandard2.0/Microsoft.OpenApi.pdb", 121 | "lib/netstandard2.0/Microsoft.OpenApi.xml", 122 | "microsoft.openapi.1.2.3.nupkg.sha512", 123 | "microsoft.openapi.nuspec" 124 | ] 125 | }, 126 | "Swashbuckle.AspNetCore/5.6.3": { 127 | "sha512": "UkL9GU0mfaA+7RwYjEaBFvAzL8qNQhNqAeV5uaWUu/Z+fVgvK9FHkGCpTXBqSQeIHuZaIElzxnLDdIqGzuCnVg==", 128 | "type": "package", 129 | "path": "swashbuckle.aspnetcore/5.6.3", 130 | "files": [ 131 | ".nupkg.metadata", 132 | ".signature.p7s", 133 | "build/Swashbuckle.AspNetCore.props", 134 | "swashbuckle.aspnetcore.5.6.3.nupkg.sha512", 135 | "swashbuckle.aspnetcore.nuspec" 136 | ] 137 | }, 138 | "Swashbuckle.AspNetCore.Swagger/5.6.3": { 139 | "sha512": "rn/MmLscjg6WSnTZabojx5DQYle2GjPanSPbCU3Kw8Hy72KyQR3uy8R1Aew5vpNALjfUFm2M/vwUtqdOlzw+GA==", 140 | "type": "package", 141 | "path": "swashbuckle.aspnetcore.swagger/5.6.3", 142 | "files": [ 143 | ".nupkg.metadata", 144 | ".signature.p7s", 145 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.Swagger.dll", 146 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.Swagger.pdb", 147 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.Swagger.xml", 148 | "lib/netstandard2.0/Swashbuckle.AspNetCore.Swagger.dll", 149 | "lib/netstandard2.0/Swashbuckle.AspNetCore.Swagger.pdb", 150 | "lib/netstandard2.0/Swashbuckle.AspNetCore.Swagger.xml", 151 | "swashbuckle.aspnetcore.swagger.5.6.3.nupkg.sha512", 152 | "swashbuckle.aspnetcore.swagger.nuspec" 153 | ] 154 | }, 155 | "Swashbuckle.AspNetCore.SwaggerGen/5.6.3": { 156 | "sha512": "CkhVeod/iLd3ikVTDOwG5sym8BE5xbqGJ15iF3cC7ZPg2kEwDQL4a88xjkzsvC9oOB2ax6B0rK0EgRK+eOBX+w==", 157 | "type": "package", 158 | "path": "swashbuckle.aspnetcore.swaggergen/5.6.3", 159 | "files": [ 160 | ".nupkg.metadata", 161 | ".signature.p7s", 162 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerGen.dll", 163 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerGen.pdb", 164 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerGen.xml", 165 | "lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerGen.dll", 166 | "lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerGen.pdb", 167 | "lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerGen.xml", 168 | "swashbuckle.aspnetcore.swaggergen.5.6.3.nupkg.sha512", 169 | "swashbuckle.aspnetcore.swaggergen.nuspec" 170 | ] 171 | }, 172 | "Swashbuckle.AspNetCore.SwaggerUI/5.6.3": { 173 | "sha512": "BPvcPxQRMsYZ3HnYmGKRWDwX4Wo29WHh14Q6B10BB8Yfbbcza+agOC2UrBFA1EuaZuOsFLbp6E2+mqVNF/Je8A==", 174 | "type": "package", 175 | "path": "swashbuckle.aspnetcore.swaggerui/5.6.3", 176 | "files": [ 177 | ".nupkg.metadata", 178 | ".signature.p7s", 179 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerUI.dll", 180 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerUI.pdb", 181 | "lib/netcoreapp3.0/Swashbuckle.AspNetCore.SwaggerUI.xml", 182 | "lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerUI.dll", 183 | "lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerUI.pdb", 184 | "lib/netstandard2.0/Swashbuckle.AspNetCore.SwaggerUI.xml", 185 | "swashbuckle.aspnetcore.swaggerui.5.6.3.nupkg.sha512", 186 | "swashbuckle.aspnetcore.swaggerui.nuspec" 187 | ] 188 | } 189 | }, 190 | "projectFileDependencyGroups": { 191 | "net5.0": [ 192 | "Swashbuckle.AspNetCore >= 5.6.3" 193 | ] 194 | }, 195 | "packageFolders": { 196 | "C:\\Users\\Author\\.nuget\\packages\\": {}, 197 | "C:\\Microsoft\\Xamarin\\NuGet\\": {} 198 | }, 199 | "project": { 200 | "version": "1.0.0", 201 | "restore": { 202 | "projectUniqueName": "C:\\Users\\Author\\source\\repos\\my-books\\my-books\\my-books.csproj", 203 | "projectName": "my-books", 204 | "projectPath": "C:\\Users\\Author\\source\\repos\\my-books\\my-books\\my-books.csproj", 205 | "packagesPath": "C:\\Users\\Author\\.nuget\\packages\\", 206 | "outputPath": "C:\\Users\\Author\\source\\repos\\my-books\\my-books\\obj\\", 207 | "projectStyle": "PackageReference", 208 | "fallbackFolders": [ 209 | "C:\\Microsoft\\Xamarin\\NuGet\\" 210 | ], 211 | "configFilePaths": [ 212 | "C:\\Users\\Author\\AppData\\Roaming\\NuGet\\NuGet.Config", 213 | "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config", 214 | "C:\\Program Files (x86)\\NuGet\\Config\\Xamarin.Offline.config" 215 | ], 216 | "originalTargetFrameworks": [ 217 | "net5.0" 218 | ], 219 | "sources": { 220 | "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, 221 | "https://api.nuget.org/v3/index.json": {} 222 | }, 223 | "frameworks": { 224 | "net5.0": { 225 | "targetAlias": "net5.0", 226 | "projectReferences": {} 227 | } 228 | }, 229 | "warningProperties": { 230 | "warnAsError": [ 231 | "NU1605" 232 | ] 233 | } 234 | }, 235 | "frameworks": { 236 | "net5.0": { 237 | "targetAlias": "net5.0", 238 | "dependencies": { 239 | "Swashbuckle.AspNetCore": { 240 | "target": "Package", 241 | "version": "[5.6.3, )" 242 | } 243 | }, 244 | "imports": [ 245 | "net461", 246 | "net462", 247 | "net47", 248 | "net471", 249 | "net472", 250 | "net48" 251 | ], 252 | "assetTargetFallback": true, 253 | "warn": true, 254 | "frameworkReferences": { 255 | "Microsoft.AspNetCore.App": { 256 | "privateAssets": "none" 257 | }, 258 | "Microsoft.NETCore.App": { 259 | "privateAssets": "all" 260 | } 261 | }, 262 | "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\5.0.102\\RuntimeIdentifierGraph.json" 263 | } 264 | } 265 | } 266 | } -------------------------------------------------------------------------------- /my-books/obj/project.nuget.cache: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "dgSpecHash": "GGxe7yC9DsPyNQB62eX6BSewChV+n0NI4HoWGCWg+nK8XOxdoIeOdk4uTIWMl6iJyHm1O9L+8wVUabPOuHbAaQ==", 4 | "success": true, 5 | "projectFilePath": "C:\\Users\\Author\\source\\repos\\my-books\\my-books\\my-books.csproj", 6 | "expectedPackageFiles": [ 7 | "C:\\Users\\Author\\.nuget\\packages\\microsoft.extensions.apidescription.server\\3.0.0\\microsoft.extensions.apidescription.server.3.0.0.nupkg.sha512", 8 | "C:\\Users\\Author\\.nuget\\packages\\microsoft.openapi\\1.2.3\\microsoft.openapi.1.2.3.nupkg.sha512", 9 | "C:\\Users\\Author\\.nuget\\packages\\swashbuckle.aspnetcore\\5.6.3\\swashbuckle.aspnetcore.5.6.3.nupkg.sha512", 10 | "C:\\Users\\Author\\.nuget\\packages\\swashbuckle.aspnetcore.swagger\\5.6.3\\swashbuckle.aspnetcore.swagger.5.6.3.nupkg.sha512", 11 | "C:\\Users\\Author\\.nuget\\packages\\swashbuckle.aspnetcore.swaggergen\\5.6.3\\swashbuckle.aspnetcore.swaggergen.5.6.3.nupkg.sha512", 12 | "C:\\Users\\Author\\.nuget\\packages\\swashbuckle.aspnetcore.swaggerui\\5.6.3\\swashbuckle.aspnetcore.swaggerui.5.6.3.nupkg.sha512" 13 | ], 14 | "logs": [] 15 | } --------------------------------------------------------------------------------