├── CleanArchitectureWebAPI.Domian ├── CleanArchitectureWebAPI.Domian.csproj ├── Models │ ├── Base │ │ ├── BaseEntity.cs │ │ ├── AuditableBaseEntity.cs │ │ └── ProductEntity.cs │ ├── Balm.cs │ ├── Oil.cs │ └── Soap.cs └── Interfaces │ ├── IOilRepository.cs │ ├── ISoapRepository.cs │ ├── IBalmRepository.cs │ └── Base │ └── IBaseRepository.cs ├── CleanArchitectureWebAPI.WebAPI ├── appsettings.Development.json ├── ViewModels │ ├── SignInViewModel.cs │ └── RegisterViewModel.cs ├── appsettings.json ├── Properties │ └── launchSettings.json ├── Middlewares │ └── ErrorLoggingMiddleware.cs ├── CleanArchitectureWebAPI.WebAPI.csproj ├── Program.cs ├── Startup.cs ├── Controllers │ ├── OilsController.cs │ ├── SoapsController.cs │ ├── AccountController.cs │ └── BalmsController.cs └── Logs │ ├── log20221129.txt │ ├── log20221209.txt │ ├── log20221207.txt │ └── log20221202.txt ├── CleanArchitectureWebAPI.Application ├── ViewModels │ ├── Balm │ │ ├── BalmListViewModel.cs │ │ └── BalmViewModel.cs │ ├── Oil │ │ ├── OilListViewModel.cs │ │ └── OilViewModel.cs │ ├── Soap │ │ ├── SoapListViewModel.cs │ │ └── SoapViewModel.cs │ └── Base │ │ └── BaseViewModel.cs ├── Interfaces │ ├── IOilService.cs │ ├── IBalmService.cs │ └── ISoapService.cs ├── ServicesExtensions.cs ├── CleanArchitectureWebAPI.Application.csproj ├── Mappers │ └── LibraryProfile.cs └── Services │ ├── OilService.cs │ ├── SoapService.cs │ └── BalmService.cs ├── CleanArchitectureWebAPI.Infrastructure.Data ├── Repositories │ ├── OilRepository.cs │ ├── SoapRepository.cs │ ├── BalmRepository.cs │ └── Base │ │ └── BaseRepository.cs ├── CleanArchitectureWebAPI.Infrastructure.Data.csproj ├── ServiceExtensions.cs ├── Context │ ├── LibraryDbContext.cs │ └── LibraryDbContextSeed.cs └── Migrations │ ├── 20221129220853_init db.cs │ ├── LibraryDbContextModelSnapshot.cs │ └── 20221129220853_init db.Designer.cs ├── CleanArchitectureWebAPI.Infrastructure.IoC ├── CleanArchitectureWebAPI.Infrastructure.IoC.csproj └── DependencyContainer.cs ├── CleanArchitectureWebAPI.Tests.XUnit ├── CleanArchitectureWebAPI.Tests.XUnit.csproj ├── BalmServiceTest.cs ├── SoapServiceTest.cs └── OilServiceTest.cs ├── .gitattributes ├── CleanArchitectureWebAPI.sln ├── .gitignore └── README.md /CleanArchitectureWebAPI.Domian/CleanArchitectureWebAPI.Domian.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Domian/Models/Base/BaseEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CleanArchitectureWebAPI.Domian.Models.Base 6 | { 7 | public abstract class BaseEntity 8 | { 9 | public virtual Guid Id { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Domian/Models/Balm.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Models.Base; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace CleanArchitectureWebAPI.Domian.Models 7 | { 8 | public class Balm : ProductEntity 9 | { 10 | public int Volume { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/ViewModels/Balm/BalmListViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CleanArchitectureWebAPI.Application.ViewModels.Balm 6 | { 7 | public class BalmListViewModel 8 | { 9 | public IEnumerable Balms { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/ViewModels/Oil/OilListViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CleanArchitectureWebAPI.Application.ViewModels.Oil 6 | { 7 | public class OilListViewModel 8 | { 9 | public IEnumerable Oils { get; set; } 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/ViewModels/Soap/SoapListViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CleanArchitectureWebAPI.Application.ViewModels.Soap 6 | { 7 | public class SoapListViewModel 8 | { 9 | public IEnumerable Soaps { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Domian/Interfaces/IOilRepository.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Interfaces.Base; 2 | using CleanArchitectureWebAPI.Domian.Models; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace CleanArchitectureWebAPI.Domian.Interfaces 8 | { 9 | public interface IOilRepository : IBaseRepository 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Domian/Interfaces/ISoapRepository.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Interfaces.Base; 2 | using CleanArchitectureWebAPI.Domian.Models; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace CleanArchitectureWebAPI.Domian.Interfaces 8 | { 9 | public interface ISoapRepository : IBaseRepository 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Domian/Models/Oil.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Models.Base; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace CleanArchitectureWebAPI.Domian.Models 7 | { 8 | public class Oil : ProductEntity 9 | { 10 | public string Scent { get; set; } 11 | public int LiquidVolume { get; set; } 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Domian/Interfaces/IBalmRepository.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Interfaces.Base; 2 | using CleanArchitectureWebAPI.Domian.Models; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace CleanArchitectureWebAPI.Domian.Interfaces 8 | { 9 | public interface IBalmRepository : IBaseRepository 10 | { 11 | // This is where we put the methods specific for that class 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/ViewModels/Soap/SoapViewModel.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Application.ViewModels.Base; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel.DataAnnotations; 5 | using System.Text; 6 | 7 | namespace CleanArchitectureWebAPI.Application.ViewModels.Soap 8 | { 9 | public class SoapViewModel : BaseViewModel 10 | { 11 | [MaxLength(50), Required] 12 | public string Edition { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Domian/Models/Soap.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Models.Base; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace CleanArchitectureWebAPI.Domian.Models 7 | { 8 | public class Soap : ProductEntity 9 | { 10 | /* 11 | This is the place where we set the 12 | specific property for that class(product). 13 | */ 14 | public string Edition { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/ViewModels/SignInViewModel.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 CleanArchitectureWebAPI.WebAPI.ViewModels 8 | { 9 | public class SignInViewModel 10 | { 11 | [Required] 12 | public string UserName { get; set; } 13 | 14 | 15 | [Required] 16 | public string Password { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/Interfaces/IOilService.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Application.ViewModels.Oil; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace CleanArchitectureWebAPI.Application.Interfaces 7 | { 8 | public interface IOilService 9 | { 10 | OilListViewModel GetOils(); 11 | OilViewModel GetOilById(Guid id); 12 | OilViewModel AddOil(OilViewModel oilRequest); 13 | void EditOil(OilViewModel oilRequest); 14 | bool DeleteOil(Guid id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Domian/Models/Base/AuditableBaseEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CleanArchitectureWebAPI.Domian.Models.Base 6 | { 7 | // Tracking data 8 | public abstract class AuditableBaseEntity : BaseEntity 9 | { 10 | public virtual string CreatedBy { get; set; } 11 | public virtual DateTime Created { get; set; } 12 | public virtual string LastModifiedBy { get; set; } 13 | public virtual DateTime LastModified { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/ViewModels/Oil/OilViewModel.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Application.ViewModels.Base; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel.DataAnnotations; 5 | using System.Text; 6 | 7 | namespace CleanArchitectureWebAPI.Application.ViewModels.Oil 8 | { 9 | public class OilViewModel : BaseViewModel 10 | { 11 | [MaxLength(30), Required] 12 | public string Scent { get; set; } 13 | 14 | [Required] 15 | public int LiquidVolume { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/Interfaces/IBalmService.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Application.ViewModels.Balm; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace CleanArchitectureWebAPI.Application.Interfaces 7 | { 8 | public interface IBalmService 9 | { 10 | BalmListViewModel GetBalms(); 11 | BalmViewModel GetBalmById(Guid id); 12 | BalmViewModel AddBalm(BalmViewModel balmRequest); 13 | void EditBalm(BalmViewModel balmRequest); 14 | bool DeleteBalm(Guid id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/Interfaces/ISoapService.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Application.ViewModels.Soap; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace CleanArchitectureWebAPI.Application.Interfaces 7 | { 8 | public interface ISoapService 9 | { 10 | SoapListViewModel GetSoaps(); 11 | SoapViewModel GetSoapById(Guid id); 12 | SoapViewModel AddSoap(SoapViewModel soapRequest); 13 | void EditSoap(SoapViewModel soapRequest); 14 | bool DeleteSoap(Guid id); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Domian/Interfaces/Base/IBaseRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CleanArchitectureWebAPI.Domian.Interfaces.Base 6 | { 7 | public interface IBaseRepository where T:class 8 | { 9 | /* 10 | This is where we put all the methods 11 | that are common for all entities. 12 | */ 13 | 14 | IReadOnlyList GetAll(); 15 | T GetById(Guid id); 16 | T Add(T entity); 17 | void Update(T entity); 18 | void Delete(T entity); 19 | void SaveChanges(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/ServicesExtensions.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Reflection; 6 | using System.Text; 7 | 8 | namespace CleanArchitectureWebAPI.Application 9 | { 10 | public static class ServicesExtensions 11 | { 12 | public static void AddApplicationLayer(this IServiceCollection services) 13 | { 14 | // Setting AutoMapper 15 | services.AddAutoMapper(Assembly.GetExecutingAssembly()); 16 | 17 | // we can add other services here 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/ViewModels/Balm/BalmViewModel.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Application.ViewModels.Base; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel.DataAnnotations; 5 | using System.Text; 6 | 7 | namespace CleanArchitectureWebAPI.Application.ViewModels.Balm 8 | { 9 | public class BalmViewModel : BaseViewModel 10 | { 11 | /* 12 | This is the model that the user sees it in the presentation/view, 13 | so here you can use Data Annotation like [Required] or [MaxLength(20)] 14 | */ 15 | [Required] 16 | public int Volume { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Serilog": { 3 | "Using": [], 4 | "MinimumLevel": { 5 | "Default": "Information", 6 | "Override": { 7 | "Microsoft": "Warning", 8 | "System": "Warning" 9 | } 10 | }, 11 | "Enrich": [ 12 | "FromLogContext", 13 | "WithMachineName", 14 | "WithProcessId", 15 | "WithThreadId" 16 | ], 17 | "Properties": { 18 | "ApplicationName": "webAPI" 19 | } 20 | }, 21 | "AllowedHosts": "*", 22 | "ConnectionStrings": { 23 | "MyConnectionString": "Server=DESKTOP-C65AVR4;Database=BeardProductsDb;Trusted_Connection=True;" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.Data/Repositories/OilRepository.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Interfaces; 2 | using CleanArchitectureWebAPI.Domian.Models; 3 | using CleanArchitectureWebAPI.Infrastructure.Data.Context; 4 | using CleanArchitectureWebAPI.Infrastructure.Data.Repositories.Base; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace CleanArchitectureWebAPI.Infrastructure.Data.Repositories 10 | { 11 | public class OilRepository : BaseRepository, IOilRepository 12 | { 13 | public OilRepository(LibraryDbContext dbContext) : base (dbContext) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Domian/Models/Base/ProductEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CleanArchitectureWebAPI.Domian.Models.Base 6 | { 7 | public class ProductEntity : AuditableBaseEntity 8 | { 9 | /* 10 | This is the class where we set all the 11 | properties that are common for all the products. 12 | */ 13 | public string Brand { get; set; } 14 | public string Description { get; set; } 15 | public int UnitPrice { get; set; } 16 | public int UnitQuantity { get; set; } 17 | public string URL { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.Data/Repositories/SoapRepository.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Interfaces; 2 | using CleanArchitectureWebAPI.Domian.Models; 3 | using CleanArchitectureWebAPI.Infrastructure.Data.Context; 4 | using CleanArchitectureWebAPI.Infrastructure.Data.Repositories.Base; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace CleanArchitectureWebAPI.Infrastructure.Data.Repositories 10 | { 11 | public class SoapRepository : BaseRepository, ISoapRepository 12 | { 13 | public SoapRepository(LibraryDbContext dbContext) : base(dbContext) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/CleanArchitectureWebAPI.Application.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/ViewModels/Base/BaseViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Text; 5 | 6 | namespace CleanArchitectureWebAPI.Application.ViewModels.Base 7 | { 8 | public class BaseViewModel 9 | { 10 | /* 11 | This is the base view model, so here you can use 12 | Data Annotations like [Required] or [MaxLength(20)] 13 | */ 14 | public Guid Id { get; set; } 15 | public string Brand { get; set; } 16 | public string Description { get; set; } 17 | public int UnitPrice { get; set; } 18 | public int UnitQuantity { get; set; } 19 | public string URL { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/ViewModels/RegisterViewModel.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 CleanArchitectureWebAPI.WebAPI.ViewModels 8 | { 9 | public class RegisterViewModel 10 | { 11 | [Required, RegularExpression(@"^[a-zA-Z0-9_-]{3,15}$")] 12 | public string UserName { get; set; } 13 | 14 | [Required, EmailAddress] 15 | public string Email { get; set; } 16 | 17 | [Required] 18 | [RegularExpression(@"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,}$")] 19 | public string Password { get; set; } 20 | 21 | [Required, Compare("Password")] 22 | public string ConfirmPassword { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.Data/Repositories/BalmRepository.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Interfaces; 2 | using CleanArchitectureWebAPI.Domian.Models; 3 | using CleanArchitectureWebAPI.Infrastructure.Data.Context; 4 | using CleanArchitectureWebAPI.Infrastructure.Data.Repositories.Base; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace CleanArchitectureWebAPI.Infrastructure.Data.Repositories 10 | { 11 | public class BalmRepository : BaseRepository, IBalmRepository 12 | { 13 | public BalmRepository(LibraryDbContext dbContext) : base(dbContext) 14 | { 15 | /* 16 | This is the place where we create the logic for query, 17 | for saving and calling data for that entity. 18 | */ 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.IoC/CleanArchitectureWebAPI.Infrastructure.IoC.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/Mappers/LibraryProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using CleanArchitectureWebAPI.Application.ViewModels.Balm; 3 | using CleanArchitectureWebAPI.Application.ViewModels.Oil; 4 | using CleanArchitectureWebAPI.Application.ViewModels.Soap; 5 | using CleanArchitectureWebAPI.Domian.Models; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Text; 9 | 10 | namespace CleanArchitectureWebAPI.Application.Mappers 11 | { 12 | public class LibraryProfile : Profile 13 | { 14 | public LibraryProfile() 15 | { 16 | /* 17 | This is where we are mapping from 18 | entity to view model and vice versa. 19 | */ 20 | CreateMap().ReverseMap(); 21 | CreateMap().ReverseMap(); 22 | CreateMap().ReverseMap(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/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:59046", 8 | "sslPort": 44342 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "swagger", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "CleanArchitectureWebAPI.WebAPI": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "api/soaps", 24 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Tests.XUnit/CleanArchitectureWebAPI.Tests.XUnit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | all 19 | 20 | 21 | runtime; build; native; contentfiles; analyzers; buildtransitive 22 | all 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.IoC/DependencyContainer.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Application.Interfaces; 2 | using CleanArchitectureWebAPI.Application.Services; 3 | using CleanArchitectureWebAPI.Domian.Interfaces; 4 | using CleanArchitectureWebAPI.Infrastructure.Data.Context; 5 | using CleanArchitectureWebAPI.Infrastructure.Data.Repositories; 6 | using Microsoft.AspNetCore.Authentication.JwtBearer; 7 | using Microsoft.AspNetCore.Identity; 8 | using Microsoft.EntityFrameworkCore; 9 | using Microsoft.Extensions.Configuration; 10 | using Microsoft.Extensions.DependencyInjection; 11 | using Microsoft.IdentityModel.Tokens; 12 | using System; 13 | using System.Collections.Generic; 14 | using System.Text; 15 | 16 | namespace CleanArchitectureWebAPI.Infrastructure.IoC 17 | { 18 | public static class DependencyContainer 19 | { 20 | public static void AddIoCService(this IServiceCollection services) 21 | { 22 | // IoC - Inversion Of Control 23 | // Application 24 | services.AddScoped(); 25 | services.AddScoped(); 26 | services.AddScoped(); 27 | 28 | // Domain.Interfaces > Infrastructure.Data.Repositories 29 | services.AddScoped(); 30 | services.AddScoped(); 31 | services.AddScoped(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.Data/CleanArchitectureWebAPI.Infrastructure.Data.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.Data/Repositories/Base/BaseRepository.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Interfaces.Base; 2 | using CleanArchitectureWebAPI.Infrastructure.Data.Context; 3 | using Microsoft.EntityFrameworkCore; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace CleanArchitectureWebAPI.Infrastructure.Data.Repositories.Base 10 | { 11 | public class BaseRepository : IBaseRepository where T : class 12 | { 13 | /* 14 | This is where we communicate with database, 15 | and it stands for all the classes. 16 | */ 17 | private readonly LibraryDbContext _dbContext; 18 | public BaseRepository(LibraryDbContext dbContext) 19 | { 20 | _dbContext = dbContext; 21 | } 22 | public T Add(T entity) 23 | { 24 | _dbContext.Set().Add(entity); 25 | return entity; 26 | } 27 | 28 | public void Delete(T entity) 29 | { 30 | _dbContext.Set().Remove(entity); 31 | } 32 | 33 | public IReadOnlyList GetAll() 34 | { 35 | return _dbContext.Set().ToList(); 36 | } 37 | 38 | public T GetById(Guid id) 39 | { 40 | return _dbContext.Set().Find(id); 41 | } 42 | 43 | public void Update(T entity) 44 | { 45 | _dbContext.Entry(entity).State = EntityState.Modified; 46 | } 47 | 48 | public void SaveChanges() 49 | { 50 | _dbContext.SaveChanges(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/Middlewares/ErrorLoggingMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Serilog; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace CleanArchitectureWebAPI.WebAPI.Middlewares 9 | { 10 | public class ErrorLoggingMiddleware 11 | { 12 | const string MessageTemplate = "HTTP {RequestMethod} {RequestPath} responded {RequestCode}"; 13 | static readonly ILogger Log = Serilog.Log.ForContext(); 14 | private readonly RequestDelegate _next; 15 | 16 | public ErrorLoggingMiddleware(RequestDelegate next) 17 | { 18 | _next = next; 19 | } 20 | 21 | public async Task Invoke(HttpContext httpContext) 22 | { 23 | try 24 | { 25 | await _next(httpContext); 26 | } 27 | catch (Exception e) 28 | { 29 | var request = httpContext.Request; 30 | 31 | var log = Log 32 | .ForContext("RequestHeaders", request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()), destructureObjects: true) 33 | .ForContext("RequestHost", request.Host) 34 | .ForContext("RequestProtocol", request.Protocol); 35 | 36 | if (request.HasFormContentType) 37 | log = log.ForContext("RequestForm", request.Form.ToDictionary(v => v.Key, v => v.Value.ToString())); 38 | 39 | log.Error(e, MessageTemplate, httpContext.Request.Method, httpContext.Request.Path, 500); 40 | 41 | throw; 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.Data/ServiceExtensions.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Infrastructure.Data.Context; 2 | using Microsoft.AspNetCore.Authentication.JwtBearer; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.IdentityModel.Tokens; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Text; 10 | 11 | namespace CleanArchitectureWebAPI.Infrastructure.Data 12 | { 13 | public static class ServiceExtensions 14 | { 15 | public static void AddIdentityInfrastructure(this IServiceCollection services) 16 | { 17 | // Setting Identity 18 | services.AddIdentity() 19 | .AddEntityFrameworkStores() 20 | .AddDefaultTokenProviders(); 21 | 22 | // Setting JWT Token 23 | var singingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("this-is-my-secret-key")); 24 | var tokenValidationParameters = new TokenValidationParameters() 25 | { 26 | IssuerSigningKey = singingKey, 27 | ValidateIssuer = false, 28 | ValidateAudience = false, 29 | ValidateLifetime = true, 30 | ClockSkew = TimeSpan.Zero 31 | }; 32 | services.AddAuthentication(x => x.DefaultAuthenticateScheme = JwtBearerDefaults 33 | .AuthenticationScheme) 34 | .AddJwtBearer(jwt => 35 | { 36 | jwt.TokenValidationParameters = tokenValidationParameters; 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/CleanArchitectureWebAPI.WebAPI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | 18 | all 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/Services/OilService.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using CleanArchitectureWebAPI.Application.Interfaces; 3 | using CleanArchitectureWebAPI.Application.ViewModels.Oil; 4 | using CleanArchitectureWebAPI.Domian.Interfaces; 5 | using CleanArchitectureWebAPI.Domian.Models; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Text; 9 | 10 | namespace CleanArchitectureWebAPI.Application.Services 11 | { 12 | public class OilService : IOilService 13 | { 14 | private readonly IOilRepository _oilRepository; 15 | private readonly IMapper _mapper; 16 | public OilService(IOilRepository oilRepository, IMapper mapper) 17 | { 18 | _mapper = mapper; 19 | _oilRepository = oilRepository; 20 | } 21 | public OilViewModel AddOil(OilViewModel oilRequest) 22 | { 23 | var oil = _mapper.Map(oilRequest); 24 | oil.Id = Guid.NewGuid(); 25 | 26 | var addedOil = _oilRepository.Add(oil); 27 | 28 | _oilRepository.SaveChanges(); 29 | 30 | return _mapper.Map(addedOil); 31 | } 32 | 33 | public bool DeleteOil(Guid id) 34 | { 35 | var oil = _oilRepository.GetById(id); 36 | 37 | if (oil != null) 38 | { 39 | _oilRepository.Delete(oil); 40 | _oilRepository.SaveChanges(); 41 | 42 | return true; 43 | } 44 | else 45 | { 46 | return false; 47 | } 48 | } 49 | 50 | public void EditOil(OilViewModel oilRequest) 51 | { 52 | var oil = _mapper.Map(oilRequest); 53 | _oilRepository.Update(oil); 54 | 55 | _oilRepository.SaveChanges(); 56 | } 57 | 58 | public OilViewModel GetOilById(Guid id) 59 | { 60 | var oil = _oilRepository.GetById(id); 61 | return _mapper.Map(oil); 62 | } 63 | 64 | public OilListViewModel GetOils() 65 | { 66 | var oils = _oilRepository.GetAll(); 67 | var oilListViewModel = _mapper.Map>(oils); 68 | 69 | return new OilListViewModel() 70 | { 71 | Oils = oilListViewModel 72 | }; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/Services/SoapService.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using CleanArchitectureWebAPI.Application.Interfaces; 3 | using CleanArchitectureWebAPI.Application.ViewModels.Soap; 4 | using CleanArchitectureWebAPI.Domian.Interfaces; 5 | using CleanArchitectureWebAPI.Domian.Models; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Text; 9 | 10 | namespace CleanArchitectureWebAPI.Application.Services 11 | { 12 | public class SoapService : ISoapService 13 | { 14 | private readonly ISoapRepository _soapRepository; 15 | private readonly IMapper _mapper; 16 | public SoapService(ISoapRepository soapRepository, IMapper mapper) 17 | { 18 | _soapRepository = soapRepository; 19 | _mapper = mapper; 20 | } 21 | public SoapViewModel AddSoap(SoapViewModel soapRequest) 22 | { 23 | var soap = _mapper.Map(soapRequest); 24 | soap.Id = Guid.NewGuid(); 25 | 26 | var addedSoap = _soapRepository.Add(soap); 27 | 28 | _soapRepository.SaveChanges(); 29 | 30 | return _mapper.Map(addedSoap); 31 | } 32 | 33 | public bool DeleteSoap(Guid id) 34 | { 35 | var soap = _soapRepository.GetById(id); 36 | 37 | if (soap != null) 38 | { 39 | _soapRepository.Delete(soap); 40 | _soapRepository.SaveChanges(); 41 | 42 | return true; 43 | } 44 | else 45 | { 46 | return false; 47 | } 48 | } 49 | 50 | public void EditSoap(SoapViewModel soapRequest) 51 | { 52 | var soap = _mapper.Map(soapRequest); 53 | _soapRepository.Update(soap); 54 | 55 | _soapRepository.SaveChanges(); 56 | } 57 | 58 | public SoapViewModel GetSoapById(Guid id) 59 | { 60 | var soap = _soapRepository.GetById(id); 61 | return _mapper.Map(soap); 62 | } 63 | 64 | public SoapListViewModel GetSoaps() 65 | { 66 | var soaps = _soapRepository.GetAll(); 67 | var soapListViewModel = _mapper.Map>(soaps); 68 | 69 | return new SoapListViewModel() 70 | { 71 | Soaps = soapListViewModel 72 | }; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Application/Services/BalmService.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using CleanArchitectureWebAPI.Application.Interfaces; 3 | using CleanArchitectureWebAPI.Application.ViewModels.Balm; 4 | using CleanArchitectureWebAPI.Domian.Interfaces; 5 | using CleanArchitectureWebAPI.Domian.Models; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Text; 9 | 10 | namespace CleanArchitectureWebAPI.Application.Services 11 | { 12 | public class BalmService : IBalmService 13 | { 14 | /* 15 | This is where all the logic is, in the Services. 16 | */ 17 | private readonly IBalmRepository _balmRepository; 18 | private readonly IMapper _mapper; 19 | public BalmService(IBalmRepository balmRepository, IMapper mapper) 20 | { 21 | _mapper = mapper; 22 | _balmRepository = balmRepository; 23 | } 24 | public BalmViewModel AddBalm(BalmViewModel balmRequest) 25 | { 26 | var balm = _mapper.Map(balmRequest); 27 | balm.Id = Guid.NewGuid(); 28 | 29 | var addedBalm = _balmRepository.Add(balm); 30 | 31 | _balmRepository.SaveChanges(); 32 | 33 | return _mapper.Map(addedBalm); 34 | } 35 | 36 | public bool DeleteBalm(Guid id) 37 | { 38 | var balm = _balmRepository.GetById(id); 39 | 40 | if (balm != null) 41 | { 42 | _balmRepository.Delete(balm); 43 | _balmRepository.SaveChanges(); 44 | 45 | return true; 46 | } 47 | else 48 | { 49 | return false; 50 | } 51 | } 52 | 53 | public void EditBalm(BalmViewModel balmRequest) 54 | { 55 | var balm = _mapper.Map(balmRequest); 56 | _balmRepository.Update(balm); 57 | 58 | _balmRepository.SaveChanges(); 59 | } 60 | 61 | public BalmViewModel GetBalmById(Guid id) 62 | { 63 | var balm = _balmRepository.GetById(id); 64 | return _mapper.Map(balm); 65 | } 66 | 67 | public BalmListViewModel GetBalms() 68 | { 69 | var balms = _balmRepository.GetAll(); 70 | var balmListViewModel = _mapper.Map>(balms); 71 | 72 | return new BalmListViewModel() 73 | { 74 | Balms = balmListViewModel 75 | }; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/Program.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Infrastructure.Data.Context; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | using Microsoft.Extensions.Logging; 7 | using Serilog; 8 | using Serilog.Formatting.Json; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Threading.Tasks; 13 | 14 | namespace CleanArchitectureWebAPI.WebAPI 15 | { 16 | public class Program 17 | { 18 | public static void Main(string[] args) 19 | { 20 | // Read configuration from appsetting.json 21 | var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); 22 | 23 | // Initialize logger 24 | Log.Logger = new LoggerConfiguration() 25 | .ReadFrom.Configuration(config) 26 | .WriteTo.File("Logs/log.txt", rollingInterval: RollingInterval.Day, outputTemplate: "{Timestamp} {Message}{NewLine:1}{Exception:1}") 27 | .WriteTo.File(new JsonFormatter(), "Logs/log.json", rollingInterval: RollingInterval.Day) 28 | .WriteTo.Console() 29 | .CreateLogger(); 30 | 31 | try 32 | { 33 | Log.Information("Application is starting"); 34 | 35 | var host = CreateHostBuilder(args).Build(); 36 | 37 | SeedDatabase(host); 38 | 39 | host.Run(); 40 | } 41 | catch (Exception e) 42 | { 43 | Log.Error(e, "The application failed to start!"); 44 | } 45 | finally 46 | { 47 | Log.CloseAndFlush(); 48 | } 49 | } 50 | 51 | public static IHostBuilder CreateHostBuilder(string[] args) => 52 | Host.CreateDefaultBuilder(args) 53 | .UseSerilog() 54 | .ConfigureWebHostDefaults(webBuilder => 55 | { 56 | webBuilder.UseStartup(); 57 | }); 58 | 59 | private static void SeedDatabase(IHost host) 60 | { 61 | using (var scope = host.Services.CreateScope()) 62 | { 63 | var services = scope.ServiceProvider; 64 | var loggerFactory = services.GetRequiredService(); 65 | 66 | try 67 | { 68 | var libraryDbContext = services.GetRequiredService(); 69 | LibraryDbContextSeed.SeedAsync(libraryDbContext, loggerFactory).Wait(); 70 | } 71 | catch (Exception exception) 72 | { 73 | var logger = loggerFactory.CreateLogger(); 74 | logger.LogError(exception, "An error occurred seeding the DB."); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.Data/Context/LibraryDbContext.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Models; 2 | using CleanArchitectureWebAPI.Domian.Models.Base; 3 | using Microsoft.AspNetCore.Http; 4 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text; 10 | 11 | namespace CleanArchitectureWebAPI.Infrastructure.Data.Context 12 | { 13 | public class LibraryDbContext : IdentityDbContext 14 | { 15 | private IHttpContextAccessor _httpContextAccessor; 16 | public LibraryDbContext() 17 | { 18 | } 19 | 20 | public LibraryDbContext(DbContextOptions options, IHttpContextAccessor httpContextAccessor) : base(options) 21 | { 22 | _httpContextAccessor = httpContextAccessor; 23 | } 24 | 25 | public DbSet Soaps { get; set; } 26 | public DbSet Balms { get; set; } 27 | public DbSet Oils { get; set; } 28 | 29 | public override int SaveChanges() 30 | { 31 | // Get all the entities that inherit from AuditableEntity 32 | // and have a state of Added or Modified 33 | var entries = ChangeTracker 34 | .Entries() 35 | .Where(e => e.Entity is AuditableBaseEntity && ( 36 | e.State == EntityState.Added 37 | || e.State == EntityState.Modified)); 38 | 39 | // For each entity we will set the Audit properties 40 | foreach (var entityEntry in entries) 41 | { 42 | // If the entity state is Added let's set 43 | // the CreatedAt and CreatedBy properties 44 | if (entityEntry.State == EntityState.Added) 45 | { 46 | ((AuditableBaseEntity)entityEntry.Entity).Created = DateTime.UtcNow; 47 | ((AuditableBaseEntity)entityEntry.Entity).CreatedBy = this._httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? "MyApp"; 48 | } 49 | else 50 | { 51 | // If the state is Modified then we don't want 52 | // to modify the CreatedAt and CreatedBy properties 53 | // so we set their state as IsModified to false 54 | Entry((AuditableBaseEntity)entityEntry.Entity).Property(p => p.Created).IsModified = false; 55 | Entry((AuditableBaseEntity)entityEntry.Entity).Property(p => p.CreatedBy).IsModified = false; 56 | } 57 | 58 | // In any case we always want to set the properties 59 | // ModifiedAt and ModifiedBy 60 | ((AuditableBaseEntity)entityEntry.Entity).LastModified = DateTime.UtcNow; 61 | ((AuditableBaseEntity)entityEntry.Entity).LastModifiedBy = this._httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? "MyApp"; 62 | } 63 | // After we set all the needed properties 64 | // we call the base implementation of SaveChanges 65 | // to actually save our entities in the database 66 | return base.SaveChanges(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/Startup.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Application; 2 | using CleanArchitectureWebAPI.Infrastructure.Data; 3 | using CleanArchitectureWebAPI.Infrastructure.Data.Context; 4 | using CleanArchitectureWebAPI.Infrastructure.IoC; 5 | using CleanArchitectureWebAPI.WebAPI.Middlewares; 6 | using Microsoft.AspNetCore.Authentication.JwtBearer; 7 | using Microsoft.AspNetCore.Builder; 8 | using Microsoft.AspNetCore.Hosting; 9 | using Microsoft.AspNetCore.HttpsPolicy; 10 | using Microsoft.AspNetCore.Identity; 11 | using Microsoft.AspNetCore.Mvc; 12 | using Microsoft.EntityFrameworkCore; 13 | using Microsoft.Extensions.Configuration; 14 | using Microsoft.Extensions.DependencyInjection; 15 | using Microsoft.Extensions.Hosting; 16 | using Microsoft.Extensions.Logging; 17 | using Microsoft.IdentityModel.Tokens; 18 | using Serilog; 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace CleanArchitectureWebAPI.WebAPI 26 | { 27 | public class Startup 28 | { 29 | public Startup(IConfiguration configuration) 30 | { 31 | Configuration = configuration; 32 | } 33 | 34 | public IConfiguration Configuration { get; } 35 | 36 | // This method gets called by the runtime. Use this method to add services to the container. 37 | public void ConfigureServices(IServiceCollection services) 38 | { 39 | // Setting Response Caching 40 | services.AddResponseCaching(); 41 | 42 | // Setting In Memory Cache 43 | services.AddMemoryCache(); 44 | 45 | services.AddControllers(); 46 | 47 | services.AddCors(o => o.AddPolicy("MyPolicy", builder => 48 | { 49 | builder.AllowAnyOrigin() 50 | .AllowAnyMethod() 51 | .AllowAnyHeader(); 52 | })); 53 | 54 | // This is where we register the context 55 | services.AddDbContext(options => 56 | options.UseSqlServer(Configuration.GetConnectionString("MyConnectionString"))); 57 | 58 | // Registering the Identity Infrastructure 59 | services.AddIdentityInfrastructure(); 60 | 61 | // Registering Inversion Of Control 62 | services.AddIoCService(); 63 | 64 | // Registering the Swagger 65 | services.AddSwaggerDocument(); 66 | 67 | // Registering the HttpContext Accessor which we use for auditing in the LibraryDbContext 68 | services.AddHttpContextAccessor(); 69 | 70 | // Registering the AutoMapper that mapps from entity to view model and vice versa 71 | services.AddApplicationLayer(); 72 | } 73 | 74 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 75 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 76 | { 77 | if (env.IsDevelopment()) 78 | { 79 | app.UseDeveloperExceptionPage(); 80 | } 81 | 82 | app.UseHttpsRedirection(); 83 | 84 | // Using the Response Caching 85 | app.UseResponseCaching(); 86 | 87 | // Use Serilog Logger 88 | app.UseSerilogRequestLogging(); 89 | 90 | // Error Logging middleware 91 | app.UseMiddleware(); 92 | 93 | app.UseRouting(); 94 | 95 | app.UseCors("MyPolicy"); 96 | 97 | app.UseAuthorization(); 98 | 99 | app.UseAuthentication(); 100 | 101 | app.UseEndpoints(endpoints => 102 | { 103 | endpoints.MapControllers(); 104 | }); 105 | 106 | app.UseOpenApi(); 107 | 108 | app.UseSwaggerUi3(); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Tests.XUnit/BalmServiceTest.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using CleanArchitectureWebAPI.Application.Services; 3 | using CleanArchitectureWebAPI.Application.ViewModels.Balm; 4 | using CleanArchitectureWebAPI.Domian.Interfaces; 5 | using CleanArchitectureWebAPI.Domian.Models; 6 | using FluentAssertions; 7 | using Moq; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Text; 11 | using Xunit; 12 | 13 | namespace CleanArchitectureWebAPI.Tests.XUnit 14 | { 15 | public class BalmServiceTest 16 | { 17 | [Fact] 18 | public void GetBalms_NotExistingBalms_ResultShouldBeEmpty() 19 | { 20 | // arrange 21 | var mockBalmRepository = new Mock(); 22 | var mockMapper = new Mock(); 23 | 24 | // act 25 | var balmService = new BalmService(mockBalmRepository.Object, mockMapper.Object); 26 | var result = balmService.GetBalms(); 27 | 28 | // assert 29 | result.Balms.Should().BeEmpty(); 30 | } 31 | 32 | [Fact] 33 | public void GetBalms_NotExistingBalms_ResultShouldBeOfTypeBalmListViewModel() 34 | { 35 | // arrance 36 | var mockBalmRepository = new Mock(); 37 | var mockMapper = new Mock(); 38 | 39 | // act 40 | var balmService = new BalmService(mockBalmRepository.Object, mockMapper.Object); 41 | var result = balmService.GetBalms(); 42 | 43 | // assert 44 | result.Should().BeOfType(typeof(BalmListViewModel)); 45 | } 46 | 47 | [Fact] 48 | public void GetBalms_ExistingBalms_ResultShouldBeTwoBalms() 49 | { 50 | // arrange 51 | var mockBalmRepository = new Mock(); 52 | 53 | var mockBalms = new List 54 | { 55 | new Balm 56 | { 57 | Id = Guid.NewGuid(), 58 | Volume = 30, 59 | Brand = "Balm Brand 1", 60 | Description = "Balm Description 1", 61 | UnitQuantity = 100, 62 | UnitPrice = 30, 63 | URL = "img/balm1.jpg" 64 | }, 65 | new Balm 66 | { 67 | Id = Guid.NewGuid(), 68 | Volume = 33, 69 | Brand = "Balm Brand 2", 70 | Description = "Balm Description 2", 71 | UnitQuantity = 100, 72 | UnitPrice = 32, 73 | URL = "img/balm2.jpg" 74 | } 75 | }; 76 | 77 | mockBalmRepository.Setup(x => x.GetAll()).Returns(mockBalms); 78 | 79 | var config = new MapperConfiguration(cfg => 80 | { 81 | cfg.CreateMap(); 82 | }); 83 | var mapper = config.CreateMapper(); 84 | 85 | // act 86 | var balmService = new BalmService(mockBalmRepository.Object, mapper); 87 | var result = balmService.GetBalms(); 88 | 89 | // assert 90 | result.Balms.Should().HaveCount(2); 91 | } 92 | 93 | [Fact] 94 | public void GetBalmById_NotExpectingBalm_ResultShouldBeNull() 95 | { 96 | // arrance 97 | var mockBalmRepository = new Mock(); 98 | var mockMapper = new Mock(); 99 | 100 | // act 101 | var balmService = new BalmService(mockBalmRepository.Object, mockMapper.Object); 102 | var result = balmService.GetBalmById(Guid.NewGuid()); 103 | 104 | // assert 105 | result.Should().BeNull(); 106 | } 107 | 108 | [Fact] 109 | public void GetBalmById_ExpectingBalm_ResultShouldReturnBalmViewModel() 110 | { 111 | // arrance 112 | var mockBalmRepository = new Mock(); 113 | 114 | var balm = new Balm() 115 | { 116 | Id = Guid.NewGuid(), 117 | Volume = 30, 118 | Brand = "Balm Brand 1", 119 | Description = "Balm Description 1", 120 | UnitQuantity = 100, 121 | UnitPrice = 30, 122 | URL = "img/balm1.jpg" 123 | }; 124 | 125 | mockBalmRepository.Setup(x => x.GetById(It.IsAny())).Returns(balm); 126 | 127 | var config = new MapperConfiguration(cfg => 128 | { 129 | cfg.CreateMap(); 130 | }); 131 | var mapper = config.CreateMapper(); 132 | 133 | // act 134 | var balmService = new BalmService(mockBalmRepository.Object, mapper); 135 | var result = balmService.GetBalmById(Guid.NewGuid()); 136 | 137 | // assert 138 | result.Should().BeOfType(typeof(BalmViewModel)); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Tests.XUnit/SoapServiceTest.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using CleanArchitectureWebAPI.Application.Services; 3 | using CleanArchitectureWebAPI.Application.ViewModels.Soap; 4 | using CleanArchitectureWebAPI.Domian.Interfaces; 5 | using CleanArchitectureWebAPI.Domian.Models; 6 | using FluentAssertions; 7 | using Moq; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Text; 11 | using Xunit; 12 | 13 | namespace CleanArchitectureWebAPI.Tests.XUnit 14 | { 15 | public class SoapServiceTest 16 | { 17 | [Fact] 18 | public void GetSoaps_NotExistingSoaps_ResultShouldBeEmpty() 19 | { 20 | // arrange 21 | var mockSoapRepository = new Mock(); 22 | var mockMapper = new Mock(); 23 | 24 | // act 25 | var soapService = new SoapService(mockSoapRepository.Object, mockMapper.Object); 26 | var result = soapService.GetSoaps(); 27 | 28 | // assert 29 | result.Soaps.Should().BeEmpty(); 30 | } 31 | 32 | [Fact] 33 | public void GetSoaps_NotExistingSoaps_ResultShouldBeOfTypeSoapListViewModel() 34 | { 35 | // arrange 36 | var mockSoapRepository = new Mock(); 37 | var mockMapper = new Mock(); 38 | 39 | // act 40 | var soapService = new SoapService(mockSoapRepository.Object, mockMapper.Object); 41 | var result = soapService.GetSoaps(); 42 | 43 | // arrange 44 | result.Should().BeOfType(typeof(SoapListViewModel)); 45 | } 46 | 47 | [Fact] 48 | public void GetSoaps_ExistingSoaps_ResultShouldBeTwoSoaps() 49 | { 50 | // arrance 51 | var mockSoapRepository = new Mock(); 52 | var mockedSoaps = new List 53 | { 54 | new Soap 55 | { 56 | Id = Guid.NewGuid(), 57 | Brand = "Soap Brand 1", 58 | Edition = "Soap Edition 1", 59 | Description = "Soap Description 1", 60 | UnitPrice = 20, 61 | UnitQuantity = 100, 62 | URL = "img/soap1.jpeg" 63 | }, 64 | new Soap 65 | { 66 | Id = Guid.NewGuid(), 67 | Brand = "Soap Brand 2", 68 | Edition = "Soap Edition 2", 69 | Description = "Soap Description 2", 70 | UnitPrice = 21, 71 | UnitQuantity = 100, 72 | URL = "img/soap2.jpeg" 73 | } 74 | }; 75 | 76 | mockSoapRepository.Setup(x => x.GetAll()).Returns(mockedSoaps); 77 | 78 | var config = new MapperConfiguration(cfg => 79 | { 80 | cfg.CreateMap(); 81 | }); 82 | var mapper = config.CreateMapper(); 83 | 84 | // act 85 | var soapService = new SoapService(mockSoapRepository.Object, mapper); 86 | var result = soapService.GetSoaps(); 87 | 88 | // assert 89 | result.Soaps.Should().HaveCount(2); 90 | } 91 | 92 | 93 | [Fact] 94 | public void GetSoapById_NotExpectingSoap_ResultShouldBeNull() 95 | { 96 | // arrange 97 | var mockSoapRepository = new Mock(); 98 | var mockMapper = new Mock(); 99 | 100 | // act 101 | var soapService = new SoapService(mockSoapRepository.Object, mockMapper.Object); 102 | var result = soapService.GetSoapById(Guid.NewGuid()); 103 | 104 | // assert 105 | result.Should().BeNull(); 106 | } 107 | 108 | [Fact] 109 | public void GetSoapById_ExpectingSoap_ResultShouldReturnSoapViewModel() 110 | { 111 | // arrange 112 | var mockSoapRepository = new Mock(); 113 | 114 | var mockSoap = new Soap() 115 | { 116 | Id = Guid.NewGuid(), 117 | Brand = "Soap Brand 1", 118 | Edition = "Soap Edition 1", 119 | Description = "Soap Description 1", 120 | UnitPrice = 20, 121 | UnitQuantity = 100, 122 | URL = "img/soap1.jpeg" 123 | }; 124 | 125 | mockSoapRepository.Setup(x => x.GetById(It.IsAny())).Returns(mockSoap); 126 | 127 | var config = new MapperConfiguration(cfg => 128 | { 129 | cfg.CreateMap(); 130 | }); 131 | 132 | var mapper = config.CreateMapper(); 133 | 134 | // act 135 | var soapService = new SoapService(mockSoapRepository.Object, mapper); 136 | var result = soapService.GetSoapById(Guid.NewGuid()); 137 | 138 | // assert 139 | result.Should().BeOfType(); 140 | } 141 | 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/Controllers/OilsController.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Application.Interfaces; 2 | using CleanArchitectureWebAPI.Application.ViewModels.Oil; 3 | using Microsoft.AspNetCore.Authentication.JwtBearer; 4 | using Microsoft.AspNetCore.Authorization; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.Extensions.Caching.Memory; 8 | using NSwag.Annotations; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Net; 13 | using System.Threading.Tasks; 14 | 15 | namespace CleanArchitectureWebAPI.WebAPI.Controllers 16 | { 17 | [Route("api/[controller]")] 18 | [OpenApiTag("Oils", Description = "Methods to work with Oils")] 19 | [ApiController] 20 | public class OilsController : Controller 21 | { 22 | private readonly IOilService _oilService; 23 | private IMemoryCache _memoryCache; 24 | private string _allOilsKey = "All_Oils_Cache"; 25 | public OilsController(IOilService oilService, IMemoryCache memoryCache) 26 | { 27 | _oilService = oilService; 28 | _memoryCache = memoryCache; 29 | } 30 | 31 | 32 | 33 | [HttpGet] //URL/api/oils http metod Get 34 | [SwaggerResponse(HttpStatusCode.OK, typeof(OilListViewModel), Description = "Successfully Returned List Of Oils")] 35 | [SwaggerResponse(HttpStatusCode.NotFound, null, Description = "List Of Oils Is Empty")] 36 | public IActionResult GetAll() 37 | { 38 | OilListViewModel oilListViewModel; 39 | oilListViewModel = (OilListViewModel)_memoryCache.Get(_allOilsKey); 40 | 41 | if (oilListViewModel == null) 42 | { 43 | oilListViewModel = _oilService.GetOils(); 44 | 45 | _memoryCache.Set(_allOilsKey, oilListViewModel, new MemoryCacheEntryOptions() 46 | .SetSlidingExpiration(TimeSpan.FromMinutes(15)) 47 | .SetAbsoluteExpiration(TimeSpan.FromHours(1))); 48 | } 49 | if (oilListViewModel != null) 50 | { 51 | return Ok(oilListViewModel); 52 | } 53 | else 54 | { 55 | return NotFound(); 56 | } 57 | } 58 | 59 | 60 | [HttpGet("{id}")] //URL/api/oils/id http metod Get 61 | [SwaggerResponse(HttpStatusCode.OK, typeof(OilViewModel), Description = "Successfully Returned Oil Model")] 62 | [SwaggerResponse(HttpStatusCode.NotFound, null, Description = "There Is No Oil Model With That Id")] 63 | public IActionResult GetById(Guid id) 64 | { 65 | var oil = _oilService.GetOilById(id); 66 | if (oil != null) 67 | { 68 | return Ok(oil); 69 | } 70 | else 71 | { 72 | return NotFound(id); 73 | } 74 | } 75 | 76 | 77 | [HttpPost] //URL/api/oils http metod Post 78 | [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Roles = "Admin")] 79 | [SwaggerResponse(HttpStatusCode.Unauthorized, null, Description = "You Don't Have Authorization For This Request")] 80 | [SwaggerResponse(HttpStatusCode.OK, typeof(OilViewModel), Description = "Ok")] 81 | [SwaggerResponse(HttpStatusCode.Created, typeof(OilViewModel), Description = "Oil Model Created")] 82 | [SwaggerResponse(HttpStatusCode.NotFound, null, Description = "Oil Model Not Found")] 83 | public IActionResult AddOrEdit(OilViewModel model) 84 | { 85 | if (model.Id == Guid.Empty) 86 | { 87 | model = _oilService.AddOil(model); 88 | } 89 | else 90 | { 91 | _oilService.EditOil(model); 92 | } 93 | _memoryCache.Remove(_allOilsKey); 94 | return Ok(model); 95 | } 96 | 97 | 98 | [HttpDelete("{id}")] //URL/api/oils/id http metod Delete 99 | [ResponseCache(Duration = 300, VaryByQueryKeys = new string[] { "id" })] 100 | [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Roles = "Admin")] 101 | [SwaggerResponse(HttpStatusCode.OK, typeof(OilViewModel), Description = "Successfully Deleted Oil Model")] 102 | [SwaggerResponse(HttpStatusCode.NotFound, typeof(Guid), Description = "Oil Model You Want To Delete Doesn't Exist")] 103 | [SwaggerResponse(HttpStatusCode.Unauthorized, null, Description = "You Don't Have Authorization For This Request")] 104 | public IActionResult Delete(Guid id) 105 | { 106 | var oil = _oilService.GetOilById(id); 107 | var status = false; 108 | 109 | if (oil != null) 110 | { 111 | status = _oilService.DeleteOil(id); 112 | _memoryCache.Remove(_allOilsKey); 113 | return Ok(status); 114 | } 115 | else 116 | { 117 | return NotFound(status); 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Tests.XUnit/OilServiceTest.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using CleanArchitectureWebAPI.Application.Services; 3 | using CleanArchitectureWebAPI.Application.ViewModels.Oil; 4 | using CleanArchitectureWebAPI.Domian.Interfaces; 5 | using CleanArchitectureWebAPI.Domian.Models; 6 | using FluentAssertions; 7 | using Moq; 8 | using NUnit.Framework; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Text; 12 | using Xunit; 13 | 14 | namespace CleanArchitectureWebAPI.Tests.XUnit 15 | { 16 | public class OilServiceTest 17 | { 18 | [Fact] 19 | public void GetOils_NotExistingOils_ResultShouldBeEmpty() 20 | { 21 | // arrange 22 | var mockOilRepository = new Mock(); 23 | var mockMapper = new Mock(); 24 | 25 | // act 26 | var oilService = new OilService(mockOilRepository.Object, mockMapper.Object); 27 | var result = oilService.GetOils(); 28 | 29 | // assert 30 | result.Oils.Should().BeEmpty(); 31 | } 32 | 33 | [Fact] 34 | public void GetOils_NoExistingOils_ResultShouldBeOfTypeOilListViewModel() 35 | { 36 | // arrange 37 | var mockOilRepository = new Mock(); 38 | var mockMapper = new Mock(); 39 | 40 | // act 41 | var oilService = new OilService(mockOilRepository.Object, mockMapper.Object); 42 | var result = oilService.GetOils(); 43 | 44 | // assert 45 | //Assert.IsType(result); 46 | result.Should().BeOfType(typeof(OilListViewModel)); 47 | } 48 | 49 | [Fact] 50 | public void GetOilById_NoExistingOil_ResultShouldBeNull() 51 | { 52 | // arrange 53 | var mockOilRepository = new Mock(); 54 | var mockMapper = new Mock(); 55 | 56 | // act 57 | var oilService = new OilService(mockOilRepository.Object, mockMapper.Object); 58 | var result = oilService.GetOilById(Guid.NewGuid()); 59 | 60 | //assert 61 | result.Should().BeNull(); 62 | } 63 | 64 | [Fact] 65 | public void GetOilById_ExistingOil_ShouldReturnOilViewModel() 66 | { 67 | // arrange 68 | var mockOilRepository = new Mock(); 69 | var oil = new Oil() 70 | { 71 | Id = Guid.NewGuid(), 72 | Brand = "New Oil", 73 | Description = "New Description", 74 | Scent = "New Scent", 75 | LiquidVolume = 22, 76 | UnitPrice = 20, 77 | UnitQuantity = 100, 78 | URL = "img/oil.jpg" 79 | }; 80 | mockOilRepository.Setup(x => x.GetById(It.IsAny())).Returns(oil); 81 | 82 | var config = new MapperConfiguration(cfg => 83 | { 84 | cfg.CreateMap(); 85 | }); 86 | var mapper = config.CreateMapper(); 87 | 88 | var oilService = new OilService(mockOilRepository.Object, mapper); 89 | 90 | // act 91 | var result = oilService.GetOilById(Guid.NewGuid()); 92 | 93 | // assert 94 | result.Should().BeOfType(); 95 | } 96 | 97 | 98 | [Fact] 99 | public void GetOils_ExistingOils_ResultShouldBeTwoOils() 100 | { 101 | // arrange 102 | var mockOilRepository = new Mock(); 103 | 104 | var mockedOils = new List 105 | { 106 | new Oil 107 | { 108 | Id = Guid.NewGuid(), 109 | Brand = "New Oil 1", 110 | Description = "New Description 1", 111 | Scent = "New Scent 1", 112 | LiquidVolume = 22, 113 | UnitPrice = 20, 114 | UnitQuantity = 100, 115 | URL = "img/oil1.jpg" 116 | }, 117 | new Oil 118 | { 119 | Id = Guid.NewGuid(), 120 | Brand = "New Oil 2", 121 | Description = "New Description 2", 122 | Scent = "New Scent 2", 123 | LiquidVolume = 21, 124 | UnitPrice = 21, 125 | UnitQuantity = 100, 126 | URL = "img/oil2.jpg" 127 | }, 128 | }; 129 | 130 | mockOilRepository.Setup(x => x.GetAll()).Returns(mockedOils); 131 | 132 | var config = new MapperConfiguration(cfg => 133 | { 134 | cfg.CreateMap(); 135 | }); 136 | var mapper = config.CreateMapper(); 137 | 138 | // act 139 | var oilService = new OilService(mockOilRepository.Object, mapper); 140 | var result = oilService.GetOils(); 141 | 142 | // assert 143 | result.Oils.Should().HaveCount(2); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/Controllers/SoapsController.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Application.Interfaces; 2 | using CleanArchitectureWebAPI.Application.ViewModels.Soap; 3 | using Microsoft.AspNetCore.Authentication.JwtBearer; 4 | using Microsoft.AspNetCore.Authorization; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.Formatters; 8 | using Microsoft.Extensions.Caching.Memory; 9 | using NSwag.Annotations; 10 | using System; 11 | using System.Collections.Generic; 12 | using System.Linq; 13 | using System.Net; 14 | using System.Threading.Tasks; 15 | 16 | namespace CleanArchitectureWebAPI.WebAPI.Controllers 17 | { 18 | [Route("api/[controller]")] 19 | [OpenApiTag("Soaps", Description = "Methods to work with Soaps")] 20 | [ApiController] 21 | public class SoapsController : Controller 22 | { 23 | private readonly ISoapService _soapService; 24 | private string _allSoapsKey = "All_Soaps_Cache"; 25 | private IMemoryCache _memoryCache; 26 | public SoapsController(ISoapService soapService, IMemoryCache memoryCache) 27 | { 28 | _soapService = soapService; 29 | _memoryCache = memoryCache; 30 | } 31 | 32 | [HttpGet] //URL/api/soaps http metod Get 33 | [SwaggerResponse(HttpStatusCode.OK, typeof(SoapListViewModel), Description = "Successfully Returned List Of Soaps")] 34 | [SwaggerResponse(HttpStatusCode.NotFound, null, Description = "List Of Soaps Is Empty")] 35 | public IActionResult GetAll() 36 | { 37 | SoapListViewModel soapListViewModel; 38 | soapListViewModel = (SoapListViewModel)_memoryCache.Get(_allSoapsKey); 39 | 40 | if (soapListViewModel == null) 41 | { 42 | soapListViewModel = _soapService.GetSoaps(); 43 | 44 | _memoryCache.Set(_allSoapsKey, soapListViewModel, new MemoryCacheEntryOptions() 45 | .SetSlidingExpiration(TimeSpan.FromMinutes(15)) 46 | .SetAbsoluteExpiration(TimeSpan.FromHours(1))); 47 | } 48 | 49 | if (soapListViewModel != null) 50 | { 51 | return Ok(soapListViewModel); 52 | } 53 | else 54 | { 55 | return NotFound(); 56 | } 57 | 58 | } 59 | 60 | 61 | [HttpGet("{id}")] //URL/api/soaps/id http metod Get 62 | [ResponseCache(Duration = 300, VaryByQueryKeys = new string[] { "id" })] 63 | [SwaggerResponse(HttpStatusCode.OK, typeof(SoapViewModel), Description = "Successfully Returned Soap Model")] 64 | [SwaggerResponse(HttpStatusCode.NotFound, null, Description = "There Is No Soap Model With That Id")] 65 | public IActionResult GetById(Guid id) 66 | { 67 | var soap = _soapService.GetSoapById(id); 68 | if (soap != null) 69 | { 70 | return Ok(soap); 71 | } 72 | else 73 | { 74 | return NotFound(id); 75 | } 76 | } 77 | 78 | 79 | [HttpPost] //URL/api/soaps http metod Post 80 | [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Roles = "Admin")] 81 | [SwaggerResponse(HttpStatusCode.Unauthorized, null, Description = "You Don't Have Authorization For This Request")] 82 | [SwaggerResponse(HttpStatusCode.OK, typeof(SoapViewModel), Description = "Ok")] 83 | [SwaggerResponse(HttpStatusCode.Created, typeof(SoapViewModel), Description = "Soap Model Created")] 84 | [SwaggerResponse(HttpStatusCode.NotFound, null, Description = "Soap Model Not Found")] 85 | public IActionResult AddOrEdit(SoapViewModel model) 86 | { 87 | if (model.Id == Guid.Empty) 88 | { 89 | model = _soapService.AddSoap(model); 90 | } 91 | else 92 | { 93 | _soapService.EditSoap(model); 94 | } 95 | 96 | _memoryCache.Remove(_allSoapsKey); 97 | 98 | return Ok(model); 99 | } 100 | 101 | [HttpDelete("{id}")] //URL/api/soaps/id http metod Delete 102 | [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Roles = "Admin")] 103 | [SwaggerResponse(HttpStatusCode.OK, typeof(SoapViewModel), Description = "Successfully Deleted Soap Model")] 104 | [SwaggerResponse(HttpStatusCode.NotFound, typeof(Guid), Description = "Soap Model You Want To Delete Doesn't Exist")] 105 | [SwaggerResponse(HttpStatusCode.Unauthorized, null, Description = "You Don't Have Authorization For This Request")] 106 | public IActionResult Delete(Guid id) 107 | { 108 | var soap = _soapService.GetSoapById(id); 109 | bool status = false; ; 110 | 111 | if (soap != null) 112 | { 113 | status = _soapService.DeleteSoap(id); 114 | _memoryCache.Remove(_allSoapsKey); 115 | return Ok(status); 116 | } 117 | else 118 | { 119 | return NotFound(status); 120 | } 121 | } 122 | 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30907.101 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Application", "Application", "{44FBF3FE-EEFE-4B4E-A779-7C8CB33A56C1}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Domian", "Domian", "{01F77FD8-02E1-41CC-8735-857F46F70681}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Infrastructure", "Infrastructure", "{FF9B442E-FC6F-4566-AC3A-69A9F574E41D}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebAPI", "WebAPI", "{7B4F42BB-99A7-4E21-BCC2-A2DE841F127B}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CleanArchitectureWebAPI.WebAPI", "CleanArchitectureWebAPI.WebAPI\CleanArchitectureWebAPI.WebAPI.csproj", "{5284677E-3D82-4AD0-B5F2-710B3EFA5313}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CleanArchitectureWebAPI.Infrastructure.Data", "CleanArchitectureWebAPI.Infrastructure.Data\CleanArchitectureWebAPI.Infrastructure.Data.csproj", "{76037064-9C31-4CCB-8A95-749517BB9A47}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CleanArchitectureWebAPI.Infrastructure.IoC", "CleanArchitectureWebAPI.Infrastructure.IoC\CleanArchitectureWebAPI.Infrastructure.IoC.csproj", "{4B1438E0-C768-4A27-ADD8-9DD247B2CF84}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CleanArchitectureWebAPI.Domian", "CleanArchitectureWebAPI.Domian\CleanArchitectureWebAPI.Domian.csproj", "{ED3F24D1-F09A-42EF-9EFD-1884BBD0F122}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CleanArchitectureWebAPI.Application", "CleanArchitectureWebAPI.Application\CleanArchitectureWebAPI.Application.csproj", "{79B0F519-43E4-4962-8243-929861DF49B7}" 23 | EndProject 24 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{36489C91-C21F-4E30-BFF9-CC57A4C8E4D0}" 25 | EndProject 26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanArchitectureWebAPI.Tests.XUnit", "CleanArchitectureWebAPI.Tests.XUnit\CleanArchitectureWebAPI.Tests.XUnit.csproj", "{4F2C1360-F483-4295-9430-05975111B743}" 27 | EndProject 28 | Global 29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 30 | Debug|Any CPU = Debug|Any CPU 31 | Release|Any CPU = Release|Any CPU 32 | EndGlobalSection 33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 34 | {5284677E-3D82-4AD0-B5F2-710B3EFA5313}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {5284677E-3D82-4AD0-B5F2-710B3EFA5313}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {5284677E-3D82-4AD0-B5F2-710B3EFA5313}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {5284677E-3D82-4AD0-B5F2-710B3EFA5313}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {76037064-9C31-4CCB-8A95-749517BB9A47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {76037064-9C31-4CCB-8A95-749517BB9A47}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {76037064-9C31-4CCB-8A95-749517BB9A47}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {76037064-9C31-4CCB-8A95-749517BB9A47}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {4B1438E0-C768-4A27-ADD8-9DD247B2CF84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {4B1438E0-C768-4A27-ADD8-9DD247B2CF84}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {4B1438E0-C768-4A27-ADD8-9DD247B2CF84}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {4B1438E0-C768-4A27-ADD8-9DD247B2CF84}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {ED3F24D1-F09A-42EF-9EFD-1884BBD0F122}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {ED3F24D1-F09A-42EF-9EFD-1884BBD0F122}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {ED3F24D1-F09A-42EF-9EFD-1884BBD0F122}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {ED3F24D1-F09A-42EF-9EFD-1884BBD0F122}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {79B0F519-43E4-4962-8243-929861DF49B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {79B0F519-43E4-4962-8243-929861DF49B7}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {79B0F519-43E4-4962-8243-929861DF49B7}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {79B0F519-43E4-4962-8243-929861DF49B7}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {4F2C1360-F483-4295-9430-05975111B743}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {4F2C1360-F483-4295-9430-05975111B743}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {4F2C1360-F483-4295-9430-05975111B743}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {4F2C1360-F483-4295-9430-05975111B743}.Release|Any CPU.Build.0 = Release|Any CPU 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(NestedProjects) = preSolution 63 | {5284677E-3D82-4AD0-B5F2-710B3EFA5313} = {7B4F42BB-99A7-4E21-BCC2-A2DE841F127B} 64 | {76037064-9C31-4CCB-8A95-749517BB9A47} = {FF9B442E-FC6F-4566-AC3A-69A9F574E41D} 65 | {4B1438E0-C768-4A27-ADD8-9DD247B2CF84} = {FF9B442E-FC6F-4566-AC3A-69A9F574E41D} 66 | {ED3F24D1-F09A-42EF-9EFD-1884BBD0F122} = {01F77FD8-02E1-41CC-8735-857F46F70681} 67 | {79B0F519-43E4-4962-8243-929861DF49B7} = {44FBF3FE-EEFE-4B4E-A779-7C8CB33A56C1} 68 | {4F2C1360-F483-4295-9430-05975111B743} = {36489C91-C21F-4E30-BFF9-CC57A4C8E4D0} 69 | EndGlobalSection 70 | GlobalSection(ExtensibilityGlobals) = postSolution 71 | SolutionGuid = {4C91D554-0D0B-410D-818E-6064D8C4991E} 72 | EndGlobalSection 73 | EndGlobal 74 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/Controllers/AccountController.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.WebAPI.ViewModels; 2 | using Microsoft.AspNetCore.Authorization; 3 | using Microsoft.AspNetCore.Http; 4 | using Microsoft.AspNetCore.Identity; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.IdentityModel.Tokens; 7 | using NSwag.Annotations; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.IdentityModel.Tokens.Jwt; 11 | using System.Linq; 12 | using System.Net; 13 | using System.Security.Claims; 14 | using System.Text; 15 | using System.Threading.Tasks; 16 | 17 | namespace CleanArchitectureWebAPI.WebAPI.Controllers 18 | { 19 | [Route("api/[controller]")] 20 | [OpenApiTag("Account", Description = "Methods to work with Account")] 21 | [ApiController] 22 | [AllowAnonymous] 23 | public class AccountController : Controller 24 | { 25 | UserManager _userManager; 26 | SignInManager _signInManager; 27 | RoleManager _roleManager; 28 | 29 | public AccountController(UserManager userManager, SignInManager signInManager, RoleManager roleManager) 30 | { 31 | _userManager = userManager; 32 | _signInManager = signInManager; 33 | _roleManager = roleManager; 34 | } 35 | 36 | [HttpPost("register")] 37 | [SwaggerResponse(HttpStatusCode.BadRequest, null, Description = "Registration Form Input Is Not Correct")] 38 | [SwaggerResponse(HttpStatusCode.OK, typeof(RegisterViewModel), Description = "Valid Registration")] 39 | public async Task> Register(RegisterViewModel model) 40 | { 41 | IdentityUser user = new IdentityUser() 42 | { 43 | UserName = model.UserName, 44 | Email = model.Email 45 | }; 46 | 47 | IdentityResult userResult = await _userManager.CreateAsync(user, model.Password); 48 | 49 | if (userResult.Succeeded) 50 | { 51 | bool roleExcist = await _roleManager.RoleExistsAsync("User"); 52 | if (!roleExcist) 53 | { 54 | await AddRole("User"); 55 | } 56 | 57 | var roleResult = await _userManager.AddToRoleAsync(user, "User"); 58 | if (roleResult.Succeeded) 59 | { 60 | return user; 61 | } 62 | 63 | foreach (var error in roleResult.Errors) 64 | { 65 | ModelState.AddModelError(error.Code, error.Description); 66 | } 67 | } 68 | 69 | foreach (var error in userResult.Errors) 70 | { 71 | ModelState.AddModelError(error.Code, error.Description); 72 | } 73 | return BadRequest(ModelState.Values); 74 | } 75 | 76 | [HttpPost("signIn")] 77 | [SwaggerResponse(HttpStatusCode.OK, typeof(SignInViewModel), Description = "Valid Sign In")] 78 | [SwaggerResponse(HttpStatusCode.BadRequest, null, Description = "User Not Found")] 79 | public async Task SignIn(SignInViewModel model) 80 | { 81 | var singInResult = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, false, false); 82 | if (singInResult.Succeeded) 83 | { 84 | var user = await _userManager.FindByNameAsync(model.UserName); 85 | var roles = await _userManager.GetRolesAsync(user); 86 | 87 | IdentityOptions identityOptions = new IdentityOptions(); 88 | var claims = new Claim[] 89 | { 90 | new Claim(identityOptions.ClaimsIdentity.UserIdClaimType, user.Id), 91 | new Claim(identityOptions.ClaimsIdentity.UserNameClaimType, user.UserName), 92 | new Claim(identityOptions.ClaimsIdentity.RoleClaimType, roles[0]) 93 | }; 94 | 95 | var singingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("this-is-my-secret-key")); 96 | var signingCredentials = new SigningCredentials(singingKey, SecurityAlgorithms.HmacSha256); 97 | var token = new JwtSecurityToken(signingCredentials: signingCredentials, 98 | expires: DateTime.Now.AddHours(1), claims: claims); 99 | 100 | var obj = new 101 | { 102 | Token = new JwtSecurityTokenHandler().WriteToken(token), 103 | UserId = user.Id, 104 | UserName = user.UserName, 105 | Role = roles[0] 106 | }; 107 | 108 | return Ok(obj); 109 | } 110 | return BadRequest(ModelState); 111 | } 112 | 113 | 114 | [HttpPost("signOut")] 115 | [SwaggerResponse(HttpStatusCode.NoContent, null, Description = "Valid Sign Out")] 116 | public async Task SignOut() 117 | { 118 | await _signInManager.SignOutAsync(); 119 | return NoContent(); 120 | } 121 | 122 | 123 | private async Task AddRole(string roleName) 124 | { 125 | var role = new IdentityRole(); 126 | role.Name = roleName; 127 | return await _roleManager.CreateAsync(role); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/Logs/log20221129.txt: -------------------------------------------------------------------------------- 1 | 11/29/2022 23:09:48 +01:00 Application is starting 2 | 11/29/2022 23:09:55 +01:00 HTTP "GET" "/api/soaps" responded 200 in 724.6136 ms 3 | 11/29/2022 23:09:55 +01:00 HTTP "GET" "/favicon.ico" responded 404 in 4.7771 ms 4 | 11/29/2022 23:11:43 +01:00 Application is starting 5 | 11/29/2022 23:11:47 +01:00 HTTP "GET" "/api/soaps" responded 200 in 470.5643 ms 6 | 11/29/2022 23:12:05 +01:00 Application is starting 7 | 11/29/2022 23:12:08 +01:00 HTTP "GET" "/swagger" responded 302 in 84.6647 ms 8 | 11/29/2022 23:12:09 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 433.3172 ms 9 | 11/29/2022 23:12:09 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 47.8614 ms 10 | 11/29/2022 23:12:09 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 47.9248 ms 11 | 11/29/2022 23:12:09 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 65.3103 ms 12 | 11/29/2022 23:12:10 +01:00 HTTP "GET" "/swagger/favicon-32x32.png" responded 200 in 1.8156 ms 13 | 11/29/2022 23:12:10 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 970.1950 ms 14 | 11/29/2022 23:13:08 +01:00 HTTP "GET" "/api/balms" responded 200 in 429.8677 ms 15 | 11/29/2022 23:13:09 +01:00 HTTP "GET" "/api/soaps" responded 200 in 248.2927 ms 16 | 11/29/2022 23:13:13 +01:00 HTTP "GET" "/api/balms" responded 200 in 10.8398 ms 17 | 11/29/2022 23:13:17 +01:00 HTTP "GET" "/api/oils" responded 200 in 183.9310 ms 18 | 11/29/2022 23:13:50 +01:00 HTTP "OPTIONS" "/api/account/register" responded 204 in 19.8020 ms 19 | 11/29/2022 23:13:51 +01:00 HTTP "POST" "/api/account/register" responded 200 in 739.2508 ms 20 | 11/29/2022 23:13:51 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.9220 ms 21 | 11/29/2022 23:14:02 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.5237 ms 22 | 11/29/2022 23:14:03 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 436.5896 ms 23 | 11/29/2022 23:14:08 +01:00 HTTP "OPTIONS" "/api/account/signout" responded 204 in 1.2595 ms 24 | 11/29/2022 23:14:08 +01:00 HTTP "POST" "/api/account/signout" responded 204 in 116.0154 ms 25 | 11/29/2022 23:19:42 +01:00 HTTP "OPTIONS" "/api/account/register" responded 204 in 1.0883 ms 26 | 11/29/2022 23:19:42 +01:00 HTTP "POST" "/api/account/register" responded 200 in 219.2383 ms 27 | 11/29/2022 23:19:42 +01:00 HTTP "GET" "/api/soaps" responded 200 in 11.4109 ms 28 | 11/29/2022 23:21:29 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 12.6860 ms 29 | 11/29/2022 23:21:30 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 156.1264 ms 30 | 11/29/2022 23:21:34 +01:00 HTTP "GET" "/api/soaps" responded 200 in 3.6219 ms 31 | 11/29/2022 23:24:23 +01:00 HTTP "GET" "/api/soaps" responded 200 in 12.4562 ms 32 | 11/29/2022 23:24:26 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.8830 ms 33 | 11/29/2022 23:25:43 +01:00 HTTP "GET" "/api/soaps" responded 200 in 9.0596 ms 34 | 11/29/2022 23:28:14 +01:00 HTTP "GET" "/api/soaps" responded 200 in 12.1400 ms 35 | 11/29/2022 23:30:39 +01:00 HTTP "GET" "/api/soaps" responded 200 in 9.3043 ms 36 | 11/29/2022 23:33:12 +01:00 HTTP "GET" "/api/soaps" responded 200 in 14.3681 ms 37 | 11/29/2022 23:33:17 +01:00 HTTP "GET" "/api/soaps" responded 200 in 8.7317 ms 38 | 11/29/2022 23:33:57 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.5686 ms 39 | 11/29/2022 23:35:04 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 3.8506 ms 40 | 11/29/2022 23:35:05 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 128.4022 ms 41 | 11/29/2022 23:35:09 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.2158 ms 42 | 11/29/2022 23:37:45 +01:00 HTTP "GET" "/api/soaps" responded 200 in 13.9420 ms 43 | 11/29/2022 23:38:18 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.3003 ms 44 | 11/29/2022 23:38:31 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.4020 ms 45 | 11/29/2022 23:38:31 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 109.8202 ms 46 | 11/29/2022 23:38:36 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.5807 ms 47 | 11/29/2022 23:39:24 +01:00 HTTP "GET" "/api/soaps" responded 200 in 46.9351 ms 48 | 11/29/2022 23:39:32 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.6574 ms 49 | 11/29/2022 23:39:32 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 100.8753 ms 50 | 11/29/2022 23:39:34 +01:00 HTTP "GET" "/api/soaps" responded 200 in 14.7844 ms 51 | 11/29/2022 23:40:59 +01:00 HTTP "GET" "/api/soaps" responded 200 in 10.4308 ms 52 | 11/29/2022 23:41:18 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.4209 ms 53 | 11/29/2022 23:41:18 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 102.8204 ms 54 | 11/29/2022 23:41:20 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.3092 ms 55 | 11/29/2022 23:42:01 +01:00 HTTP "GET" "/api/soaps" responded 200 in 11.8909 ms 56 | 11/29/2022 23:42:14 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2311 ms 57 | 11/29/2022 23:42:14 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 129.4010 ms 58 | 11/29/2022 23:42:16 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.3074 ms 59 | 11/29/2022 23:44:14 +01:00 HTTP "GET" "/api/soaps" responded 200 in 3.9691 ms 60 | 11/29/2022 23:44:29 +01:00 HTTP "GET" "/api/soaps" responded 200 in 6.7360 ms 61 | 11/29/2022 23:44:39 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.7411 ms 62 | 11/29/2022 23:44:49 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.4334 ms 63 | 11/29/2022 23:44:49 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 67.9731 ms 64 | 11/29/2022 23:44:56 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.8087 ms 65 | 11/29/2022 23:46:20 +01:00 HTTP "GET" "/api/soaps" responded 200 in 7.5476 ms 66 | 11/29/2022 23:46:28 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.8595 ms 67 | 11/29/2022 23:46:28 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 108.6035 ms 68 | 11/29/2022 23:46:29 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.6106 ms 69 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/Controllers/BalmsController.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Application.Interfaces; 2 | using CleanArchitectureWebAPI.Application.ViewModels.Balm; 3 | using Microsoft.AspNetCore.Authentication.JwtBearer; 4 | using Microsoft.AspNetCore.Authorization; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.Extensions.Caching.Memory; 8 | using NSwag.Annotations; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Net; 13 | using System.Threading.Tasks; 14 | 15 | namespace CleanArchitectureWebAPI.WebAPI.Controllers 16 | { 17 | [Route("api/[controller]")] 18 | [OpenApiTag("Balms", Description = "Methods to work with Balms")] 19 | [ApiController] 20 | public class BalmsController : Controller 21 | { 22 | private readonly IBalmService _balmService; 23 | private IMemoryCache _memoryCache; 24 | private string _allBalmsKey = "All_Balms_Cache"; 25 | public BalmsController(IBalmService balmService, IMemoryCache memoryCache) 26 | { 27 | _balmService = balmService; 28 | _memoryCache = memoryCache; 29 | } 30 | 31 | 32 | [HttpGet] //URL/api/balms http metod Get 33 | [SwaggerResponse(HttpStatusCode.OK, typeof(BalmListViewModel), Description = "Successfully Returned List Of Balms")] 34 | [SwaggerResponse(HttpStatusCode.NotFound, null, Description = "List Of Balms Is Empty")] 35 | public IActionResult GetAll() 36 | { 37 | BalmListViewModel balmListViewModel; 38 | 39 | // Returns an entry from the cache 40 | balmListViewModel = (BalmListViewModel)_memoryCache.Get(_allBalmsKey); 41 | 42 | // If there is no entry in the cache for that key, go to database 43 | if (balmListViewModel == null) 44 | { 45 | balmListViewModel = _balmService.GetBalms(); 46 | // Setting cache entry for that key. 47 | _memoryCache.Set(_allBalmsKey, balmListViewModel, new MemoryCacheEntryOptions(). 48 | SetSlidingExpiration(TimeSpan.FromMinutes(15)). 49 | SetAbsoluteExpiration(TimeSpan.FromHours(1))); 50 | // SetSlidingExpiration Sets how long the cache entry can be inactive 51 | // SetAbsoluteExpiration Sets an absolute expiration date for the cache entry 52 | 53 | // THIS IS JUST TO DEMONSTRATE HOW CACHE WORKS. YOU CAN ALLWAYS CHANGE THE TIMESPAN 54 | } 55 | 56 | if (balmListViewModel != null) 57 | { 58 | return Ok(balmListViewModel); 59 | } 60 | else 61 | { 62 | return NotFound(); 63 | } 64 | } 65 | 66 | 67 | [HttpGet("{id}")] //URL/api/balms/id http metod Get 68 | [SwaggerResponse(HttpStatusCode.OK, typeof(BalmViewModel), Description = "Successfully Returned Balm Model")] 69 | [SwaggerResponse(HttpStatusCode.NotFound, null, Description = "There Is No Balm Model With That Id")] 70 | [ResponseCache(Duration = 300, VaryByQueryKeys = new string[] { "id" })] // This is the Response Cache 71 | public IActionResult GetById(Guid id) 72 | { 73 | var balm = _balmService.GetBalmById(id); 74 | if (balm != null) 75 | { 76 | return Ok(balm); 77 | } 78 | else 79 | { 80 | return NotFound(id); 81 | } 82 | 83 | } 84 | 85 | 86 | 87 | [HttpPost] //URL/api/balms http metod Post 88 | [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Roles = "Admin")] 89 | [SwaggerResponse(HttpStatusCode.Unauthorized, null, Description = "You Don't Have Authorization For This Request")] 90 | [SwaggerResponse(HttpStatusCode.OK, typeof(BalmViewModel), Description = "Ok")] 91 | [SwaggerResponse(HttpStatusCode.Created, typeof(BalmViewModel), Description = "Balm Model Created")] 92 | [SwaggerResponse(HttpStatusCode.NotFound, null, Description = "Balm Model Not Found")] 93 | public IActionResult AddOrEdit(BalmViewModel model) 94 | { 95 | if (model.Id == Guid.Empty) 96 | { 97 | model = _balmService.AddBalm(model); 98 | } 99 | else 100 | { 101 | _balmService.EditBalm(model); 102 | } 103 | 104 | _memoryCache.Remove(_allBalmsKey); 105 | 106 | return Ok(model); 107 | } 108 | 109 | 110 | 111 | [HttpDelete("{id}")] //URL/api/balms/id http metod Delete 112 | [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Roles = "Admin")] 113 | [SwaggerResponse(HttpStatusCode.OK, typeof(BalmViewModel), Description = "Successfully Deleted Balm Model")] 114 | [SwaggerResponse(HttpStatusCode.NotFound, typeof(Guid), Description = "Balm Model You Want To Delete Doesn't Exist")] 115 | [SwaggerResponse(HttpStatusCode.Unauthorized, null, Description = "You Don't Have Authorization For This Request")] 116 | public IActionResult Delete(Guid id) 117 | { 118 | var balm = _balmService.GetBalmById(id); 119 | var status = false; 120 | if (balm != null) 121 | { 122 | status = _balmService.DeleteBalm(id); 123 | _memoryCache.Remove(_allBalmsKey); 124 | return Ok(balm); 125 | } 126 | else 127 | { 128 | return NotFound(status); 129 | } 130 | 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clean Architecture ASP.NET Core Web API 3.1 2 | 3 | ## Project Use Case 4 | 5 | This is a WebAPI Project, implemented with Clean Architecture pattern. The code is very clean and it is very manageable. 6 | You can add your own models, validations, logic, etc. You can also create MVC project on top of it, or just 7 | use it as a api, deployed locally or publish on some server and use some front-end framework to show the data. 8 | 9 | The front-end for this project is available on GitHub, and can be found [here](https://github.com/viktor1vasilevski/beard-products-ui). 10 | 11 | 12 | ## Installation 13 | 14 | 1. Download the code - Clone the repository or download the zip file 15 | 16 | 2. Change the connection string - In the WebAPI project in the ```appsettings.json``` file enter your server name 17 | and name of the database(I was working on SQL Server 2014 Management Studio). 18 | 19 | 3. Go into the Package Manager Console and type: ```Add-Migration "Init```" 20 |
21 |
22 | ***!IMPORTANT - Make sure that your WebAPI is Set as Startup Project, and in the Package Manager Console your Default project is CleanArchitectureWebAPI.Infrastructure.Data selected.*** 23 | - this will create folder Migrations in CleanArchitectureWebAPI.Infrastructure.Data with the migration. 24 | 25 | 4. When this is done, just type in the Package Manager Console: ```Update-Database``` 26 | - this will create the database with you database name with all the ASP.NET Identity tables and the models. 27 | 28 | 5. Run the project 29 | - this will build the project and it will seed the database with some data, just something to work with. 30 | (maybe you have to close the SQL Server 2014 Management Studio and start it again) 31 | - in the WebAPI project it will also be created folder Log with two files. One .json file and other .txt. 32 | These are for detail logging information. 33 | 34 | 6. Next step is that you have to create "Admin" to take full experience of the API. 35 | - because the API works with roles "Admin" and "User", you have to go first to create roles "Admin" and "User" in dbo.AspNetRoles. 36 | - you can use this set of commands in SQL Server 2014 Management Studio to create the roles "Admin" and "User". 37 | 38 | ```sql 39 | USE [yourDatabaseName] 40 | GO 41 | INSERT INTO dbo.AspNetRoles(Id, Name, NormalizedName, ConcurrencyStamp) 42 | VALUES (1, 'Admin', 'ADMIN', null) 43 | INSERT INTO dbo.AspNetRoles(Id, Name, NormalizedName, ConcurrencyStamp) 44 | VALUES (2, 'User', 'USER', null) 45 | ``` 46 | 47 | 7. Next step is to register some user
48 | - ***from this point on, your api/project should be running all the time during the register, login and CRUD operations***
49 | - ***I hosted the api/project locally, on my computer*** 50 | - you can use Postman or Fiddler for registration, or some other program, and provide this json format in the body with your own values. 51 | (I used Postman) 52 | - The method is ```Post``` and the url will be ```localhost:port/api/account/register```
53 | 54 | ```json 55 | { 56 | "Username": "YourUsername", 57 | "Email": "YourEmail@yahoo.com", 58 | "Password": "YourPassword@123", 59 | "ConfirmPassword": "YourPassword@123" 60 | } 61 | ``` 62 | - after you get registered, automatically, this user will have the role "User". 63 | Go in the SQL Server 2014 Management Studio, your database, table AspNetUserRoles and notice that the RoleId is already 2 for that one user. 64 | Just edit the table and change it manually to 1 and press TAB, 65 | or write this command in SQL 66 | 67 | ```sql 68 | USE [yourDatabaseName] 69 | GO 70 | UPDATE [dbo].[AspNetUserRoles] SET RoleId = 1 71 | WHERE UserId = 'userId' --here enter the user ID 72 | ``` 73 | This user, from then on will be with role of "Admin". 74 | 75 | 8. Next step is to Sign In some user 76 | - url: ```localhost/port/api/account/signin```, and this method is also ```Post``` and you should provide this json format into the body 77 | ```json 78 | { 79 | "Username": "YourUsername", 80 | "Password": "YourPassword@123" 81 | } 82 | ``` 83 | the logging user will be successful and you will recive a JWT Token,
84 | which you must use for Authorization with the prefix Bearer : YourToken 85 | ``` 86 | In Postman just select the Auth, and from the dropdown menu select Bearer Token 87 | ``` 88 | 89 | Now the commands Post, Create, Edit and Delete will be available, otherwise you will get the: 90 | ```js 91 | 401 Unauthorized 92 | ``` 93 | *(for Get and GetById you dont need no Authorization)* 94 |
95 |
96 | Every other registered user in the future will be with the role "User". To change it to "Admin" just do the step 7, part 5. 97 | (in the project there is no request that is authorized by "User", so you can use this below some other Http request).
98 | ```C# 99 | [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Roles = "User")] 100 | ``` 101 | ## Principle, Patterns and external libraries used. 102 | 103 | 1. Clean (Onion) Architecture Project with Domain Driven Design and SOLID principles. 104 | 2. ASP.NET Core Dependency Injection 105 | 3. Repository Pattern 106 | 4. Unit Of Work Pattern 107 | 5. Automapper 108 | 6. Logging with Serilog 109 | 7. In Memory Caching 110 | 8. Response Caching 111 | 9. Swagger 112 | 10. JWT Token 113 | 11. Unit Testing with Moq 114 | 115 | ## ToDO 116 | 117 | 1. There is no business logic, since this is only a concept. 118 | 2. The enities don't have foreign keys or any common table 119 | 120 | ## Notes 121 | 1. This project is build somewhere in the beginning of 2021 and I was just starting to apply for a job. Now, that I changed few companies and I gained experience working on real projects, and think about the architecure of the project, I can see that the database, or the models, are not well structured. 122 | Because the api is build for a kind of web shop application, ultimatly what you want is to buy a product. Well now, as the architecture is build, it is possible but the solution is not good. Say you have build a front-end project with Angular and you have cart section, and in that cart you have one soap and one balm as a products. 123 | Now the next step is to have separate controller in the back-end that handles this logic. In this controller you have to have all the services because you don't know user what will pick, soap, balm or oil. And for every item, you have to check in each service if that id is in that table of the database. Because on the back-end, as the user checkouts, the user want to buy two items, and you will get two ids, nothing more. Those ids don't tell what is it. Is it a soap or balm. And imagine if you have hundred products. For instance hand soaps, scissors, shampoos and what not. The project will be difficult to manage and in this controller where the buying is made, you will end up with hundred servers, or instances from the tables of the database, and when the user wants to buy just one product, you have to search in all the tables just to find that one product which the user wants to buy. Or even if you send from front end some information about the product, you have to have if statements or switch logic. At the very end I think it's a bad way of dealing with this kind of logic. 124 | 125 | The solution for this problem is to have one table, named Products, and in this table you will have the columns like Name, Brand, Edition, Unit Price and so on. 126 | Or even better you will have another table Categories, and in that table you will save the categories like, beard category, hair category, hands category, and in this 127 | Products table you will have CategoryId, respectively for every product. This way all the products are in one table and your search will be only in this table, that's it. The buying of products will be much easier and no matter the product, you will recive array of ids and the search will be done only in one table. This project can be even more improved, for instance you can write the logic for creating generic unit of work and generic repositories pattern, you can have another table Product Details where you will store the details for each product, you can insert column in Product table named ProductDetailsJson where all the details from the product you will store as a json file and on the front end you will handle this object, and so on. Hope this helps a little bit. 128 | 129 | 2. The solution folder Domian, should be named Domain. And also the name of the Class Library from that folder should be named CleanArchitectureWebAPI.Dom**ai**n, not CleanArchitectureWebAPI.Dom**ia**n. 130 | 131 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.Data/Context/LibraryDbContextSeed.cs: -------------------------------------------------------------------------------- 1 | using CleanArchitectureWebAPI.Domian.Models; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Logging; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace CleanArchitectureWebAPI.Infrastructure.Data.Context 11 | { 12 | public class LibraryDbContextSeed 13 | { 14 | public static async Task SeedAsync(LibraryDbContext libraryDbContext, ILoggerFactory loggerFactory, int? retry = 0) 15 | { 16 | int retryForAvailability = retry.Value; 17 | 18 | try 19 | { 20 | // NOTE : Only run this if using a real database 21 | libraryDbContext.Database.Migrate(); 22 | libraryDbContext.Database.EnsureCreated(); 23 | 24 | // seed Soaps 25 | await SeedSoapsAsync(libraryDbContext); 26 | 27 | // seed Oils 28 | await SeedOilsAsync(libraryDbContext); 29 | 30 | //// seed Balms 31 | await SeedBalmsAsync(libraryDbContext); 32 | 33 | } 34 | catch (Exception exception) 35 | { 36 | if (retryForAvailability < 10) 37 | { 38 | retryForAvailability++; 39 | var log = loggerFactory.CreateLogger(); 40 | log.LogError(exception.Message); 41 | await SeedAsync(libraryDbContext, loggerFactory, retryForAvailability); 42 | } 43 | throw; 44 | } 45 | } 46 | 47 | private static async Task SeedSoapsAsync(LibraryDbContext libraryDbContext) 48 | { 49 | if (libraryDbContext.Soaps.Any()) 50 | return; 51 | 52 | var soaps = new List() 53 | { 54 | new Soap() 55 | { 56 | Edition = "Orange Brick", 57 | Brand = "Craftsman", 58 | Description = "With the bright, earthy smell of the forest and a hint of lavender," + 59 | " our beard soap delivers a refreshing start to your beard care regiment. " + 60 | "Made from a choice blend of oils, this bar is formulated to build a particularly thick, " + 61 | "creamy lather for a thorough beard cleaning that won't leave your beard or face dry", 62 | UnitPrice = 13, 63 | UnitQuantity = 100, 64 | URL = LibraryDbContextSeedData.ORANGE_BRICK, 65 | Created = DateTime.Now, 66 | LastModified = DateTime.Now, 67 | CreatedBy = "Viktor" 68 | }, 69 | 70 | new Soap () 71 | { 72 | Edition = "Brown", 73 | Brand = "Honest Amish", 74 | Description = "Exclusively Handmade Natural Skin Care Soap Bar for dry skin. " + 75 | "Beautiful handcrafted natural skin care soap bar from Organic Goat milk, " + 76 | "extra virgin organic Coconut, organic Palm and extra virgin Olive oils.", 77 | UnitPrice = 11, 78 | UnitQuantity = 100, 79 | URL = LibraryDbContextSeedData.BROWN, 80 | Created = DateTime.Now, 81 | LastModified = DateTime.Now, 82 | CreatedBy = "Viktor" 83 | }, 84 | 85 | new Soap() 86 | { 87 | Edition = "Light Yellow", 88 | Brand = "Crocodile", 89 | Description = "Artisanal soap handmade in Ojai, California with locally farmed fresh raw " + 90 | "Goat Milk and Organic Essential Oils, Hand mixed, poured and cut into long lasting bars", 91 | UnitPrice = 12, 92 | UnitQuantity = 100, 93 | URL = LibraryDbContextSeedData.LIGHT_YELLOW, 94 | Created = DateTime.Now, 95 | LastModified = DateTime.Now, 96 | CreatedBy = "Viktor" 97 | } 98 | }; 99 | 100 | libraryDbContext.Soaps.AddRange(soaps); 101 | await libraryDbContext.SaveChangesAsync(); 102 | } 103 | 104 | 105 | private static async Task SeedOilsAsync(LibraryDbContext libraryDbContext) 106 | { 107 | if (libraryDbContext.Oils.Any()) 108 | return; 109 | 110 | var oils = new List() 111 | { 112 | new Oil() 113 | { 114 | Scent = "Forest Woods", 115 | LiquidVolume = 30, 116 | Brand = "Hawkins&Brimble", 117 | Description = "Perfect for sensitive skin, Le Labo’s formula is entirely " + 118 | "plant-based (making it suitable for vegans). " + 119 | "The nonirritating elixir carries the comforting scent of lavender, " + 120 | "along with bergamot and tonka bean.", 121 | UnitPrice = 23, 122 | UnitQuantity = 100, 123 | URL = LibraryDbContextSeedData.FOREST_WOODS, 124 | Created = DateTime.Now, 125 | LastModified = DateTime.Now, 126 | CreatedBy = "Viktor" 127 | }, 128 | 129 | new Oil() 130 | { 131 | Scent = "Cedar", 132 | LiquidVolume = 50, 133 | Brand = "Johnny's Boat", 134 | Description = "Our beard oil comes equipped with a nifty ball rod " + 135 | "cap so that you can take a little or a lot depending on your " + 136 | "beard size. Just add a few drops to your fingertips and massage the " + 137 | "oils through your beard and mustache hair", 138 | UnitPrice = 28, 139 | UnitQuantity = 100, 140 | URL = LibraryDbContextSeedData.CEDAR, 141 | Created = DateTime.Now, 142 | LastModified = DateTime.Now, 143 | CreatedBy = "Viktor" 144 | }, 145 | 146 | new Oil() 147 | { 148 | Scent = "Summer Breeze", 149 | LiquidVolume = 50, 150 | Brand = "Beardo", 151 | Description = "Handmade with 100% natural oils, this beard oil " + 152 | "absorbs quickly and gives your beard a smooth, soft, subtle shine. " + 153 | "Great for conditioning the skin underneath your beard. " + 154 | "Promotes hair growth by helping you maintain a healthy beard. " + 155 | "Timber - Mild Scent of Cedar & Fir NeedleMB BEARD OIL TIMBER", 156 | UnitPrice = 25, 157 | UnitQuantity = 100, 158 | URL = LibraryDbContextSeedData.SUMMER_BREEZE, 159 | Created = DateTime.Now, 160 | LastModified = DateTime.Now, 161 | CreatedBy = "Viktor" 162 | } 163 | }; 164 | 165 | libraryDbContext.Oils.AddRange(oils); 166 | await libraryDbContext.SaveChangesAsync(); 167 | } 168 | 169 | private static async Task SeedBalmsAsync(LibraryDbContext libraryDbContext) 170 | { 171 | if (libraryDbContext.Balms.Any()) 172 | return; 173 | 174 | var balms = new List() 175 | { 176 | new Balm() 177 | { 178 | Volume = 70, 179 | Brand = "Honest Amish", 180 | Description = "The best for your beard we guarantee it. " + 181 | "Honest Amish Beard Balm is created from the finest organic " + 182 | "ingredients available. We start with a proprietary blend of hair " + 183 | "strengthening botanical infused in a base of Virgin Argan, Avocado, " + 184 | "Almond, Virgin Pumpkin Seed, and Apricot Kernel Oils", 185 | UnitPrice = 21, 186 | UnitQuantity = 100, 187 | URL = LibraryDbContextSeedData.HONEST_AMISH, 188 | Created = DateTime.Now, 189 | LastModified = DateTime.Now, 190 | CreatedBy = "Viktor" 191 | }, 192 | 193 | new Balm () 194 | { 195 | Volume = 50, 196 | Brand = "Rocky Mountain", 197 | Description = "The natural, organic ingredients get deep into the hair and nourishes " + 198 | "it from inside and out! It works on long and short beards to condition & soften " + 199 | "your hair, improve strength & shine", 200 | UnitPrice = 19, 201 | UnitQuantity = 100, 202 | URL = LibraryDbContextSeedData.ROCKY_MOUNTAIN, 203 | Created = DateTime.Now, 204 | LastModified = DateTime.Now, 205 | CreatedBy = "Viktor" 206 | }, 207 | 208 | new Balm() 209 | { 210 | Volume = 100, 211 | Brand = "Olympus", 212 | Description = "All Natural Ingredients - Featuring over eight essential oils, " + 213 | "we are proud to say that our product is all-natural with ingredients that will " + 214 | "leave your beard feeling and looking amazing", 215 | UnitPrice = 20, 216 | UnitQuantity = 100, 217 | URL = LibraryDbContextSeedData.OLYMPUS, 218 | Created = DateTime.Now, 219 | LastModified = DateTime.Now, 220 | CreatedBy = "Viktor" 221 | } 222 | }; 223 | 224 | libraryDbContext.Balms.AddRange(balms); 225 | await libraryDbContext.SaveChangesAsync(); 226 | } 227 | } 228 | 229 | 230 | } 231 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/Logs/log20221209.txt: -------------------------------------------------------------------------------- 1 | 12/09/2022 00:00:11 +01:00 HTTP "GET" "/api/soaps" responded 200 in 10.1264 ms 2 | 12/09/2022 00:00:51 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.4816 ms 3 | 12/09/2022 00:01:01 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1286 ms 4 | 12/09/2022 00:01:01 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 57.7227 ms 5 | 12/09/2022 00:01:02 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0586 ms 6 | 12/09/2022 00:01:27 +01:00 HTTP "GET" "/api/soaps" responded 200 in 11.6115 ms 7 | 12/09/2022 00:01:29 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1617 ms 8 | 12/09/2022 00:01:29 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 98.0712 ms 9 | 12/09/2022 00:01:30 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0933 ms 10 | 12/09/2022 00:02:07 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5965 ms 11 | 12/09/2022 00:02:27 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.4775 ms 12 | 12/09/2022 00:02:32 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1021 ms 13 | 12/09/2022 00:02:32 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 96.9925 ms 14 | 12/09/2022 00:02:32 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.5075 ms 15 | 12/09/2022 00:03:04 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.6631 ms 16 | 12/09/2022 00:03:06 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.4180 ms 17 | 12/09/2022 00:03:06 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 101.6925 ms 18 | 12/09/2022 00:03:07 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.3358 ms 19 | 12/09/2022 00:03:30 +01:00 HTTP "GET" "/api/soaps" responded 200 in 10.1174 ms 20 | 12/09/2022 00:04:30 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.2093 ms 21 | 12/09/2022 00:04:32 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.5478 ms 22 | 12/09/2022 00:04:32 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 52.2908 ms 23 | 12/09/2022 00:04:32 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0387 ms 24 | 12/09/2022 00:05:24 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.4310 ms 25 | 12/09/2022 00:10:45 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1330 ms 26 | 12/09/2022 00:10:45 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 189.3405 ms 27 | 12/09/2022 00:10:45 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.8746 ms 28 | 12/09/2022 00:11:52 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.6648 ms 29 | 12/09/2022 00:12:11 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.2471 ms 30 | 12/09/2022 00:12:19 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2020 ms 31 | 12/09/2022 00:12:19 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 26.9546 ms 32 | 12/09/2022 00:12:20 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.8205 ms 33 | 12/09/2022 00:14:33 +01:00 HTTP "GET" "/api/soaps" responded 200 in 15.3233 ms 34 | 12/09/2022 00:20:20 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.4819 ms 35 | 12/09/2022 00:20:22 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.4616 ms 36 | 12/09/2022 00:30:04 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2252 ms 37 | 12/09/2022 00:30:04 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 198.3786 ms 38 | 12/09/2022 00:30:05 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.2145 ms 39 | 12/09/2022 00:30:27 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0599 ms 40 | 12/09/2022 00:31:07 +01:00 HTTP "GET" "/api/soaps" responded 200 in 3.3731 ms 41 | 12/09/2022 00:31:10 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.5877 ms 42 | 12/09/2022 00:31:10 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 121.1429 ms 43 | 12/09/2022 00:31:16 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.5882 ms 44 | 12/09/2022 00:31:56 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.7513 ms 45 | 12/09/2022 00:31:58 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1395 ms 46 | 12/09/2022 00:31:58 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 59.9206 ms 47 | 12/09/2022 00:31:59 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.8714 ms 48 | 12/09/2022 00:32:42 +01:00 HTTP "GET" "/api/soaps" responded 200 in 9.4609 ms 49 | 12/09/2022 00:34:44 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1062 ms 50 | 12/09/2022 00:35:07 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.8878 ms 51 | 12/09/2022 00:36:25 +01:00 HTTP "GET" "/api/soaps" responded 200 in 7.2185 ms 52 | 12/09/2022 00:41:23 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.2597 ms 53 | 12/09/2022 00:43:08 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0102 ms 54 | 12/09/2022 00:44:01 +01:00 HTTP "GET" "/swagger/[object%20Module]" responded 404 in 3.0251 ms 55 | 12/09/2022 00:45:00 +01:00 HTTP "POST" "/api/Soaps" responded 401 in 44.5475 ms 56 | 12/09/2022 00:47:16 +01:00 Application is starting 57 | 12/09/2022 00:47:19 +01:00 HTTP "GET" "/swagger" responded 302 in 81.3948 ms 58 | 12/09/2022 00:47:20 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 294.4948 ms 59 | 12/09/2022 00:47:20 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 69.7981 ms 60 | 12/09/2022 00:47:20 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 69.9286 ms 61 | 12/09/2022 00:47:20 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 70.3680 ms 62 | 12/09/2022 00:47:21 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 928.6946 ms 63 | 12/09/2022 00:47:38 +01:00 HTTP "GET" "/swagger/[object%20Module]" responded 404 in 3.5914 ms 64 | 12/09/2022 00:48:28 +01:00 Application is starting 65 | 12/09/2022 00:48:31 +01:00 HTTP "GET" "/swagger" responded 302 in 77.6278 ms 66 | 12/09/2022 00:48:31 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 300.3175 ms 67 | 12/09/2022 00:48:31 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 45.6879 ms 68 | 12/09/2022 00:48:31 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 45.1633 ms 69 | 12/09/2022 00:48:31 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 45.6820 ms 70 | 12/09/2022 00:48:32 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 808.8700 ms 71 | 12/09/2022 00:49:31 +01:00 HTTP "GET" "/swagger/[object%20Module]" responded 404 in 5.3797 ms 72 | 12/09/2022 00:50:01 +01:00 HTTP "POST" "/api/account/signin" responded 415 in 201.8797 ms 73 | 12/09/2022 00:50:15 +01:00 HTTP "POST" "/api/account/signin" responded 415 in 18.1274 ms 74 | 12/09/2022 00:51:55 +01:00 HTTP "GET" "/api/soaps" responded 200 in 4124.0604 ms 75 | 12/09/2022 00:52:27 +01:00 HTTP "POST" "/api/account/signin" responded 415 in 20.1832 ms 76 | 12/09/2022 00:52:43 +01:00 HTTP "POST" "/api/account/signin" responded 400 in 26.1706 ms 77 | 12/09/2022 00:53:02 +01:00 HTTP "POST" "/api/account/signin?username=Viktor&password=Viktor@123" responded 400 in 6.1172 ms 78 | 12/09/2022 00:53:17 +01:00 HTTP "POST" "/api/account/signin?username=Viktor&password=Viktor@123" responded 400 in 8.7271 ms 79 | 12/09/2022 00:54:30 +01:00 HTTP "POST" "/api/account/signin?userName=Viktor&password=Viktor@123" responded 400 in 40.7582 ms 80 | 12/09/2022 00:55:18 +01:00 HTTP "POST" "/api/account/signin" responded 415 in 4.3326 ms 81 | 12/09/2022 00:55:56 +01:00 HTTP "POST" "/api/account/signin" responded 415 in 21.5124 ms 82 | 12/09/2022 00:57:15 +01:00 HTTP "POST" "/api/Account/signIn" responded 200 in 2398.2690 ms 83 | 12/09/2022 00:57:34 +01:00 HTTP "GET" "/swagger/[object%20Module]" responded 404 in 0.5008 ms 84 | 12/09/2022 01:01:02 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 4456.3782 ms 85 | 12/09/2022 01:02:43 +01:00 HTTP "GET" "/swagger/[object%20Module]" responded 404 in 4.2604 ms 86 | 12/09/2022 01:03:30 +01:00 HTTP "POST" "/api/soaps" responded 400 in 136.2441 ms 87 | 12/09/2022 01:04:09 +01:00 HTTP "POST" "/api/soaps" responded 400 in 17.8104 ms 88 | 12/09/2022 01:05:24 +01:00 HTTP "POST" "/api/soaps" responded 200 in 60500.1453 ms 89 | 12/09/2022 01:16:36 +01:00 Application is starting 90 | 12/09/2022 01:16:41 +01:00 HTTP "GET" "/swagger" responded 302 in 83.1426 ms 91 | 12/09/2022 01:16:41 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 280.4513 ms 92 | 12/09/2022 01:16:41 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 72.0183 ms 93 | 12/09/2022 01:16:41 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 72.0649 ms 94 | 12/09/2022 01:16:41 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 72.1175 ms 95 | 12/09/2022 01:16:42 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 761.2729 ms 96 | 12/09/2022 01:18:05 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 19.0850 ms 97 | 12/09/2022 01:18:16 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 10979.6440 ms 98 | 12/09/2022 01:18:22 +01:00 HTTP "GET" "/api/soaps" responded 200 in 4341.2447 ms 99 | 12/09/2022 01:18:26 +01:00 HTTP "OPTIONS" "/api/soaps/7680581a-25cf-434b-b40f-830d8c217ecf" responded 204 in 1.1519 ms 100 | 12/09/2022 01:18:27 +01:00 HTTP "DELETE" "/api/soaps/7680581a-25cf-434b-b40f-830d8c217ecf" responded 200 in 434.0389 ms 101 | 12/09/2022 01:18:28 +01:00 HTTP "OPTIONS" "/api/soaps/f14fcdce-daf6-498d-0920-08dad9693d5b" responded 204 in 1.0246 ms 102 | 12/09/2022 01:18:28 +01:00 HTTP "DELETE" "/api/soaps/f14fcdce-daf6-498d-0920-08dad9693d5b" responded 200 in 77.0524 ms 103 | 12/09/2022 01:18:30 +01:00 HTTP "OPTIONS" "/api/soaps/3944ab7e-5be6-4284-091f-08dad9693d5b" responded 204 in 1.1154 ms 104 | 12/09/2022 01:18:30 +01:00 HTTP "DELETE" "/api/soaps/3944ab7e-5be6-4284-091f-08dad9693d5b" responded 200 in 90.5854 ms 105 | 12/09/2022 01:18:31 +01:00 HTTP "OPTIONS" "/api/soaps/146ad7a3-12b6-4d25-091e-08dad9693d5b" responded 204 in 0.8602 ms 106 | 12/09/2022 01:18:32 +01:00 HTTP "DELETE" "/api/soaps/146ad7a3-12b6-4d25-091e-08dad9693d5b" responded 200 in 71.7995 ms 107 | 12/09/2022 01:18:45 +01:00 Application is starting 108 | 12/09/2022 01:18:49 +01:00 HTTP "GET" "/swagger" responded 302 in 71.2008 ms 109 | 12/09/2022 01:18:49 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 266.2446 ms 110 | 12/09/2022 01:18:49 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 48.6887 ms 111 | 12/09/2022 01:18:49 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 48.9039 ms 112 | 12/09/2022 01:18:49 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 48.9418 ms 113 | 12/09/2022 01:18:50 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 795.1755 ms 114 | 12/09/2022 01:19:32 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 39.8699 ms 115 | 12/09/2022 01:19:33 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 643.7539 ms 116 | 12/09/2022 01:19:36 +01:00 HTTP "GET" "/api/soaps" responded 200 in 390.6769 ms 117 | 12/09/2022 01:19:49 +01:00 HTTP "OPTIONS" "/api/soaps/80291510-04b6-4674-ea0c-08dad97af143" responded 204 in 1.7393 ms 118 | 12/09/2022 01:19:49 +01:00 HTTP "DELETE" "/api/soaps/80291510-04b6-4674-ea0c-08dad97af143" responded 200 in 350.4012 ms 119 | 12/09/2022 01:19:51 +01:00 HTTP "OPTIONS" "/api/soaps/f274de95-617b-4853-ea0d-08dad97af143" responded 204 in 2.0896 ms 120 | 12/09/2022 01:19:51 +01:00 HTTP "DELETE" "/api/soaps/f274de95-617b-4853-ea0d-08dad97af143" responded 200 in 39.0143 ms 121 | 12/09/2022 01:19:52 +01:00 HTTP "OPTIONS" "/api/soaps/a0420b16-6dc9-4814-ea0e-08dad97af143" responded 204 in 1.6985 ms 122 | 12/09/2022 01:19:52 +01:00 HTTP "DELETE" "/api/soaps/a0420b16-6dc9-4814-ea0e-08dad97af143" responded 200 in 90.9983 ms 123 | 12/09/2022 01:22:12 +01:00 Application is starting 124 | 12/09/2022 01:22:16 +01:00 HTTP "GET" "/swagger" responded 302 in 79.7484 ms 125 | 12/09/2022 01:22:16 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 260.6743 ms 126 | 12/09/2022 01:22:16 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 53.5819 ms 127 | 12/09/2022 01:22:16 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 53.5405 ms 128 | 12/09/2022 01:22:16 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 55.3886 ms 129 | 12/09/2022 01:22:17 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 881.6002 ms 130 | 12/09/2022 01:22:20 +01:00 HTTP "GET" "/api/soaps" responded 200 in 300.1814 ms 131 | 12/09/2022 01:49:15 +01:00 Application is starting 132 | 12/09/2022 01:49:19 +01:00 HTTP "GET" "/swagger" responded 302 in 74.0062 ms 133 | 12/09/2022 01:49:19 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 241.9837 ms 134 | 12/09/2022 01:49:20 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 53.0287 ms 135 | 12/09/2022 01:49:20 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 52.7231 ms 136 | 12/09/2022 01:49:20 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 53.0381 ms 137 | 12/09/2022 01:49:21 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 709.1719 ms 138 | 12/09/2022 01:50:07 +01:00 HTTP "GET" "/api/balms" responded 200 in 431.9337 ms 139 | 12/09/2022 01:50:09 +01:00 HTTP "GET" "/api/soaps" responded 200 in 289.4988 ms 140 | 12/09/2022 01:50:15 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 4.9255 ms 141 | 12/09/2022 01:50:15 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 584.5419 ms 142 | 12/09/2022 01:50:16 +01:00 HTTP "GET" "/api/soaps" responded 200 in 13.0885 ms 143 | 12/09/2022 01:50:19 +01:00 HTTP "OPTIONS" "/api/soaps/2fa0d1bd-0932-404f-7ec3-08dad97b6c9b" responded 204 in 0.9698 ms 144 | 12/09/2022 01:50:19 +01:00 HTTP "DELETE" "/api/soaps/2fa0d1bd-0932-404f-7ec3-08dad97b6c9b" responded 200 in 245.9339 ms 145 | 12/09/2022 01:50:21 +01:00 HTTP "OPTIONS" "/api/soaps/2e0a9dc1-6719-4c71-7ec2-08dad97b6c9b" responded 204 in 0.8591 ms 146 | 12/09/2022 01:50:21 +01:00 HTTP "DELETE" "/api/soaps/2e0a9dc1-6719-4c71-7ec2-08dad97b6c9b" responded 200 in 85.0612 ms 147 | 12/09/2022 01:50:22 +01:00 HTTP "OPTIONS" "/api/soaps/c18310f3-0d4a-4a9e-7ec1-08dad97b6c9b" responded 204 in 0.9214 ms 148 | 12/09/2022 01:50:22 +01:00 HTTP "DELETE" "/api/soaps/c18310f3-0d4a-4a9e-7ec1-08dad97b6c9b" responded 200 in 101.9597 ms 149 | 12/09/2022 01:50:23 +01:00 HTTP "GET" "/api/balms" responded 200 in 7.7168 ms 150 | 12/09/2022 01:50:26 +01:00 HTTP "GET" "/api/oils" responded 200 in 121.7575 ms 151 | 12/09/2022 01:50:36 +01:00 Application is starting 152 | 12/09/2022 01:50:40 +01:00 HTTP "GET" "/swagger" responded 302 in 74.4629 ms 153 | 12/09/2022 01:50:40 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 233.1627 ms 154 | 12/09/2022 01:50:40 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 51.0331 ms 155 | 12/09/2022 01:50:40 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 51.0382 ms 156 | 12/09/2022 01:50:40 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 52.6252 ms 157 | 12/09/2022 01:50:41 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 914.5669 ms 158 | 12/09/2022 01:50:46 +01:00 HTTP "GET" "/api/soaps" responded 200 in 334.3577 ms 159 | 12/09/2022 01:50:52 +01:00 HTTP "GET" "/api/balms" responded 200 in 232.1565 ms 160 | 12/09/2022 01:50:52 +01:00 HTTP "GET" "/api/oils" responded 200 in 162.8215 ms 161 | 12/09/2022 01:50:58 +01:00 HTTP "GET" "/api/oils" responded 200 in 7.4290 ms 162 | 12/09/2022 01:51:00 +01:00 HTTP "GET" "/api/balms" responded 200 in 12.6530 ms 163 | 12/09/2022 01:51:05 +01:00 HTTP "GET" "/api/soaps" responded 200 in 36.4332 ms 164 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.Data/Migrations/20221129220853_init db.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace CleanArchitectureWebAPI.Infrastructure.Data.Migrations 5 | { 6 | public partial class initdb : 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 | UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 30 | NormalizedUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 31 | Email = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 32 | NormalizedEmail = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), 33 | EmailConfirmed = table.Column(type: "bit", nullable: false), 34 | PasswordHash = table.Column(type: "nvarchar(max)", nullable: true), 35 | SecurityStamp = table.Column(type: "nvarchar(max)", nullable: true), 36 | ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true), 37 | PhoneNumber = table.Column(type: "nvarchar(max)", nullable: true), 38 | PhoneNumberConfirmed = table.Column(type: "bit", nullable: false), 39 | TwoFactorEnabled = table.Column(type: "bit", nullable: false), 40 | LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), 41 | LockoutEnabled = table.Column(type: "bit", nullable: false), 42 | AccessFailedCount = table.Column(type: "int", nullable: false) 43 | }, 44 | constraints: table => 45 | { 46 | table.PrimaryKey("PK_AspNetUsers", x => x.Id); 47 | }); 48 | 49 | migrationBuilder.CreateTable( 50 | name: "Balms", 51 | columns: table => new 52 | { 53 | Id = table.Column(type: "uniqueidentifier", nullable: false), 54 | Volume = table.Column(type: "int", nullable: false), 55 | CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), 56 | Created = table.Column(type: "datetime2", nullable: false), 57 | LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), 58 | LastModified = table.Column(type: "datetime2", nullable: false), 59 | Brand = table.Column(type: "nvarchar(max)", nullable: true), 60 | Description = table.Column(type: "nvarchar(max)", nullable: true), 61 | UnitPrice = table.Column(type: "int", nullable: false), 62 | UnitQuantity = table.Column(type: "int", nullable: false), 63 | URL = table.Column(type: "nvarchar(max)", nullable: true) 64 | }, 65 | constraints: table => 66 | { 67 | table.PrimaryKey("PK_Balms", x => x.Id); 68 | }); 69 | 70 | migrationBuilder.CreateTable( 71 | name: "Oils", 72 | columns: table => new 73 | { 74 | Id = table.Column(type: "uniqueidentifier", nullable: false), 75 | Scent = table.Column(type: "nvarchar(max)", nullable: true), 76 | LiquidVolume = table.Column(type: "int", nullable: false), 77 | CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), 78 | Created = table.Column(type: "datetime2", nullable: false), 79 | LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), 80 | LastModified = table.Column(type: "datetime2", nullable: false), 81 | Brand = table.Column(type: "nvarchar(max)", nullable: true), 82 | Description = table.Column(type: "nvarchar(max)", nullable: true), 83 | UnitPrice = table.Column(type: "int", nullable: false), 84 | UnitQuantity = table.Column(type: "int", nullable: false), 85 | URL = table.Column(type: "nvarchar(max)", nullable: true) 86 | }, 87 | constraints: table => 88 | { 89 | table.PrimaryKey("PK_Oils", x => x.Id); 90 | }); 91 | 92 | migrationBuilder.CreateTable( 93 | name: "Soaps", 94 | columns: table => new 95 | { 96 | Id = table.Column(type: "uniqueidentifier", nullable: false), 97 | Edition = table.Column(type: "nvarchar(max)", nullable: true), 98 | CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), 99 | Created = table.Column(type: "datetime2", nullable: false), 100 | LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), 101 | LastModified = table.Column(type: "datetime2", nullable: false), 102 | Brand = table.Column(type: "nvarchar(max)", nullable: true), 103 | Description = table.Column(type: "nvarchar(max)", nullable: true), 104 | UnitPrice = table.Column(type: "int", nullable: false), 105 | UnitQuantity = table.Column(type: "int", nullable: false), 106 | URL = table.Column(type: "nvarchar(max)", nullable: true) 107 | }, 108 | constraints: table => 109 | { 110 | table.PrimaryKey("PK_Soaps", x => x.Id); 111 | }); 112 | 113 | migrationBuilder.CreateTable( 114 | name: "AspNetRoleClaims", 115 | columns: table => new 116 | { 117 | Id = table.Column(type: "int", nullable: false) 118 | .Annotation("SqlServer:Identity", "1, 1"), 119 | RoleId = table.Column(type: "nvarchar(450)", nullable: false), 120 | ClaimType = table.Column(type: "nvarchar(max)", nullable: true), 121 | ClaimValue = table.Column(type: "nvarchar(max)", nullable: true) 122 | }, 123 | constraints: table => 124 | { 125 | table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); 126 | table.ForeignKey( 127 | name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", 128 | column: x => x.RoleId, 129 | principalTable: "AspNetRoles", 130 | principalColumn: "Id", 131 | onDelete: ReferentialAction.Cascade); 132 | }); 133 | 134 | migrationBuilder.CreateTable( 135 | name: "AspNetUserClaims", 136 | columns: table => new 137 | { 138 | Id = table.Column(type: "int", nullable: false) 139 | .Annotation("SqlServer:Identity", "1, 1"), 140 | UserId = table.Column(type: "nvarchar(450)", nullable: false), 141 | ClaimType = table.Column(type: "nvarchar(max)", nullable: true), 142 | ClaimValue = table.Column(type: "nvarchar(max)", nullable: true) 143 | }, 144 | constraints: table => 145 | { 146 | table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); 147 | table.ForeignKey( 148 | name: "FK_AspNetUserClaims_AspNetUsers_UserId", 149 | column: x => x.UserId, 150 | principalTable: "AspNetUsers", 151 | principalColumn: "Id", 152 | onDelete: ReferentialAction.Cascade); 153 | }); 154 | 155 | migrationBuilder.CreateTable( 156 | name: "AspNetUserLogins", 157 | columns: table => new 158 | { 159 | LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), 160 | ProviderKey = table.Column(type: "nvarchar(450)", nullable: false), 161 | ProviderDisplayName = table.Column(type: "nvarchar(max)", nullable: true), 162 | UserId = table.Column(type: "nvarchar(450)", nullable: false) 163 | }, 164 | constraints: table => 165 | { 166 | table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); 167 | table.ForeignKey( 168 | name: "FK_AspNetUserLogins_AspNetUsers_UserId", 169 | column: x => x.UserId, 170 | principalTable: "AspNetUsers", 171 | principalColumn: "Id", 172 | onDelete: ReferentialAction.Cascade); 173 | }); 174 | 175 | migrationBuilder.CreateTable( 176 | name: "AspNetUserRoles", 177 | columns: table => new 178 | { 179 | UserId = table.Column(type: "nvarchar(450)", nullable: false), 180 | RoleId = table.Column(type: "nvarchar(450)", nullable: false) 181 | }, 182 | constraints: table => 183 | { 184 | table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); 185 | table.ForeignKey( 186 | name: "FK_AspNetUserRoles_AspNetRoles_RoleId", 187 | column: x => x.RoleId, 188 | principalTable: "AspNetRoles", 189 | principalColumn: "Id", 190 | onDelete: ReferentialAction.Cascade); 191 | table.ForeignKey( 192 | name: "FK_AspNetUserRoles_AspNetUsers_UserId", 193 | column: x => x.UserId, 194 | principalTable: "AspNetUsers", 195 | principalColumn: "Id", 196 | onDelete: ReferentialAction.Cascade); 197 | }); 198 | 199 | migrationBuilder.CreateTable( 200 | name: "AspNetUserTokens", 201 | columns: table => new 202 | { 203 | UserId = table.Column(type: "nvarchar(450)", nullable: false), 204 | LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), 205 | Name = table.Column(type: "nvarchar(450)", nullable: false), 206 | Value = table.Column(type: "nvarchar(max)", nullable: true) 207 | }, 208 | constraints: table => 209 | { 210 | table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); 211 | table.ForeignKey( 212 | name: "FK_AspNetUserTokens_AspNetUsers_UserId", 213 | column: x => x.UserId, 214 | principalTable: "AspNetUsers", 215 | principalColumn: "Id", 216 | onDelete: ReferentialAction.Cascade); 217 | }); 218 | 219 | migrationBuilder.CreateIndex( 220 | name: "IX_AspNetRoleClaims_RoleId", 221 | table: "AspNetRoleClaims", 222 | column: "RoleId"); 223 | 224 | migrationBuilder.CreateIndex( 225 | name: "RoleNameIndex", 226 | table: "AspNetRoles", 227 | column: "NormalizedName", 228 | unique: true, 229 | filter: "[NormalizedName] IS NOT NULL"); 230 | 231 | migrationBuilder.CreateIndex( 232 | name: "IX_AspNetUserClaims_UserId", 233 | table: "AspNetUserClaims", 234 | column: "UserId"); 235 | 236 | migrationBuilder.CreateIndex( 237 | name: "IX_AspNetUserLogins_UserId", 238 | table: "AspNetUserLogins", 239 | column: "UserId"); 240 | 241 | migrationBuilder.CreateIndex( 242 | name: "IX_AspNetUserRoles_RoleId", 243 | table: "AspNetUserRoles", 244 | column: "RoleId"); 245 | 246 | migrationBuilder.CreateIndex( 247 | name: "EmailIndex", 248 | table: "AspNetUsers", 249 | column: "NormalizedEmail"); 250 | 251 | migrationBuilder.CreateIndex( 252 | name: "UserNameIndex", 253 | table: "AspNetUsers", 254 | column: "NormalizedUserName", 255 | unique: true, 256 | filter: "[NormalizedUserName] IS NOT NULL"); 257 | } 258 | 259 | protected override void Down(MigrationBuilder migrationBuilder) 260 | { 261 | migrationBuilder.DropTable( 262 | name: "AspNetRoleClaims"); 263 | 264 | migrationBuilder.DropTable( 265 | name: "AspNetUserClaims"); 266 | 267 | migrationBuilder.DropTable( 268 | name: "AspNetUserLogins"); 269 | 270 | migrationBuilder.DropTable( 271 | name: "AspNetUserRoles"); 272 | 273 | migrationBuilder.DropTable( 274 | name: "AspNetUserTokens"); 275 | 276 | migrationBuilder.DropTable( 277 | name: "Balms"); 278 | 279 | migrationBuilder.DropTable( 280 | name: "Oils"); 281 | 282 | migrationBuilder.DropTable( 283 | name: "Soaps"); 284 | 285 | migrationBuilder.DropTable( 286 | name: "AspNetRoles"); 287 | 288 | migrationBuilder.DropTable( 289 | name: "AspNetUsers"); 290 | } 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.Data/Migrations/LibraryDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using CleanArchitectureWebAPI.Infrastructure.Data.Context; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | namespace CleanArchitectureWebAPI.Infrastructure.Data.Migrations 10 | { 11 | [DbContext(typeof(LibraryDbContext))] 12 | partial class LibraryDbContextModelSnapshot : 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.0"); 21 | 22 | modelBuilder.Entity("CleanArchitectureWebAPI.Domian.Models.Balm", b => 23 | { 24 | b.Property("Id") 25 | .ValueGeneratedOnAdd() 26 | .HasColumnType("uniqueidentifier"); 27 | 28 | b.Property("Brand") 29 | .HasColumnType("nvarchar(max)"); 30 | 31 | b.Property("Created") 32 | .HasColumnType("datetime2"); 33 | 34 | b.Property("CreatedBy") 35 | .HasColumnType("nvarchar(max)"); 36 | 37 | b.Property("Description") 38 | .HasColumnType("nvarchar(max)"); 39 | 40 | b.Property("LastModified") 41 | .HasColumnType("datetime2"); 42 | 43 | b.Property("LastModifiedBy") 44 | .HasColumnType("nvarchar(max)"); 45 | 46 | b.Property("URL") 47 | .HasColumnType("nvarchar(max)"); 48 | 49 | b.Property("UnitPrice") 50 | .HasColumnType("int"); 51 | 52 | b.Property("UnitQuantity") 53 | .HasColumnType("int"); 54 | 55 | b.Property("Volume") 56 | .HasColumnType("int"); 57 | 58 | b.HasKey("Id"); 59 | 60 | b.ToTable("Balms"); 61 | }); 62 | 63 | modelBuilder.Entity("CleanArchitectureWebAPI.Domian.Models.Oil", b => 64 | { 65 | b.Property("Id") 66 | .ValueGeneratedOnAdd() 67 | .HasColumnType("uniqueidentifier"); 68 | 69 | b.Property("Brand") 70 | .HasColumnType("nvarchar(max)"); 71 | 72 | b.Property("Created") 73 | .HasColumnType("datetime2"); 74 | 75 | b.Property("CreatedBy") 76 | .HasColumnType("nvarchar(max)"); 77 | 78 | b.Property("Description") 79 | .HasColumnType("nvarchar(max)"); 80 | 81 | b.Property("LastModified") 82 | .HasColumnType("datetime2"); 83 | 84 | b.Property("LastModifiedBy") 85 | .HasColumnType("nvarchar(max)"); 86 | 87 | b.Property("LiquidVolume") 88 | .HasColumnType("int"); 89 | 90 | b.Property("Scent") 91 | .HasColumnType("nvarchar(max)"); 92 | 93 | b.Property("URL") 94 | .HasColumnType("nvarchar(max)"); 95 | 96 | b.Property("UnitPrice") 97 | .HasColumnType("int"); 98 | 99 | b.Property("UnitQuantity") 100 | .HasColumnType("int"); 101 | 102 | b.HasKey("Id"); 103 | 104 | b.ToTable("Oils"); 105 | }); 106 | 107 | modelBuilder.Entity("CleanArchitectureWebAPI.Domian.Models.Soap", b => 108 | { 109 | b.Property("Id") 110 | .ValueGeneratedOnAdd() 111 | .HasColumnType("uniqueidentifier"); 112 | 113 | b.Property("Brand") 114 | .HasColumnType("nvarchar(max)"); 115 | 116 | b.Property("Created") 117 | .HasColumnType("datetime2"); 118 | 119 | b.Property("CreatedBy") 120 | .HasColumnType("nvarchar(max)"); 121 | 122 | b.Property("Description") 123 | .HasColumnType("nvarchar(max)"); 124 | 125 | b.Property("Edition") 126 | .HasColumnType("nvarchar(max)"); 127 | 128 | b.Property("LastModified") 129 | .HasColumnType("datetime2"); 130 | 131 | b.Property("LastModifiedBy") 132 | .HasColumnType("nvarchar(max)"); 133 | 134 | b.Property("URL") 135 | .HasColumnType("nvarchar(max)"); 136 | 137 | b.Property("UnitPrice") 138 | .HasColumnType("int"); 139 | 140 | b.Property("UnitQuantity") 141 | .HasColumnType("int"); 142 | 143 | b.HasKey("Id"); 144 | 145 | b.ToTable("Soaps"); 146 | }); 147 | 148 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 149 | { 150 | b.Property("Id") 151 | .HasColumnType("nvarchar(450)"); 152 | 153 | b.Property("ConcurrencyStamp") 154 | .IsConcurrencyToken() 155 | .HasColumnType("nvarchar(max)"); 156 | 157 | b.Property("Name") 158 | .HasMaxLength(256) 159 | .HasColumnType("nvarchar(256)"); 160 | 161 | b.Property("NormalizedName") 162 | .HasMaxLength(256) 163 | .HasColumnType("nvarchar(256)"); 164 | 165 | b.HasKey("Id"); 166 | 167 | b.HasIndex("NormalizedName") 168 | .IsUnique() 169 | .HasDatabaseName("RoleNameIndex") 170 | .HasFilter("[NormalizedName] IS NOT NULL"); 171 | 172 | b.ToTable("AspNetRoles"); 173 | }); 174 | 175 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 176 | { 177 | b.Property("Id") 178 | .ValueGeneratedOnAdd() 179 | .HasColumnType("int") 180 | .UseIdentityColumn(); 181 | 182 | b.Property("ClaimType") 183 | .HasColumnType("nvarchar(max)"); 184 | 185 | b.Property("ClaimValue") 186 | .HasColumnType("nvarchar(max)"); 187 | 188 | b.Property("RoleId") 189 | .IsRequired() 190 | .HasColumnType("nvarchar(450)"); 191 | 192 | b.HasKey("Id"); 193 | 194 | b.HasIndex("RoleId"); 195 | 196 | b.ToTable("AspNetRoleClaims"); 197 | }); 198 | 199 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => 200 | { 201 | b.Property("Id") 202 | .HasColumnType("nvarchar(450)"); 203 | 204 | b.Property("AccessFailedCount") 205 | .HasColumnType("int"); 206 | 207 | b.Property("ConcurrencyStamp") 208 | .IsConcurrencyToken() 209 | .HasColumnType("nvarchar(max)"); 210 | 211 | b.Property("Email") 212 | .HasMaxLength(256) 213 | .HasColumnType("nvarchar(256)"); 214 | 215 | b.Property("EmailConfirmed") 216 | .HasColumnType("bit"); 217 | 218 | b.Property("LockoutEnabled") 219 | .HasColumnType("bit"); 220 | 221 | b.Property("LockoutEnd") 222 | .HasColumnType("datetimeoffset"); 223 | 224 | b.Property("NormalizedEmail") 225 | .HasMaxLength(256) 226 | .HasColumnType("nvarchar(256)"); 227 | 228 | b.Property("NormalizedUserName") 229 | .HasMaxLength(256) 230 | .HasColumnType("nvarchar(256)"); 231 | 232 | b.Property("PasswordHash") 233 | .HasColumnType("nvarchar(max)"); 234 | 235 | b.Property("PhoneNumber") 236 | .HasColumnType("nvarchar(max)"); 237 | 238 | b.Property("PhoneNumberConfirmed") 239 | .HasColumnType("bit"); 240 | 241 | b.Property("SecurityStamp") 242 | .HasColumnType("nvarchar(max)"); 243 | 244 | b.Property("TwoFactorEnabled") 245 | .HasColumnType("bit"); 246 | 247 | b.Property("UserName") 248 | .HasMaxLength(256) 249 | .HasColumnType("nvarchar(256)"); 250 | 251 | b.HasKey("Id"); 252 | 253 | b.HasIndex("NormalizedEmail") 254 | .HasDatabaseName("EmailIndex"); 255 | 256 | b.HasIndex("NormalizedUserName") 257 | .IsUnique() 258 | .HasDatabaseName("UserNameIndex") 259 | .HasFilter("[NormalizedUserName] IS NOT NULL"); 260 | 261 | b.ToTable("AspNetUsers"); 262 | }); 263 | 264 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 265 | { 266 | b.Property("Id") 267 | .ValueGeneratedOnAdd() 268 | .HasColumnType("int") 269 | .UseIdentityColumn(); 270 | 271 | b.Property("ClaimType") 272 | .HasColumnType("nvarchar(max)"); 273 | 274 | b.Property("ClaimValue") 275 | .HasColumnType("nvarchar(max)"); 276 | 277 | b.Property("UserId") 278 | .IsRequired() 279 | .HasColumnType("nvarchar(450)"); 280 | 281 | b.HasKey("Id"); 282 | 283 | b.HasIndex("UserId"); 284 | 285 | b.ToTable("AspNetUserClaims"); 286 | }); 287 | 288 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 289 | { 290 | b.Property("LoginProvider") 291 | .HasColumnType("nvarchar(450)"); 292 | 293 | b.Property("ProviderKey") 294 | .HasColumnType("nvarchar(450)"); 295 | 296 | b.Property("ProviderDisplayName") 297 | .HasColumnType("nvarchar(max)"); 298 | 299 | b.Property("UserId") 300 | .IsRequired() 301 | .HasColumnType("nvarchar(450)"); 302 | 303 | b.HasKey("LoginProvider", "ProviderKey"); 304 | 305 | b.HasIndex("UserId"); 306 | 307 | b.ToTable("AspNetUserLogins"); 308 | }); 309 | 310 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 311 | { 312 | b.Property("UserId") 313 | .HasColumnType("nvarchar(450)"); 314 | 315 | b.Property("RoleId") 316 | .HasColumnType("nvarchar(450)"); 317 | 318 | b.HasKey("UserId", "RoleId"); 319 | 320 | b.HasIndex("RoleId"); 321 | 322 | b.ToTable("AspNetUserRoles"); 323 | }); 324 | 325 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 326 | { 327 | b.Property("UserId") 328 | .HasColumnType("nvarchar(450)"); 329 | 330 | b.Property("LoginProvider") 331 | .HasColumnType("nvarchar(450)"); 332 | 333 | b.Property("Name") 334 | .HasColumnType("nvarchar(450)"); 335 | 336 | b.Property("Value") 337 | .HasColumnType("nvarchar(max)"); 338 | 339 | b.HasKey("UserId", "LoginProvider", "Name"); 340 | 341 | b.ToTable("AspNetUserTokens"); 342 | }); 343 | 344 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 345 | { 346 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 347 | .WithMany() 348 | .HasForeignKey("RoleId") 349 | .OnDelete(DeleteBehavior.Cascade) 350 | .IsRequired(); 351 | }); 352 | 353 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 354 | { 355 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 356 | .WithMany() 357 | .HasForeignKey("UserId") 358 | .OnDelete(DeleteBehavior.Cascade) 359 | .IsRequired(); 360 | }); 361 | 362 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 363 | { 364 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 365 | .WithMany() 366 | .HasForeignKey("UserId") 367 | .OnDelete(DeleteBehavior.Cascade) 368 | .IsRequired(); 369 | }); 370 | 371 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 372 | { 373 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 374 | .WithMany() 375 | .HasForeignKey("RoleId") 376 | .OnDelete(DeleteBehavior.Cascade) 377 | .IsRequired(); 378 | 379 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 380 | .WithMany() 381 | .HasForeignKey("UserId") 382 | .OnDelete(DeleteBehavior.Cascade) 383 | .IsRequired(); 384 | }); 385 | 386 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 387 | { 388 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 389 | .WithMany() 390 | .HasForeignKey("UserId") 391 | .OnDelete(DeleteBehavior.Cascade) 392 | .IsRequired(); 393 | }); 394 | #pragma warning restore 612, 618 395 | } 396 | } 397 | } 398 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.Infrastructure.Data/Migrations/20221129220853_init db.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using CleanArchitectureWebAPI.Infrastructure.Data.Context; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | using Microsoft.EntityFrameworkCore.Migrations; 8 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 9 | 10 | namespace CleanArchitectureWebAPI.Infrastructure.Data.Migrations 11 | { 12 | [DbContext(typeof(LibraryDbContext))] 13 | [Migration("20221129220853_init db")] 14 | partial class initdb 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.0"); 23 | 24 | modelBuilder.Entity("CleanArchitectureWebAPI.Domian.Models.Balm", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("uniqueidentifier"); 29 | 30 | b.Property("Brand") 31 | .HasColumnType("nvarchar(max)"); 32 | 33 | b.Property("Created") 34 | .HasColumnType("datetime2"); 35 | 36 | b.Property("CreatedBy") 37 | .HasColumnType("nvarchar(max)"); 38 | 39 | b.Property("Description") 40 | .HasColumnType("nvarchar(max)"); 41 | 42 | b.Property("LastModified") 43 | .HasColumnType("datetime2"); 44 | 45 | b.Property("LastModifiedBy") 46 | .HasColumnType("nvarchar(max)"); 47 | 48 | b.Property("URL") 49 | .HasColumnType("nvarchar(max)"); 50 | 51 | b.Property("UnitPrice") 52 | .HasColumnType("int"); 53 | 54 | b.Property("UnitQuantity") 55 | .HasColumnType("int"); 56 | 57 | b.Property("Volume") 58 | .HasColumnType("int"); 59 | 60 | b.HasKey("Id"); 61 | 62 | b.ToTable("Balms"); 63 | }); 64 | 65 | modelBuilder.Entity("CleanArchitectureWebAPI.Domian.Models.Oil", b => 66 | { 67 | b.Property("Id") 68 | .ValueGeneratedOnAdd() 69 | .HasColumnType("uniqueidentifier"); 70 | 71 | b.Property("Brand") 72 | .HasColumnType("nvarchar(max)"); 73 | 74 | b.Property("Created") 75 | .HasColumnType("datetime2"); 76 | 77 | b.Property("CreatedBy") 78 | .HasColumnType("nvarchar(max)"); 79 | 80 | b.Property("Description") 81 | .HasColumnType("nvarchar(max)"); 82 | 83 | b.Property("LastModified") 84 | .HasColumnType("datetime2"); 85 | 86 | b.Property("LastModifiedBy") 87 | .HasColumnType("nvarchar(max)"); 88 | 89 | b.Property("LiquidVolume") 90 | .HasColumnType("int"); 91 | 92 | b.Property("Scent") 93 | .HasColumnType("nvarchar(max)"); 94 | 95 | b.Property("URL") 96 | .HasColumnType("nvarchar(max)"); 97 | 98 | b.Property("UnitPrice") 99 | .HasColumnType("int"); 100 | 101 | b.Property("UnitQuantity") 102 | .HasColumnType("int"); 103 | 104 | b.HasKey("Id"); 105 | 106 | b.ToTable("Oils"); 107 | }); 108 | 109 | modelBuilder.Entity("CleanArchitectureWebAPI.Domian.Models.Soap", b => 110 | { 111 | b.Property("Id") 112 | .ValueGeneratedOnAdd() 113 | .HasColumnType("uniqueidentifier"); 114 | 115 | b.Property("Brand") 116 | .HasColumnType("nvarchar(max)"); 117 | 118 | b.Property("Created") 119 | .HasColumnType("datetime2"); 120 | 121 | b.Property("CreatedBy") 122 | .HasColumnType("nvarchar(max)"); 123 | 124 | b.Property("Description") 125 | .HasColumnType("nvarchar(max)"); 126 | 127 | b.Property("Edition") 128 | .HasColumnType("nvarchar(max)"); 129 | 130 | b.Property("LastModified") 131 | .HasColumnType("datetime2"); 132 | 133 | b.Property("LastModifiedBy") 134 | .HasColumnType("nvarchar(max)"); 135 | 136 | b.Property("URL") 137 | .HasColumnType("nvarchar(max)"); 138 | 139 | b.Property("UnitPrice") 140 | .HasColumnType("int"); 141 | 142 | b.Property("UnitQuantity") 143 | .HasColumnType("int"); 144 | 145 | b.HasKey("Id"); 146 | 147 | b.ToTable("Soaps"); 148 | }); 149 | 150 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => 151 | { 152 | b.Property("Id") 153 | .HasColumnType("nvarchar(450)"); 154 | 155 | b.Property("ConcurrencyStamp") 156 | .IsConcurrencyToken() 157 | .HasColumnType("nvarchar(max)"); 158 | 159 | b.Property("Name") 160 | .HasMaxLength(256) 161 | .HasColumnType("nvarchar(256)"); 162 | 163 | b.Property("NormalizedName") 164 | .HasMaxLength(256) 165 | .HasColumnType("nvarchar(256)"); 166 | 167 | b.HasKey("Id"); 168 | 169 | b.HasIndex("NormalizedName") 170 | .IsUnique() 171 | .HasDatabaseName("RoleNameIndex") 172 | .HasFilter("[NormalizedName] IS NOT NULL"); 173 | 174 | b.ToTable("AspNetRoles"); 175 | }); 176 | 177 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 178 | { 179 | b.Property("Id") 180 | .ValueGeneratedOnAdd() 181 | .HasColumnType("int") 182 | .UseIdentityColumn(); 183 | 184 | b.Property("ClaimType") 185 | .HasColumnType("nvarchar(max)"); 186 | 187 | b.Property("ClaimValue") 188 | .HasColumnType("nvarchar(max)"); 189 | 190 | b.Property("RoleId") 191 | .IsRequired() 192 | .HasColumnType("nvarchar(450)"); 193 | 194 | b.HasKey("Id"); 195 | 196 | b.HasIndex("RoleId"); 197 | 198 | b.ToTable("AspNetRoleClaims"); 199 | }); 200 | 201 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => 202 | { 203 | b.Property("Id") 204 | .HasColumnType("nvarchar(450)"); 205 | 206 | b.Property("AccessFailedCount") 207 | .HasColumnType("int"); 208 | 209 | b.Property("ConcurrencyStamp") 210 | .IsConcurrencyToken() 211 | .HasColumnType("nvarchar(max)"); 212 | 213 | b.Property("Email") 214 | .HasMaxLength(256) 215 | .HasColumnType("nvarchar(256)"); 216 | 217 | b.Property("EmailConfirmed") 218 | .HasColumnType("bit"); 219 | 220 | b.Property("LockoutEnabled") 221 | .HasColumnType("bit"); 222 | 223 | b.Property("LockoutEnd") 224 | .HasColumnType("datetimeoffset"); 225 | 226 | b.Property("NormalizedEmail") 227 | .HasMaxLength(256) 228 | .HasColumnType("nvarchar(256)"); 229 | 230 | b.Property("NormalizedUserName") 231 | .HasMaxLength(256) 232 | .HasColumnType("nvarchar(256)"); 233 | 234 | b.Property("PasswordHash") 235 | .HasColumnType("nvarchar(max)"); 236 | 237 | b.Property("PhoneNumber") 238 | .HasColumnType("nvarchar(max)"); 239 | 240 | b.Property("PhoneNumberConfirmed") 241 | .HasColumnType("bit"); 242 | 243 | b.Property("SecurityStamp") 244 | .HasColumnType("nvarchar(max)"); 245 | 246 | b.Property("TwoFactorEnabled") 247 | .HasColumnType("bit"); 248 | 249 | b.Property("UserName") 250 | .HasMaxLength(256) 251 | .HasColumnType("nvarchar(256)"); 252 | 253 | b.HasKey("Id"); 254 | 255 | b.HasIndex("NormalizedEmail") 256 | .HasDatabaseName("EmailIndex"); 257 | 258 | b.HasIndex("NormalizedUserName") 259 | .IsUnique() 260 | .HasDatabaseName("UserNameIndex") 261 | .HasFilter("[NormalizedUserName] IS NOT NULL"); 262 | 263 | b.ToTable("AspNetUsers"); 264 | }); 265 | 266 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 267 | { 268 | b.Property("Id") 269 | .ValueGeneratedOnAdd() 270 | .HasColumnType("int") 271 | .UseIdentityColumn(); 272 | 273 | b.Property("ClaimType") 274 | .HasColumnType("nvarchar(max)"); 275 | 276 | b.Property("ClaimValue") 277 | .HasColumnType("nvarchar(max)"); 278 | 279 | b.Property("UserId") 280 | .IsRequired() 281 | .HasColumnType("nvarchar(450)"); 282 | 283 | b.HasKey("Id"); 284 | 285 | b.HasIndex("UserId"); 286 | 287 | b.ToTable("AspNetUserClaims"); 288 | }); 289 | 290 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 291 | { 292 | b.Property("LoginProvider") 293 | .HasColumnType("nvarchar(450)"); 294 | 295 | b.Property("ProviderKey") 296 | .HasColumnType("nvarchar(450)"); 297 | 298 | b.Property("ProviderDisplayName") 299 | .HasColumnType("nvarchar(max)"); 300 | 301 | b.Property("UserId") 302 | .IsRequired() 303 | .HasColumnType("nvarchar(450)"); 304 | 305 | b.HasKey("LoginProvider", "ProviderKey"); 306 | 307 | b.HasIndex("UserId"); 308 | 309 | b.ToTable("AspNetUserLogins"); 310 | }); 311 | 312 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 313 | { 314 | b.Property("UserId") 315 | .HasColumnType("nvarchar(450)"); 316 | 317 | b.Property("RoleId") 318 | .HasColumnType("nvarchar(450)"); 319 | 320 | b.HasKey("UserId", "RoleId"); 321 | 322 | b.HasIndex("RoleId"); 323 | 324 | b.ToTable("AspNetUserRoles"); 325 | }); 326 | 327 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 328 | { 329 | b.Property("UserId") 330 | .HasColumnType("nvarchar(450)"); 331 | 332 | b.Property("LoginProvider") 333 | .HasColumnType("nvarchar(450)"); 334 | 335 | b.Property("Name") 336 | .HasColumnType("nvarchar(450)"); 337 | 338 | b.Property("Value") 339 | .HasColumnType("nvarchar(max)"); 340 | 341 | b.HasKey("UserId", "LoginProvider", "Name"); 342 | 343 | b.ToTable("AspNetUserTokens"); 344 | }); 345 | 346 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => 347 | { 348 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 349 | .WithMany() 350 | .HasForeignKey("RoleId") 351 | .OnDelete(DeleteBehavior.Cascade) 352 | .IsRequired(); 353 | }); 354 | 355 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => 356 | { 357 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 358 | .WithMany() 359 | .HasForeignKey("UserId") 360 | .OnDelete(DeleteBehavior.Cascade) 361 | .IsRequired(); 362 | }); 363 | 364 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => 365 | { 366 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 367 | .WithMany() 368 | .HasForeignKey("UserId") 369 | .OnDelete(DeleteBehavior.Cascade) 370 | .IsRequired(); 371 | }); 372 | 373 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => 374 | { 375 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) 376 | .WithMany() 377 | .HasForeignKey("RoleId") 378 | .OnDelete(DeleteBehavior.Cascade) 379 | .IsRequired(); 380 | 381 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 382 | .WithMany() 383 | .HasForeignKey("UserId") 384 | .OnDelete(DeleteBehavior.Cascade) 385 | .IsRequired(); 386 | }); 387 | 388 | modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => 389 | { 390 | b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) 391 | .WithMany() 392 | .HasForeignKey("UserId") 393 | .OnDelete(DeleteBehavior.Cascade) 394 | .IsRequired(); 395 | }); 396 | #pragma warning restore 612, 618 397 | } 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/Logs/log20221207.txt: -------------------------------------------------------------------------------- 1 | 12/07/2022 18:03:44 +01:00 Application is starting 2 | 12/07/2022 18:03:49 +01:00 HTTP "GET" "/swagger" responded 302 in 86.6612 ms 3 | 12/07/2022 18:03:49 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 322.9698 ms 4 | 12/07/2022 18:03:49 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 40.9553 ms 5 | 12/07/2022 18:03:49 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 40.3122 ms 6 | 12/07/2022 18:03:49 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 57.7726 ms 7 | 12/07/2022 18:03:50 +01:00 HTTP "GET" "/swagger/favicon-32x32.png" responded 200 in 0.6265 ms 8 | 12/07/2022 18:03:50 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 794.5260 ms 9 | 12/07/2022 18:05:29 +01:00 HTTP "GET" "/api/soaps" responded 200 in 551.8804 ms 10 | 12/07/2022 18:05:32 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 9.3480 ms 11 | 12/07/2022 18:05:33 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 560.4033 ms 12 | 12/07/2022 18:05:34 +01:00 HTTP "GET" "/api/soaps" responded 200 in 4.6569 ms 13 | 12/07/2022 18:06:03 +01:00 HTTP "GET" "/api/balms" responded 200 in 136.4115 ms 14 | 12/07/2022 18:06:04 +01:00 HTTP "GET" "/api/soaps" responded 200 in 3.9267 ms 15 | 12/07/2022 18:06:45 +01:00 HTTP "GET" "/api/soaps" responded 200 in 9.8078 ms 16 | 12/07/2022 18:06:49 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.7529 ms 17 | 12/07/2022 18:06:49 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 164.8767 ms 18 | 12/07/2022 18:06:50 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.7294 ms 19 | 12/07/2022 18:07:04 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 1.1268 ms 20 | 12/07/2022 18:07:04 +01:00 HTTP "POST" "/api/soaps" responded 200 in 250.4246 ms 21 | 12/07/2022 18:07:43 +01:00 HTTP "GET" "/api/soaps" responded 200 in 8.2106 ms 22 | 12/07/2022 18:09:12 +01:00 HTTP "GET" "/api/soaps" responded 200 in 8.4629 ms 23 | 12/07/2022 18:09:36 +01:00 HTTP "GET" "/api/soaps" responded 200 in 6.2646 ms 24 | 12/07/2022 18:10:08 +01:00 HTTP "GET" "/api/soaps" responded 200 in 4.4248 ms 25 | 12/07/2022 18:10:17 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.5881 ms 26 | 12/07/2022 18:10:17 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 182.8688 ms 27 | 12/07/2022 18:10:18 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.3777 ms 28 | 12/07/2022 18:10:37 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 1.1252 ms 29 | 12/07/2022 18:10:37 +01:00 HTTP "POST" "/api/soaps" responded 200 in 105.0115 ms 30 | 12/07/2022 18:10:56 +01:00 HTTP "GET" "/api/soaps" responded 200 in 7.3178 ms 31 | 12/07/2022 18:11:01 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.9267 ms 32 | 12/07/2022 18:20:53 +01:00 Application is starting 33 | 12/07/2022 18:20:56 +01:00 HTTP "GET" "/swagger" responded 302 in 108.2031 ms 34 | 12/07/2022 18:20:56 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 244.7200 ms 35 | 12/07/2022 18:20:56 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 58.8359 ms 36 | 12/07/2022 18:20:56 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 58.8609 ms 37 | 12/07/2022 18:20:56 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 58.8183 ms 38 | 12/07/2022 18:20:58 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 859.0026 ms 39 | 12/07/2022 18:23:31 +01:00 HTTP "GET" "/api/soaps" responded 200 in 422.4670 ms 40 | 12/07/2022 18:31:06 +01:00 HTTP "GET" "/api/soaps" responded 200 in 32.0518 ms 41 | 12/07/2022 22:22:01 +01:00 Application is starting 42 | 12/07/2022 22:22:06 +01:00 HTTP "GET" "/swagger" responded 302 in 87.8070 ms 43 | 12/07/2022 22:22:06 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 438.1698 ms 44 | 12/07/2022 22:22:06 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 34.2758 ms 45 | 12/07/2022 22:22:06 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 34.2595 ms 46 | 12/07/2022 22:22:06 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 50.4535 ms 47 | 12/07/2022 22:22:07 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 829.4728 ms 48 | 12/07/2022 22:31:33 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 74.7782 ms 49 | 12/07/2022 22:31:34 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 977.1721 ms 50 | 12/07/2022 22:31:36 +01:00 HTTP "GET" "/api/soaps" responded 200 in 321.3867 ms 51 | 12/07/2022 22:36:53 +01:00 HTTP "OPTIONS" "/api/account/signout" responded 204 in 1.4846 ms 52 | 12/07/2022 22:36:53 +01:00 HTTP "POST" "/api/account/signout" responded 204 in 41.5527 ms 53 | 12/07/2022 22:36:59 +01:00 HTTP "GET" "/api/soaps" responded 200 in 22.3061 ms 54 | 12/07/2022 22:38:08 +01:00 HTTP "GET" "/api/soaps" responded 200 in 9.8981 ms 55 | 12/07/2022 22:39:07 +01:00 Application is starting 56 | 12/07/2022 22:39:11 +01:00 HTTP "GET" "/swagger" responded 302 in 77.8150 ms 57 | 12/07/2022 22:39:11 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 275.5752 ms 58 | 12/07/2022 22:39:11 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 43.8910 ms 59 | 12/07/2022 22:39:11 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 43.9739 ms 60 | 12/07/2022 22:39:11 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 45.1806 ms 61 | 12/07/2022 22:39:12 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 824.7320 ms 62 | 12/07/2022 22:39:35 +01:00 HTTP "GET" "/api/soaps" responded 200 in 442.4601 ms 63 | 12/07/2022 22:44:43 +01:00 HTTP "GET" "/api/soaps" responded 200 in 23.0870 ms 64 | 12/07/2022 22:44:50 +01:00 HTTP "GET" "/api/balms" responded 200 in 221.0423 ms 65 | 12/07/2022 22:44:50 +01:00 HTTP "GET" "/api/soaps" responded 200 in 36.4716 ms 66 | 12/07/2022 22:45:18 +01:00 HTTP "GET" "/api/soaps" responded 200 in 49.2282 ms 67 | 12/07/2022 22:48:27 +01:00 HTTP "GET" "/api/soaps" responded 200 in 15.4472 ms 68 | 12/07/2022 22:49:40 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 11.5019 ms 69 | 12/07/2022 22:49:41 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 600.7842 ms 70 | 12/07/2022 22:49:41 +01:00 HTTP "GET" "/api/soaps" responded 200 in 25.4190 ms 71 | 12/07/2022 22:49:44 +01:00 HTTP "OPTIONS" "/api/soaps/29405e1f-2f54-4f93-e3fd-08dad7d0cf08" responded 204 in 0.7508 ms 72 | 12/07/2022 22:49:45 +01:00 HTTP "DELETE" "/api/soaps/29405e1f-2f54-4f93-e3fd-08dad7d0cf08" responded 200 in 449.5312 ms 73 | 12/07/2022 22:49:46 +01:00 HTTP "OPTIONS" "/api/soaps/6ba195c1-8a39-4fa8-e3fe-08dad7d0cf08" responded 204 in 0.7317 ms 74 | 12/07/2022 22:49:46 +01:00 HTTP "DELETE" "/api/soaps/6ba195c1-8a39-4fa8-e3fe-08dad7d0cf08" responded 200 in 31.9460 ms 75 | 12/07/2022 22:49:48 +01:00 HTTP "OPTIONS" "/api/soaps/354a61e0-43c2-4908-e3ff-08dad7d0cf08" responded 204 in 0.6960 ms 76 | 12/07/2022 22:49:48 +01:00 HTTP "DELETE" "/api/soaps/354a61e0-43c2-4908-e3ff-08dad7d0cf08" responded 200 in 80.4631 ms 77 | 12/07/2022 22:49:49 +01:00 HTTP "OPTIONS" "/api/soaps/d5e0f71d-5f6a-4b26-ac46-7011ef571752" responded 204 in 0.5162 ms 78 | 12/07/2022 22:49:49 +01:00 HTTP "DELETE" "/api/soaps/d5e0f71d-5f6a-4b26-ac46-7011ef571752" responded 200 in 25.0995 ms 79 | 12/07/2022 22:49:52 +01:00 HTTP "OPTIONS" "/api/soaps/c2492b82-24d8-412d-ae33-f6afb55a30e5" responded 204 in 0.4607 ms 80 | 12/07/2022 22:49:52 +01:00 HTTP "DELETE" "/api/soaps/c2492b82-24d8-412d-ae33-f6afb55a30e5" responded 200 in 76.7014 ms 81 | 12/07/2022 22:50:04 +01:00 Application is starting 82 | 12/07/2022 22:50:07 +01:00 HTTP "GET" "/swagger" responded 302 in 84.1396 ms 83 | 12/07/2022 22:50:07 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 240.6994 ms 84 | 12/07/2022 22:50:07 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 43.6902 ms 85 | 12/07/2022 22:50:07 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 43.6861 ms 86 | 12/07/2022 22:50:07 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 43.7014 ms 87 | 12/07/2022 22:50:08 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 705.4594 ms 88 | 12/07/2022 22:57:36 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 18.1526 ms 89 | 12/07/2022 22:57:36 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 481.6689 ms 90 | 12/07/2022 22:57:39 +01:00 HTTP "GET" "/api/soaps" responded 200 in 282.4160 ms 91 | 12/07/2022 22:58:11 +01:00 HTTP "GET" "/api/soaps" responded 200 in 16.7258 ms 92 | 12/07/2022 22:58:16 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 11.8199 ms 93 | 12/07/2022 22:58:16 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 154.4180 ms 94 | 12/07/2022 22:58:17 +01:00 HTTP "GET" "/api/soaps" responded 200 in 20.9893 ms 95 | 12/07/2022 22:59:27 +01:00 HTTP "GET" "/api/soaps" responded 200 in 17.6607 ms 96 | 12/07/2022 22:59:30 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.7846 ms 97 | 12/07/2022 22:59:32 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.3560 ms 98 | 12/07/2022 22:59:32 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 46.1054 ms 99 | 12/07/2022 22:59:33 +01:00 HTTP "GET" "/api/soaps" responded 200 in 7.2068 ms 100 | 12/07/2022 22:59:59 +01:00 HTTP "GET" "/api/soaps" responded 200 in 9.2832 ms 101 | 12/07/2022 23:00:03 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.7939 ms 102 | 12/07/2022 23:00:03 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 175.3255 ms 103 | 12/07/2022 23:00:04 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.7356 ms 104 | 12/07/2022 23:00:17 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.6745 ms 105 | 12/07/2022 23:00:19 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1737 ms 106 | 12/07/2022 23:00:19 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 39.7021 ms 107 | 12/07/2022 23:00:20 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.5599 ms 108 | 12/07/2022 23:00:59 +01:00 HTTP "GET" "/api/soaps" responded 200 in 29.2347 ms 109 | 12/07/2022 23:01:03 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.4085 ms 110 | 12/07/2022 23:01:03 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 118.9248 ms 111 | 12/07/2022 23:01:20 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.3735 ms 112 | 12/07/2022 23:03:04 +01:00 HTTP "GET" "/api/soaps" responded 200 in 10.9920 ms 113 | 12/07/2022 23:04:07 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.5945 ms 114 | 12/07/2022 23:04:07 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 196.8453 ms 115 | 12/07/2022 23:04:08 +01:00 HTTP "GET" "/api/soaps" responded 200 in 3.9520 ms 116 | 12/07/2022 23:04:28 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 1.1645 ms 117 | 12/07/2022 23:04:29 +01:00 HTTP "POST" "/api/soaps" responded 200 in 234.5010 ms 118 | 12/07/2022 23:06:05 +01:00 HTTP "GET" "/api/soaps" responded 200 in 26.2659 ms 119 | 12/07/2022 23:06:10 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1167 ms 120 | 12/07/2022 23:06:10 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 39.2089 ms 121 | 12/07/2022 23:06:11 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.5294 ms 122 | 12/07/2022 23:07:24 +01:00 HTTP "GET" "/api/balms" responded 200 in 209.3661 ms 123 | 12/07/2022 23:07:24 +01:00 HTTP "GET" "/api/soaps" responded 200 in 4.0043 ms 124 | 12/07/2022 23:09:07 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.8080 ms 125 | 12/07/2022 23:11:19 +01:00 HTTP "GET" "/api/soaps" responded 200 in 30.5688 ms 126 | 12/07/2022 23:11:22 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 1.1254 ms 127 | 12/07/2022 23:11:22 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 96.9709 ms 128 | 12/07/2022 23:11:23 +01:00 HTTP "GET" "/api/soaps" responded 200 in 3.7917 ms 129 | 12/07/2022 23:11:33 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 0.7247 ms 130 | 12/07/2022 23:11:33 +01:00 HTTP "POST" "/api/soaps" responded 200 in 57.2773 ms 131 | 12/07/2022 23:14:03 +01:00 HTTP "GET" "/api/soaps" responded 200 in 33.1199 ms 132 | 12/07/2022 23:14:04 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.7069 ms 133 | 12/07/2022 23:14:46 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0029 ms 134 | 12/07/2022 23:14:55 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.3879 ms 135 | 12/07/2022 23:14:55 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 114.8867 ms 136 | 12/07/2022 23:14:57 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.2734 ms 137 | 12/07/2022 23:15:30 +01:00 HTTP "GET" "/api/soaps" responded 200 in 10.9861 ms 138 | 12/07/2022 23:15:43 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.0900 ms 139 | 12/07/2022 23:15:43 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 31.3617 ms 140 | 12/07/2022 23:15:45 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5793 ms 141 | 12/07/2022 23:16:35 +01:00 HTTP "GET" "/api/soaps" responded 200 in 10.4297 ms 142 | 12/07/2022 23:16:38 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2084 ms 143 | 12/07/2022 23:16:38 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 117.6405 ms 144 | 12/07/2022 23:16:39 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5606 ms 145 | 12/07/2022 23:21:24 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1377 ms 146 | 12/07/2022 23:21:28 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1424 ms 147 | 12/07/2022 23:21:28 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 30.0174 ms 148 | 12/07/2022 23:21:28 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.3203 ms 149 | 12/07/2022 23:22:30 +01:00 HTTP "GET" "/api/soaps" responded 200 in 19.4234 ms 150 | 12/07/2022 23:26:01 +01:00 HTTP "GET" "/api/soaps" responded 200 in 13.8041 ms 151 | 12/07/2022 23:26:04 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 1.1906 ms 152 | 12/07/2022 23:26:04 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 33.2175 ms 153 | 12/07/2022 23:26:06 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0988 ms 154 | 12/07/2022 23:26:54 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.4217 ms 155 | 12/07/2022 23:26:59 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.4569 ms 156 | 12/07/2022 23:26:59 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 95.1900 ms 157 | 12/07/2022 23:27:01 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.7308 ms 158 | 12/07/2022 23:27:36 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.9855 ms 159 | 12/07/2022 23:27:41 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.5383 ms 160 | 12/07/2022 23:27:41 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 71.3001 ms 161 | 12/07/2022 23:27:45 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1341 ms 162 | 12/07/2022 23:28:21 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0095 ms 163 | 12/07/2022 23:28:25 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.3195 ms 164 | 12/07/2022 23:28:25 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 92.7927 ms 165 | 12/07/2022 23:28:26 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1967 ms 166 | 12/07/2022 23:28:47 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.4830 ms 167 | 12/07/2022 23:28:51 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1906 ms 168 | 12/07/2022 23:28:51 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 102.4479 ms 169 | 12/07/2022 23:28:52 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.7233 ms 170 | 12/07/2022 23:30:04 +01:00 HTTP "GET" "/api/soaps" responded 200 in 21.3624 ms 171 | 12/07/2022 23:30:10 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.6109 ms 172 | 12/07/2022 23:30:14 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2106 ms 173 | 12/07/2022 23:30:14 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 101.4332 ms 174 | 12/07/2022 23:30:15 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5423 ms 175 | 12/07/2022 23:31:24 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.7739 ms 176 | 12/07/2022 23:31:26 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1730 ms 177 | 12/07/2022 23:31:26 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 102.1630 ms 178 | 12/07/2022 23:31:27 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.8039 ms 179 | 12/07/2022 23:31:47 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5345 ms 180 | 12/07/2022 23:31:52 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1132 ms 181 | 12/07/2022 23:31:52 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 49.1865 ms 182 | 12/07/2022 23:31:53 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.7896 ms 183 | 12/07/2022 23:32:42 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.2431 ms 184 | 12/07/2022 23:32:47 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2168 ms 185 | 12/07/2022 23:32:47 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 127.4554 ms 186 | 12/07/2022 23:32:48 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.2145 ms 187 | 12/07/2022 23:33:52 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.8433 ms 188 | 12/07/2022 23:33:55 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1717 ms 189 | 12/07/2022 23:33:55 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 109.7207 ms 190 | 12/07/2022 23:33:57 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.2548 ms 191 | 12/07/2022 23:34:27 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 0.0796 ms 192 | 12/07/2022 23:34:27 +01:00 HTTP "POST" "/api/soaps" responded 200 in 51.8033 ms 193 | 12/07/2022 23:34:33 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.4698 ms 194 | 12/07/2022 23:34:37 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.4675 ms 195 | 12/07/2022 23:34:38 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 102.4065 ms 196 | 12/07/2022 23:34:39 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.6163 ms 197 | 12/07/2022 23:34:45 +01:00 HTTP "GET" "/api/balms" responded 200 in 3.1266 ms 198 | 12/07/2022 23:34:47 +01:00 HTTP "GET" "/api/oils" responded 200 in 111.8755 ms 199 | 12/07/2022 23:34:48 +01:00 HTTP "GET" "/api/oils" responded 200 in 1.6699 ms 200 | 12/07/2022 23:34:51 +01:00 HTTP "GET" "/api/balms" responded 200 in 6.7540 ms 201 | 12/07/2022 23:34:51 +01:00 HTTP "GET" "/api/oils" responded 200 in 5.2313 ms 202 | 12/07/2022 23:36:07 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0132 ms 203 | 12/07/2022 23:36:09 +01:00 HTTP "OPTIONS" "/api/account/signout" responded 204 in 0.1192 ms 204 | 12/07/2022 23:36:09 +01:00 HTTP "POST" "/api/account/signout" responded 204 in 29.2050 ms 205 | -------------------------------------------------------------------------------- /CleanArchitectureWebAPI.WebAPI/Logs/log20221202.txt: -------------------------------------------------------------------------------- 1 | 12/02/2022 18:17:19 +01:00 Application is starting 2 | 12/02/2022 18:17:24 +01:00 HTTP "GET" "/swagger" responded 302 in 104.3704 ms 3 | 12/02/2022 18:17:24 +01:00 HTTP "GET" "/swagger" responded 302 in 104.4601 ms 4 | 12/02/2022 18:17:24 +01:00 HTTP "GET" "/swagger" responded 302 in 103.5755 ms 5 | 12/02/2022 18:17:24 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 159.0960 ms 6 | 12/02/2022 18:17:24 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 89.6204 ms 7 | 12/02/2022 18:17:24 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 76.7441 ms 8 | 12/02/2022 18:17:24 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 90.5082 ms 9 | 12/02/2022 18:17:24 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js.map" responded 404 in 0.7941 ms 10 | 12/02/2022 18:17:24 +01:00 HTTP "GET" "/swagger/favicon-32x32.png" responded 200 in 1.1873 ms 11 | 12/02/2022 18:17:25 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js.map" responded 404 in 0.1135 ms 12 | 12/02/2022 18:17:25 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 938.2799 ms 13 | 12/02/2022 18:18:46 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 15.0087 ms 14 | 12/02/2022 18:18:47 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 611.2226 ms 15 | 12/02/2022 18:18:48 +01:00 HTTP "GET" "/api/soaps" responded 200 in 340.8900 ms 16 | 12/02/2022 18:36:36 +01:00 Application is starting 17 | 12/02/2022 18:36:40 +01:00 HTTP "GET" "/swagger" responded 302 in 96.2999 ms 18 | 12/02/2022 18:36:40 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 372.6341 ms 19 | 12/02/2022 18:36:40 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 36.3904 ms 20 | 12/02/2022 18:36:40 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 36.9243 ms 21 | 12/02/2022 18:36:40 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 39.3404 ms 22 | 12/02/2022 18:36:41 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 748.9905 ms 23 | 12/02/2022 18:36:55 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 22.6398 ms 24 | 12/02/2022 18:36:56 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 649.7622 ms 25 | 12/02/2022 18:36:57 +01:00 HTTP "GET" "/api/soaps" responded 200 in 269.1352 ms 26 | 12/02/2022 18:37:49 +01:00 HTTP "GET" "/api/soaps" responded 200 in 15.6331 ms 27 | 12/02/2022 18:38:15 +01:00 HTTP "GET" "/api/soaps" responded 200 in 12.7769 ms 28 | 12/02/2022 18:38:22 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.2992 ms 29 | 12/02/2022 18:39:30 +01:00 HTTP "GET" "/api/soaps" responded 200 in 36.0250 ms 30 | 12/02/2022 18:39:31 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 3.9832 ms 31 | 12/02/2022 18:39:31 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 241.7453 ms 32 | 12/02/2022 18:39:36 +01:00 HTTP "GET" "/api/soaps" responded 200 in 6.5098 ms 33 | 12/02/2022 18:40:11 +01:00 HTTP "GET" "/api/soaps" responded 200 in 8.3899 ms 34 | 12/02/2022 18:40:28 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.8750 ms 35 | 12/02/2022 18:40:58 +01:00 HTTP "GET" "/api/soaps" responded 200 in 7.7210 ms 36 | 12/02/2022 18:41:19 +01:00 HTTP "GET" "/api/soaps" responded 200 in 6.5725 ms 37 | 12/02/2022 18:42:51 +01:00 HTTP "GET" "/api/soaps" responded 200 in 9.1951 ms 38 | 12/02/2022 18:43:29 +01:00 HTTP "GET" "/api/soaps" responded 200 in 10.7975 ms 39 | 12/02/2022 18:43:52 +01:00 HTTP "GET" "/api/soaps" responded 200 in 25.0565 ms 40 | 12/02/2022 18:44:19 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.4552 ms 41 | 12/02/2022 18:44:19 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 230.9201 ms 42 | 12/02/2022 18:44:22 +01:00 HTTP "GET" "/api/soaps" responded 200 in 3.9697 ms 43 | 12/02/2022 18:45:24 +01:00 HTTP "GET" "/api/soaps" responded 200 in 13.8828 ms 44 | 12/02/2022 18:45:27 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.5041 ms 45 | 12/02/2022 18:45:27 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 92.4763 ms 46 | 12/02/2022 18:45:31 +01:00 HTTP "GET" "/api/soaps" responded 200 in 3.8224 ms 47 | 12/02/2022 18:46:15 +01:00 HTTP "GET" "/api/soaps" responded 200 in 8.6822 ms 48 | 12/02/2022 18:46:19 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.4337 ms 49 | 12/02/2022 18:46:19 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 155.0731 ms 50 | 12/02/2022 18:46:23 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.1401 ms 51 | 12/02/2022 18:49:15 +01:00 HTTP "GET" "/api/soaps" responded 200 in 13.2117 ms 52 | 12/02/2022 18:49:40 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 3.9789 ms 53 | 12/02/2022 18:49:40 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 200.7785 ms 54 | 12/02/2022 18:49:41 +01:00 HTTP "GET" "/api/soaps" responded 200 in 4.0891 ms 55 | 12/02/2022 18:50:16 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 2.6287 ms 56 | 12/02/2022 18:50:35 +01:00 HTTP "GET" "/api/soaps" responded 200 in 36.9880 ms 57 | 12/02/2022 18:50:35 +01:00 HTTP "GET" "/api/soaps" responded 200 in 7.5627 ms 58 | 12/02/2022 18:50:35 +01:00 HTTP "GET" "/api/balms" responded 200 in 169.1386 ms 59 | 12/02/2022 18:50:35 +01:00 HTTP "POST" "/api/soaps" responded 200 in 19037.2626 ms 60 | 12/02/2022 18:50:44 +01:00 HTTP "GET" "/api/balms" responded 200 in 1.5811 ms 61 | 12/02/2022 18:50:44 +01:00 HTTP "GET" "/api/soaps" responded 200 in 27.8329 ms 62 | 12/02/2022 18:50:47 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.3730 ms 63 | 12/02/2022 18:50:47 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 86.7934 ms 64 | 12/02/2022 18:50:48 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.6253 ms 65 | 12/02/2022 18:50:53 +01:00 HTTP "GET" "/api/balms" responded 200 in 9.5675 ms 66 | 12/02/2022 18:50:54 +01:00 HTTP "GET" "/api/balms" responded 200 in 1.0796 ms 67 | 12/02/2022 18:50:56 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.7974 ms 68 | 12/02/2022 18:51:12 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2435 ms 69 | 12/02/2022 18:51:12 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 99.4415 ms 70 | 12/02/2022 18:51:13 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.3677 ms 71 | 12/02/2022 18:51:23 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5891 ms 72 | 12/02/2022 18:52:50 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.8246 ms 73 | 12/02/2022 18:53:08 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.6161 ms 74 | 12/02/2022 18:53:30 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.9022 ms 75 | 12/02/2022 18:53:37 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 4.1327 ms 76 | 12/02/2022 18:53:37 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 94.1179 ms 77 | 12/02/2022 18:53:38 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0028 ms 78 | 12/02/2022 18:54:07 +01:00 HTTP "GET" "/api/balms" responded 200 in 2.4802 ms 79 | 12/02/2022 18:54:08 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.7041 ms 80 | 12/02/2022 18:55:42 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.9913 ms 81 | 12/02/2022 18:55:52 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.8993 ms 82 | 12/02/2022 18:56:10 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2265 ms 83 | 12/02/2022 18:56:10 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 139.8944 ms 84 | 12/02/2022 18:56:11 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.2733 ms 85 | 12/02/2022 19:00:27 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.5602 ms 86 | 12/02/2022 19:00:34 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.0688 ms 87 | 12/02/2022 19:01:02 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0532 ms 88 | 12/02/2022 19:01:04 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2679 ms 89 | 12/02/2022 19:01:04 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 133.1324 ms 90 | 12/02/2022 19:01:05 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0479 ms 91 | 12/02/2022 19:02:16 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1766 ms 92 | 12/02/2022 19:02:19 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.7949 ms 93 | 12/02/2022 19:02:19 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 91.2110 ms 94 | 12/02/2022 19:02:20 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1118 ms 95 | 12/02/2022 19:03:07 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5736 ms 96 | 12/02/2022 19:03:11 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1426 ms 97 | 12/02/2022 19:03:11 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 42.4009 ms 98 | 12/02/2022 19:03:12 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.8246 ms 99 | 12/02/2022 19:03:38 +01:00 HTTP "GET" "/api/soaps" responded 200 in 14.1866 ms 100 | 12/02/2022 19:04:07 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.7771 ms 101 | 12/02/2022 19:04:12 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.6977 ms 102 | 12/02/2022 19:04:12 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 89.6496 ms 103 | 12/02/2022 19:04:13 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.6515 ms 104 | 12/02/2022 19:05:04 +01:00 HTTP "GET" "/api/soaps" responded 200 in 10.0993 ms 105 | 12/02/2022 19:05:40 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.9126 ms 106 | 12/02/2022 19:05:48 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 1.4401 ms 107 | 12/02/2022 19:05:48 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 33.7858 ms 108 | 12/02/2022 19:05:49 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.8436 ms 109 | 12/02/2022 19:08:08 +01:00 HTTP "GET" "/api/soaps" responded 200 in 6.9527 ms 110 | 12/02/2022 19:08:25 +01:00 HTTP "GET" "/api/soaps" responded 200 in 6.8460 ms 111 | 12/02/2022 19:08:29 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1252 ms 112 | 12/02/2022 19:08:29 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 29.0235 ms 113 | 12/02/2022 19:08:31 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1767 ms 114 | 12/02/2022 19:09:22 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.7404 ms 115 | 12/02/2022 19:09:24 +01:00 HTTP "GET" "/api/soaps" responded 200 in 14.9175 ms 116 | 12/02/2022 19:09:27 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.5483 ms 117 | 12/02/2022 19:09:27 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 104.7567 ms 118 | 12/02/2022 19:09:28 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1296 ms 119 | 12/02/2022 19:09:48 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.7882 ms 120 | 12/02/2022 19:09:52 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1580 ms 121 | 12/02/2022 19:09:52 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 98.9175 ms 122 | 12/02/2022 19:09:53 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1145 ms 123 | 12/02/2022 19:10:13 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5826 ms 124 | 12/02/2022 19:10:16 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.5270 ms 125 | 12/02/2022 19:10:16 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 58.0370 ms 126 | 12/02/2022 19:10:19 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.3902 ms 127 | 12/02/2022 19:12:14 +01:00 HTTP "GET" "/api/soaps" responded 200 in 10.5782 ms 128 | 12/02/2022 19:12:27 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.9233 ms 129 | 12/02/2022 19:12:29 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1971 ms 130 | 12/02/2022 19:12:29 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 99.5285 ms 131 | 12/02/2022 19:12:31 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1692 ms 132 | 12/02/2022 19:14:41 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.9888 ms 133 | 12/02/2022 19:16:43 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.5698 ms 134 | 12/02/2022 19:16:51 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.6619 ms 135 | 12/02/2022 19:17:02 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.6935 ms 136 | 12/02/2022 19:17:10 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.0707 ms 137 | 12/02/2022 19:17:10 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 26.2388 ms 138 | 12/02/2022 19:17:11 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1504 ms 139 | 12/02/2022 19:19:33 +01:00 HTTP "GET" "/api/soaps" responded 200 in 9.4900 ms 140 | 12/02/2022 19:21:27 +01:00 HTTP "GET" "/api/soaps" responded 200 in 11.3339 ms 141 | 12/02/2022 19:21:57 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.8603 ms 142 | 12/02/2022 19:22:07 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.8571 ms 143 | 12/02/2022 19:22:21 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.7187 ms 144 | 12/02/2022 19:22:36 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1677 ms 145 | 12/02/2022 19:22:36 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 265.1853 ms 146 | 12/02/2022 19:22:37 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0930 ms 147 | 12/02/2022 19:24:06 +01:00 HTTP "GET" "/api/soaps" responded 200 in 13.5244 ms 148 | 12/02/2022 19:24:52 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0741 ms 149 | 12/02/2022 19:25:04 +01:00 HTTP "GET" "/api/soaps" responded 200 in 7.2538 ms 150 | 12/02/2022 19:25:08 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.5849 ms 151 | 12/02/2022 19:25:09 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 86.5282 ms 152 | 12/02/2022 19:25:10 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1070 ms 153 | 12/02/2022 19:35:06 +01:00 HTTP "GET" "/api/soaps" responded 200 in 10.3697 ms 154 | 12/02/2022 19:36:31 +01:00 HTTP "GET" "/api/soaps" responded 200 in 9.4408 ms 155 | 12/02/2022 19:36:34 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2330 ms 156 | 12/02/2022 19:36:34 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 206.1558 ms 157 | 12/02/2022 19:36:36 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.3809 ms 158 | 12/02/2022 19:37:04 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.1182 ms 159 | 12/02/2022 19:37:09 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1393 ms 160 | 12/02/2022 19:37:09 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 79.0963 ms 161 | 12/02/2022 19:37:11 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.2763 ms 162 | 12/02/2022 19:37:29 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0040 ms 163 | 12/02/2022 19:37:32 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.5035 ms 164 | 12/02/2022 19:37:32 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 131.9091 ms 165 | 12/02/2022 19:37:33 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.4779 ms 166 | 12/02/2022 19:38:05 +01:00 HTTP "GET" "/api/soaps" responded 200 in 5.0597 ms 167 | 12/02/2022 19:38:09 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.0682 ms 168 | 12/02/2022 19:38:09 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 46.3141 ms 169 | 12/02/2022 19:38:10 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.3864 ms 170 | 12/02/2022 19:38:29 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.6215 ms 171 | 12/02/2022 19:38:33 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2132 ms 172 | 12/02/2022 19:38:33 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 86.5867 ms 173 | 12/02/2022 19:38:34 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.3196 ms 174 | 12/02/2022 19:39:37 +01:00 HTTP "GET" "/api/soaps" responded 200 in 9.7509 ms 175 | 12/02/2022 19:45:24 +01:00 HTTP "GET" "/api/soaps" responded 200 in 13.3524 ms 176 | 12/02/2022 19:45:56 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5624 ms 177 | 12/02/2022 19:46:02 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2178 ms 178 | 12/02/2022 19:46:02 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 161.8311 ms 179 | 12/02/2022 19:46:04 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5112 ms 180 | 12/02/2022 19:46:17 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5628 ms 181 | 12/02/2022 19:46:56 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.0048 ms 182 | 12/02/2022 19:47:03 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1102 ms 183 | 12/02/2022 19:47:03 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 103.9306 ms 184 | 12/02/2022 19:47:04 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1038 ms 185 | 12/02/2022 19:47:48 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.5785 ms 186 | 12/02/2022 19:49:38 +01:00 HTTP "GET" "/api/soaps" responded 200 in 8.5998 ms 187 | 12/02/2022 19:50:03 +01:00 HTTP "GET" "/api/soaps" responded 200 in 4.3965 ms 188 | 12/02/2022 19:51:07 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1717 ms 189 | 12/02/2022 19:51:07 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 135.9013 ms 190 | 12/02/2022 19:51:08 +01:00 HTTP "GET" "/api/soaps" responded 200 in 51.7826 ms 191 | 12/02/2022 19:51:51 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 0.0875 ms 192 | 12/02/2022 19:51:51 +01:00 HTTP "POST" "/api/soaps" responded 400 in 58.0963 ms 193 | 12/02/2022 19:52:31 +01:00 HTTP "GET" "/api/soaps" responded 200 in 4.5387 ms 194 | 12/02/2022 19:52:38 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.6170 ms 195 | 12/02/2022 19:52:38 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 120.3268 ms 196 | 12/02/2022 19:52:39 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1506 ms 197 | 12/02/2022 19:53:06 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 0.2230 ms 198 | 12/02/2022 19:53:06 +01:00 HTTP "POST" "/api/soaps" responded 400 in 20.9887 ms 199 | 12/02/2022 19:54:59 +01:00 HTTP "GET" "/api/soaps" responded 200 in 10.5560 ms 200 | 12/02/2022 19:55:02 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.1565 ms 201 | 12/02/2022 19:55:02 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 38.8910 ms 202 | 12/02/2022 19:55:03 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1198 ms 203 | 12/02/2022 19:55:53 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 0.2368 ms 204 | 12/02/2022 19:55:53 +01:00 HTTP "POST" "/api/soaps" responded 400 in 9.0029 ms 205 | 12/02/2022 19:58:44 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 0.3218 ms 206 | 12/02/2022 19:58:49 +01:00 HTTP "POST" "/api/soaps" responded 200 in 4585.9301 ms 207 | 12/02/2022 19:59:50 +01:00 HTTP "GET" "/api/soaps" responded 200 in 24.5634 ms 208 | 12/02/2022 19:59:58 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.4736 ms 209 | 12/02/2022 19:59:58 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 118.7118 ms 210 | 12/02/2022 19:59:59 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.8010 ms 211 | 12/02/2022 20:00:20 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 0.1413 ms 212 | 12/02/2022 20:00:25 +01:00 HTTP "POST" "/api/soaps" responded 200 in 4996.2047 ms 213 | 12/02/2022 20:00:30 +01:00 HTTP "GET" "/api/balms" responded 200 in 57.0468 ms 214 | 12/02/2022 20:00:30 +01:00 HTTP "GET" "/api/soaps" responded 200 in 2.1573 ms 215 | 12/02/2022 20:00:57 +01:00 HTTP "GET" "/api/soaps" responded 200 in 1.1848 ms 216 | 12/02/2022 20:04:40 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 0.2279 ms 217 | 12/02/2022 20:04:40 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 138.8704 ms 218 | 12/02/2022 20:04:41 +01:00 HTTP "GET" "/api/soaps" responded 200 in 0.4767 ms 219 | 12/02/2022 20:04:44 +01:00 HTTP "OPTIONS" "/api/soaps" responded 204 in 0.3623 ms 220 | 12/02/2022 20:04:55 +01:00 Application is starting 221 | 12/02/2022 20:04:57 +01:00 HTTP "GET" "/swagger" responded 302 in 76.2873 ms 222 | 12/02/2022 20:04:58 +01:00 HTTP "GET" "/swagger/index.html" responded 200 in 251.8758 ms 223 | 12/02/2022 20:04:58 +01:00 HTTP "GET" "/swagger/swagger-ui.css" responded 200 in 44.9076 ms 224 | 12/02/2022 20:04:58 +01:00 HTTP "GET" "/swagger/swagger-ui-standalone-preset.js" responded 200 in 44.7168 ms 225 | 12/02/2022 20:04:58 +01:00 HTTP "GET" "/swagger/swagger-ui-bundle.js" responded 200 in 44.8938 ms 226 | 12/02/2022 20:04:59 +01:00 HTTP "GET" "/swagger/v1/swagger.json" responded 200 in 707.3798 ms 227 | 12/02/2022 20:05:16 +01:00 HTTP "OPTIONS" "/api/account/signin" responded 204 in 26.5853 ms 228 | 12/02/2022 20:05:17 +01:00 HTTP "POST" "/api/account/signin" responded 200 in 864.5183 ms 229 | 12/02/2022 20:05:18 +01:00 HTTP "GET" "/api/soaps" responded 200 in 359.9196 ms 230 | --------------------------------------------------------------------------------