diff options
| author | Syndamia <kamen.d.mladenov@protonmail.com> | 2021-05-13 15:05:53 +0300 |
|---|---|---|
| committer | Syndamia <kamen.d.mladenov@protonmail.com> | 2021-05-13 15:05:53 +0300 |
| commit | ef163726a5444ba0cbc631f74730184172c1c486 (patch) | |
| tree | d7d60837bb093c4256ad6506bc10ab981dafd491 | |
| parent | 19bb4631a7c0b57c8da19ca7aa89864ac1555836 (diff) | |
| download | it-kariera-exam-template-ef163726a5444ba0cbc631f74730184172c1c486.tar it-kariera-exam-template-ef163726a5444ba0cbc631f74730184172c1c486.tar.gz it-kariera-exam-template-ef163726a5444ba0cbc631f74730184172c1c486.zip | |
Implemented BaseService that uses generics to implement very basic CRUD; Moved away from 3 service model to 1 service model in add feature script
| -rw-r--r-- | ExamTemplate/Services/Interfaces/IBaseService.cs | 21 | ||||
| -rw-r--r-- | ExamTemplate/Services/Interfaces/IUserService.cs | 4 | ||||
| -rw-r--r-- | ExamTemplate/Services/Models/User/EditUserServiceModel.cs | 9 | ||||
| -rw-r--r-- | ExamTemplate/Services/Services/BaseService.cs | 81 | ||||
| -rw-r--r-- | ExamTemplate/Services/Services/UserService.cs | 8 | ||||
| -rw-r--r-- | ExamTemplate/Web/Configurations/ControllerUserMappings.cs | 2 | ||||
| -rw-r--r-- | ExamTemplate/Web/Controllers/AccountController.cs | 4 | ||||
| -rw-r--r-- | README.md | 6 | ||||
| -rwxr-xr-x | tools/add-feature-template.sh | 112 |
9 files changed, 128 insertions, 119 deletions
diff --git a/ExamTemplate/Services/Interfaces/IBaseService.cs b/ExamTemplate/Services/Interfaces/IBaseService.cs new file mode 100644 index 0000000..55500ff --- /dev/null +++ b/ExamTemplate/Services/Interfaces/IBaseService.cs @@ -0,0 +1,21 @@ +using System; +using System.Threading.Tasks; +using System.Collections.Generic; + +namespace ExamTemplate.Services.Interfaces +{ + public interface IBaseService<DbModel, ServiceModel> + where DbModel : class + where ServiceModel : class + { + Task<bool> CreateAsync(ServiceModel serviceModel); + + Task<ServiceModel> GetByIdAsync(Guid id); + + Task<List<ServiceModel>> GetAll(); + + Task<bool> EditAsync(ServiceModel serviceModel); + + Task<bool> DeleteAsync(Guid id); + } +} diff --git a/ExamTemplate/Services/Interfaces/IUserService.cs b/ExamTemplate/Services/Interfaces/IUserService.cs index 7f4c26f..35f14e3 100644 --- a/ExamTemplate/Services/Interfaces/IUserService.cs +++ b/ExamTemplate/Services/Interfaces/IUserService.cs @@ -1,8 +1,6 @@ using System.Security.Claims; using System.Threading.Tasks; using ExamTemplate.Services.Models.User; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; namespace ExamTemplate.Services.Interfaces { @@ -18,7 +16,7 @@ namespace ExamTemplate.Services.Interfaces Task<UserServiceModel> GetUserByClaimsAsync(ClaimsPrincipal claimsPrincipal); - Task<bool> EditUserAsync(ClaimsPrincipal claimsPrincipal, EditUserServiceModel editUserServiceModel); + Task<bool> EditUserAsync(ClaimsPrincipal claimsPrincipal, UserServiceModel userServiceModel); Task<bool> DeleteUserAsync(ClaimsPrincipal claimsPrincipal); diff --git a/ExamTemplate/Services/Models/User/EditUserServiceModel.cs b/ExamTemplate/Services/Models/User/EditUserServiceModel.cs deleted file mode 100644 index c8b9971..0000000 --- a/ExamTemplate/Services/Models/User/EditUserServiceModel.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ExamTemplate.Services.Models.User -{ - public class EditUserServiceModel - { - public string FirstName { get; set; } - public string LastName { get; set; } - public string Username { get; set; } - } -} diff --git a/ExamTemplate/Services/Services/BaseService.cs b/ExamTemplate/Services/Services/BaseService.cs new file mode 100644 index 0000000..89b3239 --- /dev/null +++ b/ExamTemplate/Services/Services/BaseService.cs @@ -0,0 +1,81 @@ +using System; +using System.Threading.Tasks; +using AutoMapper; +using ExamTemplate.Data; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using System.Linq; +using ExamTemplate.Services.Interfaces; + +namespace ExamTemplate.Services.Services +{ + public abstract class BaseService<DbModel, ServiceModel> : IBaseService<DbModel, ServiceModel> + where DbModel : class + where ServiceModel : class + { + protected IMapper _autoMapper { get; private set; } + protected TemplateContext _context { get; private set; } + + protected BaseService(IMapper autoMapper, TemplateContext context) + { + this._autoMapper = autoMapper; + this._context = context; + } + + public virtual async Task<bool> CreateAsync(ServiceModel serviceModel) + { + DbModel newEntity = this._autoMapper.Map<DbModel>(serviceModel); + + await this.GetDbSet() + .AddAsync(newEntity); + + return await this.SaveChangesAsync(); + } + + public virtual async Task<ServiceModel> GetByIdAsync(Guid id) + { + DbModel entity = await this.GetDbSet() + .FindAsync(id); + + return this._autoMapper.Map<ServiceModel>(entity); + } + + public virtual async Task<List<ServiceModel>> GetAll() + { + return await this.GetDbSet() + .Select(x => this._autoMapper.Map<ServiceModel>(x)) + .ToListAsync(); + } + + public virtual async Task<bool> EditAsync(ServiceModel serviceModel) + { + DbModel entity = this._autoMapper.Map<DbModel>(serviceModel); + + this._context.Update(entity); + + return await this.SaveChangesAsync(); + } + + public virtual async Task<bool> DeleteAsync(Guid id) + { + DbModel entity = this.GetDbSet() + .Find(id); + + this._context.Remove(entity); + + return await this.SaveChangesAsync(); + } + + /// Get, Create, Edit and Delete use this method + /// Override it to add include statements (and so all other methods will work with includes too) + protected virtual DbSet<DbModel> GetDbSet() + { + return this._context.Set<DbModel>(); + } + + protected async Task<bool> SaveChangesAsync() + { + return await this._context.SaveChangesAsync() >= 1; + } + } +} diff --git a/ExamTemplate/Services/Services/UserService.cs b/ExamTemplate/Services/Services/UserService.cs index dab0801..f2a3e9f 100644 --- a/ExamTemplate/Services/Services/UserService.cs +++ b/ExamTemplate/Services/Services/UserService.cs @@ -78,13 +78,13 @@ namespace ExamTemplate.Services.Services return this._autoMapper.Map<UserServiceModel>(user);
}
- public async Task<bool> EditUserAsync(ClaimsPrincipal claimsPrincipal, EditUserServiceModel editUserServiceModel)
+ public async Task<bool> EditUserAsync(ClaimsPrincipal claimsPrincipal, UserServiceModel userServiceModel)
{
User user = await this._userManager.GetUserAsync(claimsPrincipal);
- user.UserName = editUserServiceModel.Username;
- user.FirstName = editUserServiceModel.FirstName;
- user.LastName = editUserServiceModel.LastName;
+ user.UserName = userServiceModel.Username;
+ user.FirstName = userServiceModel.FirstName;
+ user.LastName = userServiceModel.LastName;
IdentityResult result = await this._userManager.UpdateAsync(user);
return result.Succeeded;
diff --git a/ExamTemplate/Web/Configurations/ControllerUserMappings.cs b/ExamTemplate/Web/Configurations/ControllerUserMappings.cs index 0a797af..9b798e6 100644 --- a/ExamTemplate/Web/Configurations/ControllerUserMappings.cs +++ b/ExamTemplate/Web/Configurations/ControllerUserMappings.cs @@ -12,7 +12,7 @@ namespace ExamTemplate.Services.Configurations CreateMap<LoginUserViewModel, LoginUserServiceModel>(); CreateMap<UserServiceModel, UserViewModel>(); CreateMap<UserServiceModel, EditUserViewModel>(); - CreateMap<EditUserViewModel, EditUserServiceModel>(); + CreateMap<EditUserViewModel, UserServiceModel>(); } } } diff --git a/ExamTemplate/Web/Controllers/AccountController.cs b/ExamTemplate/Web/Controllers/AccountController.cs index b7a1207..414304f 100644 --- a/ExamTemplate/Web/Controllers/AccountController.cs +++ b/ExamTemplate/Web/Controllers/AccountController.cs @@ -117,8 +117,8 @@ namespace ExamTemplate.Web.Controllers UserServiceModel loggedInUser = await this._userService.GetUserByClaimsAsync(HttpContext.User); - EditUserServiceModel editUserServiceModel = this._autoMapper.Map<EditUserServiceModel>(editUserViewModel); - bool result = await this._userService.EditUserAsync(HttpContext.User, editUserServiceModel); + UserServiceModel userServiceModel = this._autoMapper.Map<UserServiceModel>(editUserViewModel); + bool result = await this._userService.EditUserAsync(HttpContext.User, userServiceModel); if (result) { @@ -72,9 +72,7 @@ The script will create (and edit where specified) the following files: │ │ └─ ServiceCarMappings.cs │ ├─ Models │ │ └─ Car -│ │ ├─ CarServiceModel.cs -│ │ ├─ CreateCarServiceModel.cs -│ │ └─ EditCarServiceModel.cs +│ │ └─ CarServiceModel.cs │ └─ CarService.cs ├─ Web │ ├─ Configurations @@ -95,7 +93,7 @@ The script will create (and edit where specified) the following files: │ └─ _ViewImports.cshtml (Only edited; Adds reference to the Car View Models namespace) └─ Startup.cs (Only edited; Adds dependency injection configuration for CarService) ``` -All of the models have all given properties **and a "Guid Id" property**. Only the Create models don't have the "Guid Id" property. +All of the models have all given properties **and a "Guid Id" property**. Only the Web Create models don't have the "Guid Id" property. Controller and Service have **very basic** CRUD of the model. No view links are added, so you'll need to provide them (and to test out if everything work: just edit the link in the browser). diff --git a/tools/add-feature-template.sh b/tools/add-feature-template.sh index c5ebe45..e5433f3 100755 --- a/tools/add-feature-template.sh +++ b/tools/add-feature-template.sh @@ -67,100 +67,31 @@ dir="../$project_name/Services" # Create Service and Interface cat > $dir/Interfaces/I${feature_name}Service.cs<< EOF -using System; -using System.Threading.Tasks; +using $project_name.Data.Models; using $project_name.Services.Models.$feature_name; -using System.Collections.Generic; namespace $project_name.Services.Interfaces { - public interface I${feature_name}Service - { - Task<bool> CreateAsync(Create${feature_name}ServiceModel create${feature_name}ServiceModel); - - Task<${feature_name}ServiceModel> GetByIdAsync(Guid id); - - List<${feature_name}ServiceModel> GetAll(); - - Task<bool> EditAsync(Edit${feature_name}ServiceModel edit${feature_name}ServiceModel); - - Task<bool> DeleteAsync(Guid id); - } + public interface I${feature_name}Service : IBaseService<${feature_name}, ${feature_name}ServiceModel> + { } } EOF cat > $dir/Services/${feature_name}Service.cs<< EOF using $project_name.Services.Interfaces; using System; -using System.Threading.Tasks; using AutoMapper; using $project_name.Data; using $project_name.Data.Models; using $project_name.Services.Models.$feature_name; -using System.Collections.Generic; -using System.Linq; namespace $project_name.Services.Services { - public class ${feature_name}Service : I${feature_name}Service + public class ${feature_name}Service : BaseService<${feature_name}, ${feature_name}ServiceModel>, I${feature_name}Service { - private readonly IMapper _autoMapper; - private readonly ${project_name}Context _context; - public ${feature_name}Service(IMapper autoMapper, ${project_name}Context context) - { - this._autoMapper = autoMapper; - this._context = context; - } - - public async Task<bool> CreateAsync(Create${feature_name}ServiceModel create${feature_name}ServiceModel) - { - $feature_name new$feature_name = this._autoMapper.Map<$feature_name>(create${feature_name}ServiceModel); - - await this._context.${feature_name}s - .AddAsync(new$feature_name); - - return await this.SaveChangesAsync(); - } - - public async Task<${feature_name}ServiceModel> GetByIdAsync(Guid id) - { - $feature_name curr$feature_name = await this._context.${feature_name}s - .FindAsync(id); - - return this._autoMapper.Map<${feature_name}ServiceModel>(curr$feature_name); - } - - public async Task<List<${feature_name}ServiceModel>> GetAll() - { - return await this._context.${feature_name}s - .Select(x => this._autoMapper.Map<${feature_name}ServiceModel>(x)) - .ToListAsync(); - } - - public async Task<bool> EditAsync(Edit${feature_name}ServiceModel edit${feature_name}ServiceModel) - { - $feature_name curr$feature_name = this._autoMapper.Map<$feature_name>(edit${feature_name}ServiceModel); - - this._context.Update(curr$feature_name); - - return await this.SaveChangesAsync(); - } - - public async Task<bool> DeleteAsync(Guid id) - { - $feature_name curr$feature_name = await this._context.${feature_name}s - .FindAsync(id); - - this._context.Remove(curr$feature_name); - - return await this.SaveChangesAsync(); - } - - private async Task<bool> SaveChangesAsync() - { - return await this._context.SaveChangesAsync() >= 1; - } + :base(autoMapper, context) + { } } } EOF @@ -168,28 +99,18 @@ EOF # }}} ---------------------------< # {{{ ---------------------------> -# Create Service Models +# Create Service Model subdir="$dir/Models/$feature_name" mkdir -p $subdir -models=("" "Create" "Edit") -for model in "${models[@]}" -do cat > $subdir/$model${feature_name}ServiceModel.cs<< EOF -using System;$( -if [ "$model" != "Create" ]; then -echo -e "\nusing $project_name.Services.Models;" -fi -) +using System; +using $project_name.Services.Models; namespace $project_name.Services.Models.$feature_name { - public class $model${feature_name}ServiceModel$( -if [ "$model" != "Create" ]; then -echo -e ' : BaseServiceModel' -fi -) + public class $model${feature_name}ServiceModel : BaseServiceModel { $( for feature in "${features[@]}"; do @@ -199,7 +120,6 @@ done } } EOF -done # }}} ---------------------------< @@ -208,7 +128,7 @@ done subdir="${dir}/Configurations" -mappings=("Create${feature_name}ServiceModel, $feature_name" "$feature_name, ${feature_name}ServiceModel" "Edit${feature_name}ServiceModel, $feature_name") +mappings=("${feature_name}ServiceModel, $feature_name" "${feature_name}, ${feature_name}ServiceModel") cat > $subdir/Service${feature_name}Mappings.cs<< EOF using AutoMapper; using $project_name.Data.Models; @@ -422,9 +342,9 @@ namespace $project_name.Web.Controllers [HttpPost] public async Task<IActionResult> Create(Create${feature_name}WebModel webModel) { - Create${feature_name}ServiceModel create${feature_name}ServiceModel = this._autoMapper.Map<Create${feature_name}ServiceModel>(webModel); + ${feature_name}ServiceModel serviceModel = this._autoMapper.Map<${feature_name}ServiceModel>(webModel); - bool result = await this._service.CreateAsync(create${feature_name}ServiceModel); + bool result = await this._service.CreateAsync(serviceModel); if (result) return RedirectToAction("Profile", "Account"); @@ -447,9 +367,9 @@ namespace $project_name.Web.Controllers [HttpPost] public async Task<IActionResult> Edit(Edit${feature_name}WebModel webModel) { - Edit${feature_name}ServiceModel edit${feature_name}ServiceModel = this._autoMapper.Map<Edit${feature_name}ServiceModel>(webModel); + ${feature_name}ServiceModel serviceModel = this._autoMapper.Map<${feature_name}ServiceModel>(webModel); - bool result = await this._service.EditAsync(edit${feature_name}ServiceModel); + bool result = await this._service.EditAsync(serviceModel); if (result) return RedirectToAction("Index", new { id = webModel.Id.ToString() }); @@ -484,7 +404,7 @@ EOF subdir="${dir}/Configurations" -mappings=("${feature_name}ServiceModel, ${feature_name}WebModel" "Create${feature_name}WebModel, Create${feature_name}ServiceModel" "${feature_name}ServiceModel, Edit${feature_name}WebModel" "Edit${feature_name}WebModel, Edit${feature_name}ServiceModel") +mappings=("${feature_name}ServiceModel, ${feature_name}WebModel" "Create${feature_name}WebModel, ${feature_name}ServiceModel" "${feature_name}ServiceModel, Edit${feature_name}WebModel" "Edit${feature_name}WebModel, ${feature_name}ServiceModel") cat > $subdir/Controller${feature_name}Mappings.cs<< EOF using AutoMapper; using $project_name.Services.Models.$feature_name; |
