Implement Repository-Service pattern

This commit is contained in:
Stanislav Mykhailenko 2023-05-17 12:36:49 +03:00
parent 16ef307140
commit 50f20ffc5c
GPG key ID: 1E95E66A9C9D6A36
22 changed files with 226 additions and 110 deletions

View file

@ -1,4 +1,4 @@
using NG_2023_Kanban.BusinessLayer.Service;
using NG_2023_Kanban.BusinessLayer.Services;
using Microsoft.Extensions.DependencyInjection;
namespace NG_2023_Kanban.BusinessLayer.Inject
@ -8,7 +8,7 @@ namespace NG_2023_Kanban.BusinessLayer.Inject
public static void InjectBLL(
this IServiceCollection services)
{
services.AddScoped<BusinessService>();
services.AddScoped<UserService>();
}
}
}

View file

@ -0,0 +1,10 @@
using NG_2023_Kanban.DataLayer.Entities;
namespace NG_2023_Kanban.BusinessLayer.Interfaces
{
public interface IUserService
{
Task<User> LoginAsync(User user);
Task<User> RegisterAsync(User user);
}
}

View file

@ -1,33 +0,0 @@
using NG_2023_Kanban.DataLayer.Service;
using NG_2023_Kanban.DataLayer.Entities;
using Microsoft.EntityFrameworkCore;
namespace NG_2023_Kanban.BusinessLayer.Service
{
public class BusinessService
{
private readonly DataService _service;
public BusinessService(DataService service)
{
_service = service;
}
public async Task<User> LoginAsync(string username, string password)
{
return await _service.LoginAsync(username, password);
}
public async Task<User> RegisterAsync(string fullName, string username, string password)
{
User account = await _service.AddAsync(new User
{
FullName = fullName,
Username = username,
Password = password, // TODO: hashing
IsAdmin = false
});
return account;
}
}
}

View file

@ -0,0 +1,33 @@
using NG_2023_Kanban.BusinessLayer.Interfaces;
using NG_2023_Kanban.DataLayer.Repositories;
using NG_2023_Kanban.DataLayer.Entities;
using NG_2023_Kanban.DataLayer.Interfaces;
using Microsoft.EntityFrameworkCore;
namespace NG_2023_Kanban.BusinessLayer.Services
{
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public async Task<User?> LoginAsync(User user)
{
var data = await _userRepository.FindAsync(x => x.Username == user.Username && x.Password == user.Password);
if (data.Any())
return data.First();
else
return null;
}
public async Task<User> RegisterAsync(User user)
{
await _userRepository.CreateAsync(user);
return user;
}
}
}

View file

@ -6,18 +6,20 @@ namespace NG_2023_Kanban.DataLayer.DbStartup
{
public class DatabaseContext : DbContext
{
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { }
public DatabaseContext(DbContextOptions options) : base(options) { }
public DbSet<Board> Boards { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<Card> Cards { get; set; }
public DbSet<Column> Columns { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new BoardConfiguration());
modelBuilder.ApplyConfiguration(new CommentConfiguration());
modelBuilder.ApplyConfiguration(new CardConfiguration());
modelBuilder.ApplyConfiguration(new ColumnConfiguration());
modelBuilder.ApplyConfiguration(new CommentConfiguration());
modelBuilder.ApplyConfiguration(new UserConfiguration());
base.OnModelCreating(modelBuilder);

View file

@ -1,4 +1,6 @@
using NG_2023_Kanban.DataLayer.Service;
using NG_2023_Kanban.DataLayer.Repositories;
using NG_2023_Kanban.DataLayer.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@ -11,12 +13,23 @@ namespace NG_2023_Kanban.DataLayer.DbStartup
this IServiceCollection services,
IConfiguration configuration)
{
services.AddTransient<IBoardRepository, BoardRepository>();
services.AddTransient<ICardRepository, CardRepository>();
services.AddTransient<IColumnRepository, ColumnRepository>();
services.AddTransient<ICommentRepository, CommentRepository>();
services.AddTransient<IUserRepository, UserRepository>();
var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
optionsBuilder.UseSqlServer(configuration["ConnectionString"]);
services.AddDbContext<DatabaseContext>(options =>
{
options.UseSqlServer(
configuration["ConnectionString"]);
});
services.AddScoped<DataService>();
(new DatabaseContext(optionsBuilder.Options)).Database.EnsureCreated(); // possibly misplaced
}
}
}

View file

