From 23cf04f4d0f42ff683840e039dbd73b20ebcc489 Mon Sep 17 00:00:00 2001 From: dmitry Date: Wed, 27 Jan 2021 15:12:09 +0500 Subject: [PATCH 01/28] =?UTF-8?q?=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20l2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UI/WebStore/Startup.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/UI/WebStore/Startup.cs b/UI/WebStore/Startup.cs index de4f804..f2b59ac 100644 --- a/UI/WebStore/Startup.cs +++ b/UI/WebStore/Startup.cs @@ -26,6 +26,7 @@ public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + private readonly IConfiguration _Configuration; public Startup(IConfiguration Configuration) => _Configuration = Configuration; From 1969eb1ba8911da41e90d34d5b703701a964ed4c Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 12:50:50 +0500 Subject: [PATCH 02/28] =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8?= =?UTF-8?q?=D1=81=D0=BE=D0=B2=20=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=82=D0=B5?= =?UTF-8?q?=D0=B9=D0=BD=D0=B5=D1=80=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Services/WebStore.ServiceHosting/Startup.cs | 45 +++++++++++++- .../WebStore.ServiceHosting.csproj | 7 +++ .../WebStore.ServiceHosting/appsettings.json | 3 + UI/WebStore/Startup.cs | 60 +++++++++---------- 4 files changed, 82 insertions(+), 33 deletions(-) diff --git a/Services/WebStore.ServiceHosting/Startup.cs b/Services/WebStore.ServiceHosting/Startup.cs index f4cb774..8071915 100644 --- a/Services/WebStore.ServiceHosting/Startup.cs +++ b/Services/WebStore.ServiceHosting/Startup.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -10,6 +12,13 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Webstore.DAL.Context; +using Webstore.Interfaces.Services; +using Webstore.Services.Data; +using Webstore.Services.Products; +using Webstore.Services.Products.InCookies; +using Webstore.Services.Products.InSql; +using WebStore.Domain.Entities.Identity; namespace WebStore.ServiceHosting { @@ -17,14 +26,43 @@ public class Startup { public Startup(IConfiguration configuration) { - Configuration = configuration; + _Configuration = configuration; } - public IConfiguration Configuration { get; } + private readonly IConfiguration _Configuration; // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + services.AddDbContext(opt => opt.UseSqlServer(_Configuration.GetConnectionString("Default"))); + services.AddTransient(); + + services.AddIdentity() + .AddEntityFrameworkStores() + .AddDefaultTokenProviders(); + + services.AddSingleton(); + services.AddTransient(); + services.AddScoped(); + services.AddScoped(); + + services.Configure(opt => + { +#if DEBUG + opt.Password.RequiredLength = 3; + opt.Password.RequireDigit = false; + opt.Password.RequireLowercase = false; + opt.Password.RequireUppercase = false; + opt.Password.RequireNonAlphanumeric = false; + opt.Password.RequiredUniqueChars = 3; +#endif + opt.User.RequireUniqueEmail = false; + opt.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + + opt.Lockout.AllowedForNewUsers = true; + opt.Lockout.MaxFailedAccessAttempts = 10; + opt.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10); + }); services.AddControllers(); services.AddSwaggerGen(c => @@ -34,8 +72,9 @@ public void ConfigureServices(IServiceCollection services) } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, WebStoreDbInitializer db) { + db.Initialize(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); diff --git a/Services/WebStore.ServiceHosting/WebStore.ServiceHosting.csproj b/Services/WebStore.ServiceHosting/WebStore.ServiceHosting.csproj index 2884716..7169942 100644 --- a/Services/WebStore.ServiceHosting/WebStore.ServiceHosting.csproj +++ b/Services/WebStore.ServiceHosting/WebStore.ServiceHosting.csproj @@ -8,4 +8,11 @@ + + + + + + + diff --git a/Services/WebStore.ServiceHosting/appsettings.json b/Services/WebStore.ServiceHosting/appsettings.json index d9d9a9b..f455cbb 100644 --- a/Services/WebStore.ServiceHosting/appsettings.json +++ b/Services/WebStore.ServiceHosting/appsettings.json @@ -1,4 +1,7 @@ { + "ConnectionStrings": { + "Default": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WebStore-DB" + }, "Logging": { "LogLevel": { "Default": "Information", diff --git a/UI/WebStore/Startup.cs b/UI/WebStore/Startup.cs index f2b59ac..13b9aae 100644 --- a/UI/WebStore/Startup.cs +++ b/UI/WebStore/Startup.cs @@ -32,30 +32,30 @@ public class Startup public Startup(IConfiguration Configuration) => _Configuration = Configuration; public void ConfigureServices(IServiceCollection services) { - services.AddDbContext(opt => opt.UseSqlServer(_Configuration.GetConnectionString("Default"))); - services.AddTransient(); - - services.AddIdentity() - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); - - services.Configure(opt => - { -#if DEBUG - opt.Password.RequiredLength = 3; - opt.Password.RequireDigit = false; - opt.Password.RequireLowercase = false; - opt.Password.RequireUppercase = false; - opt.Password.RequireNonAlphanumeric = false; - opt.Password.RequiredUniqueChars = 3; -#endif - opt.User.RequireUniqueEmail = false; - opt.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - - opt.Lockout.AllowedForNewUsers = true; - opt.Lockout.MaxFailedAccessAttempts = 10; - opt.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10); - }); +// services.AddDbContext(opt => opt.UseSqlServer(_Configuration.GetConnectionString("Default"))); +// services.AddTransient(); + +// services.AddIdentity() +// .AddEntityFrameworkStores() +// .AddDefaultTokenProviders(); + +// services.Configure(opt => +// { +//#if DEBUG +// opt.Password.RequiredLength = 3; +// opt.Password.RequireDigit = false; +// opt.Password.RequireLowercase = false; +// opt.Password.RequireUppercase = false; +// opt.Password.RequireNonAlphanumeric = false; +// opt.Password.RequiredUniqueChars = 3; +//#endif +// opt.User.RequireUniqueEmail = false; +// opt.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + +// opt.Lockout.AllowedForNewUsers = true; +// opt.Lockout.MaxFailedAccessAttempts = 10; +// opt.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10); +// }); services.ConfigureApplicationCookie(opt => { @@ -71,21 +71,21 @@ public void ConfigureServices(IServiceCollection services) }); services.AddControllersWithViews().AddRazorRuntimeCompilation(); - services.AddSingleton(); + //services.AddSingleton(); //services.AddTransient(); - services.AddTransient(); + //services.AddTransient(); //InMemoryBlogsData: IBlogsData services.AddSingleton(); - services.AddScoped(); - services.AddScoped(); + //services.AddScoped(); + //services.AddScoped(); services.AddScoped(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, WebStoreDbInitializer db) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env)/*, WebStoreDbInitializer db)*/ { - db.Initialize(); + //db.Initialize(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); From 8fa07164067a3ed7a53af223ab4b47f01cd5f5da Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 13:02:49 +0500 Subject: [PATCH 03/28] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5?= =?UTF-8?q?=D1=80=20api=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=BE=D1=82=D1=80?= =?UTF-8?q?=D1=83=D0=B4=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/EmployeesApiController.cs | 53 ++++++++++++++++ UI/WebStore/Startup.cs | 61 +++++++++---------- 2 files changed, 83 insertions(+), 31 deletions(-) create mode 100644 Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs diff --git a/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs b/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs new file mode 100644 index 0000000..44ccddc --- /dev/null +++ b/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs @@ -0,0 +1,53 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Webstore.Interfaces.Services; +using WebStore.Domain.Models; + +namespace WebStore.ServiceHosting.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class EmployeesApiController : ControllerBase, IEmployeesData + { + private readonly IEmployeesData _db; + + public EmployeesApiController(IEmployeesData db) + { + _db = db; + } + + [HttpPost] + public int Add(Employee employee) + { + return _db.Add(employee); + } + + [HttpDelete("{id}")] + public bool Delete(int id) + { + return _db.Delete(id); + } + + [HttpGet] + public IEnumerable Get() + { + return _db.Get(); + } + + [HttpGet("{id}")] + public Employee Get(int id) + { + return _db.Get(id); + } + + [HttpPut] + public void Update(Employee employee) + { + _db.Update(employee); + } + } +} diff --git a/UI/WebStore/Startup.cs b/UI/WebStore/Startup.cs index 13b9aae..e334c0f 100644 --- a/UI/WebStore/Startup.cs +++ b/UI/WebStore/Startup.cs @@ -32,30 +32,30 @@ public class Startup public Startup(IConfiguration Configuration) => _Configuration = Configuration; public void ConfigureServices(IServiceCollection services) { -// services.AddDbContext(opt => opt.UseSqlServer(_Configuration.GetConnectionString("Default"))); -// services.AddTransient(); - -// services.AddIdentity() -// .AddEntityFrameworkStores() -// .AddDefaultTokenProviders(); - -// services.Configure(opt => -// { -//#if DEBUG -// opt.Password.RequiredLength = 3; -// opt.Password.RequireDigit = false; -// opt.Password.RequireLowercase = false; -// opt.Password.RequireUppercase = false; -// opt.Password.RequireNonAlphanumeric = false; -// opt.Password.RequiredUniqueChars = 3; -//#endif -// opt.User.RequireUniqueEmail = false; -// opt.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - -// opt.Lockout.AllowedForNewUsers = true; -// opt.Lockout.MaxFailedAccessAttempts = 10; -// opt.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10); -// }); + services.AddDbContext(opt => opt.UseSqlServer(_Configuration.GetConnectionString("Default"))); + services.AddTransient(); + + services.AddIdentity() + .AddEntityFrameworkStores() + .AddDefaultTokenProviders(); + + services.Configure(opt => + { +#if DEBUG + opt.Password.RequiredLength = 3; + opt.Password.RequireDigit = false; + opt.Password.RequireLowercase = false; + opt.Password.RequireUppercase = false; + opt.Password.RequireNonAlphanumeric = false; + opt.Password.RequiredUniqueChars = 3; +#endif + opt.User.RequireUniqueEmail = false; + opt.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + + opt.Lockout.AllowedForNewUsers = true; + opt.Lockout.MaxFailedAccessAttempts = 10; + opt.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10); + }); services.ConfigureApplicationCookie(opt => { @@ -71,21 +71,20 @@ public void ConfigureServices(IServiceCollection services) }); services.AddControllersWithViews().AddRazorRuntimeCompilation(); - //services.AddSingleton(); + services.AddSingleton(); //services.AddTransient(); - //services.AddTransient(); - //InMemoryBlogsData: IBlogsData + services.AddTransient(); services.AddSingleton(); - //services.AddScoped(); - //services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddScoped(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env)/*, WebStoreDbInitializer db)*/ + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, WebStoreDbInitializer db) { - //db.Initialize(); + db.Initialize(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); From 03f97c9fcf2f7ed85005c4224caa5fea751931c9 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 13:14:31 +0500 Subject: [PATCH 04/28] =?UTF-8?q?api=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=20=D1=81=D0=BE=D1=82=D1=80=D1=83?= =?UTF-8?q?=D0=B4=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/EmployeesApiController.cs | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs b/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs index 44ccddc..7f204cb 100644 --- a/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs +++ b/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; @@ -14,22 +15,46 @@ namespace WebStore.ServiceHosting.Controllers public class EmployeesApiController : ControllerBase, IEmployeesData { private readonly IEmployeesData _db; + private readonly ILogger _Logger; - public EmployeesApiController(IEmployeesData db) + public EmployeesApiController(IEmployeesData db, ILogger Logger) { _db = db; + _Logger = Logger; } [HttpPost] public int Add(Employee employee) { - return _db.Add(employee); + if (!ModelState.IsValid) + { + _Logger.LogWarning("Ошибка модели данных при добавлении нового сотрудника {0} {1}", + employee.LastName, employee.FirstName); + return 0; + } + _Logger.LogInformation("Добавление сотрудника {0} {1}", + employee.LastName, employee.FirstName); + var id = _db.Add(employee); + if (id > 0) + _Logger.LogInformation("Cотрудник [id:{0}] {1} {2} добавлен успешно", + employee.Id, employee.LastName, employee.FirstName); + else + _Logger.LogWarning("Ошибка при добавлении сотрудника {0} {1}", + employee.LastName, employee.FirstName); + return id; } [HttpDelete("{id}")] public bool Delete(int id) { - return _db.Delete(id); + + var result = _db.Delete(id); + if (result) + _Logger.LogInformation("Сотрудник с id:{0} успешно удалён", id); + else + _Logger.LogWarning("ошибка при попытке удаления сотрдуника с id:{0}", id); + + return result; } [HttpGet] From 01c2d66043145e2d8602628a49a18078d683f322 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 13:23:07 +0500 Subject: [PATCH 05/28] =?UTF-8?q?=D0=97=D0=B0=D0=B3=D0=BE=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=B0=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=20Emploees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Employees/EmployeesClient.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Services/WebStore.Client/Employees/EmployeesClient.cs diff --git a/Services/WebStore.Client/Employees/EmployeesClient.cs b/Services/WebStore.Client/Employees/EmployeesClient.cs new file mode 100644 index 0000000..3124d0a --- /dev/null +++ b/Services/WebStore.Client/Employees/EmployeesClient.cs @@ -0,0 +1,46 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Text; +using Webstore.Interfaces.Services; +using WebStore.Client.Base; +using WebStore.Domain.Models; + +namespace WebStore.Client.Employees +{ + public class EmployeesClient: BaseClient, IEmployeesData + { + private readonly ILogger logger; + + public EmployeesClient(IConfiguration Configuration, ILogger Logger): base(Configuration, "api/employees") + { + logger = Logger; + } + + public int Add(Employee employee) + { + throw new NotImplementedException(); + } + + public bool Delete(int id) + { + throw new NotImplementedException(); + } + + public IEnumerable Get() + { + throw new NotImplementedException(); + } + + public Employee Get(int id) + { + throw new NotImplementedException(); + } + + public void Update(Employee employee) + { + throw new NotImplementedException(); + } + } +} From cd4bc9d7cdb21d36f10102c77af47214aa2a9bbd Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 13:32:35 +0500 Subject: [PATCH 06/28] =?UTF-8?q?=D0=A0=D0=B0=D1=81=D1=88=D0=B8=D1=80?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B1=D0=B0=D0=B7=D0=BE=D0=B2=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Services/WebStore.Client/Base/BaseClient.cs | 32 +++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Services/WebStore.Client/Base/BaseClient.cs b/Services/WebStore.Client/Base/BaseClient.cs index 00a968e..b587d52 100644 --- a/Services/WebStore.Client/Base/BaseClient.cs +++ b/Services/WebStore.Client/Base/BaseClient.cs @@ -1,6 +1,7 @@ using System; using System.Net.Http; using System.Net.Http.Headers; +using System.Threading.Tasks; using Microsoft.Extensions.Configuration; namespace WebStore.Client.Base @@ -22,5 +23,36 @@ protected BaseClient(IConfiguration Configuration, string ServiceAddress) } }; } + + protected T Get(string url) => GetAsync(url).Result; + protected async Task GetAsync(string url) + { + var response = await Http.GetAsync(url); + return await response.EnsureSuccessStatusCode().Content.ReadAsAsync(); + } + + protected HttpResponseMessage Post(string url, T item) => PostAsync(url, item).Result; + + protected async Task PostAsync(string url, T item) + { + var response = await Http.PostAsJsonAsync(url, item); + return response.EnsureSuccessStatusCode(); + } + + protected HttpResponseMessage Put(string url, T item) => PutAsync(url, item).Result; + + protected async Task PutAsync(string url, T item) + { + var response = await Http.PutAsJsonAsync(url, item); + return response.EnsureSuccessStatusCode(); + } + + protected HttpResponseMessage Delete(string url) => DeleteAsync(url).Result; + + protected async Task DeleteAsync(string url) + { + var response = await Http.DeleteAsync(url); + return response; + } } } From 938b543c37133e926e13291448d9635e6e579c3e Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 13:39:20 +0500 Subject: [PATCH 07/28] =?UTF-8?q?=D0=9A=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=81=D0=BE=D1=82=D1=80=D1=83=D0=B4=D0=BD?= =?UTF-8?q?=D0=B8=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Employees/EmployeesClient.cs | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/Services/WebStore.Client/Employees/EmployeesClient.cs b/Services/WebStore.Client/Employees/EmployeesClient.cs index 3124d0a..235e727 100644 --- a/Services/WebStore.Client/Employees/EmployeesClient.cs +++ b/Services/WebStore.Client/Employees/EmployeesClient.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; +using System.Net.Http; using System.Text; using Webstore.Interfaces.Services; using WebStore.Client.Base; @@ -11,36 +12,25 @@ namespace WebStore.Client.Employees { public class EmployeesClient: BaseClient, IEmployeesData { - private readonly ILogger logger; + private readonly ILogger _Logger; public EmployeesClient(IConfiguration Configuration, ILogger Logger): base(Configuration, "api/employees") { - logger = Logger; + _Logger = Logger; } - public int Add(Employee employee) - { - throw new NotImplementedException(); - } + public int Add(Employee employee)=>Post(Address,employee).Content.ReadAsAsync().Result; - public bool Delete(int id) - { - throw new NotImplementedException(); - } + public bool Delete(int id) => Delete($"{Address}/{id}").IsSuccessStatusCode; - public IEnumerable Get() - { - throw new NotImplementedException(); - } + public IEnumerable Get() => Get>(Address); - public Employee Get(int id) - { - throw new NotImplementedException(); - } + public Employee Get(int id) => Get($"{Address}/{id}"); public void Update(Employee employee) { - throw new NotImplementedException(); + _Logger.LogInformation("Редактирование сотрудника с id:{ 0}", employee.Id); + Put(Address, employee); } } } From 6ba7e97ae524a60b6931f82ea80050863226ddd5 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 16:47:30 +0500 Subject: [PATCH 08/28] =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E.?= =?UTF-8?q?=D1=87=D0=B8=D0=BB=D0=B8=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=20=D1=81=D0=BE=D1=82=D1=80=D1=83=D0=B4=D0=BD=D0=B8=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=BA=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D0=BE?= =?UTF-8?q?=D0=BC=D1=83=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/EmployeesApiController.cs | 2 +- UI/WebStore/Startup.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs b/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs index 7f204cb..9e91be0 100644 --- a/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs +++ b/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs @@ -10,7 +10,7 @@ namespace WebStore.ServiceHosting.Controllers { - [Route("api/[controller]")] + [Route("api/employees")] [ApiController] public class EmployeesApiController : ControllerBase, IEmployeesData { diff --git a/UI/WebStore/Startup.cs b/UI/WebStore/Startup.cs index e334c0f..dd8472a 100644 --- a/UI/WebStore/Startup.cs +++ b/UI/WebStore/Startup.cs @@ -19,6 +19,7 @@ using Webstore.Services.Products.InSql; using WebStore.Client.Values; using WebStore.Interfaces.TestAPI; +using WebStore.Client.Employees; namespace WebStore { @@ -71,7 +72,7 @@ public void ConfigureServices(IServiceCollection services) }); services.AddControllersWithViews().AddRazorRuntimeCompilation(); - services.AddSingleton(); + services.AddSingleton(); //services.AddTransient(); services.AddTransient(); services.AddSingleton(); From 11ef00325dc8d57b63f439c7aff5dfad0bc08b6b Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 17:05:34 +0500 Subject: [PATCH 09/28] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B1=D1=80=D0=B5=D0=BD=D0=B4=D0=B0=20=D0=B8=20=D0=BA?= =?UTF-8?q?=D0=B0=D1=82=D0=B5=D0=B3=D0=BE=D1=80=D0=BD=D0=B8=D0=B8=20=D0=BF?= =?UTF-8?q?=D0=BE=20id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Services/Webstore.Interfaces/Services/IProductData.cs | 4 ++++ .../Webstore.Services/Products/InMemoryProductsData.cs | 10 ++++++++++ .../Products/InSql/InSqIProductData.cs | 10 ++++++++++ 3 files changed, 24 insertions(+) diff --git a/Services/Webstore.Interfaces/Services/IProductData.cs b/Services/Webstore.Interfaces/Services/IProductData.cs index 2c753ed..b6e46b5 100644 --- a/Services/Webstore.Interfaces/Services/IProductData.cs +++ b/Services/Webstore.Interfaces/Services/IProductData.cs @@ -8,7 +8,11 @@ public interface IProductData { IEnumerable GetСategories(); + Category GetСategoriesById(int id); + IEnumerable GetBrands(); + + Brand GetBrandsById(int id); IEnumerable GetProducts(ProductFilter Filter = null); diff --git a/Services/Webstore.Services/Products/InMemoryProductsData.cs b/Services/Webstore.Services/Products/InMemoryProductsData.cs index 885aca1..e179639 100644 --- a/Services/Webstore.Services/Products/InMemoryProductsData.cs +++ b/Services/Webstore.Services/Products/InMemoryProductsData.cs @@ -31,5 +31,15 @@ public Product GetProductById(int id) { throw new NotImplementedException(); } + + public Category GetСategoriesById(int id) + { + throw new NotImplementedException(); + } + + public Brand GetBrandsById(int id) + { + throw new NotImplementedException(); + } } } diff --git a/Services/Webstore.Services/Products/InSql/InSqIProductData.cs b/Services/Webstore.Services/Products/InSql/InSqIProductData.cs index 250a022..729a146 100644 --- a/Services/Webstore.Services/Products/InSql/InSqIProductData.cs +++ b/Services/Webstore.Services/Products/InSql/InSqIProductData.cs @@ -21,6 +21,11 @@ public InSqIProductData(WebStoreDB db) public IEnumerable GetBrands() => _db.Brands.Include(brand => brand.Products); + public Brand GetBrandsById(int id) + { + throw new NotImplementedException(); + } + public Product GetProductById(int id) { return _db.Products.Include(p => p.Brand).Include(p => p.Category).FirstOrDefault(p => p.Id == id); @@ -47,5 +52,10 @@ public IEnumerable GetProducts(ProductFilter Filter = null) } public IEnumerable GetСategories() => _db.Categories.Include(category => category.Products); + + public Category GetСategoriesById(int id) + { + throw new NotImplementedException(); + } } } From 74aedb9491a1762286b6bb8f64fa79e0ecc24496 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 17:06:07 +0500 Subject: [PATCH 10/28] =?UTF-8?q?=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BB=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B?= =?UTF-8?q?=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81=D0=B0?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=BA=D0=B0=D1=82=D0=B5=D0=B3=D0=BE=D0=B8?= =?UTF-8?q?=D1=80=D0=B8=D0=B8=20=D0=B8=20=D0=B1=D1=80=D0=B5=D0=BD=D0=B4?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BE=20id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Services/Webstore.Services/Products/InSql/InSqIProductData.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Services/Webstore.Services/Products/InSql/InSqIProductData.cs b/Services/Webstore.Services/Products/InSql/InSqIProductData.cs index 729a146..c8f81c7 100644 --- a/Services/Webstore.Services/Products/InSql/InSqIProductData.cs +++ b/Services/Webstore.Services/Products/InSql/InSqIProductData.cs @@ -23,7 +23,7 @@ public InSqIProductData(WebStoreDB db) public Brand GetBrandsById(int id) { - throw new NotImplementedException(); + return _db.Brands.Include(brand => brand.Products).FirstOrDefault(brand => brand.Id == id); } public Product GetProductById(int id) @@ -55,7 +55,7 @@ public IEnumerable GetProducts(ProductFilter Filter = null) public Category GetСategoriesById(int id) { - throw new NotImplementedException(); + return _db.Categories.Include(category => category.Products).FirstOrDefault(category => category.Id == id); } } } From 3698f456addac99c8c13f13f7e0d7425e3529d70 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 17:06:20 +0500 Subject: [PATCH 11/28] =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=BB=D0=BB=D0=B5=D1=80=20=D0=B4=D0=BB=D1=8F=20=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/ProductsApiController.cs | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs diff --git a/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs new file mode 100644 index 0000000..d18056b --- /dev/null +++ b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs @@ -0,0 +1,64 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Webstore.Interfaces.Services; +using WebStore.Domain; +using WebStore.Domain.Entities; + +namespace WebStore.ServiceHosting.Controllers +{ + [Route("api/products")] + [ApiController] + public class ProductsApiController : ControllerBase, IProductData + { + private readonly IProductData _db; + private readonly ILogger _Logger; + + public ProductsApiController(IProductData db, ILogger Logger) + { + _db = db; + _Logger = Logger; + } + + [HttpGet("brands")] + public IEnumerable GetBrands() + { + return _db.GetBrands(); + } + + [HttpGet("brands/{id}")] + public Brand GetBrandsById(int id) + { + throw new NotImplementedException(); + } + + [HttpGet("products/{id}")] + public Product GetProductById(int id) + { + return _db.GetProductById(id); + } + + + [HttpGet("products")] + public IEnumerable GetProducts(ProductFilter Filter = null) + { + return _db.GetProducts(Filter); + } + + [HttpGet("categories")] + public IEnumerable GetСategories() + { + return _db.GetСategories(); + } + + [HttpGet("categories/{id}")] + public Category GetСategoriesById(int id) + { + throw new NotImplementedException(); + } + } +} From 4e47daddde8e084f33c6621ad760e4cc2f6083e5 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 17:07:56 +0500 Subject: [PATCH 12/28] =?UTF-8?q?=D1=80=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/ProductsApiController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs index d18056b..1fe2977 100644 --- a/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs +++ b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs @@ -36,15 +36,15 @@ public Brand GetBrandsById(int id) throw new NotImplementedException(); } - [HttpGet("products/{id}")] + [HttpGet("{id}")] public Product GetProductById(int id) { return _db.GetProductById(id); } - [HttpGet("products")] - public IEnumerable GetProducts(ProductFilter Filter = null) + [HttpPost] + public IEnumerable GetProducts([FromBody]ProductFilter Filter = null) { return _db.GetProducts(Filter); } From b0f8dd98979ad484c3400fb09f78cd693a97f0c7 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 17:20:45 +0500 Subject: [PATCH 13/28] =?UTF-8?q?=D0=9E=D0=BF=D0=B8=D1=81=D0=B0=D0=BB=20DT?= =?UTF-8?q?O?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WebStore.Domain/DTO/Products/BrandDTO.cs | 16 ++++++++++++++ .../DTO/Products/CategoryDTO.cs | 19 +++++++++++++++++ .../DTO/Products/ProductDTO.cs | 21 +++++++++++++++++++ Common/WebStore.Domain/WebStore.Domain.csproj | 4 ++-- 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 Common/WebStore.Domain/DTO/Products/BrandDTO.cs create mode 100644 Common/WebStore.Domain/DTO/Products/CategoryDTO.cs create mode 100644 Common/WebStore.Domain/DTO/Products/ProductDTO.cs diff --git a/Common/WebStore.Domain/DTO/Products/BrandDTO.cs b/Common/WebStore.Domain/DTO/Products/BrandDTO.cs new file mode 100644 index 0000000..2fb9862 --- /dev/null +++ b/Common/WebStore.Domain/DTO/Products/BrandDTO.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebStore.Domain.Entities.Base; + +namespace WebStore.Domain.DTO.Products +{ + class BrandDTO: NamedEntity + { + public int Order { get; set; } + + public int ProductsCount { get; set; } + } +} diff --git a/Common/WebStore.Domain/DTO/Products/CategoryDTO.cs b/Common/WebStore.Domain/DTO/Products/CategoryDTO.cs new file mode 100644 index 0000000..798c6f8 --- /dev/null +++ b/Common/WebStore.Domain/DTO/Products/CategoryDTO.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebStore.Domain.Entities.Base; + +namespace WebStore.Domain.DTO.Products +{ + class CategoryDTO: NamedEntity + { + + public int Order { get; set; } + + public int? ParentId { get; set; } + + public int ProductsCount { get; set; } + } +} diff --git a/Common/WebStore.Domain/DTO/Products/ProductDTO.cs b/Common/WebStore.Domain/DTO/Products/ProductDTO.cs new file mode 100644 index 0000000..76f3a6f --- /dev/null +++ b/Common/WebStore.Domain/DTO/Products/ProductDTO.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebStore.Domain.Entities.Base; + +namespace WebStore.Domain.DTO.Products +{ + class ProductDTO: NamedEntity + { + public int Order { get; set; } + public decimal Price { get; set; } + public string ImageUrl { get; set; } + public BrandDTO Brand { get; set; } + public CategoryDTO Category { get; set; } + public string Description { get; set; } + public int Discount { get; set; } + + } +} diff --git a/Common/WebStore.Domain/WebStore.Domain.csproj b/Common/WebStore.Domain/WebStore.Domain.csproj index e9a2516..0632141 100644 --- a/Common/WebStore.Domain/WebStore.Domain.csproj +++ b/Common/WebStore.Domain/WebStore.Domain.csproj @@ -1,7 +1,7 @@ - + - netstandard2.0 + net5.0 From fabbb8f435327dff759b71c81c05a2d1057e0bb8 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 18:01:02 +0500 Subject: [PATCH 14/28] net5 --- Services/WebStore.Client/WebStore.Client.csproj | 2 +- Services/Webstore.Interfaces/Webstore.Interfaces.csproj | 2 +- Services/Webstore.Services/Webstore.Services.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Services/WebStore.Client/WebStore.Client.csproj b/Services/WebStore.Client/WebStore.Client.csproj index 5af1b39..d23926e 100644 --- a/Services/WebStore.Client/WebStore.Client.csproj +++ b/Services/WebStore.Client/WebStore.Client.csproj @@ -1,7 +1,7 @@ - netstandard2.1 + net5.0 diff --git a/Services/Webstore.Interfaces/Webstore.Interfaces.csproj b/Services/Webstore.Interfaces/Webstore.Interfaces.csproj index aa3cb70..2f2fc48 100644 --- a/Services/Webstore.Interfaces/Webstore.Interfaces.csproj +++ b/Services/Webstore.Interfaces/Webstore.Interfaces.csproj @@ -1,7 +1,7 @@ - netstandard2.1 + net5.0 diff --git a/Services/Webstore.Services/Webstore.Services.csproj b/Services/Webstore.Services/Webstore.Services.csproj index 794bced..459e7cd 100644 --- a/Services/Webstore.Services/Webstore.Services.csproj +++ b/Services/Webstore.Services/Webstore.Services.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net5.0 From 47b2861d53f477aee012a91c77a4b411eee92d72 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 18:01:12 +0500 Subject: [PATCH 15/28] =?UTF-8?q?=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BB=20DT?= =?UTF-8?q?O?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Common/WebStore.Domain/DTO/Products/BrandDTO.cs | 2 +- Common/WebStore.Domain/DTO/Products/CategoryDTO.cs | 2 +- Common/WebStore.Domain/DTO/Products/ProductDTO.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/WebStore.Domain/DTO/Products/BrandDTO.cs b/Common/WebStore.Domain/DTO/Products/BrandDTO.cs index 2fb9862..1fd121a 100644 --- a/Common/WebStore.Domain/DTO/Products/BrandDTO.cs +++ b/Common/WebStore.Domain/DTO/Products/BrandDTO.cs @@ -7,7 +7,7 @@ namespace WebStore.Domain.DTO.Products { - class BrandDTO: NamedEntity + public class BrandDTO: NamedEntity { public int Order { get; set; } diff --git a/Common/WebStore.Domain/DTO/Products/CategoryDTO.cs b/Common/WebStore.Domain/DTO/Products/CategoryDTO.cs index 798c6f8..996e962 100644 --- a/Common/WebStore.Domain/DTO/Products/CategoryDTO.cs +++ b/Common/WebStore.Domain/DTO/Products/CategoryDTO.cs @@ -7,7 +7,7 @@ namespace WebStore.Domain.DTO.Products { - class CategoryDTO: NamedEntity + public class CategoryDTO: NamedEntity { public int Order { get; set; } diff --git a/Common/WebStore.Domain/DTO/Products/ProductDTO.cs b/Common/WebStore.Domain/DTO/Products/ProductDTO.cs index 76f3a6f..2255f9d 100644 --- a/Common/WebStore.Domain/DTO/Products/ProductDTO.cs +++ b/Common/WebStore.Domain/DTO/Products/ProductDTO.cs @@ -7,7 +7,7 @@ namespace WebStore.Domain.DTO.Products { - class ProductDTO: NamedEntity + public class ProductDTO: NamedEntity { public int Order { get; set; } public decimal Price { get; set; } From 56f0c4a3948db4cfca62638d303fc150e5698281 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 18:02:24 +0500 Subject: [PATCH 16/28] =?UTF-8?q?=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84?= =?UTF-8?q?=D0=B5=D0=B9=D1=81=20DTO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/ProductsApiController.cs | 15 +++++++------ .../Services/IProductDataDTO.cs | 22 +++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 Services/Webstore.Interfaces/Services/IProductDataDTO.cs diff --git a/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs index 1fe2977..a2cda0d 100644 --- a/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs +++ b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs @@ -7,13 +7,14 @@ using System.Threading.Tasks; using Webstore.Interfaces.Services; using WebStore.Domain; +using WebStore.Domain.DTO.Products; using WebStore.Domain.Entities; namespace WebStore.ServiceHosting.Controllers { [Route("api/products")] [ApiController] - public class ProductsApiController : ControllerBase, IProductData + public class ProductsApiController : ControllerBase, IProductDataDTO { private readonly IProductData _db; private readonly ILogger _Logger; @@ -25,38 +26,38 @@ public ProductsApiController(IProductData db, ILogger Log } [HttpGet("brands")] - public IEnumerable GetBrands() + public IEnumerable GetBrands() { return _db.GetBrands(); } [HttpGet("brands/{id}")] - public Brand GetBrandsById(int id) + public BrandDTO GetBrandsById(int id) { throw new NotImplementedException(); } [HttpGet("{id}")] - public Product GetProductById(int id) + public ProductDTO GetProductById(int id) { return _db.GetProductById(id); } [HttpPost] - public IEnumerable GetProducts([FromBody]ProductFilter Filter = null) + public IEnumerable GetProducts([FromBody]ProductFilter Filter = null) { return _db.GetProducts(Filter); } [HttpGet("categories")] - public IEnumerable GetСategories() + public IEnumerable GetСategories() { return _db.GetСategories(); } [HttpGet("categories/{id}")] - public Category GetСategoriesById(int id) + public CategoryDTO GetСategoriesById(int id) { throw new NotImplementedException(); } diff --git a/Services/Webstore.Interfaces/Services/IProductDataDTO.cs b/Services/Webstore.Interfaces/Services/IProductDataDTO.cs new file mode 100644 index 0000000..e1efe0a --- /dev/null +++ b/Services/Webstore.Interfaces/Services/IProductDataDTO.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using WebStore.Domain; +using WebStore.Domain.DTO.Products; +using WebStore.Domain.Entities; + +namespace Webstore.Interfaces.Services +{ + public interface IProductDataDTO + { + IEnumerable GetСategories(); + + CategoryDTO GetСategoriesById(int id); + + IEnumerable GetBrands(); + + BrandDTO GetBrandsById(int id); + + IEnumerable GetProducts(ProductFilter Filter = null); + + ProductDTO GetProductById(int id); + } +} From 9e8ac34a6e8e255f796a9dc04aa1abcc617d74e7 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 20:39:12 +0500 Subject: [PATCH 17/28] mapping --- Services/Webstore.DAL/Webstore.DAL.csproj | 2 +- .../Webstore.Services/Mapping/BrandMapper.cs | 33 +++++++++++++++++ .../Mapping/CategoryMapper.cs | 34 +++++++++++++++++ .../Mapping/ProductMapper.cs | 37 ++++++++++++++++++- 4 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 Services/Webstore.Services/Mapping/BrandMapper.cs create mode 100644 Services/Webstore.Services/Mapping/CategoryMapper.cs diff --git a/Services/Webstore.DAL/Webstore.DAL.csproj b/Services/Webstore.DAL/Webstore.DAL.csproj index be79c82..d57450a 100644 --- a/Services/Webstore.DAL/Webstore.DAL.csproj +++ b/Services/Webstore.DAL/Webstore.DAL.csproj @@ -1,7 +1,7 @@ - netstandard2.1 + net5.0 diff --git a/Services/Webstore.Services/Mapping/BrandMapper.cs b/Services/Webstore.Services/Mapping/BrandMapper.cs new file mode 100644 index 0000000..298a701 --- /dev/null +++ b/Services/Webstore.Services/Mapping/BrandMapper.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebStore.Domain.DTO.Products; +using WebStore.Domain.Entities; + +namespace Webstore.Services.Mapping +{ + public static class BrandMapper + { + public static BrandDTO ToDTO(this Brand Brand) => Brand is null ? null + : new BrandDTO + { + Id = Brand.Id, + Name = Brand.Name, + Order = Brand.Order, + ProductsCount = Brand.Products.Count(), + }; + public static Brand FromDTO(this BrandDTO Brand) => Brand is null ? null + : new Brand + { + Id = Brand.Id, + Name = Brand.Name, + Order = Brand.Order + }; + public static IEnumerable ToDTO(this IEnumerable Brands) => Brands.Select(ToDTO); + + public static IEnumerable FromDTO(this IEnumerable Brands) => Brands.Select(FromDTO); + + } +} diff --git a/Services/Webstore.Services/Mapping/CategoryMapper.cs b/Services/Webstore.Services/Mapping/CategoryMapper.cs new file mode 100644 index 0000000..813a4d1 --- /dev/null +++ b/Services/Webstore.Services/Mapping/CategoryMapper.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebStore.Domain.DTO.Products; +using WebStore.Domain.Entities; + +namespace Webstore.Services.Mapping +{ + public static class CategoryMapper + { + public static CategoryDTO ToDTO(this Category Category) => Category is null ? null + : new CategoryDTO + { + Id = Category.Id, + Name = Category.Name, + Order = Category.Order, + ParentId = Category.ParentId, + ProductsCount = Category.Products.Count() + }; + public static Category FromDTO(this CategoryDTO Category) => Category is null ? null + : new Category + { + Id = Category.Id, + Name = Category.Name, + Order = Category.Order, + ParentId = Category.ParentId + }; + public static IEnumerable ToDTO(this IEnumerable Categories) => Categories.Select(ToDTO); + + public static IEnumerable FromDTO(this IEnumerable Categories) => Categories.Select(FromDTO); + } +} diff --git a/Services/Webstore.Services/Mapping/ProductMapper.cs b/Services/Webstore.Services/Mapping/ProductMapper.cs index 9ecb34b..85af67a 100644 --- a/Services/Webstore.Services/Mapping/ProductMapper.cs +++ b/Services/Webstore.Services/Mapping/ProductMapper.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using WebStore.Domain.DTO.Products; using WebStore.Domain.Entities; using WebStore.Domain.ViewModels; @@ -21,9 +22,43 @@ public static class ProductMapper ImageUrl = p.ImageUrl, Name = p.Name, Order = p.Order, - Price = p.Price + Price = p.Price }; public static IEnumerable ToView(this IEnumerable p) => p.Select(ToView); + + public static ProductDTO ToDTO(this Product product) => product is null ? null + : new ProductDTO + { + Id = product.Id, + Name = product.Name, + Order = product.Order, + Price = product.Price, + ImageUrl = product.ImageUrl, + Brand = product.Brand.ToDTO(), + Category = product.Category.ToDTO(), + Description = product.Description, + Discount = product.Discount + }; + + public static Product FromDTO(this ProductDTO Product) => Product is null ? null + : new Product + { + Id = Product.Id, + Name = Product.Name, + Order = Product.Order, + Price = Product.Price, + ImageUrl = Product.ImageUrl, + Description = Product.Description, + Discount = Product.Discount, + Brand = Product.Brand.FromDTO(), + Category = Product.Category.FromDTO(), + BrandId = Product.Brand.Id, + CategoryId = Product.Category.Id + + }; + public static IEnumerable ToDTO(this IEnumerable products) => products.Select(ToDTO); + + public static IEnumerable FromDTO(this IEnumerable products) => products.Select(FromDTO); } } From 3ebd6ad1c45e7de9b5998d15238bba60273ff3fe Mon Sep 17 00:00:00 2001 From: dmitry Date: Wed, 3 Feb 2021 12:18:19 +0500 Subject: [PATCH 18/28] =?UTF-8?q?=D0=BF=D0=BE=D0=BC=D0=B5=D0=BD=D1=8F?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9?= =?UTF-8?q?=D1=81=20=D0=BD=D0=B0=20DTO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/IProductData.cs | 13 ++++++----- .../InCookies/InCookiesCartService.cs | 2 +- .../Products/InMemoryProductsData.cs | 16 ++++++++------ .../Products/InSql/InSqIProductData.cs | 22 ++++++++++--------- UI/WebStore/Controllers/ShopController.cs | 9 ++++---- 5 files changed, 33 insertions(+), 29 deletions(-) diff --git a/Services/Webstore.Interfaces/Services/IProductData.cs b/Services/Webstore.Interfaces/Services/IProductData.cs index b6e46b5..20811fd 100644 --- a/Services/Webstore.Interfaces/Services/IProductData.cs +++ b/Services/Webstore.Interfaces/Services/IProductData.cs @@ -1,21 +1,22 @@ using System.Collections.Generic; using WebStore.Domain; +using WebStore.Domain.DTO.Products; using WebStore.Domain.Entities; namespace Webstore.Interfaces.Services { public interface IProductData { - IEnumerable GetСategories(); + IEnumerable GetСategories(); - Category GetСategoriesById(int id); + CategoryDTO GetСategoriesById(int id); - IEnumerable GetBrands(); + IEnumerable GetBrands(); - Brand GetBrandsById(int id); + BrandDTO GetBrandsById(int id); - IEnumerable GetProducts(ProductFilter Filter = null); + IEnumerable GetProducts(ProductFilter Filter = null); - Product GetProductById(int id); + ProductDTO GetProductById(int id); } } diff --git a/Services/Webstore.Services/Products/InCookies/InCookiesCartService.cs b/Services/Webstore.Services/Products/InCookies/InCookiesCartService.cs index dc77a4b..eb32380 100644 --- a/Services/Webstore.Services/Products/InCookies/InCookiesCartService.cs +++ b/Services/Webstore.Services/Products/InCookies/InCookiesCartService.cs @@ -113,7 +113,7 @@ public CartViewModel TransformFromCart() Ids = Cart.Items.Select(item => item.ProductId).ToArray() }); - var product_view_models = products.ToView().ToDictionary(p => p.Id); + var product_view_models = products.FromDTO().ToView().ToDictionary(p => p.Id); return new CartViewModel { diff --git a/Services/Webstore.Services/Products/InMemoryProductsData.cs b/Services/Webstore.Services/Products/InMemoryProductsData.cs index e179639..e042302 100644 --- a/Services/Webstore.Services/Products/InMemoryProductsData.cs +++ b/Services/Webstore.Services/Products/InMemoryProductsData.cs @@ -6,17 +6,19 @@ using WebStore.Domain; using WebStore.Domain.Entities; using Webstore.Services.Data; +using WebStore.Domain.DTO.Products; +using Webstore.Services.Mapping; namespace Webstore.Services.Products { [Obsolete("Класс устарел и не реализует необходимые методы")] public class InMemoryProductsData : IProductData { - public IEnumerable GetBrands() => TestDB.Brands; + public IEnumerable GetBrands() => TestDB.Brands.ToDTO(); - public IEnumerable GetСategories() => TestDB.Сategories; + public IEnumerable GetСategories() => TestDB.Сategories.ToDTO(); - public IEnumerable GetProducts(ProductFilter Filter = null) + public IEnumerable GetProducts(ProductFilter Filter = null) { var query = TestDB.Products; @@ -24,20 +26,20 @@ public IEnumerable GetProducts(ProductFilter Filter = null) query = query.Where(product => product.CategoryId == category_id).ToList(); if (Filter?.BrandId is { } brand_id) query = query.Where(product => product.BrandId == brand_id).ToList(); - return query; + return query.ToDTO(); } - public Product GetProductById(int id) + public ProductDTO GetProductById(int id) { throw new NotImplementedException(); } - public Category GetСategoriesById(int id) + public CategoryDTO GetСategoriesById(int id) { throw new NotImplementedException(); } - public Brand GetBrandsById(int id) + public BrandDTO GetBrandsById(int id) { throw new NotImplementedException(); } diff --git a/Services/Webstore.Services/Products/InSql/InSqIProductData.cs b/Services/Webstore.Services/Products/InSql/InSqIProductData.cs index c8f81c7..e8fc7cc 100644 --- a/Services/Webstore.Services/Products/InSql/InSqIProductData.cs +++ b/Services/Webstore.Services/Products/InSql/InSqIProductData.cs @@ -7,6 +7,8 @@ using Webstore.Interfaces.Services; using WebStore.Domain; using WebStore.Domain.Entities; +using Webstore.Services.Mapping; +using WebStore.Domain.DTO.Products; namespace Webstore.Services.Products.InSql { @@ -19,19 +21,19 @@ public InSqIProductData(WebStoreDB db) _db = db; } - public IEnumerable GetBrands() => _db.Brands.Include(brand => brand.Products); + public IEnumerable GetBrands() => _db.Brands.Include(brand => brand.Products).ToDTO(); - public Brand GetBrandsById(int id) + public BrandDTO GetBrandsById(int id) { - return _db.Brands.Include(brand => brand.Products).FirstOrDefault(brand => brand.Id == id); + return _db.Brands.Include(brand => brand.Products).FirstOrDefault(brand => brand.Id == id).ToDTO(); } - public Product GetProductById(int id) + public ProductDTO GetProductById(int id) { - return _db.Products.Include(p => p.Brand).Include(p => p.Category).FirstOrDefault(p => p.Id == id); + return _db.Products.Include(p => p.Brand).Include(p => p.Category).FirstOrDefault(p => p.Id == id).ToDTO(); } - public IEnumerable GetProducts(ProductFilter Filter = null) + public IEnumerable GetProducts(ProductFilter Filter = null) { IQueryable query = _db.Products.Include(p => p.Category).Include(p => p.Brand); @@ -48,14 +50,14 @@ public IEnumerable GetProducts(ProductFilter Filter = null) query = query.Where(product => product.CategoryId == Filter.СategoryId); } - return query; + return query.AsEnumerable().ToDTO(); } - public IEnumerable GetСategories() => _db.Categories.Include(category => category.Products); + public IEnumerable GetСategories() => _db.Categories.Include(category => category.Products).ToDTO(); - public Category GetСategoriesById(int id) + public CategoryDTO GetСategoriesById(int id) { - return _db.Categories.Include(category => category.Products).FirstOrDefault(category => category.Id == id); + return _db.Categories.Include(category => category.Products).FirstOrDefault(category => category.Id == id).ToDTO(); } } } diff --git a/UI/WebStore/Controllers/ShopController.cs b/UI/WebStore/Controllers/ShopController.cs index 334b6bc..2a530af 100644 --- a/UI/WebStore/Controllers/ShopController.cs +++ b/UI/WebStore/Controllers/ShopController.cs @@ -5,7 +5,6 @@ using WebStore.Domain; using WebStore.Domain.ViewModels; using WebStore.Domain.Entities; -using WebStore.Domain.ViewModels; using Webstore.Interfaces.Services; using Webstore.Services.Mapping; @@ -24,9 +23,9 @@ public IActionResult Index(int? BrandId, int? CategoryID) СategoryId = CategoryID, }; - var productc = _ProductData.GetProducts(filter); - var brends = _ProductData.GetBrands(); - var categories = _ProductData.GetСategories(); + var productc = _ProductData.GetProducts(filter).FromDTO(); + var brends = _ProductData.GetBrands().FromDTO(); + var categories = _ProductData.GetСategories().FromDTO(); @@ -73,7 +72,7 @@ private IEnumerable Categories(IEnumerable Icateg } public IActionResult Product(int id) { - var product = _ProductData.GetProductById(id); + var product = _ProductData.GetProductById(id).FromDTO(); if (product is null) return NotFound(); return View(product.ToView()); From b89c68ea54ceb8e6c8749ca93ef7f6a3480e0ef8 Mon Sep 17 00:00:00 2001 From: dmitry Date: Wed, 3 Feb 2021 12:34:27 +0500 Subject: [PATCH 19/28] =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B8=D0=BB=D0=B8=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D0=B4=D1=83=D0=BA=D1=82=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=BA=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D0=BE=D0=BC=D1=83?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Products/ProductsClient.cs | 55 +++++++++++++++++++ .../Controllers/ProductsApiController.cs | 2 +- .../Services/IProductDataDTO.cs | 22 -------- Services/Webstore.Interfaces/WebAPI.cs | 16 ++++++ UI/WebStore/Startup.cs | 4 +- 5 files changed, 75 insertions(+), 24 deletions(-) create mode 100644 Services/WebStore.Client/Products/ProductsClient.cs delete mode 100644 Services/Webstore.Interfaces/Services/IProductDataDTO.cs create mode 100644 Services/Webstore.Interfaces/WebAPI.cs diff --git a/Services/WebStore.Client/Products/ProductsClient.cs b/Services/WebStore.Client/Products/ProductsClient.cs new file mode 100644 index 0000000..12d4d38 --- /dev/null +++ b/Services/WebStore.Client/Products/ProductsClient.cs @@ -0,0 +1,55 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Webstore.Interfaces; +using Webstore.Interfaces.Services; +using WebStore.Client.Base; +using WebStore.Domain; +using WebStore.Domain.DTO.Products; + +namespace WebStore.Client.Products +{ + public class ProductsClient : BaseClient, IProductData + { + public ProductsClient(IConfiguration Configuration) : base(Configuration, WebAPI.Products) + { + } + + public IEnumerable GetBrands() + { + return Get>($"{Address}/brands"); + } + + public BrandDTO GetBrandsById(int id) + { + return Get($"{Address}/brands/{id}"); + } + + public ProductDTO GetProductById(int id) + { + return Get($"{Address}/{id}"); + } + + public IEnumerable GetProducts(ProductFilter Filter = null) + { + return Post(Address, Filter ?? new ProductFilter()) + .Content + .ReadAsAsync>() + .Result; + } + + public IEnumerable GetСategories() + { + return Get>($"{Address}/categories"); + } + + public CategoryDTO GetСategoriesById(int id) + { + return Get($"{Address}/categories/{id}"); + } + } +} diff --git a/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs index a2cda0d..35251c8 100644 --- a/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs +++ b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs @@ -14,7 +14,7 @@ namespace WebStore.ServiceHosting.Controllers { [Route("api/products")] [ApiController] - public class ProductsApiController : ControllerBase, IProductDataDTO + public class ProductsApiController : ControllerBase, IProductData { private readonly IProductData _db; private readonly ILogger _Logger; diff --git a/Services/Webstore.Interfaces/Services/IProductDataDTO.cs b/Services/Webstore.Interfaces/Services/IProductDataDTO.cs deleted file mode 100644 index e1efe0a..0000000 --- a/Services/Webstore.Interfaces/Services/IProductDataDTO.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; -using WebStore.Domain; -using WebStore.Domain.DTO.Products; -using WebStore.Domain.Entities; - -namespace Webstore.Interfaces.Services -{ - public interface IProductDataDTO - { - IEnumerable GetСategories(); - - CategoryDTO GetСategoriesById(int id); - - IEnumerable GetBrands(); - - BrandDTO GetBrandsById(int id); - - IEnumerable GetProducts(ProductFilter Filter = null); - - ProductDTO GetProductById(int id); - } -} diff --git a/Services/Webstore.Interfaces/WebAPI.cs b/Services/Webstore.Interfaces/WebAPI.cs new file mode 100644 index 0000000..dcc7edd --- /dev/null +++ b/Services/Webstore.Interfaces/WebAPI.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Webstore.Interfaces +{ + public static class WebAPI + { + public const string Products = "api/products"; + public const string Values = "api/values"; + public const string Employees = "api/employees"; + public const string Orders = "api/orders"; + } +} diff --git a/UI/WebStore/Startup.cs b/UI/WebStore/Startup.cs index dd8472a..8499276 100644 --- a/UI/WebStore/Startup.cs +++ b/UI/WebStore/Startup.cs @@ -20,6 +20,7 @@ using WebStore.Client.Values; using WebStore.Interfaces.TestAPI; using WebStore.Client.Employees; +using WebStore.Client.Products; namespace WebStore { @@ -74,7 +75,8 @@ public void ConfigureServices(IServiceCollection services) services.AddControllersWithViews().AddRazorRuntimeCompilation(); services.AddSingleton(); //services.AddTransient(); - services.AddTransient(); + //services.AddTransient(); + services.AddTransient(); services.AddSingleton(); services.AddScoped(); services.AddScoped(); From bac6c607954d3dccc0e0cc4efb5b3c3b054dda4d Mon Sep 17 00:00:00 2001 From: dmitry Date: Wed, 3 Feb 2021 16:28:07 +0500 Subject: [PATCH 20/28] =?UTF-8?q?=D0=B7=D0=B0=D0=BF=D0=B8=D0=BB=D0=B8?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=B7=D0=B0=D0=BA=D0=B0=D0=B7=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Common/WebStore.Domain/DTO/Orders/OrderDTO.cs | 18 ++++++++ .../WebStore.Client/Orders/OrdersClient.cs | 35 ++++++++++++++ .../Controllers/OrdersApiController.cs | 46 +++++++++++++++++++ .../Services/IOrderService.cs | 7 +-- .../Webstore.Services/Mapping/OrderMapper.cs | 38 +++++++++++++++ .../Products/InSql/SqlOrderService.cs | 39 ++++++++-------- UI/WebStore/Controllers/CartController.cs | 13 +++++- 7 files changed, 170 insertions(+), 26 deletions(-) create mode 100644 Common/WebStore.Domain/DTO/Orders/OrderDTO.cs create mode 100644 Services/WebStore.Client/Orders/OrdersClient.cs create mode 100644 Services/WebStore.ServiceHosting/Controllers/OrdersApiController.cs create mode 100644 Services/Webstore.Services/Mapping/OrderMapper.cs diff --git a/Common/WebStore.Domain/DTO/Orders/OrderDTO.cs b/Common/WebStore.Domain/DTO/Orders/OrderDTO.cs new file mode 100644 index 0000000..0540696 --- /dev/null +++ b/Common/WebStore.Domain/DTO/Orders/OrderDTO.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using WebStore.Domain.ViewModels; + +namespace WebStore.Domain.DTO.Orders +{ + public record OrderItemDTO(int Id, decimal Price, int Quantity); + + public record OrderDTO( + int Id, + string Name, + string Phone, + string Address, + DateTime Date, + IEnumerable Items); + + public record CreateOrderModel(OrderViewModel Order, IList Items); +} diff --git a/Services/WebStore.Client/Orders/OrdersClient.cs b/Services/WebStore.Client/Orders/OrdersClient.cs new file mode 100644 index 0000000..cb0e6dc --- /dev/null +++ b/Services/WebStore.Client/Orders/OrdersClient.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Webstore.Interfaces; +using Webstore.Interfaces.Services; +using WebStore.Client.Base; +using WebStore.Domain.DTO.Orders; +using WebStore.Domain.ViewModels; +using WebStore.Interfaces; + +namespace WebStore.Client.Orders +{ + public class OrdersClient : BaseClient, IOrderService + { + private readonly ILogger _Logger; + public OrdersClient(IConfiguration Configuration, ILogger Logger) + : base(Configuration, WebAPI.Orders) => + _Logger = Logger; + + + public async Task> GetUserOrders(string UserName) => + await GetAsync>($"{Address}/user/{UserName}"); + + public async Task GetOrderById(int id) => + await GetAsync($"{Address}/{id}"); + + public async Task CreateOrder(string UserName, CreateOrderModel OrderModel) + { + var response = await PostAsync($"{Address}/{UserName}", OrderModel); + return await response.Content.ReadAsAsync(); + } + } +} diff --git a/Services/WebStore.ServiceHosting/Controllers/OrdersApiController.cs b/Services/WebStore.ServiceHosting/Controllers/OrdersApiController.cs new file mode 100644 index 0000000..151c665 --- /dev/null +++ b/Services/WebStore.ServiceHosting/Controllers/OrdersApiController.cs @@ -0,0 +1,46 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Webstore.Interfaces; +using Webstore.Interfaces.Services; +using WebStore.Domain.DTO.Orders; +using WebStore.Domain.Entities.Orders; +using WebStore.Domain.ViewModels; + +namespace WebStore.ServiceHosting.Controllers +{ + [Route(WebAPI.Orders)] + [ApiController] + public class OrdersApiController : ControllerBase, IOrderService + { + private readonly IOrderService orderService; + private readonly ILogger logger; + + public OrdersApiController(IOrderService orderService, ILogger Logger) + { + this.orderService = orderService; + logger = Logger; + } + + [HttpPost("{UserName}")] + public async Task CreateOrder(string UserName, CreateOrderModel OrderModel) + { + return await orderService.CreateOrder(UserName, OrderModel); + } + + [HttpGet("{id}")] + public async Task GetOrderById(int id) + { + return await orderService.GetOrderById(id); + } + [HttpGet("user/{UserName}")] + public async Task> GetUserOrders(string UserName) + { + return await orderService.GetUserOrders(UserName); + } + } +} diff --git a/Services/Webstore.Interfaces/Services/IOrderService.cs b/Services/Webstore.Interfaces/Services/IOrderService.cs index 024e0c0..fba8b44 100644 --- a/Services/Webstore.Interfaces/Services/IOrderService.cs +++ b/Services/Webstore.Interfaces/Services/IOrderService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using WebStore.Domain.DTO.Orders; using WebStore.Domain.Entities.Orders; using WebStore.Domain.ViewModels; @@ -7,10 +8,10 @@ namespace Webstore.Interfaces.Services { public interface IOrderService { - Task> GetUserOrders(string UserName); + Task> GetUserOrders(string UserName); - Task GetOrderById(int id); + Task GetOrderById(int id); - Task CreateOrder(string UserName, CartViewModel Cart, OrderViewModel OrderModel); + Task CreateOrder(string UserName, CreateOrderModel OrderModel); } } diff --git a/Services/Webstore.Services/Mapping/OrderMapper.cs b/Services/Webstore.Services/Mapping/OrderMapper.cs new file mode 100644 index 0000000..e90ae88 --- /dev/null +++ b/Services/Webstore.Services/Mapping/OrderMapper.cs @@ -0,0 +1,38 @@ +using System.Linq; +using WebStore.Domain.DTO.Orders; +using WebStore.Domain.Entities.Orders; + +namespace WebStore.Services.Mapping +{ + public static class OrderMapper + { + public static OrderItemDTO ToDTO(this OrderItem Item) => Item is null + ? null + : new OrderItemDTO(Item.Id, Item.Price, Item.Quantity); + + public static OrderItem FromDTO(this OrderItemDTO Item) => Item is null + ? null + : new OrderItem + { + Id = Item.Id, + Price = Item.Price, + Quantity = Item.Quantity + }; + + public static OrderDTO ToDTO(this Order Order) => Order is null + ? null + : new OrderDTO(Order.Id, Order.Name, Order.Phone, Order.Address, Order.Date, Order.Items.Select(ToDTO)); + + public static Order FromDTO(this OrderDTO Order) => Order is null + ? null + : new Order + { + Id = Order.Id, + Name = Order.Name, + Phone = Order.Phone, + Address = Order.Address, + Date = Order.Date, + Items = Order.Items.Select(FromDTO).ToList() + }; + } +} diff --git a/Services/Webstore.Services/Products/InSql/SqlOrderService.cs b/Services/Webstore.Services/Products/InSql/SqlOrderService.cs index 30be498..9f5876d 100644 --- a/Services/Webstore.Services/Products/InSql/SqlOrderService.cs +++ b/Services/Webstore.Services/Products/InSql/SqlOrderService.cs @@ -7,9 +7,11 @@ using Microsoft.EntityFrameworkCore; using Webstore.DAL.Context; using Webstore.Interfaces.Services; +using WebStore.Domain.DTO.Orders; using WebStore.Domain.Entities.Identity; using WebStore.Domain.Entities.Orders; using WebStore.Domain.ViewModels; +using WebStore.Services.Mapping; namespace Webstore.Services.Products.InSql { @@ -24,18 +26,18 @@ public SqlOrderService(WebStoreDB db, UserManager UserManager) _UserManager = UserManager; } - public async Task> GetUserOrders(string UserName) => await _db.Orders + public async Task> GetUserOrders(string UserName) => (await _db.Orders .Include(order => order.User) .Include(order => order.Items) .Where(order => order.User.UserName == UserName) - .ToArrayAsync(); + .ToArrayAsync()).Select(o => o.ToDTO()); - public async Task GetOrderById(int id) => await _db.Orders + public async Task GetOrderById(int id) => (await _db.Orders .Include(order => order.User) .Include(order => order.Items) - .FirstOrDefaultAsync(order => order.Id == id); + .FirstOrDefaultAsync(order => order.Id == id)).ToDTO(); - public async Task CreateOrder(string UserName, CartViewModel Cart, OrderViewModel OrderModel) + public async Task CreateOrder(string UserName, CreateOrderModel OrderModel) { var user = await _UserManager.FindByNameAsync(UserName); if (user is null) @@ -45,32 +47,27 @@ public async Task CreateOrder(string UserName, CartViewModel Cart, OrderV var order = new Order { - Name = OrderModel.Name, - Address = OrderModel.Address, - Phone = OrderModel.Phone, + Name = OrderModel.Order.Name, + Address = OrderModel.Order.Address, + Phone = OrderModel.Order.Phone, User = user, Date = DateTime.Now, }; - var product_ids = Cart.Items.Select(i => i.Product.Id).ToArray(); - var cart_products = await _db.Products - .Where(p => product_ids.Contains(p.Id)) - .ToArrayAsync(); + foreach (var (id, _, quantity) in OrderModel.Items) + { + var product = await _db.Products.FindAsync(id); + if (product is null) continue; - var items = - from cart_item in Cart.Items - join product in cart_products - on cart_item.Product.Id equals product.Id - select new OrderItem + var order_item = new OrderItem { Order = order, Price = product.Price, - Quantity = cart_item.Quantity, + Quantity = quantity, Product = product }; - - foreach (var order_item in items) order.Items.Add(order_item); + } await _db.Orders.AddAsync(order); @@ -78,7 +75,7 @@ on cart_item.Product.Id equals product.Id await transaction.CommitAsync(); - return order; + return order.ToDTO(); } } } diff --git a/UI/WebStore/Controllers/CartController.cs b/UI/WebStore/Controllers/CartController.cs index 6771fdc..58aa5d2 100644 --- a/UI/WebStore/Controllers/CartController.cs +++ b/UI/WebStore/Controllers/CartController.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using Webstore.Interfaces.Services; +using WebStore.Domain.DTO.Orders; using WebStore.Domain.ViewModels; namespace WebStore.Controllers @@ -60,10 +61,18 @@ public async Task CheckOut(OrderViewModel OrderModel, [FromServic Order = OrderModel }); + var create_order_model = new CreateOrderModel( + OrderModel, + _CartService.TransformFromCart().Items + .Select(item => new OrderItemDTO( + item.Product.Id, + item.Product.Price, + item.Quantity)) + .ToList()); + var order = await OrderService.CreateOrder( User.Identity!.Name, - _CartService.TransformFromCart(), - OrderModel); + create_order_model); _CartService.Clear(); From 370adc1a3810201b7edf4d2bcc5102b6248b52c2 Mon Sep 17 00:00:00 2001 From: dmitry Date: Wed, 3 Feb 2021 17:10:13 +0500 Subject: [PATCH 21/28] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D1=80=D0=BE=D1=84=D0=B8=D0=BB=D1=8C=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewModels/UserOrderViewModel.cs | 20 ++++++++++++ .../Controllers/UserProfileController.cs | 31 +++++++++++++++++++ UI/WebStore/Startup.cs | 4 ++- .../Components/UserInfo/UserInfo.cshtml | 2 +- UI/WebStore/Views/UserProfile/Index.cshtml | 8 +++++ UI/WebStore/Views/UserProfile/Orders.cshtml | 31 +++++++++++++++++++ .../UserProfile/Partial/_Index_Scripts.cshtml | 10 ++++++ .../UserProfile/Partial/_Index_Styles.cshtml | 2 ++ .../Partial/_UserProfileMenu.cshtml | 15 +++++++++ .../UserProfile/_UserProfileLayout.cshtml | 20 ++++++++++++ 10 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 Common/WebStore.Domain/ViewModels/UserOrderViewModel.cs create mode 100644 UI/WebStore/Controllers/UserProfileController.cs create mode 100644 UI/WebStore/Views/UserProfile/Index.cshtml create mode 100644 UI/WebStore/Views/UserProfile/Orders.cshtml create mode 100644 UI/WebStore/Views/UserProfile/Partial/_Index_Scripts.cshtml create mode 100644 UI/WebStore/Views/UserProfile/Partial/_Index_Styles.cshtml create mode 100644 UI/WebStore/Views/UserProfile/Partial/_UserProfileMenu.cshtml create mode 100644 UI/WebStore/Views/UserProfile/_UserProfileLayout.cshtml diff --git a/Common/WebStore.Domain/ViewModels/UserOrderViewModel.cs b/Common/WebStore.Domain/ViewModels/UserOrderViewModel.cs new file mode 100644 index 0000000..e8a77fd --- /dev/null +++ b/Common/WebStore.Domain/ViewModels/UserOrderViewModel.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace WebStore.Domain.ViewModels +{ + public class UserOrderViewModel + { + public int Id { get; set; } + + [Required] + public string Name { get; set; } + + [Required] + public string Phone { get; set; } + + [Required] + public string Address { get; set; } + + public decimal TotalSum { get; set; } + } +} diff --git a/UI/WebStore/Controllers/UserProfileController.cs b/UI/WebStore/Controllers/UserProfileController.cs new file mode 100644 index 0000000..57d0d57 --- /dev/null +++ b/UI/WebStore/Controllers/UserProfileController.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Webstore.Interfaces.Services; +using WebStore.Domain.ViewModels; + +namespace WebStore.Controllers +{ + [Authorize] + public class UserProfileController : Controller + { + public IActionResult Index() => View(); + + public async Task Orders([FromServices] IOrderService OrderService) + { + var orders = await OrderService.GetUserOrders(User.Identity!.Name); + + return View(orders.Select(order => new UserOrderViewModel + { + Id = order.Id, + Name = order.Name, + Phone = order.Phone, + Address = order.Address, + TotalSum = order.Items.Sum(item => item.Price * item.Quantity) + })); + } + } +} diff --git a/UI/WebStore/Startup.cs b/UI/WebStore/Startup.cs index 8499276..686f987 100644 --- a/UI/WebStore/Startup.cs +++ b/UI/WebStore/Startup.cs @@ -21,6 +21,7 @@ using WebStore.Interfaces.TestAPI; using WebStore.Client.Employees; using WebStore.Client.Products; +using WebStore.Client.Orders; namespace WebStore { @@ -79,7 +80,8 @@ public void ConfigureServices(IServiceCollection services) services.AddTransient(); services.AddSingleton(); services.AddScoped(); - services.AddScoped(); + //services.AddScoped(); + services.AddScoped(); services.AddScoped(); } diff --git a/UI/WebStore/Views/Shared/Components/UserInfo/UserInfo.cshtml b/UI/WebStore/Views/Shared/Components/UserInfo/UserInfo.cshtml index e4ffcc0..eaa69a3 100644 --- a/UI/WebStore/Views/Shared/Components/UserInfo/UserInfo.cshtml +++ b/UI/WebStore/Views/Shared/Components/UserInfo/UserInfo.cshtml @@ -1,5 +1,5 @@ @using WebStore.Domain.Entities.Identity - + @if (User.IsInRole(Role.Administrator)) { diff --git a/UI/WebStore/Views/UserProfile/Index.cshtml b/UI/WebStore/Views/UserProfile/Index.cshtml new file mode 100644 index 0000000..82d9a69 --- /dev/null +++ b/UI/WebStore/Views/UserProfile/Index.cshtml @@ -0,0 +1,8 @@ + +@{ + Layout = "_UserProfileLayout"; + ViewData["Title"] = "Профиль пользователя"; +} + +

Профиль пользователя

+ diff --git a/UI/WebStore/Views/UserProfile/Orders.cshtml b/UI/WebStore/Views/UserProfile/Orders.cshtml new file mode 100644 index 0000000..9dfa990 --- /dev/null +++ b/UI/WebStore/Views/UserProfile/Orders.cshtml @@ -0,0 +1,31 @@ +@model IEnumerable +@{ + Layout = "_UserProfileLayout"; + ViewData["Title"] = "Заказы"; +} + + + + + + + + + + + + + @{ var i = 1; } + @foreach (var order in Model) + { + + + + + + + + } + +
ИмяАдресТелефонСумма
@(i++)@order.Name@order.Address@order.Phone@order.TotalSum
+ diff --git a/UI/WebStore/Views/UserProfile/Partial/_Index_Scripts.cshtml b/UI/WebStore/Views/UserProfile/Partial/_Index_Scripts.cshtml new file mode 100644 index 0000000..f5b2aed --- /dev/null +++ b/UI/WebStore/Views/UserProfile/Partial/_Index_Scripts.cshtml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/UI/WebStore/Views/UserProfile/Partial/_Index_Styles.cshtml b/UI/WebStore/Views/UserProfile/Partial/_Index_Styles.cshtml new file mode 100644 index 0000000..40166d6 --- /dev/null +++ b/UI/WebStore/Views/UserProfile/Partial/_Index_Styles.cshtml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/UI/WebStore/Views/UserProfile/Partial/_UserProfileMenu.cshtml b/UI/WebStore/Views/UserProfile/Partial/_UserProfileMenu.cshtml new file mode 100644 index 0000000..f7dbebb --- /dev/null +++ b/UI/WebStore/Views/UserProfile/Partial/_UserProfileMenu.cshtml @@ -0,0 +1,15 @@ +
+ +
+ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/UI/WebStore/Views/UserProfile/_UserProfileLayout.cshtml b/UI/WebStore/Views/UserProfile/_UserProfileLayout.cshtml new file mode 100644 index 0000000..9da4ea5 --- /dev/null +++ b/UI/WebStore/Views/UserProfile/_UserProfileLayout.cshtml @@ -0,0 +1,20 @@ +@section Styles { + +} +@section Scripts { + +} +@{ + Layout = "_Layout"; +} + +
+
+
+ +
+
+ @RenderBody() +
+
+
\ No newline at end of file From f133052de919d9f67d2f34331b93523b4f1b2a57 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 30 Jan 2021 17:21:26 +0500 Subject: [PATCH 22/28] =?UTF-8?q?=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UI/WebStore/Startup.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/UI/WebStore/Startup.cs b/UI/WebStore/Startup.cs index 686f987..1a11475 100644 --- a/UI/WebStore/Startup.cs +++ b/UI/WebStore/Startup.cs @@ -75,6 +75,7 @@ public void ConfigureServices(IServiceCollection services) services.AddControllersWithViews().AddRazorRuntimeCompilation(); services.AddSingleton(); + //services.AddTransient(); //services.AddTransient(); services.AddTransient(); From 16f4b5f247a345b23663fc1fa87420111c081a72 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sun, 7 Feb 2021 14:37:48 +0500 Subject: [PATCH 23/28] =?UTF-8?q?=D0=9C=D0=BE=D0=B4=D0=B5=D0=BB=D0=B8=20DT?= =?UTF-8?q?O=20=D0=B4=D0=BB=D1=8F=20identity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WebStore.Domain/DTO/Identity/ClaimDTO.cs | 21 +++++++++++++++ .../WebStore.Domain/DTO/Identity/UserDTO.cs | 26 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 Common/WebStore.Domain/DTO/Identity/ClaimDTO.cs create mode 100644 Common/WebStore.Domain/DTO/Identity/UserDTO.cs diff --git a/Common/WebStore.Domain/DTO/Identity/ClaimDTO.cs b/Common/WebStore.Domain/DTO/Identity/ClaimDTO.cs new file mode 100644 index 0000000..a359689 --- /dev/null +++ b/Common/WebStore.Domain/DTO/Identity/ClaimDTO.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Security.Claims; + +namespace WebStore.Domain.DTO.Identity +{ + public abstract class ClaimDTO : UserDTO + { + public IEnumerable Claims { get; set; } + } + + public class AddClaimDTO : ClaimDTO { } + + public class RemoveClaimDTO : ClaimDTO { } + + public class ReplaceClaimDTO : UserDTO + { + public Claim Claim { get; set; } + + public Claim NewClaim { get; set; } + } +} diff --git a/Common/WebStore.Domain/DTO/Identity/UserDTO.cs b/Common/WebStore.Domain/DTO/Identity/UserDTO.cs new file mode 100644 index 0000000..465b7bb --- /dev/null +++ b/Common/WebStore.Domain/DTO/Identity/UserDTO.cs @@ -0,0 +1,26 @@ +using System; +using Microsoft.AspNetCore.Identity; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.Domain.DTO.Identity +{ + public abstract class UserDTO + { + public User User { get; set; } + } + + public class AddLoginDTO : UserDTO + { + public UserLoginInfo UserLoginInfo { get; set; } + } + + public class PasswordHashDTO : UserDTO + { + public string Hash { get; set; } + } + + public class SetLockoutDTO : UserDTO + { + public DateTimeOffset? LockoutEnd { get; set; } + } +} From 1097f9f23fdfc153d92e5978a0539c2caccb3a3a Mon Sep 17 00:00:00 2001 From: dmitry Date: Sun, 7 Feb 2021 14:38:50 +0500 Subject: [PATCH 24/28] =?UTF-8?q?=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84?= =?UTF-8?q?=D0=B5=D0=B9=D1=81=D1=8B=20=D0=B4=D0=BB=D1=8F=20Identity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/Identity/IRolesClient.cs | 7 +++++++ .../Services/Identity/IUsersClient.cs | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 Services/Webstore.Interfaces/Services/Identity/IRolesClient.cs create mode 100644 Services/Webstore.Interfaces/Services/Identity/IUsersClient.cs diff --git a/Services/Webstore.Interfaces/Services/Identity/IRolesClient.cs b/Services/Webstore.Interfaces/Services/Identity/IRolesClient.cs new file mode 100644 index 0000000..e740a45 --- /dev/null +++ b/Services/Webstore.Interfaces/Services/Identity/IRolesClient.cs @@ -0,0 +1,7 @@ +using Microsoft.AspNetCore.Identity; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.Interfaces.Services.Identity +{ + public interface IRolesClient : IRoleStore { } +} diff --git a/Services/Webstore.Interfaces/Services/Identity/IUsersClient.cs b/Services/Webstore.Interfaces/Services/Identity/IUsersClient.cs new file mode 100644 index 0000000..5b9bc66 --- /dev/null +++ b/Services/Webstore.Interfaces/Services/Identity/IUsersClient.cs @@ -0,0 +1,16 @@ +using Microsoft.AspNetCore.Identity; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.Interfaces.Services.Identity +{ + public interface IUsersClient : + IUserRoleStore, + IUserPasswordStore, + IUserEmailStore, + IUserPhoneNumberStore, + IUserTwoFactorStore, + IUserLoginStore, + IUserClaimStore + { + } +} From 3f9e2dd86936c856be9151ddc4b1be4bbbe2109a Mon Sep 17 00:00:00 2001 From: dmitry Date: Sun, 7 Feb 2021 14:44:09 +0500 Subject: [PATCH 25/28] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=81=D1=82=D0=B0=D1=82=D0=B8=D1=87?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=B0=D0=B4=D1=80=D0=B5=D1=81=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B8=D0=B7=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B0=20WEBApi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Employees/EmployeesClient.cs | 3 ++- .../WebStore.Client/Values/ValuesClient.cs | 3 ++- .../Controllers/EmployeesApiController.cs | 3 ++- .../Controllers/ProductsApiController.cs | 3 ++- .../Controllers/ValuesController.cs | 3 ++- Services/Webstore.Interfaces/WebAPI.cs | 18 ++++++++++++++---- 6 files changed, 24 insertions(+), 9 deletions(-) diff --git a/Services/WebStore.Client/Employees/EmployeesClient.cs b/Services/WebStore.Client/Employees/EmployeesClient.cs index 235e727..2ef0a82 100644 --- a/Services/WebStore.Client/Employees/EmployeesClient.cs +++ b/Services/WebStore.Client/Employees/EmployeesClient.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Net.Http; using System.Text; +using Webstore.Interfaces; using Webstore.Interfaces.Services; using WebStore.Client.Base; using WebStore.Domain.Models; @@ -14,7 +15,7 @@ public class EmployeesClient: BaseClient, IEmployeesData { private readonly ILogger _Logger; - public EmployeesClient(IConfiguration Configuration, ILogger Logger): base(Configuration, "api/employees") + public EmployeesClient(IConfiguration Configuration, ILogger Logger): base(Configuration, WebAPI.Employees) { _Logger = Logger; } diff --git a/Services/WebStore.Client/Values/ValuesClient.cs b/Services/WebStore.Client/Values/ValuesClient.cs index 273b5e0..f2109d0 100644 --- a/Services/WebStore.Client/Values/ValuesClient.cs +++ b/Services/WebStore.Client/Values/ValuesClient.cs @@ -4,6 +4,7 @@ using System.Net; using System.Net.Http; using Microsoft.Extensions.Configuration; +using Webstore.Interfaces; using WebStore.Client.Base; using WebStore.Interfaces.TestAPI; @@ -11,7 +12,7 @@ namespace WebStore.Client.Values { public class ValuesClient : BaseClient, IValuesServices { - public ValuesClient(IConfiguration Configuration) : base(Configuration, "api/values") { } + public ValuesClient(IConfiguration Configuration) : base(Configuration, WebAPI.Values) { } public IEnumerable Get() { diff --git a/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs b/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs index 9e91be0..5ee2691 100644 --- a/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs +++ b/Services/WebStore.ServiceHosting/Controllers/EmployeesApiController.cs @@ -5,12 +5,13 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Webstore.Interfaces; using Webstore.Interfaces.Services; using WebStore.Domain.Models; namespace WebStore.ServiceHosting.Controllers { - [Route("api/employees")] + [Route(WebAPI.Employees)] [ApiController] public class EmployeesApiController : ControllerBase, IEmployeesData { diff --git a/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs index 35251c8..49063bd 100644 --- a/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs +++ b/Services/WebStore.ServiceHosting/Controllers/ProductsApiController.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Webstore.Interfaces; using Webstore.Interfaces.Services; using WebStore.Domain; using WebStore.Domain.DTO.Products; @@ -12,7 +13,7 @@ namespace WebStore.ServiceHosting.Controllers { - [Route("api/products")] + [Route(WebAPI.Products)] [ApiController] public class ProductsApiController : ControllerBase, IProductData { diff --git a/Services/WebStore.ServiceHosting/Controllers/ValuesController.cs b/Services/WebStore.ServiceHosting/Controllers/ValuesController.cs index 4976812..f1d1be6 100644 --- a/Services/WebStore.ServiceHosting/Controllers/ValuesController.cs +++ b/Services/WebStore.ServiceHosting/Controllers/ValuesController.cs @@ -2,10 +2,11 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; +using Webstore.Interfaces; namespace WebStore.ServiceHosting.Controllers { - [Route("api/[controller]")] // http://localhost:5001/api/values + [Route(WebAPI.Values)] // http://localhost:5001/api/values [ApiController] public class ValuesController : ControllerBase { diff --git a/Services/Webstore.Interfaces/WebAPI.cs b/Services/Webstore.Interfaces/WebAPI.cs index dcc7edd..f1a1ce0 100644 --- a/Services/Webstore.Interfaces/WebAPI.cs +++ b/Services/Webstore.Interfaces/WebAPI.cs @@ -8,9 +8,19 @@ namespace Webstore.Interfaces { public static class WebAPI { - public const string Products = "api/products"; - public const string Values = "api/values"; - public const string Employees = "api/employees"; - public const string Orders = "api/orders"; + private const string api = "api/"; + + public const string Version = "v1"; + + public const string Products = api + Version + "api/products"; + public const string Values = api + Version + "api/values"; + public const string Employees = api + Version + "api/employees"; + public const string Orders = api + Version + "api/orders"; + + public static class Identity + { + public const string User = api + Version + "/users"; + public const string Role = api + Version + "/roles"; + } } } From fb5c2767877b1677e66ad0aef1b8f6eeb7ecb98d Mon Sep 17 00:00:00 2001 From: dmitry Date: Sun, 7 Feb 2021 14:46:41 +0500 Subject: [PATCH 26/28] =?UTF-8?q?=D0=9A=D0=BE=D0=BD=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=BB=D0=BB=D0=B5=D1=80=D1=8B=20WebAPI=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?identity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Identity/RolesApiController.cs | 78 +++++ .../Identity/UsersApiController.cs | 299 ++++++++++++++++++ 2 files changed, 377 insertions(+) create mode 100644 Services/WebStore.ServiceHosting/Controllers/Identity/RolesApiController.cs create mode 100644 Services/WebStore.ServiceHosting/Controllers/Identity/UsersApiController.cs diff --git a/Services/WebStore.ServiceHosting/Controllers/Identity/RolesApiController.cs b/Services/WebStore.ServiceHosting/Controllers/Identity/RolesApiController.cs new file mode 100644 index 0000000..5208a40 --- /dev/null +++ b/Services/WebStore.ServiceHosting/Controllers/Identity/RolesApiController.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Webstore.DAL.Context; +using Webstore.Interfaces; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.ServiceHosting.Controllers.Identity +{ + [Route(WebAPI.Identity.Role)] + [ApiController] + public class RolesApiController : ControllerBase + { + private readonly RoleStore _RoleStore; + + public RolesApiController(WebStoreDB db) + { + _RoleStore = new RoleStore(db); + } + + [HttpGet("all")] + public async Task> GetAllRoles() => await _RoleStore.Roles.ToArrayAsync(); + + [HttpPost] + public async Task CreateAsync(Role role) + { + var creation_result = await _RoleStore.CreateAsync(role); + return creation_result.Succeeded; + } + + [HttpPut] + public async Task UpdateAsync(Role role) + { + var uprate_result = await _RoleStore.UpdateAsync(role); + return uprate_result.Succeeded; + } + + [HttpPost("Delete")] + public async Task DeleteAsync(Role role) + { + var delete_result = await _RoleStore.DeleteAsync(role); + return delete_result.Succeeded; + } + + [HttpPost("GetRoleId")] + public async Task GetRoleIdAsync([FromBody] Role role) => await _RoleStore.GetRoleIdAsync(role); + + [HttpPost("GetRoleName")] + public async Task GetRoleNameAsync([FromBody] Role role) => await _RoleStore.GetRoleNameAsync(role); + + [HttpPost("SetRoleName/{name}")] + public async Task SetRoleNameAsync(Role role, string name) + { + await _RoleStore.SetRoleNameAsync(role, name); + await _RoleStore.UpdateAsync(role); + return role.Name; + } + + [HttpPost("GetNormalizedRoleName")] + public async Task GetNormalizedRoleNameAsync(Role role) => await _RoleStore.GetNormalizedRoleNameAsync(role); + + [HttpPost("SetNormalizedRoleName/{name}")] + public async Task SetNormalizedRoleNameAsync(Role role, string name) + { + await _RoleStore.SetNormalizedRoleNameAsync(role, name); + await _RoleStore.UpdateAsync(role); + return role.NormalizedName; + } + + [HttpGet("FindById/{id}")] + public async Task FindByIdAsync(string id) => await _RoleStore.FindByIdAsync(id); + + [HttpGet("FindByName/{name}")] + public async Task FindByNameAsync(string name) => await _RoleStore.FindByNameAsync(name); + } +} diff --git a/Services/WebStore.ServiceHosting/Controllers/Identity/UsersApiController.cs b/Services/WebStore.ServiceHosting/Controllers/Identity/UsersApiController.cs new file mode 100644 index 0000000..bb50d84 --- /dev/null +++ b/Services/WebStore.ServiceHosting/Controllers/Identity/UsersApiController.cs @@ -0,0 +1,299 @@ +using System; +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Webstore.DAL.Context; +using Webstore.Interfaces; +using WebStore.Domain.DTO.Identity; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.ServiceHosting.Controllers.Identity +{ + [Route(WebAPI.Identity.User)] + [ApiController] + public class UsersApiController : ControllerBase + { + private readonly UserStore _UserStore; + + public UsersApiController(WebStoreDB db) + { + _UserStore = new UserStore(db); + } + + [HttpGet("all")] + public async Task> GetAllUsers() => await _UserStore.Users.ToArrayAsync(); + + #region Users + + [HttpPost("UserId")] // POST: api/users/UserId + public async Task GetUserIdAsync([FromBody] User user) => await _UserStore.GetUserIdAsync(user); + + [HttpPost("UserName")] + public async Task GetUserNameAsync([FromBody] User user) => await _UserStore.GetUserNameAsync(user); + + [HttpPost("UserName/{name}")] // api/users/UserName/TestUser + public async Task SetUserNameAsync([FromBody] User user, string name) + { + await _UserStore.SetUserNameAsync(user, name); + await _UserStore.UpdateAsync(user); + return user.UserName; + } + + [HttpPost("NormalUserName")] + public async Task GetNormalizedUserNameAsync([FromBody] User user) => await _UserStore.GetNormalizedUserNameAsync(user); + + [HttpPost("NormalUserName/{name}")] + public async Task SetNormalizedUserNameAsync([FromBody] User user, string name) + { + await _UserStore.SetNormalizedUserNameAsync(user, name); + await _UserStore.UpdateAsync(user); + return user.NormalizedUserName; + } + + [HttpPost("User")] // api/users/user + public async Task CreateAsync([FromBody] User user) + { + var creation_result = await _UserStore.CreateAsync(user); + // добавление ошибок создания нового пользователя в журнал + return creation_result.Succeeded; + } + + [HttpPut("User")] + public async Task UpdateAsync([FromBody] User user) + { + var update_result = await _UserStore.UpdateAsync(user); + return update_result.Succeeded; + } + + [HttpPost("User/Delete")] + public async Task DeleteAsync([FromBody] User user) + { + var delete_result = await _UserStore.DeleteAsync(user); + return delete_result.Succeeded; + } + + [HttpGet("User/Find/{id}")] // api/users/user/Find/9E5CB5E7-41DE-4449-829E-45F4C97AA54B + public async Task FindByIdAsync(string id) => await _UserStore.FindByIdAsync(id); + + [HttpGet("User/Normal/{name}")] // api/users/user/Normal/TestUser + public async Task FindByNameAsync(string name) => await _UserStore.FindByNameAsync(name); + + [HttpPost("Role/{role}")] + public async Task AddToRoleAsync([FromBody] User user, string role, [FromServices] WebStoreDB db) + { + await _UserStore.AddToRoleAsync(user, role); + await db.SaveChangesAsync(); + } + + [HttpPost("Role/Delete/{role}")] + public async Task RemoveFromRoleAsync([FromBody] User user, string role, [FromServices] WebStoreDB db) + { + await _UserStore.RemoveFromRoleAsync(user, role); + await db.SaveChangesAsync(); + } + + [HttpPost("Roles")] + public async Task> GetRolesAsync([FromBody] User user) => await _UserStore.GetRolesAsync(user); + + [HttpPost("InRole/{role}")] + public async Task IsInRoleAsync([FromBody] User user, string role) => await _UserStore.IsInRoleAsync(user, role); + + [HttpGet("UsersInRole/{role}")] + public async Task> GetUsersInRoleAsync(string role) => await _UserStore.GetUsersInRoleAsync(role); + + [HttpPost("GetPasswordHash")] + public async Task GetPasswordHashAsync([FromBody] User user) => await _UserStore.GetPasswordHashAsync(user); + + [HttpPost("SetPasswordHash")] + public async Task SetPasswordHashAsync([FromBody] PasswordHashDTO hash) + { + await _UserStore.SetPasswordHashAsync(hash.User, hash.Hash); + await _UserStore.UpdateAsync(hash.User); + return hash.User.PasswordHash; + } + + [HttpPost("HasPassword")] + public async Task HasPasswordAsync([FromBody] User user) => await _UserStore.HasPasswordAsync(user); + + #endregion + + #region Claims + + [HttpPost("GetClaims")] + public async Task> GetClaimsAsync([FromBody] User user) => await _UserStore.GetClaimsAsync(user); + + [HttpPost("AddClaims")] + public async Task AddClaimsAsync([FromBody] AddClaimDTO ClaimInfo, [FromServices] WebStoreDB db) + { + await _UserStore.AddClaimsAsync(ClaimInfo.User, ClaimInfo.Claims); + await db.SaveChangesAsync(); + } + + [HttpPost("ReplaceClaim")] + public async Task ReplaceClaimAsync([FromBody] ReplaceClaimDTO ClaimInfo, [FromServices] WebStoreDB db) + { + await _UserStore.ReplaceClaimAsync(ClaimInfo.User, ClaimInfo.Claim, ClaimInfo.NewClaim); + await db.SaveChangesAsync(); + } + + [HttpPost("RemoveClaim")] + public async Task RemoveClaimsAsync([FromBody] RemoveClaimDTO ClaimInfo, [FromServices] WebStoreDB db) + { + await _UserStore.RemoveClaimsAsync(ClaimInfo.User, ClaimInfo.Claims); + await db.SaveChangesAsync(); + } + + [HttpPost("GetUsersForClaim")] + public async Task> GetUsersForClaimAsync([FromBody] Claim claim) => + await _UserStore.GetUsersForClaimAsync(claim); + + #endregion + + #region TwoFactor + + [HttpPost("GetTwoFactorEnabled")] + public async Task GetTwoFactorEnabledAsync([FromBody] User user) => await _UserStore.GetTwoFactorEnabledAsync(user); + + [HttpPost("SetTwoFactor/{enable}")] + public async Task SetTwoFactorEnabledAsync([FromBody] User user, bool enable) + { + await _UserStore.SetTwoFactorEnabledAsync(user, enable); + await _UserStore.UpdateAsync(user); + return user.TwoFactorEnabled; + } + + #endregion + + #region Email/Phone + + [HttpPost("GetEmail")] + public async Task GetEmailAsync([FromBody] User user) => await _UserStore.GetEmailAsync(user); + + [HttpPost("SetEmail/{email}")] + public async Task SetEmailAsync([FromBody] User user, string email) + { + await _UserStore.SetEmailAsync(user, email); + await _UserStore.UpdateAsync(user); + return user.Email; + } + + [HttpPost("GetEmailConfirmed")] + public async Task GetEmailConfirmedAsync([FromBody] User user) => await _UserStore.GetEmailConfirmedAsync(user); + + [HttpPost("SetEmailConfirmed/{enable}")] + public async Task SetEmailConfirmedAsync([FromBody] User user, bool enable) + { + await _UserStore.SetEmailConfirmedAsync(user, enable); + await _UserStore.UpdateAsync(user); + return user.EmailConfirmed; + } + + [HttpGet("UserFindByEmail/{email}")] + public async Task FindByEmailAsync(string email) => await _UserStore.FindByEmailAsync(email); + + [HttpPost("GetNormalizedEmail")] + public async Task GetNormalizedEmailAsync([FromBody] User user) => await _UserStore.GetNormalizedEmailAsync(user); + + [HttpPost("SetNormalizedEmail/{email?}")] + public async Task SetNormalizedEmailAsync([FromBody] User user, string email) + { + await _UserStore.SetNormalizedEmailAsync(user, email); + await _UserStore.UpdateAsync(user); + return user.NormalizedEmail; + } + + [HttpPost("GetPhoneNumber")] + public async Task GetPhoneNumberAsync([FromBody] User user) => await _UserStore.GetPhoneNumberAsync(user); + + [HttpPost("SetPhoneNumber/{phone}")] + public async Task SetPhoneNumberAsync([FromBody] User user, string phone) + { + await _UserStore.SetPhoneNumberAsync(user, phone); + await _UserStore.UpdateAsync(user); + return user.PhoneNumber; + } + + [HttpPost("GetPhoneNumberConfirmed")] + public async Task GetPhoneNumberConfirmedAsync([FromBody] User user) => + await _UserStore.GetPhoneNumberConfirmedAsync(user); + + [HttpPost("SetPhoneNumberConfirmed/{confirmed}")] + public async Task SetPhoneNumberConfirmedAsync([FromBody] User user, bool confirmed) + { + await _UserStore.SetPhoneNumberConfirmedAsync(user, confirmed); + await _UserStore.UpdateAsync(user); + return user.PhoneNumberConfirmed; + } + + #endregion + + #region Login/Lockout + + [HttpPost("AddLogin")] + public async Task AddLoginAsync([FromBody] AddLoginDTO login, [FromServices] WebStoreDB db) + { + await _UserStore.AddLoginAsync(login.User, login.UserLoginInfo); + await db.SaveChangesAsync(); + } + + [HttpPost("RemoveLogin/{LoginProvider}/{ProviderKey}")] + public async Task RemoveLoginAsync([FromBody] User user, string LoginProvider, string ProviderKey, [FromServices] WebStoreDB db) + { + await _UserStore.RemoveLoginAsync(user, LoginProvider, ProviderKey); + await db.SaveChangesAsync(); + } + + [HttpPost("GetLogins")] + public async Task> GetLoginsAsync([FromBody] User user) => await _UserStore.GetLoginsAsync(user); + + [HttpGet("User/FindByLogin/{LoginProvider}/{ProviderKey}")] + public async Task FindByLoginAsync(string LoginProvider, string ProviderKey) => await _UserStore.FindByLoginAsync(LoginProvider, ProviderKey); + + [HttpPost("GetLockoutEndDate")] + public async Task GetLockoutEndDateAsync([FromBody] User user) => await _UserStore.GetLockoutEndDateAsync(user); + + [HttpPost("SetLockoutEndDate")] + public async Task SetLockoutEndDateAsync([FromBody] SetLockoutDTO LockoutInfo) + { + await _UserStore.SetLockoutEndDateAsync(LockoutInfo.User, LockoutInfo.LockoutEnd); + await _UserStore.UpdateAsync(LockoutInfo.User); + return LockoutInfo.User.LockoutEnd; + } + + [HttpPost("IncrementAccessFailedCount")] + public async Task IncrementAccessFailedCountAsync([FromBody] User user) + { + var count = await _UserStore.IncrementAccessFailedCountAsync(user); + await _UserStore.UpdateAsync(user); + return count; + } + + [HttpPost("ResetAccessFailedCount")] + public async Task ResetAccessFailedCountAsync([FromBody] User user) + { + await _UserStore.ResetAccessFailedCountAsync(user); + await _UserStore.UpdateAsync(user); + return user.AccessFailedCount; + } + + [HttpPost("GetAccessFailedCount")] + public async Task GetAccessFailedCountAsync([FromBody] User user) => await _UserStore.GetAccessFailedCountAsync(user); + + [HttpPost("GetLockoutEnabled")] + public async Task GetLockoutEnabledAsync([FromBody] User user) => await _UserStore.GetLockoutEnabledAsync(user); + + [HttpPost("SetLockoutEnabled/{enable}")] + public async Task SetLockoutEnabledAsync([FromBody] User user, bool enable) + { + await _UserStore.SetLockoutEnabledAsync(user, enable); + await _UserStore.UpdateAsync(user); + return user.LockoutEnabled; + } + + #endregion + } +} From d87cca8a7cbb2e3431b5f7c7f7b832d5a161d630 Mon Sep 17 00:00:00 2001 From: dmitry Date: Sun, 7 Feb 2021 14:49:24 +0500 Subject: [PATCH 27/28] =?UTF-8?q?=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D1=8B=20identity=20=D0=B4=D0=BB=D1=8F=20WEBApi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Services/WebStore.Client/Base/BaseClient.cs | 37 +- .../Identity/IdentityExtensions.cs | 32 ++ .../WebStore.Client/Identity/RolesClient.cs | 76 ++++ .../WebStore.Client/Identity/UsersClient.cs | 378 ++++++++++++++++++ 4 files changed, 510 insertions(+), 13 deletions(-) create mode 100644 Services/WebStore.Client/Identity/IdentityExtensions.cs create mode 100644 Services/WebStore.Client/Identity/RolesClient.cs create mode 100644 Services/WebStore.Client/Identity/UsersClient.cs diff --git a/Services/WebStore.Client/Base/BaseClient.cs b/Services/WebStore.Client/Base/BaseClient.cs index b587d52..2e4853b 100644 --- a/Services/WebStore.Client/Base/BaseClient.cs +++ b/Services/WebStore.Client/Base/BaseClient.cs @@ -1,12 +1,13 @@ using System; using System.Net.Http; using System.Net.Http.Headers; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; namespace WebStore.Client.Base { - public abstract class BaseClient + public abstract class BaseClient : IDisposable { protected string Address { get; } protected HttpClient Http { get; } @@ -25,34 +26,44 @@ protected BaseClient(IConfiguration Configuration, string ServiceAddress) } protected T Get(string url) => GetAsync(url).Result; - protected async Task GetAsync(string url) + protected async Task GetAsync(string url, CancellationToken Cancel = default) { - var response = await Http.GetAsync(url); - return await response.EnsureSuccessStatusCode().Content.ReadAsAsync(); + var response = await Http.GetAsync(url, Cancel); + return await response.EnsureSuccessStatusCode().Content.ReadAsAsync(Cancel); } protected HttpResponseMessage Post(string url, T item) => PostAsync(url, item).Result; - - protected async Task PostAsync(string url, T item) + protected async Task PostAsync(string url, T item, CancellationToken Cancel = default) { - var response = await Http.PostAsJsonAsync(url, item); + var response = await Http.PostAsJsonAsync(url, item, Cancel); return response.EnsureSuccessStatusCode(); } protected HttpResponseMessage Put(string url, T item) => PutAsync(url, item).Result; - - protected async Task PutAsync(string url, T item) + protected async Task PutAsync(string url, T item, CancellationToken Cancel = default) { - var response = await Http.PutAsJsonAsync(url, item); + var response = await Http.PutAsJsonAsync(url, item, Cancel); return response.EnsureSuccessStatusCode(); } protected HttpResponseMessage Delete(string url) => DeleteAsync(url).Result; - - protected async Task DeleteAsync(string url) + protected async Task DeleteAsync(string url, CancellationToken Cancel = default) { - var response = await Http.DeleteAsync(url); + var response = await Http.DeleteAsync(url, Cancel); return response; } + + public void Dispose() => Dispose(true); + + protected virtual void Dispose(bool Disposing) + { + if (Disposing) + { + // освобождение управляемых ресурсов + Http.Dispose(); + } + + // освобождение неуправляемых ресурсов + } } } diff --git a/Services/WebStore.Client/Identity/IdentityExtensions.cs b/Services/WebStore.Client/Identity/IdentityExtensions.cs new file mode 100644 index 0000000..5982b38 --- /dev/null +++ b/Services/WebStore.Client/Identity/IdentityExtensions.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; +using WebStore.Domain.Entities.Identity; + +namespace WebStore.Clients.Identity +{ + public static class IdentityExtensions + { + public static IServiceCollection AddIdentityWebStoreWebAPIClients(this IServiceCollection services) + { + services + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>() + .AddTransient, UsersClient>(); + + services.AddTransient, RolesClient>(); + + return services; + } + + public static IdentityBuilder AddIdentityWebStoreWebAPIClients(this IdentityBuilder builder) + { + builder.Services.AddIdentityWebStoreWebAPIClients(); + return builder; + } + } +} diff --git a/Services/WebStore.Client/Identity/RolesClient.cs b/Services/WebStore.Client/Identity/RolesClient.cs new file mode 100644 index 0000000..ac29ecf --- /dev/null +++ b/Services/WebStore.Client/Identity/RolesClient.cs @@ -0,0 +1,76 @@ +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Configuration; +using WebStore.Client.Base; +using WebStore.Domain.Entities.Identity; +using WebStore.Interfaces.Services.Identity; + +namespace WebStore.Clients.Identity +{ + public class RolesClient : BaseClient, IRolesClient + { + public RolesClient(IConfiguration Configuration) : base(Configuration, WebAPI.Identity.Role) { } + + #region IRoleStore + + public async Task CreateAsync(Role role, CancellationToken cancel) => + await (await PostAsync(Address, role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel) + ? IdentityResult.Success + : IdentityResult.Failed(); + + public async Task UpdateAsync(Role role, CancellationToken cancel) => + await (await PutAsync(Address, role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel) + ? IdentityResult.Success + : IdentityResult.Failed(); + + public async Task DeleteAsync(Role role, CancellationToken cancel) => + await (await PostAsync($"{Address}/Delete", role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel) + ? IdentityResult.Success + : IdentityResult.Failed(); + + public async Task GetRoleIdAsync(Role role, CancellationToken cancel) => + await (await PostAsync($"{Address}/GetRoleId", role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel); + + public async Task GetRoleNameAsync(Role role, CancellationToken cancel) => + await (await PostAsync($"{Address}/GetRoleName", role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel); + + public async Task SetRoleNameAsync(Role role, string name, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetRoleName/{name}", role, cancel).ConfigureAwait(false); + role.Name = await response.Content.ReadAsAsync(cancel); + } + + public async Task GetNormalizedRoleNameAsync(Role role, CancellationToken cancel) => + await (await PostAsync($"{Address}/GetNormalizedRoleName", role, cancel).ConfigureAwait(false)) + .Content + .ReadAsAsync(cancel); + + public async Task SetNormalizedRoleNameAsync(Role role, string name, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetNormalizedRoleName/{name}", role, cancel).ConfigureAwait(false); + role.NormalizedName = await response.Content.ReadAsAsync(cancel); + } + + public async Task FindByIdAsync(string id, CancellationToken cancel) => + await GetAsync($"{Address}/FindById/{id}", cancel) + .ConfigureAwait(false); + + public async Task FindByNameAsync(string name, CancellationToken cancel) => + await GetAsync($"{Address}/FindByName/{name}", cancel) + .ConfigureAwait(false); + + #endregion + } +} diff --git a/Services/WebStore.Client/Identity/UsersClient.cs b/Services/WebStore.Client/Identity/UsersClient.cs new file mode 100644 index 0000000..f0f4bbb --- /dev/null +++ b/Services/WebStore.Client/Identity/UsersClient.cs @@ -0,0 +1,378 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Configuration; +using Webstore.Interfaces; +using WebStore.Client.Base; +using WebStore.Domain.DTO.Identity; +using WebStore.Domain.Entities.Identity; +using WebStore.Interfaces.Services.Identity; + +namespace WebStore.Clients.Identity +{ + public class UsersClient : BaseClient, IUsersClient + { + public UsersClient(IConfiguration Configuration) : base(Configuration, WebAPI.Identity.User) { } + + #region Implementation of IUserStore + + public async Task GetUserIdAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/UserId", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + } + + public async Task GetUserNameAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/UserName", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + } + + public async Task SetUserNameAsync(User user, string name, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/UserName/{name}", user, cancel); + user.UserName = await response.Content.ReadAsAsync(cancel); + } + + public async Task GetNormalizedUserNameAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/NormalUserName/", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + } + + public async Task SetNormalizedUserNameAsync(User user, string name, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/NormalUserName/{name}", user, cancel); + user.NormalizedUserName = await response.Content.ReadAsAsync(cancel).ConfigureAwait(false); + } + + public async Task CreateAsync(User user, CancellationToken cancel) + { + var creation_success = await (await PostAsync($"{Address}/User", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + + return creation_success + ? IdentityResult.Success + : IdentityResult.Failed(); + } + + public async Task UpdateAsync(User user, CancellationToken cancel) + { + return await (await PutAsync($"{Address}/User", user, cancel)) + .Content + .ReadAsAsync(cancel).ConfigureAwait(false) + ? IdentityResult.Success + : IdentityResult.Failed(); + } + + public async Task DeleteAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/User/Delete", user, cancel)) + .Content + .ReadAsAsync(cancel) + ? IdentityResult.Success + : IdentityResult.Failed(); + } + + public async Task FindByIdAsync(string id, CancellationToken cancel) + { + return await GetAsync($"{Address}/User/Find/{id}", cancel); + } + + public async Task FindByNameAsync(string name, CancellationToken cancel) + { + return await GetAsync($"{Address}/User/Normal/{name}", cancel); + } + + #endregion + + #region Implementation of IUserRoleStore + + public async Task AddToRoleAsync(User user, string role, CancellationToken cancel) + { + await PostAsync($"{Address}/Role/{role}", user, cancel); + } + + public async Task RemoveFromRoleAsync(User user, string role, CancellationToken cancel) + { + await PostAsync($"{Address}/Role/Delete/{role}", user, cancel); + } + + public async Task> GetRolesAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/roles", user, cancel)) + .Content + .ReadAsAsync>(cancel); + } + + public async Task IsInRoleAsync(User user, string role, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/InRole/{role}", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task> GetUsersInRoleAsync(string role, CancellationToken cancel) + { + return await GetAsync>($"{Address}/UsersInRole/{role}", cancel); + } + + #endregion + + #region Implementation of IUserPasswordStore + + public async Task SetPasswordHashAsync(User user, string hash, CancellationToken cancel) + { + var response = await PostAsync( + $"{Address}/SetPasswordHash", new PasswordHashDTO { User = user, Hash = hash }, + cancel) + .ConfigureAwait(false); + user.PasswordHash = await response.Content.ReadAsAsync(cancel).ConfigureAwait(false); + } + + public async Task GetPasswordHashAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetPasswordHash", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + } + + public async Task HasPasswordAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/HasPassword", user, cancel)) + .Content + .ReadAsAsync(cancel) + .ConfigureAwait(false); + } + + #endregion + + #region Implementation of IUserEmailStore + + public async Task SetEmailAsync(User user, string email, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetEmail/{email}", user, cancel); + user.Email = await response.Content.ReadAsAsync(cancel); + } + + public async Task GetEmailAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetEmail", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task GetEmailConfirmedAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetEmailConfirmed", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task SetEmailConfirmedAsync(User user, bool confirmed, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetEmailConfirmed/{confirmed}", user, cancel); + user.EmailConfirmed = await response.Content.ReadAsAsync(cancel); + } + + public async Task FindByEmailAsync(string email, CancellationToken cancel) + { + return await GetAsync($"{Address}/User/FindByEmail/{email}", cancel); + } + + public async Task GetNormalizedEmailAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/User/GetNormalizedEmail", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task SetNormalizedEmailAsync(User user, string email, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetNormalizedEmail/{email}", user, cancel); + user.NormalizedEmail = await response.Content.ReadAsAsync(cancel); + } + + #endregion + + #region Implementation of IUserPhoneNumberStore + + public async Task SetPhoneNumberAsync(User user, string phone, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetPhoneNumber/{phone}", user, cancel); + user.PhoneNumber = await response.Content.ReadAsAsync(cancel); + } + + public async Task GetPhoneNumberAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetPhoneNumber", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task GetPhoneNumberConfirmedAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetPhoneNumberConfirmed", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task SetPhoneNumberConfirmedAsync(User user, bool confirmed, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetPhoneNumberConfirmed/{confirmed}", user, cancel); + user.PhoneNumberConfirmed = await response.Content.ReadAsAsync(cancel); + } + + #endregion + + #region Implementation of IUserLoginStore + + public async Task AddLoginAsync(User user, UserLoginInfo login, CancellationToken cancel) + { + await PostAsync($"{Address}/AddLogin", new AddLoginDTO { User = user, UserLoginInfo = login }, cancel); + } + + public async Task RemoveLoginAsync(User user, string LoginProvider, string ProviderKey, CancellationToken cancel) + { + await PostAsync($"{Address}/RemoveLogin/{LoginProvider}/{ProviderKey}", user, cancel); + } + + public async Task> GetLoginsAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetLogins", user, cancel)) + .Content + .ReadAsAsync>(cancel); + } + + public async Task FindByLoginAsync(string LoginProvider, string ProviderKey, CancellationToken cancel) + { + return await GetAsync($"{Address}/User/FindByLogin/{LoginProvider}/{ProviderKey}", cancel); + } + + #endregion + + #region Implementation of IUserLockoutStore + + public async Task GetLockoutEndDateAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetLockoutEndDate", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task SetLockoutEndDateAsync(User user, DateTimeOffset? EndDate, CancellationToken cancel) + { + var response = await PostAsync( + $"{Address}/SetLockoutEndDate", + new SetLockoutDTO { User = user, LockoutEnd = EndDate }, + cancel); + user.LockoutEnd = await response.Content.ReadAsAsync(cancel); + } + + public async Task IncrementAccessFailedCountAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/IncrementAccessFailedCount", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task ResetAccessFailedCountAsync(User user, CancellationToken cancel) + { + await PostAsync($"{Address}/ResetAccessFailedCont", user, cancel); + } + + public async Task GetAccessFailedCountAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetAccessFailedCount", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task GetLockoutEnabledAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetLockoutEnabled", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + public async Task SetLockoutEnabledAsync(User user, bool enabled, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetLockoutEnabled/{enabled}", user, cancel); + user.LockoutEnabled = await response.Content.ReadAsAsync(cancel); + } + + #endregion + + #region Implementation of IUserTwoFactorStore + + public async Task SetTwoFactorEnabledAsync(User user, bool enabled, CancellationToken cancel) + { + var response = await PostAsync($"{Address}/SetTwoFactor/{enabled}", user, cancel); + user.TwoFactorEnabled = await response.Content.ReadAsAsync(cancel); + } + + public async Task GetTwoFactorEnabledAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetTwoFactorEnabled", user, cancel)) + .Content + .ReadAsAsync(cancel); + } + + #endregion + + #region Implementation of IUserClaimStore + + public async Task> GetClaimsAsync(User user, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetClaims", user, cancel)) + .Content + .ReadAsAsync>(cancel); + } + + public async Task AddClaimsAsync(User user, IEnumerable claims, CancellationToken cancel) + { + await PostAsync( + $"{Address}/AddClaims", + new AddClaimDTO { User = user, Claims = claims }, + cancel); + } + + public async Task ReplaceClaimAsync(User user, Claim OldClaim, Claim NewClaim, CancellationToken cancel) + { + await PostAsync( + $"{Address}/ReplaceClaim", + new ReplaceClaimDTO { User = user, Claim = OldClaim, NewClaim = NewClaim }, + cancel); + } + + public async Task RemoveClaimsAsync(User user, IEnumerable claims, CancellationToken cancel) + { + await PostAsync( + $"{Address}/RemoveClaims", + new RemoveClaimDTO { User = user, Claims = claims }, + cancel); + } + + public async Task> GetUsersForClaimAsync(Claim claim, CancellationToken cancel) + { + return await (await PostAsync($"{Address}/GetUsersForClaim", claim, cancel)) + .Content + .ReadAsAsync>(cancel); + } + + #endregion + } +} From 8c859b743e2a3cf8ae69f0631c0ffaa7f906b6eb Mon Sep 17 00:00:00 2001 From: dmitry Date: Sun, 7 Feb 2021 14:52:12 +0500 Subject: [PATCH 28/28] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B8=D0=BB=D0=B8=20=D0=B1=D0=B0=D0=B7=D1=83=20=D0=B4=D0=B0?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B8=D0=B7=20UI=20=D0=BA=D0=BB?= =?UTF-8?q?=D0=B8=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Services/WebStore.Client/Identity/RolesClient.cs | 1 + UI/WebStore/Startup.cs | 13 +++---------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Services/WebStore.Client/Identity/RolesClient.cs b/Services/WebStore.Client/Identity/RolesClient.cs index ac29ecf..98a84a1 100644 --- a/Services/WebStore.Client/Identity/RolesClient.cs +++ b/Services/WebStore.Client/Identity/RolesClient.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; +using Webstore.Interfaces; using WebStore.Client.Base; using WebStore.Domain.Entities.Identity; using WebStore.Interfaces.Services.Identity; diff --git a/UI/WebStore/Startup.cs b/UI/WebStore/Startup.cs index 1a11475..05fb28f 100644 --- a/UI/WebStore/Startup.cs +++ b/UI/WebStore/Startup.cs @@ -22,6 +22,7 @@ using WebStore.Client.Employees; using WebStore.Client.Products; using WebStore.Client.Orders; +using WebStore.Clients.Identity; namespace WebStore { @@ -35,11 +36,8 @@ public class Startup public Startup(IConfiguration Configuration) => _Configuration = Configuration; public void ConfigureServices(IServiceCollection services) { - services.AddDbContext(opt => opt.UseSqlServer(_Configuration.GetConnectionString("Default"))); - services.AddTransient(); - services.AddIdentity() - .AddEntityFrameworkStores() + .AddIdentityWebStoreWebAPIClients() .AddDefaultTokenProviders(); services.Configure(opt => @@ -75,22 +73,17 @@ public void ConfigureServices(IServiceCollection services) services.AddControllersWithViews().AddRazorRuntimeCompilation(); services.AddSingleton(); - - //services.AddTransient(); - //services.AddTransient(); services.AddTransient(); services.AddSingleton(); services.AddScoped(); - //services.AddScoped(); services.AddScoped(); services.AddScoped(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, WebStoreDbInitializer db) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - db.Initialize(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage();