diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..530220b --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +/AccountOwnerServer/obj +/AccountOwnerServer/bin +/Contracts/obj +/Contracts/bin +/Entities/obj +/Entities/bin +/LoggerService/obj +/LoggerService/bin +/Repository/obj +/Repository/bin +/.vs +/AccountOwnerServer/*.user diff --git a/AccountOwnerServer.sln b/AccountOwnerServer.sln new file mode 100644 index 0000000..297e2e6 --- /dev/null +++ b/AccountOwnerServer.sln @@ -0,0 +1,49 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29318.209 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AccountOwnerServer", "AccountOwnerServer\AccountOwnerServer.csproj", "{D6116708-5D20-43C2-A796-9716AC8885F3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Contracts", "Contracts\Contracts.csproj", "{C6A5877A-BCBF-487C-B9EE-F678F921D3F2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LoggerService", "LoggerService\LoggerService.csproj", "{8F7CB858-3196-4D0C-A3DB-A850443CA462}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entities", "Entities\Entities.csproj", "{CA018972-3651-4802-9930-69E855892B7A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Repository", "Repository\Repository.csproj", "{A1DEC662-9D40-45E3-A8DE-22AF6A1BE970}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D6116708-5D20-43C2-A796-9716AC8885F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6116708-5D20-43C2-A796-9716AC8885F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6116708-5D20-43C2-A796-9716AC8885F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6116708-5D20-43C2-A796-9716AC8885F3}.Release|Any CPU.Build.0 = Release|Any CPU + {C6A5877A-BCBF-487C-B9EE-F678F921D3F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6A5877A-BCBF-487C-B9EE-F678F921D3F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6A5877A-BCBF-487C-B9EE-F678F921D3F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6A5877A-BCBF-487C-B9EE-F678F921D3F2}.Release|Any CPU.Build.0 = Release|Any CPU + {8F7CB858-3196-4D0C-A3DB-A850443CA462}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F7CB858-3196-4D0C-A3DB-A850443CA462}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F7CB858-3196-4D0C-A3DB-A850443CA462}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F7CB858-3196-4D0C-A3DB-A850443CA462}.Release|Any CPU.Build.0 = Release|Any CPU + {CA018972-3651-4802-9930-69E855892B7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA018972-3651-4802-9930-69E855892B7A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA018972-3651-4802-9930-69E855892B7A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA018972-3651-4802-9930-69E855892B7A}.Release|Any CPU.Build.0 = Release|Any CPU + {A1DEC662-9D40-45E3-A8DE-22AF6A1BE970}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1DEC662-9D40-45E3-A8DE-22AF6A1BE970}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1DEC662-9D40-45E3-A8DE-22AF6A1BE970}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1DEC662-9D40-45E3-A8DE-22AF6A1BE970}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9552CCB3-10D6-4D12-8C27-FDD7440E23EB} + EndGlobalSection +EndGlobal diff --git a/AccountOwnerServer/AccountOwnerServer.csproj b/AccountOwnerServer/AccountOwnerServer.csproj new file mode 100644 index 0000000..d02125a --- /dev/null +++ b/AccountOwnerServer/AccountOwnerServer.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + + + + + diff --git a/AccountOwnerServer/Controllers/AccountController.cs b/AccountOwnerServer/Controllers/AccountController.cs new file mode 100644 index 0000000..75cb62c --- /dev/null +++ b/AccountOwnerServer/Controllers/AccountController.cs @@ -0,0 +1,47 @@ +using Contracts; +using Entities.Extensions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; +using System; + +namespace AccountOwnerServer.Controllers +{ + [Route("api/owners/{ownerId}/accounts")] + [ApiController] + public class AccountController : ControllerBase + { + private ILoggerManager _logger; + private IRepositoryWrapper _repository; + + public AccountController(ILoggerManager logger, + IRepositoryWrapper repository) + { + _logger = logger; + _repository = repository; + } + + [HttpGet] + public IActionResult GetAccountsForOwner(Guid ownerId) + { + var accounts = _repository.Account.GetAccountsByOwner(ownerId); + + _logger.LogInfo($"Returned all accounts from database."); + + return Ok(accounts); + } + + [HttpGet("{id}")] + public IActionResult GetAccountForOwner(Guid ownerId, Guid id) + { + var account = _repository.Account.GetAccountByOwner(ownerId, id); + + if (account.IsEmptyObject()) + { + _logger.LogError($"Account with id: {id}, hasn't been found in db."); + return NotFound(); + } + + return Ok(account); + } + } +} diff --git a/AccountOwnerServer/Controllers/OwnerController.cs b/AccountOwnerServer/Controllers/OwnerController.cs new file mode 100644 index 0000000..e6e5037 --- /dev/null +++ b/AccountOwnerServer/Controllers/OwnerController.cs @@ -0,0 +1,114 @@ +using Contracts; +using Entities.Extensions; +using Entities.Models; +using Microsoft.AspNetCore.Mvc; +using System; + +namespace AccountOwnerServer.Controllers +{ + [Route("api/owners")] + [ApiController] + public class OwnerController : ControllerBase + { + private ILoggerManager _logger; + private IRepositoryWrapper _repository; + + public OwnerController(ILoggerManager logger, IRepositoryWrapper repository) + { + _logger = logger; + _repository = repository; + } + + [HttpGet] + public IActionResult GetOwners() + { + var owners = _repository.Owner.GetOwners(); + + _logger.LogInfo($"Returned all owners from database."); + + return Ok(owners); + } + + [HttpGet("{id}", Name = "OwnerById")] + public IActionResult GetOwnerById(Guid id) + { + var owner = _repository.Owner.GetOwnerById(id); + + if (owner.IsEmptyObject()) + { + _logger.LogError($"Owner with id: {id}, hasn't been found in db."); + return NotFound(); + } + else + { + _logger.LogInfo($"Returned owner with id: {id}"); + return Ok(owner); + } + } + + [HttpPost] + public IActionResult CreateOwner([FromBody]Owner owner) + { + if (owner.IsObjectNull()) + { + _logger.LogError("Owner object sent from client is null."); + return BadRequest("Owner object is null"); + } + + if (!ModelState.IsValid) + { + _logger.LogError("Invalid owner object sent from client."); + return BadRequest("Invalid model object"); + } + + _repository.Owner.CreateOwner(owner); + _repository.Save(); + + return CreatedAtRoute("OwnerById", new { id = owner.Id }, owner); + } + + [HttpPut("{id}")] + public IActionResult UpdateOwner(Guid id, [FromBody]Owner owner) + { + if (owner.IsObjectNull()) + { + _logger.LogError("Owner object sent from client is null."); + return BadRequest("Owner object is null"); + } + + if (!ModelState.IsValid) + { + _logger.LogError("Invalid owner object sent from client."); + return BadRequest("Invalid model object"); + } + + var dbOwner = _repository.Owner.GetOwnerById(id); + if (dbOwner.IsEmptyObject()) + { + _logger.LogError($"Owner with id: {id}, hasn't been found in db."); + return NotFound(); + } + + _repository.Owner.UpdateOwner(dbOwner, owner); + _repository.Save(); + + return NoContent(); + } + + [HttpDelete("{id}")] + public IActionResult DeleteOwner(Guid id) + { + var owner = _repository.Owner.GetOwnerById(id); + if (owner.IsEmptyObject()) + { + _logger.LogError($"Owner with id: {id}, hasn't been found in db."); + return NotFound(); + } + + _repository.Owner.DeleteOwner(owner); + _repository.Save(); + + return NoContent(); + } + } +} \ No newline at end of file diff --git a/AccountOwnerServer/Extensions/ServiceExtensions.cs b/AccountOwnerServer/Extensions/ServiceExtensions.cs new file mode 100644 index 0000000..78bf5b1 --- /dev/null +++ b/AccountOwnerServer/Extensions/ServiceExtensions.cs @@ -0,0 +1,50 @@ +using Contracts; +using Entities; +using LoggerService; +using Microsoft.AspNetCore.Builder; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Repository; + +namespace AccountOwnerServer.Extensions +{ + public static class ServiceExtensions + { + public static void ConfigureCors(this IServiceCollection services) + { + services.AddCors(options => + { + options.AddPolicy("CorsPolicy", + builder => builder.WithOrigins("http://localhost:5000", "https://localhost:5001") + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials()); + }); + } + + public static void ConfigureIISIntegration(this IServiceCollection services) + { + services.Configure(options => + { + + }); + } + + public static void ConfigureLoggerService(this IServiceCollection services) + { + services.AddSingleton(); + } + + public static void ConfigureMySqlContext(this IServiceCollection services, IConfiguration config) + { + var connectionString = config["mysqlconnection:connectionString"]; + services.AddDbContext(o => o.UseMySql(connectionString)); + } + + public static void ConfigureRepositoryWrapper(this IServiceCollection services) + { + services.AddScoped(); + } + } +} diff --git a/AccountOwnerServer/Program.cs b/AccountOwnerServer/Program.cs new file mode 100644 index 0000000..5baa7d0 --- /dev/null +++ b/AccountOwnerServer/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace AccountOwnerServer +{ + public class Program + { + public static void Main(string[] args) + { + CreateWebHostBuilder(args).Build().Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup(); + } +} diff --git a/AccountOwnerServer/Properties/launchSettings.json b/AccountOwnerServer/Properties/launchSettings.json new file mode 100644 index 0000000..334d3a2 --- /dev/null +++ b/AccountOwnerServer/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:5000", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": false, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "AccountOwnerServer": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api/owner", + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/AccountOwnerServer/Startup.cs b/AccountOwnerServer/Startup.cs new file mode 100644 index 0000000..767f354 --- /dev/null +++ b/AccountOwnerServer/Startup.cs @@ -0,0 +1,97 @@ +using AccountOwnerServer.Extensions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using NLog; +using System; +using System.IO; +using System.Net; + +namespace AccountOwnerServer +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + LogManager.LoadConfiguration(String.Concat(Directory.GetCurrentDirectory(), "/nlog.config")); + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.ConfigureCors(); + + services.ConfigureIISIntegration(); + + services.ConfigureLoggerService(); + + services.ConfigureMySqlContext(Configuration); + + services.ConfigureRepositoryWrapper(); + + services.AddControllers(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseExceptionHandler(appError => + { + appError.Run(async context => + { + context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; + context.Response.ContentType = "application/json"; + + var contextFeature = context.Features.Get(); + if (contextFeature != null) + { + Console.WriteLine($"Something went wrong: {contextFeature.Error}"); + + await context.Response.WriteAsync(new + { + context.Response.StatusCode, + Message = "Internal Server Error." + }.ToString()); + } + }); + }); + + app.UseHttpsRedirection(); + + app.UseCors("CorsPolicy"); + + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.All + }); + + app.UseStaticFiles(); + + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } +} diff --git a/AccountOwnerServer/appsettings.Development.json b/AccountOwnerServer/appsettings.Development.json new file mode 100644 index 0000000..e203e94 --- /dev/null +++ b/AccountOwnerServer/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/AccountOwnerServer/appsettings.json b/AccountOwnerServer/appsettings.json new file mode 100644 index 0000000..0c61fec --- /dev/null +++ b/AccountOwnerServer/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Warning" + } + }, + "mysqlconnection": { + "connectionString": "server=localhost;userid=root;password=Popokatapetl12;database=codemaze;" + }, + "AllowedHosts": "*" +} diff --git a/AccountOwnerServer/nlog.config b/AccountOwnerServer/nlog.config new file mode 100644 index 0000000..47744e0 --- /dev/null +++ b/AccountOwnerServer/nlog.config @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Contracts/Contracts.csproj b/Contracts/Contracts.csproj new file mode 100644 index 0000000..ea0a350 --- /dev/null +++ b/Contracts/Contracts.csproj @@ -0,0 +1,11 @@ + + + + netcoreapp3.0 + + + + + + + diff --git a/Contracts/IAccountRepository.cs b/Contracts/IAccountRepository.cs new file mode 100644 index 0000000..ba1c7cc --- /dev/null +++ b/Contracts/IAccountRepository.cs @@ -0,0 +1,12 @@ +using Entities.Models; +using System; +using System.Collections.Generic; + +namespace Contracts +{ + public interface IAccountRepository:IRepositoryBase + { + IEnumerable GetAccountsByOwner(Guid ownerId); + Account GetAccountByOwner(Guid ownerId, Guid id); + } +} diff --git a/Contracts/ILoggerManager.cs b/Contracts/ILoggerManager.cs new file mode 100644 index 0000000..7dcd872 --- /dev/null +++ b/Contracts/ILoggerManager.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Contracts +{ + public interface ILoggerManager + { + void LogInfo(string message); + void LogWarn(string message); + void LogDebug(string message); + void LogError(string message); + } +} diff --git a/Contracts/IOwnerRepository.cs b/Contracts/IOwnerRepository.cs new file mode 100644 index 0000000..63b9d5d --- /dev/null +++ b/Contracts/IOwnerRepository.cs @@ -0,0 +1,15 @@ +using Entities.Models; +using System; +using System.Collections.Generic; + +namespace Contracts +{ + public interface IOwnerRepository : IRepositoryBase + { + IEnumerable GetOwners(); + Owner GetOwnerById(Guid ownerId); + void CreateOwner(Owner owner); + void UpdateOwner(Owner dbOwner, Owner owner); + void DeleteOwner(Owner owner); + } +} diff --git a/Contracts/IRepositoryBase.cs b/Contracts/IRepositoryBase.cs new file mode 100644 index 0000000..c0eca4a --- /dev/null +++ b/Contracts/IRepositoryBase.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace Contracts +{ + public interface IRepositoryBase + { + IQueryable FindAll(); + IQueryable FindByCondition(Expression> expression); + void Create(T entity); + void Update(T entity); + void Delete(T entity); + } +} diff --git a/Contracts/IRepositoryWrapper.cs b/Contracts/IRepositoryWrapper.cs new file mode 100644 index 0000000..d0ce0c2 --- /dev/null +++ b/Contracts/IRepositoryWrapper.cs @@ -0,0 +1,9 @@ +namespace Contracts +{ + public interface IRepositoryWrapper + { + IOwnerRepository Owner { get; } + IAccountRepository Account { get; } + void Save(); + } +} diff --git a/Entities/Entities.csproj b/Entities/Entities.csproj new file mode 100644 index 0000000..94ec53c --- /dev/null +++ b/Entities/Entities.csproj @@ -0,0 +1,11 @@ + + + + netcoreapp3.0 + + + + + + + diff --git a/Entities/Enumerations/AccountType.cs b/Entities/Enumerations/AccountType.cs new file mode 100644 index 0000000..7cad9c9 --- /dev/null +++ b/Entities/Enumerations/AccountType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Entities.Enumerations +{ + public enum AccountType + { + Domestic, + Savings, + Foreign + } +} diff --git a/Entities/Extensions/IEntityExtensions.cs b/Entities/Extensions/IEntityExtensions.cs new file mode 100644 index 0000000..992fca0 --- /dev/null +++ b/Entities/Extensions/IEntityExtensions.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Entities.Extensions +{ + public static class IEntityExtensions + { + public static bool IsObjectNull(this IEntity entity) + { + return entity == null; + } + + public static bool IsEmptyObject(this IEntity entity) + { + return entity.Id.Equals(Guid.Empty); + } + } +} diff --git a/Entities/Extensions/OwnerExtensions.cs b/Entities/Extensions/OwnerExtensions.cs new file mode 100644 index 0000000..03e8a0a --- /dev/null +++ b/Entities/Extensions/OwnerExtensions.cs @@ -0,0 +1,17 @@ +using Entities.Models; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Entities.Extensions +{ + public static class OwnerExtensions + { + public static void Map(this Owner dbOwner, Owner owner) + { + dbOwner.Name = owner.Name; + dbOwner.Address = owner.Address; + dbOwner.DateOfBirth = owner.DateOfBirth; + } + } +} diff --git a/Entities/IEntity.cs b/Entities/IEntity.cs new file mode 100644 index 0000000..8dcadc4 --- /dev/null +++ b/Entities/IEntity.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Entities +{ + public interface IEntity + { + Guid Id { get; set; } + } +} diff --git a/Entities/Models/Account.cs b/Entities/Models/Account.cs new file mode 100644 index 0000000..105d588 --- /dev/null +++ b/Entities/Models/Account.cs @@ -0,0 +1,26 @@ +using Entities.Enumerations; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text; + +namespace Entities.Models +{ + [Table("account")] + public class Account : IEntity + { + [Key] + [Column("AccountId")] + public Guid Id { get; set; } + + [Required(ErrorMessage = "Date created is required")] + public DateTime DateCreated { get; set; } + + [Required(ErrorMessage = "Account type is required")] + public string AccountType { get; set; } + + [Required(ErrorMessage = "Owner Id is required")] + public Guid OwnerId { get; set; } + } +} diff --git a/Entities/Models/Owner.cs b/Entities/Models/Owner.cs new file mode 100644 index 0000000..bed85f5 --- /dev/null +++ b/Entities/Models/Owner.cs @@ -0,0 +1,25 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Entities.Models +{ + [Table("owner")] + public class Owner : IEntity + { + [Key] + [Column("OwnerId")] + public Guid Id { get; set; } + + [Required(ErrorMessage = "Name is required")] + [StringLength(60, ErrorMessage = "Name can't be longer than 60 characters")] + public string Name { get; set; } + + [Required(ErrorMessage = "Date of birth is required")] + public DateTime DateOfBirth { get; set; } + + [Required(ErrorMessage = "Address is required")] + [StringLength(100, ErrorMessage = "Address can not be loner then 100 characters")] + public string Address { get; set; } + } +} diff --git a/Entities/RepositoryContext.cs b/Entities/RepositoryContext.cs new file mode 100644 index 0000000..5687078 --- /dev/null +++ b/Entities/RepositoryContext.cs @@ -0,0 +1,16 @@ +using Entities.Models; +using Microsoft.EntityFrameworkCore; + +namespace Entities +{ + public class RepositoryContext: DbContext + { + public RepositoryContext(DbContextOptions options) + :base(options) + { + } + + public DbSet Owners { get; set; } + public DbSet Accounts { get; set; } + } +} diff --git a/LoggerService/LoggerManager.cs b/LoggerService/LoggerManager.cs new file mode 100644 index 0000000..5ee74b9 --- /dev/null +++ b/LoggerService/LoggerManager.cs @@ -0,0 +1,34 @@ +using Contracts; +using NLog; + +namespace LoggerService +{ + public class LoggerManager : ILoggerManager + { + private static ILogger logger = LogManager.GetCurrentClassLogger(); + + public LoggerManager() + { + } + + public void LogDebug(string message) + { + logger.Debug(message); + } + + public void LogError(string message) + { + logger.Error(message); + } + + public void LogInfo(string message) + { + logger.Info(message); + } + + public void LogWarn(string message) + { + logger.Warn(message); + } + } +} diff --git a/LoggerService/LoggerService.csproj b/LoggerService/LoggerService.csproj new file mode 100644 index 0000000..953adf9 --- /dev/null +++ b/LoggerService/LoggerService.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp3.0 + + + + + + + + + + + diff --git a/README.md b/README.md index 9c6ab1c..3737c01 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# advanced-rest-concepts-aspnetcore -This repository contains the source code for the "Advanced Rest Concepts Series" of articles on Code Maze +# Paging in ASP.NET Core Web API +This branch contains the source code for the "Paging in ASP.NET Core Web API" article on Code Maze diff --git a/Repository/AccountRepository.cs b/Repository/AccountRepository.cs new file mode 100644 index 0000000..59ee7ab --- /dev/null +++ b/Repository/AccountRepository.cs @@ -0,0 +1,30 @@ +using Contracts; +using Entities; +using Entities.Models; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Repository +{ + public class AccountRepository : RepositoryBase, IAccountRepository + { + public AccountRepository(RepositoryContext repositoryContext) + : base(repositoryContext) + { + + } + + public IEnumerable GetAccountsByOwner(Guid ownerId) + { + var accounts = FindByCondition(a => a.OwnerId.Equals(ownerId)); + + return accounts; + } + + public Account GetAccountByOwner(Guid ownerId, Guid id) + { + return FindByCondition(a => a.OwnerId.Equals(ownerId) && a.Id.Equals(id)).SingleOrDefault(); + } + } +} diff --git a/Repository/OwnerRepository.cs b/Repository/OwnerRepository.cs new file mode 100644 index 0000000..7e73835 --- /dev/null +++ b/Repository/OwnerRepository.cs @@ -0,0 +1,47 @@ +using Contracts; +using Entities; +using Entities.Extensions; +using Entities.Models; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Repository +{ + public class OwnerRepository : RepositoryBase, IOwnerRepository + { + public OwnerRepository(RepositoryContext repositoryContext) + : base(repositoryContext) + { + } + + public IEnumerable GetOwners() + { + return FindAll() + .OrderBy(ow => ow.Name); + } + + public Owner GetOwnerById(Guid ownerId) + { + return FindByCondition(owner => owner.Id.Equals(ownerId)) + .DefaultIfEmpty(new Owner()) + .FirstOrDefault(); + } + + public void CreateOwner(Owner owner) + { + Create(owner); + } + + public void UpdateOwner(Owner dbOwner, Owner owner) + { + dbOwner.Map(owner); + Update(dbOwner); + } + + public void DeleteOwner(Owner owner) + { + Delete(owner); + } + } +} \ No newline at end of file diff --git a/Repository/Repository.csproj b/Repository/Repository.csproj new file mode 100644 index 0000000..57127ad --- /dev/null +++ b/Repository/Repository.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp3.0 + + + + + + + + + + + diff --git a/Repository/RepositoryBase.cs b/Repository/RepositoryBase.cs new file mode 100644 index 0000000..b5ec43d --- /dev/null +++ b/Repository/RepositoryBase.cs @@ -0,0 +1,49 @@ +using Contracts; +using Entities; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace Repository +{ + public abstract class RepositoryBase : IRepositoryBase where T : class + { + protected RepositoryContext RepositoryContext { get; set; } + + public RepositoryBase(RepositoryContext repositoryContext) + { + this.RepositoryContext = repositoryContext; + } + + public IQueryable FindAll() + { + return this.RepositoryContext.Set() + .AsNoTracking(); + } + + public IQueryable FindByCondition(Expression> expression) + { + return this.RepositoryContext.Set() + .Where(expression) + .AsNoTracking(); + } + + public void Create(T entity) + { + this.RepositoryContext.Set().Add(entity); + } + + public void Update(T entity) + { + this.RepositoryContext.Set().Update(entity); + } + + public void Delete(T entity) + { + this.RepositoryContext.Set().Remove(entity); + } + } +} diff --git a/Repository/RepositoryWrapper.cs b/Repository/RepositoryWrapper.cs new file mode 100644 index 0000000..e7e5056 --- /dev/null +++ b/Repository/RepositoryWrapper.cs @@ -0,0 +1,48 @@ +using Contracts; +using Entities; + +namespace Repository +{ + public class RepositoryWrapper : IRepositoryWrapper + { + private RepositoryContext _repoContext; + private IOwnerRepository _owner; + private IAccountRepository _account; + + public IOwnerRepository Owner + { + get + { + if (_owner == null) + { + _owner = new OwnerRepository(_repoContext); + } + + return _owner; + } + } + + public IAccountRepository Account + { + get + { + if (_account == null) + { + _account = new AccountRepository(_repoContext); + } + + return _account; + } + } + + public RepositoryWrapper(RepositoryContext repositoryContext) + { + _repoContext = repositoryContext; + } + + public void Save() + { + _repoContext.SaveChanges(); + } + } +} diff --git a/_MySQL_Init_Script/init.sql b/_MySQL_Init_Script/init.sql new file mode 100644 index 0000000..648857d --- /dev/null +++ b/_MySQL_Init_Script/init.sql @@ -0,0 +1,81 @@ +-- MySQL dump 10.13 Distrib 5.7.17, for Win64 (x86_64) +-- +-- Host: localhost Database: accountowner +-- ------------------------------------------------------ +-- Server version 5.7.17-log + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `account` +-- + +DROP TABLE IF EXISTS `account`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `account` ( + `AccountId` char(36) NOT NULL, + `DateCreated` date NOT NULL, + `AccountType` varchar(45) NOT NULL, + `OwnerId` char(36) NOT NULL, + PRIMARY KEY (`AccountId`), + KEY `fk_Account_Owner_idx` (`OwnerId`), + CONSTRAINT `fk_Account_Owner` FOREIGN KEY (`OwnerId`) REFERENCES `owner` (`OwnerId`) ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `account` +-- + +LOCK TABLES `account` WRITE; +/*!40000 ALTER TABLE `account` DISABLE KEYS */; +INSERT INTO `account` VALUES ('03e91478-5608-4132-a753-d494dafce00b','2003-12-15','Domestic','f98e4d74-0f68-4aac-89fd-047f1aaca6b6'),('356a5a9b-64bf-4de0-bc84-5395a1fdc9c4','1996-02-15','Domestic','261e1685-cf26-494c-b17c-3546e65f5620'),('371b93f2-f8c5-4a32-894a-fc672741aa5b','1999-05-04','Domestic','24fd81f8-d58a-4bcc-9f35-dc6cd5641906'),('670775db-ecc0-4b90-a9ab-37cd0d8e2801','1999-12-21','Savings','24fd81f8-d58a-4bcc-9f35-dc6cd5641906'),('a3fbad0b-7f48-4feb-8ac0-6d3bbc997bfc','2010-05-28','Domestic','a3c1880c-674c-4d18-8f91-5d3608a2c937'),('aa15f658-04bb-4f73-82af-82db49d0fbef','1999-05-12','Foreign','24fd81f8-d58a-4bcc-9f35-dc6cd5641906'),('c6066eb0-53ca-43e1-97aa-3c2169eec659','1996-02-16','Foreign','261e1685-cf26-494c-b17c-3546e65f5620'),('eccadf79-85fe-402f-893c-32d3f03ed9b1','2010-06-20','Foreign','a3c1880c-674c-4d18-8f91-5d3608a2c937'); +/*!40000 ALTER TABLE `account` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `owner` +-- + +DROP TABLE IF EXISTS `owner`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `owner` ( + `OwnerId` char(36) NOT NULL, + `Name` varchar(60) NOT NULL, + `DateOfBirth` date NOT NULL, + `Address` varchar(100) NOT NULL, + PRIMARY KEY (`OwnerId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `owner` +-- + +LOCK TABLES `owner` WRITE; +/*!40000 ALTER TABLE `owner` DISABLE KEYS */; +INSERT INTO `owner` VALUES ('24fd81f8-d58a-4bcc-9f35-dc6cd5641906','John Keen','1980-12-05','61 Wellfield Road'),('261e1685-cf26-494c-b17c-3546e65f5620','Anna Bosh','1974-11-14','27 Colored Row'),('66774006-2371-4d5b-8518-2177bcf3f73e','Nick Somion','1998-12-15','North sunny address 102'),('a3c1880c-674c-4d18-8f91-5d3608a2c937','Sam Query','1990-04-22','91 Western Roads'),('f98e4d74-0f68-4aac-89fd-047f1aaca6b6','Martin Miller','1983-05-21','3 Edgar Buildings'); +/*!40000 ALTER TABLE `owner` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2017-12-24 15:53:17