@ -7,7 +7,7 @@
public string Username { get; set; }
public string Password { get; set; }
public bool IsAdmin { get; set; }
public bool IsAdmin { get; set; } = false;
public virtual ICollection<Board>? Boards { get; set; } = new HashSet<Board>();
public virtual ICollection<Card>? Cards { get; set; } = new HashSet<Card>();

View file

@ -14,9 +14,6 @@ namespace NG_2023_Kanban.DataLayer.EntityConfiguration
builder.Property(x => x.Name).IsRequired();
builder.Property(x => x.Name).HasMaxLength(100);
builder.Property(x => x.Board).IsRequired();
builder.Property(x => x.Board).HasMaxLength(100);
builder
.HasOne(x => x.Board)
.WithMany(x => x.Columns)

View file

@ -0,0 +1,8 @@
using NG_2023_Kanban.DataLayer.Entities;
namespace NG_2023_Kanban.DataLayer.Interfaces
{
public interface IBoardRepository : IRepository<Board>
{
}
}

View file

@ -0,0 +1,8 @@
using NG_2023_Kanban.DataLayer.Entities;
namespace NG_2023_Kanban.DataLayer.Interfaces
{
public interface ICardRepository : IRepository<Card>
{
}
}

View file

@ -0,0 +1,8 @@
using NG_2023_Kanban.DataLayer.Entities;
namespace NG_2023_Kanban.DataLayer.Interfaces
{
public interface IColumnRepository : IRepository<Column>
{
}
}

View file

@ -0,0 +1,8 @@
using NG_2023_Kanban.DataLayer.Entities;
namespace NG_2023_Kanban.DataLayer.Interfaces
{
public interface ICommentRepository : IRepository<Comment>
{
}
}

View file

@ -0,0 +1,13 @@
namespace NG_2023_Kanban.DataLayer.Interfaces
{
public interface IRepository<T> where T : class
{
Task<ICollection<T>> GetAllAsync();
Task<T> GetAsync(int id);
Task<ICollection<T>> FindAsync(Func<T, Boolean> predicate);
Task CreateAsync(T entity);
Task UpdateAsync(T entity);
Task DeleteAsync(int id);
Task DeleteAsync(T entity);
}
}

View file

@ -0,0 +1,8 @@
using NG_2023_Kanban.DataLayer.Entities;
namespace NG_2023_Kanban.DataLayer.Interfaces
{
public interface IUserRepository : IRepository<User>
{
}
}

View file

@ -0,0 +1,50 @@
using NG_2023_Kanban.DataLayer.DbStartup;
using NG_2023_Kanban.DataLayer.Entities;
using NG_2023_Kanban.DataLayer.Interfaces;
using Microsoft.EntityFrameworkCore;
namespace NG_2023_Kanban.DataLayer.Repositories;
public class BaseRepository<T> : IRepository<T> where T : BaseEntity
{
private DatabaseContext _context;
public BaseRepository(DatabaseContext context)
=> _context = context;
public async Task<ICollection<T>> GetAllAsync()
=> await _context.Set<T>().Select(x => x).ToListAsync();
public async Task<T> GetAsync(int id)
=> await _context.Set<T>().FirstAsync(x => x.Id == id);
public async Task<ICollection<T>> FindAsync(Func<T, bool> predicate)
{
var entities = await GetAllAsync();
return entities.Where(predicate).ToList();
}
public async Task CreateAsync(T entity)
{
await _context.Set<T>().AddAsync(entity);
await _context.SaveChangesAsync();
}
public async Task UpdateAsync(T entity)
{
_context.Set<T>().Update(entity);
await _context.SaveChangesAsync();
}
public async Task DeleteAsync(int id)
{
var entity = await GetAsync(id);
await DeleteAsync(entity);
}
public async Task DeleteAsync(T entity)
{
_context.Set<T>().Remove(entity);
await _context.SaveChangesAsync();
}
}

View file

@ -0,0 +1,10 @@
using NG_2023_Kanban.DataLayer.DbStartup;
using NG_2023_Kanban.DataLayer.Entities;
using NG_2023_Kanban.DataLayer.Interfaces;
namespace NG_2023_Kanban.DataLayer.Repositories;
public class BoardRepository : BaseRepository<Board>, IBoardRepository
{
public BoardRepository(DatabaseContext context) : base(context) { }
}

View file

@ -0,0 +1,10 @@
using NG_2023_Kanban.DataLayer.DbStartup;
using NG_2023_Kanban.DataLayer.Entities;
using NG_2023_Kanban.DataLayer.Interfaces;
namespace NG_2023_Kanban.DataLayer.Repositories;
public class CardRepository : BaseRepository<Card>, ICardRepository
{
public CardRepository(DatabaseContext context) : base(context) { }
}

View file

@ -0,0 +1,10 @@
using NG_2023_Kanban.DataLayer.DbStartup;
using NG_2023_Kanban.DataLayer.Entities;
using NG_2023_Kanban.DataLayer.Interfaces;
namespace NG_2023_Kanban.DataLayer.Repositories;
public class ColumnRepository : BaseRepository<Column>, IColumnRepository
{
public ColumnRepository(DatabaseContext context) : base(context) { }
}

View file

@ -0,0 +1,10 @@
using NG_2023_Kanban.DataLayer.DbStartup;
using NG_2023_Kanban.DataLayer.Entities;
using NG_2023_Kanban.DataLayer.Interfaces;
namespace NG_2023_Kanban.DataLayer.Repositories;
public class CommentRepository : BaseRepository<Comment>, ICommentRepository
{
public CommentRepository(DatabaseContext context) : base(context) { }
}

View file

@ -0,0 +1,10 @@
using NG_2023_Kanban.DataLayer.DbStartup;
using NG_2023_Kanban.DataLayer.Entities;
using NG_2023_Kanban.DataLayer.Interfaces;
namespace NG_2023_Kanban.DataLayer.Repositories;
public class UserRepository : BaseRepository<User>, IUserRepository
{
public UserRepository(DatabaseContext context) : base(context) { }
}

View file

@ -1,59 +0,0 @@
using NG_2023_Kanban.DataLayer.DbStartup;
using NG_2023_Kanban.DataLayer.Entities;
using Microsoft.EntityFrameworkCore;
namespace NG_2023_Kanban.DataLayer.Service
{
public class DataService
{
private readonly DatabaseContext _context;
public DataService(DatabaseContext context)
{
_context = context;
_context.Database.EnsureCreated();
}
public async Task<User> AddAsync(User entity)
{
await _context.Set<User>().AddAsync(entity);
await _context.SaveChangesAsync();
return entity;
}
public async Task<User> GetByIdAsync(int id)
{
var entity = await _context.Set<User>().FirstOrDefaultAsync(x => x.Id == id);
return entity;
}
public async Task<User> LoginAsync(string username, string password)
{
User? entity = await _context.Set<User>().FirstOrDefaultAsync(x => x.Username == username);
if (entity != null && entity.Password == password) // TODO: hashing
return entity;
return null;
}
public async Task<ICollection<User>> GetAllAsync()
{
var entities = await _context.Set<User>().Select(x => x).ToListAsync();
return entities;
}
public async Task UpdateAsync(User model)
{
_context.Set<User>().Update(model);
await _context.SaveChangesAsync();
}
public async Task DeleteAsync(User model)
{
_context.Set<User>().Remove(model);
await _context.SaveChangesAsync();
}
}
}

View file

@ -3,19 +3,19 @@ using Microsoft.AspNetCore.Mvc;
using NG_2023_Kanban.DataLayer.Entities;
using NG_2023_Kanban.Extensions;
using NG_2023_Kanban.DataLayer.Models;
using NG_2023_Kanban.BusinessLayer.Service;
using NG_2023_Kanban.BusinessLayer.Services;
namespace NG_2023_Kanban.Controllers;
public class HomeController : Controller
{
private readonly BusinessService _service;
private readonly UserService _userService;
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger, BusinessService service)
public HomeController(ILogger<HomeController> logger, UserService userService)
{
_logger = logger;
_service = service;
_userService = userService;
}
public IActionResult Index()
@ -39,13 +39,13 @@ public class HomeController : Controller
}
[HttpPost]
public async Task<IActionResult> Login(string username, string password)
public async Task<IActionResult> Login(User user)
{
User? currentAccount = HttpContext.Session.GetObject<User>("Account");
if (currentAccount != null)
return Redirect("/Home/Index");
User? account = await _service.LoginAsync(username, password);
User? account = await _userService.LoginAsync(user);
if (account != null)
{
HttpContext.Session.SetObject("Account", account);
@ -74,7 +74,7 @@ public class HomeController : Controller
}
[HttpPost]
public async Task<IActionResult> Register(string fullName, string username, string password)
public async Task<IActionResult> Register(User user)
{
User? currentAccount = HttpContext.Session.GetObject<User>("Account");
if (currentAccount != null)
@ -82,7 +82,7 @@ public class HomeController : Controller
try
{
User account = await _service.RegisterAsync(fullName, username, password);
User account = await _userService.RegisterAsync(user);
HttpContext.Session.SetObject("Account", account);
return Redirect("/Home/Index");