From 1ca2d18f4872f7446a3c4601e1188efa334121ae Mon Sep 17 00:00:00 2001 From: "nikbel2004@outlook.com" Date: Wed, 22 May 2024 16:34:25 +0400 Subject: [PATCH] =?UTF-8?q?=D0=9B=D0=B0=D0=B1=D0=BE=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=BD=D0=B0=D1=8F=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=208?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BussinessLogic/BackUpLogic.cs | 134 ++++++++++ .../BussinessLogic/ClientLogic.cs | 2 +- .../BussinessLogic/ImplementerLogic.cs | 242 ++++++++--------- .../BussinessLogic/OrderLogic.cs | 60 ++--- .../BussinessLogic/ReportLogic.cs | 4 +- .../BussinessLogic/WorkModeling.cs | 244 +++++++++--------- .../OfficePackage/HelperModels/WordInfo.cs | 2 +- .../HelperModels/WordParagraph.cs | 2 +- .../Attributes/ColumnAttribute.cs | 33 +++ .../Attributes/GridViewAutoSize.cs | 27 ++ .../BindingModels/BackUpSaveBindingModel.cs | 13 + .../BindingModels/MessageInfoBindingModel.cs | 4 +- .../BusinessLogicsContracts/IBackUpLogic.cs | 16 ++ .../BusinessLogicsContracts/IWorkProcess.cs | 12 +- .../DI/DependencyManager.cs | 60 +++++ .../DI/IDependencyContainer.cs | 26 ++ .../DI/IImplementationExtension.cs | 18 ++ .../DI/ServiceDependencyContainer.cs | 65 +++++ .../DI/ServiceProviderLoader.cs | 61 +++++ .../DI/UnityDependencyContainer.cs | 42 +++ .../FurnitureAssemblyContracts.csproj | 6 + .../SearchModels/ImplementerSearchModel.cs | 14 +- .../StoragesContracts/IBackUpInfo.cs | 17 ++ .../StoragesContracts/IImplementerStorage.cs | 16 +- .../ViewModels/ClientViewModel.cs | 10 +- .../ViewModels/FurnitureViewModel.cs | 9 +- .../ViewModels/ImplementerViewModel.cs | 26 +- .../ViewModels/MessageInfoViewModel.cs | 18 +- .../ViewModels/OrderViewModel.cs | 24 +- .../ViewModels/WorkPieceViewModel.cs | 8 +- .../Models/IImplementerModel.cs | 12 +- .../Models/IMessageInfoModel.cs | 2 +- .../DataBaseImplementationExtension.cs | 33 +++ .../FurnitureAssemblyDatabaseImplement.csproj | 42 +-- .../Implements/BackUpInfo.cs | 35 +++ .../Implements/ImplementerStorage.cs | 140 +++++----- ... 20240518234238_InitialCreate.Designer.cs} | 2 +- ...ate.cs => 20240518234238_InitialCreate.cs} | 0 .../Models/Client.cs | 6 + .../Models/Furniture.cs | 6 + .../Models/FurnitureWorkPiece.cs | 2 + .../Models/Implementer.cs | 17 +- .../Models/MessageInfo.cs | 9 +- .../Models/Order.cs | 11 + .../Models/WorkPiece.cs | 5 + .../FileImplementationExtension.cs | 34 +++ .../FurnitureAssemblyFileImplement.csproj | 22 +- .../Implements/BackUpInfo.cs | 37 +++ .../Implements/ImplementerStorage.cs | 156 +++++------ .../Models/Client.cs | 6 + .../Models/Furniture.cs | 6 + .../Models/Implementer.cs | 7 + .../Models/MessageInfo.cs | 10 + .../Models/Order.cs | 11 + .../Models/WorkPiece.cs | 5 + .../FurnitureAssemblyListImplement.csproj | 18 +- .../Implements/BackUpInfo.cs | 22 ++ .../Implements/ImplementerStorage.cs | 186 ++++++------- .../ListImplementationExtension.cs | 33 +++ .../Models/Implementer.cs | 90 +++---- .../Models/MessageInfo.cs | 2 + .../Controllers/ImplementerController.cs | 178 ++++++------- .../FurnitureAssemblyRestApi.csproj | 28 +- .../DataGridViewExtension.cs | 62 +++++ .../FurnitureAssemblyView/FormClients.cs | 13 +- .../FurnitureAssemblyView/FormFurniture.cs | 85 +++--- .../FurnitureAssemblyView/FormFurnitures.cs | 33 +-- .../FurnitureAssemblyView/FormImplementers.cs | 185 +++++++------ .../FurnitureAssemblyView/FormMails.cs | 66 +++-- .../FormMain.Designer.cs | 19 +- .../FurnitureAssemblyView/FormMain.cs | 105 ++++---- .../FurnitureAssemblyView/FormWorkPieces.cs | 31 +-- .../FurnitureAssemblyView/Program.cs | 98 ++++--- .../FurnitureAssemblyContracts.dll | Bin 0 -> 31744 bytes .../FurnitureAssemblyDataModels.dll | Bin 0 -> 6144 bytes .../FurnitureAssemblyDatabaseImplement.dll | Bin 0 -> 76800 bytes .../FurnitureAssemblyFileImplement.dll | Bin 0 -> 40960 bytes 77 files changed, 1961 insertions(+), 1124 deletions(-) create mode 100644 FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/BackUpLogic.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/Attributes/ColumnAttribute.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/Attributes/GridViewAutoSize.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/BackUpSaveBindingModel.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/BusinessLogicsContracts/IBackUpLogic.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/DI/DependencyManager.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/DI/IDependencyContainer.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/DI/IImplementationExtension.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/DI/ServiceDependencyContainer.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/DI/ServiceProviderLoader.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/DI/UnityDependencyContainer.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyContracts/StoragesContracts/IBackUpInfo.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyDatabaseImplement/DataBaseImplementationExtension.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/BackUpInfo.cs rename FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/{20240511234747_InitialCreate.Designer.cs => 20240518234238_InitialCreate.Designer.cs} (99%) rename FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/{20240511234747_InitialCreate.cs => 20240518234238_InitialCreate.cs} (100%) create mode 100644 FurnitureAssembly/FurnitureAssemblyFileImplement/FileImplementationExtension.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyFileImplement/Implements/BackUpInfo.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyListImplement/Implements/BackUpInfo.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyListImplement/ListImplementationExtension.cs create mode 100644 FurnitureAssembly/FurnitureAssemblyView/DataGridViewExtension.cs create mode 100644 FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyContracts.dll create mode 100644 FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyDataModels.dll create mode 100644 FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyDatabaseImplement.dll create mode 100644 FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyFileImplement.dll diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/BackUpLogic.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/BackUpLogic.cs new file mode 100644 index 0000000..0d44934 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/BackUpLogic.cs @@ -0,0 +1,134 @@ +using FurnitureAssemblyContracts.BindingModels; +using FurnitureAssemblyContracts.BusinessLogicsContracts; +using FurnitureAssemblyContracts.StoragesContracts; +using FurnitureAssemblyDataModels; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.IO.Compression; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization.Json; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyBusinessLogic.BussinessLogic +{ + // Класс, реализующий логику для BackUp + public class BackUpLogic : IBackUpLogic + { + private readonly ILogger _logger; + + private readonly IBackUpInfo _backUpInfo; + + // Конструктор + public BackUpLogic(ILogger logger, IBackUpInfo backUpInfo) + { + _logger = logger; + _backUpInfo = backUpInfo; + } + + public void CreateBackUp(BackUpSaveBindingModel model) + { + // Проверка наличия данных для бэкапа + if (_backUpInfo == null) + { + return; + } + + try + { + _logger.LogDebug("Clear folder"); + + // Зачистка папки и удаление старого архива + var dirInfo = new DirectoryInfo(model.FolderName); + + if (dirInfo.Exists) + { + // ЛУЧШЕ ВЫБИРАТЬ ОТДЕЛЬНО СОЗДАННУЮ ПАПКУ (Рабочий стол не использовать, поскольку с него всё удалится) + foreach (var file in dirInfo.GetFiles()) + { + file.Delete(); + } + } + + _logger.LogDebug("Delete archive"); + + string fileName = $"{model.FolderName}.zip"; + + if (File.Exists(fileName)) + { + File.Delete(fileName); + } + + // Берём метод для сохранения + _logger.LogDebug("Get assembly"); + + // Получение сборки и типов + var typeIId = typeof(IId); + var assembly = typeIId.Assembly; + + if (assembly == null) + { + throw new ArgumentNullException("Сборка не найдена", nameof(assembly)); + } + + var types = assembly.GetTypes(); + var method = GetType().GetMethod("SaveToFile", BindingFlags.NonPublic | BindingFlags.Instance); + + _logger.LogDebug("Find {count} types", types.Length); + + // Перебор типов и вызов метода для сохранения данных + foreach (var type in types) + { + // Проверка на то, является ли тип интерфейсом и унаследован ли он от IId + if (type.IsInterface && type.GetInterface(typeIId.Name) != null) + { + var modelType = _backUpInfo.GetTypeByModelInterface(type.Name); + + if (modelType == null) + { + throw new InvalidOperationException($"Не найден класс - модель для {type.Name}"); + } + + _logger.LogDebug("Call SaveToFile method for {name} type", type.Name); + + // Вызываем метод на выполнение (Вызываем метод типа MethodInfo) + method?.MakeGenericMethod(modelType).Invoke(this, new object[] { model.FolderName }); + } + } + + _logger.LogDebug("Create zip and remove folder"); + + // Архивируем + ZipFile.CreateFromDirectory(model.FolderName, fileName); + + // Удаляем папку + dirInfo.Delete(true); + } + catch (Exception) + { + throw; + } + } + + private void SaveToFile(string folderName) where T : class, new() + { + var records = _backUpInfo.GetList(); + + if (records == null) + { + _logger.LogWarning("{type} type get null list", typeof(T).Name); + + return; + } + + // Три строчки ниже - сериализация файлов в json + var jsonFormatter = new DataContractJsonSerializer(typeof(List)); + + using var fs = new FileStream(string.Format("{0}/{1}.json", folderName, typeof(T).Name), FileMode.OpenOrCreate); + + jsonFormatter.WriteObject(fs, records); + } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ClientLogic.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ClientLogic.cs index 575282a..9cae36e 100644 --- a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ClientLogic.cs +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ClientLogic.cs @@ -149,7 +149,7 @@ namespace FurnitureAssemblyBusinessLogic.BussinessLogic throw new ArgumentException("Некорректная почта", nameof(model.Email)); } - if (!Regex.IsMatch(model.Password, @"^((\w+\d+\W+)|(\w+\W+\d+)|(\d+\w+\W+)|(\d+\W+\w+)|(\W+\w+\d+)|(\W+\d+\w+))[\w\d\W]*$", RegexOptions.IgnoreCase) + if (!Regex.IsMatch(model.Password, @"^((\w+\d+\W+)|(\w+\W+\d+)|(\d+\w+\W+)|(\d+\W+\w+)|(\W+\w+\d+)|(\W+\d+\w+))[\w\d\W]*$", RegexOptions.IgnoreCase) && model.Password.Length < 10 && model.Password.Length > 50) { throw new ArgumentException("Необходимо придумать другой пароль", nameof(model.Password)); diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ImplementerLogic.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ImplementerLogic.cs index c1e236b..80a3fc5 100644 --- a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ImplementerLogic.cs +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ImplementerLogic.cs @@ -14,161 +14,161 @@ namespace FurnitureAssemblyBusinessLogic.BussinessLogic { // Класс, реализующий логику для исполнителей public class ImplementerLogic : IImplementerLogic - { - private readonly ILogger _logger; + { + private readonly ILogger _logger; - private readonly IImplementerStorage _implementerStorage; + private readonly IImplementerStorage _implementerStorage; - // Конструктор - public ImplementerLogic(ILogger logger, IImplementerStorage implementerStorage) - { - _logger = logger; - _implementerStorage = implementerStorage; - } + // Конструктор + public ImplementerLogic(ILogger logger, IImplementerStorage implementerStorage) + { + _logger = logger; + _implementerStorage = implementerStorage; + } - // Вывод всего отфильтрованного списка - public List? ReadList(ImplementerSearchModel? model) - { - _logger.LogInformation("ReadList. ImplementerFIO:{ImplementerFIO}. Id:{Id}", model?.ImplementerFIO, model?.Id); + // Вывод всего отфильтрованного списка + public List? ReadList(ImplementerSearchModel? model) + { + _logger.LogInformation("ReadList. ImplementerFIO:{ImplementerFIO}. Id:{Id}", model?.ImplementerFIO, model?.Id); - // list хранит весь список в случае, если model пришло со значением null на вход метода - var list = model == null ? _implementerStorage.GetFullList() : _implementerStorage.GetFilteredList(model); + // list хранит весь список в случае, если model пришло со значением null на вход метода + var list = model == null ? _implementerStorage.GetFullList() : _implementerStorage.GetFilteredList(model); - if (list == null) - { - _logger.LogWarning("ReadList return null list"); - return null; - } + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } - _logger.LogInformation("ReadList. Count:{Count}", list.Count); + _logger.LogInformation("ReadList. Count:{Count}", list.Count); - return list; - } + return list; + } - // Вывод конкретного элемента - public ImplementerViewModel? ReadElement(ImplementerSearchModel model) - { - if (model == null) - { - throw new ArgumentNullException(nameof(model)); - } + // Вывод конкретного элемента + public ImplementerViewModel? ReadElement(ImplementerSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } - _logger.LogInformation("ReadList. ImplementerFIO:{ImplementerFIO}. Id:{Id}", model.ImplementerFIO, model?.Id); + _logger.LogInformation("ReadList. ImplementerFIO:{ImplementerFIO}. Id:{Id}", model.ImplementerFIO, model?.Id); - var element = _implementerStorage.GetElement(model); + var element = _implementerStorage.GetElement(model); - if (element == null) - { - _logger.LogWarning("ReadElement element not found"); + if (element == null) + { + _logger.LogWarning("ReadElement element not found"); - return null; - } + return null; + } - _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); + _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); - return element; - } + return element; + } - // Создание работника - public bool Create(ImplementerBindingModel model) - { - CheckModel(model); + // Создание работника + public bool Create(ImplementerBindingModel model) + { + CheckModel(model); - if (_implementerStorage.Insert(model) == null) - { - _logger.LogWarning("Insert operation failed"); + if (_implementerStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); - return false; - } + return false; + } - return true; - } + return true; + } - // Обновление данных о работнике - public bool Update(ImplementerBindingModel model) - { - CheckModel(model); + // Обновление данных о работнике + public bool Update(ImplementerBindingModel model) + { + CheckModel(model); - if (_implementerStorage.Update(model) == null) - { - _logger.LogWarning("Update operation failed"); + if (_implementerStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); - return false; - } + return false; + } - return true; - } + return true; + } - // Удаление работника - public bool Delete(ImplementerBindingModel model) - { - CheckModel(model, false); + // Удаление работника + public bool Delete(ImplementerBindingModel model) + { + CheckModel(model, false); - _logger.LogInformation("Delete. Id:{Id}", model.Id); + _logger.LogInformation("Delete. Id:{Id}", model.Id); - if (_implementerStorage.Delete(model) == null) - { - _logger.LogWarning("Delete operation failed"); + if (_implementerStorage.Delete(model) == null) + { + _logger.LogWarning("Delete operation failed"); - return false; - } + return false; + } - return true; - } + return true; + } - // Проверка входного аргумента для методов Insert, Update и Delete - private void CheckModel(ImplementerBindingModel model, bool withParams = true) - { - if (model == null) - { - throw new ArgumentNullException(nameof(model)); - } + // Проверка входного аргумента для методов Insert, Update и Delete + private void CheckModel(ImplementerBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } - // Так как при удалении передаём как параметр false - if (!withParams) - { - return; - } + // Так как при удалении передаём как параметр false + if (!withParams) + { + return; + } - // Проверка на наличие ФИО - if (string.IsNullOrEmpty(model.ImplementerFIO)) - { - throw new ArgumentNullException("Отсутствие ФИО в учётной записи", nameof(model.ImplementerFIO)); - } + // Проверка на наличие ФИО + if (string.IsNullOrEmpty(model.ImplementerFIO)) + { + throw new ArgumentNullException("Отсутствие ФИО в учётной записи", nameof(model.ImplementerFIO)); + } - // Проверка на наличие пароля - if (string.IsNullOrEmpty(model.Password)) - { - throw new ArgumentNullException("Отсутствие пароля в учётной записи", nameof(model.Password)); - } + // Проверка на наличие пароля + if (string.IsNullOrEmpty(model.Password)) + { + throw new ArgumentNullException("Отсутствие пароля в учётной записи", nameof(model.Password)); + } - // Проверка на наличие квалификации - if (model.Qualification <= 0) - { - throw new ArgumentNullException("Указана некорректная квалификация", nameof(model.Qualification)); - } + // Проверка на наличие квалификации + if (model.Qualification <= 0) + { + throw new ArgumentNullException("Указана некорректная квалификация", nameof(model.Qualification)); + } - // Проверка на наличие квалификации - if (model.WorkExperience < 0) - { - throw new ArgumentNullException("Указан некорректный стаж работы", nameof(model.WorkExperience)); - } + // Проверка на наличие квалификации + if (model.WorkExperience < 0) + { + throw new ArgumentNullException("Указан некорректный стаж работы", nameof(model.WorkExperience)); + } - _logger.LogInformation("Implementer. ImplementerFIO:{ImplementerFIO}. Password:{Password}. " + - "Qualification:{Qualification}. WorkExperience:{ WorkExperience}. Id:{Id}", - model.ImplementerFIO, model.Password, model.Qualification, model.WorkExperience, model.Id); + _logger.LogInformation("Implementer. ImplementerFIO:{ImplementerFIO}. Password:{Password}. " + + "Qualification:{Qualification}. WorkExperience:{ WorkExperience}. Id:{Id}", + model.ImplementerFIO, model.Password, model.Qualification, model.WorkExperience, model.Id); - // Для проверка на наличие такого же аккаунта - var element = _implementerStorage.GetElement(new ImplementerSearchModel - { - ImplementerFIO = model.ImplementerFIO, - }); + // Для проверка на наличие такого же аккаунта + var element = _implementerStorage.GetElement(new ImplementerSearchModel + { + ImplementerFIO = model.ImplementerFIO, + }); - // Если элемент найден и его Id не совпадает с Id переданного объекта - if (element != null && element.Id != model.Id) - { - throw new InvalidOperationException("Исполнитель с таким именем уже есть"); - } - } - } + // Если элемент найден и его Id не совпадает с Id переданного объекта + if (element != null && element.Id != model.Id) + { + throw new InvalidOperationException("Исполнитель с таким именем уже есть"); + } + } + } } diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/OrderLogic.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/OrderLogic.cs index a5f8363..5e06ba5 100644 --- a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/OrderLogic.cs +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/OrderLogic.cs @@ -58,35 +58,35 @@ namespace FurnitureAssemblyBusinessLogic.BussinessLogic } // Вывод конкретного чека - public OrderViewModel? ReadElement(OrderSearchModel model) - { - if (model == null) - { - throw new ArgumentNullException(nameof(model)); - } + public OrderViewModel? ReadElement(OrderSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } - _logger.LogInformation("ReadElement. Id:{Id}", model?.Id); + _logger.LogInformation("ReadElement. Id:{Id}", model?.Id); - var element = _orderStorage.GetElement(model); + var element = _orderStorage.GetElement(model); - if (element == null) - { - _logger.LogWarning("ReadElement element not found"); + if (element == null) + { + _logger.LogWarning("ReadElement element not found"); - return null; - } + return null; + } - _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); + _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); - return element; - } + return element; + } - // Создание чека - public bool CreateOrder(OrderBindingModel model) + // Создание чека + public bool CreateOrder(OrderBindingModel model) { CheckModel(model); - if(model.Status != OrderStatus.Неизвестен) + if (model.Status != OrderStatus.Неизвестен) { _logger.LogWarning("Insert operation failed, incorrect order status"); return false; @@ -95,7 +95,7 @@ namespace FurnitureAssemblyBusinessLogic.BussinessLogic model.Status = OrderStatus.Принят; var result = _orderStorage.Insert(model); - + if (result == null) { model.Status = OrderStatus.Неизвестен; @@ -179,13 +179,13 @@ namespace FurnitureAssemblyBusinessLogic.BussinessLogic var viewModel = _orderStorage.GetElement(new OrderSearchModel { Id = model.Id }); // Если не смогли найти указанный заказ по его Id - if(viewModel == null) + if (viewModel == null) { throw new ArgumentNullException(nameof(model)); } // Проверка на возможность обновления статуса на следующий - if(viewModel.Status + 1 != newOrderStatus) + if (viewModel.Status + 1 != newOrderStatus) { _logger.LogWarning("Status update operation failed. New status " + newOrderStatus.ToString() + "incorrect"); return false; @@ -193,14 +193,14 @@ namespace FurnitureAssemblyBusinessLogic.BussinessLogic model.Status = newOrderStatus; - // Помещаем id работника, не забываем про него... - if (viewModel.ImplementerId.HasValue) - { - model.ImplementerId = viewModel.ImplementerId; - } + // Помещаем id работника, не забываем про него... + if (viewModel.ImplementerId.HasValue) + { + model.ImplementerId = viewModel.ImplementerId; + } - // Проверка на выдачу - if (model.Status == OrderStatus.Выдан) + // Проверка на выдачу + if (model.Status == OrderStatus.Выдан) { model.DateImplement = DateTime.Now; } @@ -214,7 +214,7 @@ namespace FurnitureAssemblyBusinessLogic.BussinessLogic // Финальная проверка на возможность обновления var result = _orderStorage.Update(model); - if(result == null) + if (result == null) { model.Status--; diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ReportLogic.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ReportLogic.cs index f672ccd..dbcc3d1 100644 --- a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ReportLogic.cs +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/ReportLogic.cs @@ -27,8 +27,8 @@ namespace FurnitureAssemblyBusinessLogic.BussinessLogic private readonly AbstractSaveToPdf _saveToPdf; // Инициализируем поля класса через контейнер - public ReportLogic(IFurnitureStorage furnitureStorage, - IOrderStorage orderStorage, AbstractSaveToExcel saveToExcel, + public ReportLogic(IFurnitureStorage furnitureStorage, + IOrderStorage orderStorage, AbstractSaveToExcel saveToExcel, AbstractSaveToWord saveToWord, AbstractSaveToPdf saveToPdf) { _furnitureStorage = furnitureStorage; diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/WorkModeling.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/WorkModeling.cs index 6d7f567..1784d17 100644 --- a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/WorkModeling.cs +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/BussinessLogic/WorkModeling.cs @@ -12,155 +12,155 @@ using System.Threading.Tasks; namespace FurnitureAssemblyBusinessLogic.BussinessLogic { - public class WorkModeling : IWorkProcess - { - private readonly ILogger _logger; + public class WorkModeling : IWorkProcess + { + private readonly ILogger _logger; - private readonly Random _rnd; + private readonly Random _rnd; - private IOrderLogic? _orderLogic; + private IOrderLogic? _orderLogic; - // Конструктор - public WorkModeling(ILogger logger) - { - _logger = logger; - _rnd = new Random(1000); - } + // Конструктор + public WorkModeling(ILogger logger) + { + _logger = logger; + _rnd = new Random(1000); + } - public void DoWork(IImplementerLogic implementerLogic, IOrderLogic orderLogic) - { - _orderLogic = orderLogic; - var implementers = implementerLogic.ReadList(null); + public void DoWork(IImplementerLogic implementerLogic, IOrderLogic orderLogic) + { + _orderLogic = orderLogic; + var implementers = implementerLogic.ReadList(null); - if (implementers == null) - { - _logger.LogWarning("DoWork. Implementers is null"); - return; - } + if (implementers == null) + { + _logger.LogWarning("DoWork. Implementers is null"); + return; + } - var orders = _orderLogic.ReadList(new OrderSearchModel - { - Status = OrderStatus.Принят - }); + var orders = _orderLogic.ReadList(new OrderSearchModel + { + Status = OrderStatus.Принят + }); - if (orders == null || orders.Count == 0) - { - _logger.LogWarning("Dowork. Orders is null or empty"); - return; - } + if (orders == null || orders.Count == 0) + { + _logger.LogWarning("Dowork. Orders is null or empty"); + return; + } - _logger.LogDebug("DoWork for {count} orders", orders.Count); + _logger.LogDebug("DoWork for {count} orders", orders.Count); - foreach (var implementer in implementers) - { - Task.Run(() => WorkerWorkAsync(implementer, orders)); - } - } + foreach (var implementer in implementers) + { + Task.Run(() => WorkerWorkAsync(implementer, orders)); + } + } - // Имитация работы исполнителя - private async Task WorkerWorkAsync(ImplementerViewModel implementer, List orders) - { - if (_orderLogic == null || implementer == null) - { - return; - } + // Имитация работы исполнителя + private async Task WorkerWorkAsync(ImplementerViewModel implementer, List orders) + { + if (_orderLogic == null || implementer == null) + { + return; + } - await RunOrderInWork(implementer); + await RunOrderInWork(implementer); - await Task.Run(() => - { - foreach (var order in orders) - { - try - { - _logger.LogDebug("DoWork. Worker {Id} try get order {Order}", implementer.Id, order.Id); + await Task.Run(() => + { + foreach (var order in orders) + { + try + { + _logger.LogDebug("DoWork. Worker {Id} try get order {Order}", implementer.Id, order.Id); - // Пытаемся назначить заказ на исполнителя - _orderLogic.TakeOrderInWork(new OrderBindingModel - { - Id = order.Id, - ImplementerId = implementer.Id - }); + // Пытаемся назначить заказ на исполнителя + _orderLogic.TakeOrderInWork(new OrderBindingModel + { + Id = order.Id, + ImplementerId = implementer.Id + }); - // Работу работаем, делаем-делаем - Thread.Sleep(implementer.WorkExperience * order.Count); + // Работу работаем, делаем-делаем + Thread.Sleep(implementer.WorkExperience * order.Count); - _logger.LogDebug("DoWork. Worker {Id} finish order {Order}", implementer.Id, order.Id); + _logger.LogDebug("DoWork. Worker {Id} finish order {Order}", implementer.Id, order.Id); - _orderLogic.FinishOrder(new OrderBindingModel - { - Id = order.Id - }); + _orderLogic.FinishOrder(new OrderBindingModel + { + Id = order.Id + }); - // Усёёё отдыхаем - Thread.Sleep(implementer.Qualification); - } + // Усёёё отдыхаем + Thread.Sleep(implementer.Qualification); + } - // Игнорируем ошибку, если с заказом что-то случится - catch (InvalidOperationException ex) - { - _logger.LogWarning(ex, "Error try get work"); - } + // Игнорируем ошибку, если с заказом что-то случится + catch (InvalidOperationException ex) + { + _logger.LogWarning(ex, "Error try get work"); + } - // В случае ошибки прервём выполнение имитации работы - catch (Exception ex) - { - _logger.LogError(ex, "Error while do work"); - throw; - } - } - }); - } + // В случае ошибки прервём выполнение имитации работы + catch (Exception ex) + { + _logger.LogError(ex, "Error while do work"); + throw; + } + } + }); + } - // Ищем заказ, который уже во всю в работе (вдруг прервали исполнителя) - private async Task RunOrderInWork(ImplementerViewModel implementer) - { - if (_orderLogic == null || implementer == null) - { - return; - } + // Ищем заказ, который уже во всю в работе (вдруг прервали исполнителя) + private async Task RunOrderInWork(ImplementerViewModel implementer) + { + if (_orderLogic == null || implementer == null) + { + return; + } - try - { - var runOrder = await Task.Run(() => _orderLogic.ReadElement(new OrderSearchModel - { - ImplementerId = implementer.Id, - Status = OrderStatus.Выполняется - })); + try + { + var runOrder = await Task.Run(() => _orderLogic.ReadElement(new OrderSearchModel + { + ImplementerId = implementer.Id, + Status = OrderStatus.Выполняется + })); - if (runOrder == null) - { - return; - } + if (runOrder == null) + { + return; + } - _logger.LogDebug("DoWork {Id} back to order {Order}", implementer.Id, runOrder.Id); + _logger.LogDebug("DoWork {Id} back to order {Order}", implementer.Id, runOrder.Id); - // Доделываем работу - Thread.Sleep(implementer.WorkExperience * runOrder.Count); + // Доделываем работу + Thread.Sleep(implementer.WorkExperience * runOrder.Count); - _logger.LogDebug("DoWork. Worker {Id} finish order {Order}", implementer.Id, runOrder.Id); + _logger.LogDebug("DoWork. Worker {Id} finish order {Order}", implementer.Id, runOrder.Id); - _orderLogic.FinishOrder(new OrderBindingModel - { - Id = runOrder.Id - }); + _orderLogic.FinishOrder(new OrderBindingModel + { + Id = runOrder.Id + }); - // Отдыхаем, хватит работы - Thread.Sleep(implementer.Qualification); - } + // Отдыхаем, хватит работы + Thread.Sleep(implementer.Qualification); + } - // Заказа может не быть, просто игнорируем ошибку - catch (InvalidOperationException ex) - { - _logger.LogWarning(ex, "Error try get work"); - } + // Заказа может не быть, просто игнорируем ошибку + catch (InvalidOperationException ex) + { + _logger.LogWarning(ex, "Error try get work"); + } - // Просто возникнет тупая ошибка, тогда заканчиваем выполнение имитации - catch (Exception ex) - { - _logger.LogError(ex, "Error while do work"); - throw; - } - } - } + // Просто возникнет тупая ошибка, тогда заканчиваем выполнение имитации + catch (Exception ex) + { + _logger.LogError(ex, "Error while do work"); + throw; + } + } + } } diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OfficePackage/HelperModels/WordInfo.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OfficePackage/HelperModels/WordInfo.cs index 987a54a..863ebaa 100644 --- a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OfficePackage/HelperModels/WordInfo.cs +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OfficePackage/HelperModels/WordInfo.cs @@ -14,7 +14,7 @@ namespace FurnitureAssemblyBusinessLogic.OfficePackage.HelperModels public string Title { get; set; } = string.Empty; - //список заготовок для вывода и сохранения + // Cписок заготовок для вывода и сохранения public List Furnitures { get; set; } = new(); } } diff --git a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OfficePackage/HelperModels/WordParagraph.cs b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OfficePackage/HelperModels/WordParagraph.cs index 12c062a..ada3aa6 100644 --- a/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OfficePackage/HelperModels/WordParagraph.cs +++ b/FurnitureAssembly/FurnitureAssemblyBusinessLogic/OfficePackage/HelperModels/WordParagraph.cs @@ -12,7 +12,7 @@ namespace FurnitureAssemblyBusinessLogic.OfficePackage.HelperModels // Набор текстов в абзаце (для случая, если в абзаце текст разных стилей) public List<(string, WordTextProperties)> Texts { get; set; } = new(); - //свойства параграфа, если они есть + // Cвойства параграфа, если они есть public WordTextProperties? TextProperties { get; set; } } } diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/Attributes/ColumnAttribute.cs b/FurnitureAssembly/FurnitureAssemblyContracts/Attributes/ColumnAttribute.cs new file mode 100644 index 0000000..ef344a9 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/Attributes/ColumnAttribute.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyContracts.Attributes +{ + // Укажем, что данный атрибут можно прописать только в Property + [AttributeUsage(AttributeTargets.Property)] + public class ColumnAttribute : Attribute + { + public ColumnAttribute(string title = "", bool visible = true, int width = 0, + GridViewAutoSize gridViewAutoSize = GridViewAutoSize.None, bool isUseAutoSize = false) + { + Title = title; + Visible = visible; + Width = width; + GridViewAutoSize = gridViewAutoSize; + IsUseAutoSize = isUseAutoSize; + } + + public string Title { get; private set; } + + public bool Visible { get; private set; } + + public int Width { get; private set; } + + public GridViewAutoSize GridViewAutoSize { get; private set; } + + public bool IsUseAutoSize { get; private set; } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/Attributes/GridViewAutoSize.cs b/FurnitureAssembly/FurnitureAssemblyContracts/Attributes/GridViewAutoSize.cs new file mode 100644 index 0000000..bf31304 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/Attributes/GridViewAutoSize.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyContracts.Attributes +{ + public enum GridViewAutoSize + { + NotSet = 0, + + None = 1, + + ColumnHeader = 2, + + AllCellsExceptHeader = 4, + + AllCells = 6, + + DisplayedCellsExceptHeader = 8, + + DisplayedCells = 10, + + Fill = 16 + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/BackUpSaveBindingModel.cs b/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/BackUpSaveBindingModel.cs new file mode 100644 index 0000000..c37c1d2 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/BackUpSaveBindingModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyContracts.BindingModels +{ + public class BackUpSaveBindingModel + { + public string FolderName { get; set; } = string.Empty; + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MessageInfoBindingModel.cs b/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MessageInfoBindingModel.cs index 6c4ef95..f7f3f21 100644 --- a/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MessageInfoBindingModel.cs +++ b/FurnitureAssembly/FurnitureAssemblyContracts/BindingModels/MessageInfoBindingModel.cs @@ -7,9 +7,11 @@ using System.Threading.Tasks; namespace FurnitureAssemblyContracts.BindingModels { - // Реализации сущности "Сообщение" + // Реализация сущности "Сообщение" public class MessageInfoBindingModel : IMessageInfoModel { + public int Id { get; set; } + public string MessageId { get; set; } = string.Empty; public int? ClientId { get; set; } diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/BusinessLogicsContracts/IBackUpLogic.cs b/FurnitureAssembly/FurnitureAssemblyContracts/BusinessLogicsContracts/IBackUpLogic.cs new file mode 100644 index 0000000..ff03de5 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/BusinessLogicsContracts/IBackUpLogic.cs @@ -0,0 +1,16 @@ +using FurnitureAssemblyContracts.BindingModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyContracts.BusinessLogicsContracts +{ + // Интерфейс создания бекапа + public interface IBackUpLogic + { + // Путь и имя файла для архивации + void CreateBackUp(BackUpSaveBindingModel model); + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/BusinessLogicsContracts/IWorkProcess.cs b/FurnitureAssembly/FurnitureAssemblyContracts/BusinessLogicsContracts/IWorkProcess.cs index 6c654db..e0a5ad5 100644 --- a/FurnitureAssembly/FurnitureAssemblyContracts/BusinessLogicsContracts/IWorkProcess.cs +++ b/FurnitureAssembly/FurnitureAssemblyContracts/BusinessLogicsContracts/IWorkProcess.cs @@ -6,10 +6,10 @@ using System.Threading.Tasks; namespace FurnitureAssemblyContracts.BusinessLogicsContracts { - // Интерфейс для класса, имитирующего работу - public interface IWorkProcess - { - // Запуск работы - void DoWork(IImplementerLogic implementerLogic, IOrderLogic orderLogic); - } + // Интерфейс для класса, имитирующего работу + public interface IWorkProcess + { + // Запуск работы + void DoWork(IImplementerLogic implementerLogic, IOrderLogic orderLogic); + } } diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/DI/DependencyManager.cs b/FurnitureAssembly/FurnitureAssemblyContracts/DI/DependencyManager.cs new file mode 100644 index 0000000..6b25f65 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/DI/DependencyManager.cs @@ -0,0 +1,60 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyContracts.DI +{ + // Менеджер для работы с зависимостями + public class DependencyManager + { + private readonly IDependencyContainer _dependencyManager; + + private static DependencyManager? _manager; + + private static readonly object _locjObject = new(); + + private DependencyManager() + { + _dependencyManager = new UnityDependencyContainer(); + } + + public static DependencyManager Instance + { + get + { + if (_manager == null) { lock (_locjObject) { _manager = new DependencyManager(); } } + + return _manager; + } + } + + // Инициализация библиотек, в которых идут установки зависимостей + public static void InitDependency() + { + var ext = ServiceProviderLoader.GetImplementationExtensions(); + + if (ext == null) + { + throw new ArgumentNullException("Отсутствуют компоненты для загрузки зависимостей по модулям"); + } + + // Регистрируем зависимости + ext.RegisterServices(); + } + + // Регистрация логгера + public void AddLogging(Action configure) => _dependencyManager.AddLogging(configure); + + // Добавление зависимости + public void RegisterType(bool isSingle = false) where U : class, T where T : class => _dependencyManager.RegisterType(isSingle); + + // Добавление зависимости + public void RegisterType(bool isSingle = false) where T : class => _dependencyManager.RegisterType(isSingle); + + // Получение класса со всеми зависимостями + public T Resolve() => _dependencyManager.Resolve(); + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/DI/IDependencyContainer.cs b/FurnitureAssembly/FurnitureAssemblyContracts/DI/IDependencyContainer.cs new file mode 100644 index 0000000..fec4ae8 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/DI/IDependencyContainer.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyContracts.DI +{ + // Интерфейс установки зависимости между элементами + public interface IDependencyContainer + { + // Регистрация логгера + void AddLogging(Action configure); + + // Добавление зависимости + void RegisterType(bool isSingle) where U : class, T where T : + class; + + // Добавление зависимости + void RegisterType(bool isSingle) where T : class; + + // Получение класса со всеми зависимостями + T Resolve(); + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/DI/IImplementationExtension.cs b/FurnitureAssembly/FurnitureAssemblyContracts/DI/IImplementationExtension.cs new file mode 100644 index 0000000..6b4d9ff --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/DI/IImplementationExtension.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyContracts.DI +{ + // Интерфейс для регистрации зависимостей в модулях + public interface IImplementationExtension + { + // Для установления приоритета + public int Priority { get; } + + // Регистрация сервисов + public void RegisterServices(); + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/DI/ServiceDependencyContainer.cs b/FurnitureAssembly/FurnitureAssemblyContracts/DI/ServiceDependencyContainer.cs new file mode 100644 index 0000000..63ee44a --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/DI/ServiceDependencyContainer.cs @@ -0,0 +1,65 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyContracts.DI +{ + public class ServiceDependencyContainer : IDependencyContainer + { + private ServiceProvider? _serviceProvider; + + private readonly ServiceCollection _serviceCollection; + + public ServiceDependencyContainer() + { + _serviceCollection = new ServiceCollection(); + } + + public void AddLogging(Action configure) + { + _serviceCollection.AddLogging(configure); + } + + public void RegisterType(bool isSingle) where U : class, T where T : class + { + if (isSingle) + { + _serviceCollection.AddSingleton(); + } + else + { + _serviceCollection.AddTransient(); + } + + _serviceProvider = null; + } + + public void RegisterType(bool isSingle) where T : class + { + if (isSingle) + { + _serviceCollection.AddSingleton(); + } + else + { + _serviceCollection.AddTransient(); + } + + _serviceProvider = null; + } + + public T Resolve() + { + if (_serviceProvider == null) + { + _serviceProvider = _serviceCollection.BuildServiceProvider(); + } + + return _serviceProvider.GetService()!; + } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/DI/ServiceProviderLoader.cs b/FurnitureAssembly/FurnitureAssemblyContracts/DI/ServiceProviderLoader.cs new file mode 100644 index 0000000..10d820f --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/DI/ServiceProviderLoader.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyContracts.DI +{ + // Загрузчик данных + public static partial class ServiceProviderLoader + { + // Загрузка всех классов-реализаций IImplementationExtension + public static IImplementationExtension? GetImplementationExtensions() + { + IImplementationExtension? source = null; + + var files = Directory.GetFiles(TryGetImplementationExtensionsFolder(), "*.dll", SearchOption.AllDirectories); + + foreach (var file in files.Distinct()) + { + Assembly asm = Assembly.LoadFrom(file); + + foreach (var t in asm.GetExportedTypes()) + { + if (t.IsClass && typeof(IImplementationExtension).IsAssignableFrom(t)) + { + if (source == null) + { + source = (IImplementationExtension)Activator.CreateInstance(t)!; + } + else + { + var newSource = (IImplementationExtension)Activator.CreateInstance(t)!; + + if (newSource.Priority > source.Priority) + { + source = newSource; + } + } + } + } + } + + return source; + } + + private static string TryGetImplementationExtensionsFolder() + { + var directory = new DirectoryInfo(Directory.GetCurrentDirectory()); + + while (directory != null && !directory.GetDirectories("ImplementationExtensions", + SearchOption.AllDirectories).Any(x => x.Name == "ImplementationExtensions")) + { + directory = directory.Parent; + } + + return $"{directory?.FullName}\\ImplementationExtensions"; + } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/DI/UnityDependencyContainer.cs b/FurnitureAssembly/FurnitureAssemblyContracts/DI/UnityDependencyContainer.cs new file mode 100644 index 0000000..dbb5127 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/DI/UnityDependencyContainer.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Unity.Microsoft.Logging; +using Unity; + +namespace FurnitureAssemblyContracts.DI +{ + public class UnityDependencyContainer : IDependencyContainer + { + private readonly IUnityContainer _container; + + public UnityDependencyContainer() + { + _container = new UnityContainer(); + } + + public void AddLogging(Action configure) + { + var factory = LoggerFactory.Create(configure); + _container.AddExtension(new LoggingExtension(factory)); + } + + public void RegisterType(bool isSingle) where T : class + { + _container.RegisterType(isSingle ? TypeLifetime.Singleton : TypeLifetime.Transient); + } + + public T Resolve() + { + return _container.Resolve(); + } + + void IDependencyContainer.RegisterType(bool isSingle) + { + _container.RegisterType(isSingle ? TypeLifetime.Singleton : TypeLifetime.Transient); + } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/FurnitureAssemblyContracts.csproj b/FurnitureAssembly/FurnitureAssemblyContracts/FurnitureAssemblyContracts.csproj index 04f9955..02bfc6a 100644 --- a/FurnitureAssembly/FurnitureAssemblyContracts/FurnitureAssemblyContracts.csproj +++ b/FurnitureAssembly/FurnitureAssemblyContracts/FurnitureAssemblyContracts.csproj @@ -6,6 +6,12 @@ enable + + + + + + diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/SearchModels/ImplementerSearchModel.cs b/FurnitureAssembly/FurnitureAssemblyContracts/SearchModels/ImplementerSearchModel.cs index 4821d93..4989565 100644 --- a/FurnitureAssembly/FurnitureAssemblyContracts/SearchModels/ImplementerSearchModel.cs +++ b/FurnitureAssembly/FurnitureAssemblyContracts/SearchModels/ImplementerSearchModel.cs @@ -8,15 +8,15 @@ namespace FurnitureAssemblyContracts.SearchModels { // Модель для поиска исполнителя public class ImplementerSearchModel - { - public int? Id { get; set; } + { + public int? Id { get; set; } - public string? ImplementerFIO { get; set; } + public string? ImplementerFIO { get; set; } - public string? Password { get; set; } + public string? Password { get; set; } - public int? WorkExperience { get; set; } + public int? WorkExperience { get; set; } - public int? Qualification { get; set; } - } + public int? Qualification { get; set; } + } } diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/StoragesContracts/IBackUpInfo.cs b/FurnitureAssembly/FurnitureAssemblyContracts/StoragesContracts/IBackUpInfo.cs new file mode 100644 index 0000000..9940335 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyContracts/StoragesContracts/IBackUpInfo.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyContracts.StoragesContracts +{ + // Интерфейс получения данных по всем сущностям + public interface IBackUpInfo + { + // Метод получения данных по всем сущностям + List? GetList() where T : class, new(); + + Type? GetTypeByModelInterface(string modelInterfaceName); + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/StoragesContracts/IImplementerStorage.cs b/FurnitureAssembly/FurnitureAssemblyContracts/StoragesContracts/IImplementerStorage.cs index f37fd81..0015138 100644 --- a/FurnitureAssembly/FurnitureAssemblyContracts/StoragesContracts/IImplementerStorage.cs +++ b/FurnitureAssembly/FurnitureAssemblyContracts/StoragesContracts/IImplementerStorage.cs @@ -11,17 +11,17 @@ namespace FurnitureAssemblyContracts.StoragesContracts { // Класс для хранилища исполнителей public interface IImplementerStorage - { - List GetFullList(); + { + List GetFullList(); - List GetFilteredList(ImplementerSearchModel model); + List GetFilteredList(ImplementerSearchModel model); - ImplementerViewModel? GetElement(ImplementerSearchModel model); + ImplementerViewModel? GetElement(ImplementerSearchModel model); - ImplementerViewModel? Insert(ImplementerBindingModel model); + ImplementerViewModel? Insert(ImplementerBindingModel model); - ImplementerViewModel? Update(ImplementerBindingModel model); + ImplementerViewModel? Update(ImplementerBindingModel model); - ImplementerViewModel? Delete(ImplementerBindingModel model); - } + ImplementerViewModel? Delete(ImplementerBindingModel model); + } } diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/ClientViewModel.cs b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/ClientViewModel.cs index 68687de..60ecd6b 100644 --- a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/ClientViewModel.cs +++ b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/ClientViewModel.cs @@ -1,4 +1,5 @@ -using FurnitureAssemblyDataModels.Models; +using FurnitureAssemblyContracts.Attributes; +using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; using System.ComponentModel; @@ -11,15 +12,16 @@ namespace FurnitureAssemblyContracts.ViewModels // Класс для отображения информации о клиентах public class ClientViewModel : IClientModel { + [Column(visible: false)] public int Id { get; set; } - [DisplayName("ФИО клиента")] + [Column(title: "ФИО клиента", width: 150)] public string ClientFIO { get; set; } = string.Empty; - [DisplayName("Логин (эл. почта)")] + [Column(title: "Логин (эл. почта)", gridViewAutoSize: GridViewAutoSize.Fill, isUseAutoSize: true)] public string Email { get; set; } = string.Empty; - [DisplayName("Пароль")] + [Column(title: "Пароль", width: 150)] public string Password { get; set; } = string.Empty; } } diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/FurnitureViewModel.cs b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/FurnitureViewModel.cs index f24f746..ba4f64e 100644 --- a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/FurnitureViewModel.cs +++ b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/FurnitureViewModel.cs @@ -1,4 +1,5 @@ -using FurnitureAssemblyDataModels.Models; +using FurnitureAssemblyContracts.Attributes; +using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; using System.ComponentModel; @@ -11,14 +12,16 @@ namespace FurnitureAssemblyContracts.ViewModels // Класс для отображения пользователю информации о продуктах (изделиях) public class FurnitureViewModel : IFurnitureModel { + [Column(visible: false)] public int Id { get; set; } - [DisplayName("Название изделия")] + [Column(title: "Название изделия", gridViewAutoSize: GridViewAutoSize.Fill, isUseAutoSize: true)] public string FurnitureName { get; set; } = string.Empty; - [DisplayName("Цена")] + [Column(title: "Цена", width: 150)] public double Price { get; set; } + [Column(visible: false)] public Dictionary FurnitureWorkPieces { get; set; } = new(); } } \ No newline at end of file diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/ImplementerViewModel.cs b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/ImplementerViewModel.cs index eb81af6..c317b39 100644 --- a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/ImplementerViewModel.cs +++ b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/ImplementerViewModel.cs @@ -1,4 +1,5 @@ -using FurnitureAssemblyDataModels.Models; +using FurnitureAssemblyContracts.Attributes; +using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; using System.ComponentModel; @@ -10,19 +11,20 @@ namespace FurnitureAssemblyContracts.ViewModels { // Класс для отображения информации об исполнителях public class ImplementerViewModel : IImplementerModel - { - public int Id { get; set; } + { + [Column(visible: false)] + public int Id { get; set; } - [DisplayName("ФИО исполнителя")] - public string ImplementerFIO { get; set; } = string.Empty; + [Column(title: "ФИО исполнителя", width: 150)] + public string ImplementerFIO { get; set; } = string.Empty; - [DisplayName("Пароль")] - public string Password { get; set; } = string.Empty; + [Column(title: "Пароль", width: 150)] + public string Password { get; set; } = string.Empty; - [DisplayName("Стаж")] - public int WorkExperience { get; set; } + [Column(title: "Стаж", width: 150)] + public int WorkExperience { get; set; } - [DisplayName("Квалификация")] - public int Qualification { get; set; } - } + [Column(title: "Квалификация", width: 150)] + public int Qualification { get; set; } + } } diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/MessageInfoViewModel.cs b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/MessageInfoViewModel.cs index 16c929b..2f95c09 100644 --- a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/MessageInfoViewModel.cs +++ b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/MessageInfoViewModel.cs @@ -1,4 +1,5 @@ -using FurnitureAssemblyDataModels.Models; +using FurnitureAssemblyContracts.Attributes; +using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; using System.ComponentModel; @@ -11,20 +12,25 @@ namespace FurnitureAssemblyContracts.ViewModels // Класс для отображения пользователю информации о сообщениях public class MessageInfoViewModel : IMessageInfoModel { + [Column(visible: false)] + public int Id { get; set; } + + [Column(visible: false)] public string MessageId { get; set; } = string.Empty; - public int? ClientId { get; set; } + [Column(visible: false)] + public int? ClientId { get; set; } - [DisplayName("Отправитель")] + [Column(title: "Отправитель", width: 150)] public string SenderName { get; set; } = string.Empty; - [DisplayName("Дата отправки")] + [Column(title: "Дата отправки", width: 150)] public DateTime DateDelivery { get; set; } = DateTime.Now; - [DisplayName("Заголовок")] + [Column(title: "Заголовок", width: 150)] public string Subject { get; set; } = string.Empty; - [DisplayName("Текст")] + [Column(title: "Текст", width: 150)] public string Body { get; set; } = string.Empty; } } diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/OrderViewModel.cs b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/OrderViewModel.cs index 637df08..b094861 100644 --- a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/OrderViewModel.cs +++ b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/OrderViewModel.cs @@ -1,4 +1,5 @@ -using FurnitureAssemblyDataModels.Enums; +using FurnitureAssemblyContracts.Attributes; +using FurnitureAssemblyDataModels.Enums; using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; @@ -12,37 +13,40 @@ namespace FurnitureAssemblyContracts.ViewModels // Класс для отображения пользователю информации о заказах public class OrderViewModel : IOrderModel { - [DisplayName("Номер")] + [Column(visible: false)] public int Id { get; set; } + [Column(visible: false)] public int ClientId { get; set; } - [DisplayName("ФИО клиента")] + [Column(title: "ФИО клиента", width: 150)] public string ClientFIO { get; set; } = string.Empty; + [Column(visible: false)] public int? ImplementerId { get; set; } - [DisplayName("ФИО исполнителя")] + [Column(title: "ФИО исполнителя", width: 150)] public string ImplementerFIO { get; set; } = string.Empty; + [Column(visible: false)] public int FurnitureId { get; set; } - [DisplayName("Изделие")] + [Column(title: "Изделие", width: 150)] public string FurnitureName { get; set; } = string.Empty; - [DisplayName("Количество")] + [Column(title: "Количество", width: 150)] public int Count { get; set; } - [DisplayName("Сумма")] + [Column(title: "Сумма", width: 150)] public double Sum { get; set; } - [DisplayName("Статус")] + [Column(title: "Статус", width: 150)] public OrderStatus Status { get; set; } = OrderStatus.Неизвестен; - [DisplayName("Дата создания")] + [Column(title: "Дата создания", width: 150)] public DateTime DateCreate { get; set; } = DateTime.Now; - [DisplayName("Дата выполнения")] + [Column(title: "Дата выполнения", width: 150)] public DateTime? DateImplement { get; set; } } } \ No newline at end of file diff --git a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/WorkPieceViewModel.cs b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/WorkPieceViewModel.cs index 8eb29ab..4bd7592 100644 --- a/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/WorkPieceViewModel.cs +++ b/FurnitureAssembly/FurnitureAssemblyContracts/ViewModels/WorkPieceViewModel.cs @@ -1,4 +1,5 @@ -using FurnitureAssemblyDataModels.Models; +using FurnitureAssemblyContracts.Attributes; +using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; using System.ComponentModel; @@ -11,12 +12,13 @@ namespace FurnitureAssemblyContracts.ViewModels // Класс для отображения пользователю данных о заготовке (заготовках) public class WorkPieceViewModel : IWorkPieceModel { + [Column(visible: false)] public int Id { get; set; } - [DisplayName("Название заготовки")] + [Column(title: "Название заготовки", width: 150)] public string WorkPieceName { get; set; } = string.Empty; - [DisplayName("Цена")] + [Column(title: "Цена", width: 150)] public double Cost { get; set; } } } \ No newline at end of file diff --git a/FurnitureAssembly/FurnitureAssemblyDataModels/Models/IImplementerModel.cs b/FurnitureAssembly/FurnitureAssemblyDataModels/Models/IImplementerModel.cs index 75d8518..b20edc0 100644 --- a/FurnitureAssembly/FurnitureAssemblyDataModels/Models/IImplementerModel.cs +++ b/FurnitureAssembly/FurnitureAssemblyDataModels/Models/IImplementerModel.cs @@ -8,13 +8,13 @@ namespace FurnitureAssemblyDataModels.Models { // Интерфейс, отвечающий за исполнителя public interface IImplementerModel : IId - { - string ImplementerFIO { get; } + { + string ImplementerFIO { get; } - string Password { get; } + string Password { get; } - int WorkExperience { get; } + int WorkExperience { get; } - int Qualification { get; } - } + int Qualification { get; } + } } diff --git a/FurnitureAssembly/FurnitureAssemblyDataModels/Models/IMessageInfoModel.cs b/FurnitureAssembly/FurnitureAssemblyDataModels/Models/IMessageInfoModel.cs index 4292b62..d1e064c 100644 --- a/FurnitureAssembly/FurnitureAssemblyDataModels/Models/IMessageInfoModel.cs +++ b/FurnitureAssembly/FurnitureAssemblyDataModels/Models/IMessageInfoModel.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace FurnitureAssemblyDataModels.Models { // Интерфейс, отвечающий за сообщения - public interface IMessageInfoModel + public interface IMessageInfoModel : IId { string MessageId { get; } diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/DataBaseImplementationExtension.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/DataBaseImplementationExtension.cs new file mode 100644 index 0000000..a41af44 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/DataBaseImplementationExtension.cs @@ -0,0 +1,33 @@ +using FurnitureAssemblyContracts.DI; +using FurnitureAssemblyContracts.StoragesContracts; +using FurnitureAssemblyDatabaseImplement.Implements; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyDatabaseImplement +{ + public class DataBaseImplementationExtension : IImplementationExtension + { + public int Priority => 2; + + public void RegisterServices() + { + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/FurnitureAssemblyDatabaseImplement.csproj b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/FurnitureAssemblyDatabaseImplement.csproj index 481038d..096af5a 100644 --- a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/FurnitureAssemblyDatabaseImplement.csproj +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/FurnitureAssemblyDatabaseImplement.csproj @@ -1,23 +1,31 @@ - - net6.0 - enable - enable - + + net6.0 + enable + enable + - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + - - - - + + + + + + + + + + + + diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/BackUpInfo.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/BackUpInfo.cs new file mode 100644 index 0000000..5840415 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/BackUpInfo.cs @@ -0,0 +1,35 @@ +using FurnitureAssemblyContracts.StoragesContracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyDatabaseImplement.Implements +{ + public class BackUpInfo : IBackUpInfo + { + public List? GetList() where T : class, new() + { + using var context = new FurnitureAssemblyDatabase(); + + return context.Set().ToList(); + } + + public Type? GetTypeByModelInterface(string modelInterfaceName) + { + var assembly = typeof(BackUpInfo).Assembly; + var types = assembly.GetTypes(); + + foreach (var type in types) + { + if (type.IsClass && type.GetInterface(modelInterfaceName) != null) + { + return type; + } + } + + return null; + } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/ImplementerStorage.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/ImplementerStorage.cs index 5ba5b06..742acb8 100644 --- a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/ImplementerStorage.cs +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Implements/ImplementerStorage.cs @@ -12,96 +12,96 @@ using System.Threading.Tasks; namespace FurnitureAssemblyDatabaseImplement.Implements { - public class ImplementerStorage : IImplementerStorage - { - public ImplementerViewModel? GetElement(ImplementerSearchModel model) - { - using var context = new FurnitureAssemblyDatabase(); + public class ImplementerStorage : IImplementerStorage + { + public ImplementerViewModel? GetElement(ImplementerSearchModel model) + { + using var context = new FurnitureAssemblyDatabase(); - if (model.Id.HasValue) - return context.Implementers.FirstOrDefault(x => x.Id == model.Id)?.GetViewModel; + if (model.Id.HasValue) + return context.Implementers.FirstOrDefault(x => x.Id == model.Id)?.GetViewModel; - if (model.ImplementerFIO != null && model.Password != null) - return context.Implementers.FirstOrDefault(x => x.ImplementerFIO - .Equals(model.ImplementerFIO) && x.Password.Equals(model.Password))?.GetViewModel; + if (model.ImplementerFIO != null && model.Password != null) + return context.Implementers.FirstOrDefault(x => x.ImplementerFIO + .Equals(model.ImplementerFIO) && x.Password.Equals(model.Password))?.GetViewModel; - if (model.ImplementerFIO != null) - return context.Implementers.FirstOrDefault(x => x.ImplementerFIO - .Equals(model.ImplementerFIO))?.GetViewModel; + if (model.ImplementerFIO != null) + return context.Implementers.FirstOrDefault(x => x.ImplementerFIO + .Equals(model.ImplementerFIO))?.GetViewModel; - return null; - } + return null; + } - public List GetFilteredList(ImplementerSearchModel model) - { - if (model == null) - { - return new(); - } + public List GetFilteredList(ImplementerSearchModel model) + { + if (model == null) + { + return new(); + } - if (model.ImplementerFIO != null) - { - using var context = new FurnitureAssemblyDatabase(); + if (model.ImplementerFIO != null) + { + using var context = new FurnitureAssemblyDatabase(); - return context.Implementers - .Where(x => x.ImplementerFIO.Contains(model.ImplementerFIO)) - .Select(x => x.GetViewModel) - .ToList(); - } + return context.Implementers + .Where(x => x.ImplementerFIO.Contains(model.ImplementerFIO)) + .Select(x => x.GetViewModel) + .ToList(); + } - return new(); - } + return new(); + } - public List GetFullList() - { - using var context = new FurnitureAssemblyDatabase(); + public List GetFullList() + { + using var context = new FurnitureAssemblyDatabase(); - return context.Implementers.Select(x => x.GetViewModel).ToList(); - } + return context.Implementers.Select(x => x.GetViewModel).ToList(); + } - public ImplementerViewModel? Insert(ImplementerBindingModel model) - { - using var context = new FurnitureAssemblyDatabase(); + public ImplementerViewModel? Insert(ImplementerBindingModel model) + { + using var context = new FurnitureAssemblyDatabase(); - var res = Implementer.Create(model); + var res = Implementer.Create(model); - if (res != null) - { - context.Implementers.Add(res); - context.SaveChanges(); - } + if (res != null) + { + context.Implementers.Add(res); + context.SaveChanges(); + } - return res?.GetViewModel; - } + return res?.GetViewModel; + } - public ImplementerViewModel? Update(ImplementerBindingModel model) - { - using var context = new FurnitureAssemblyDatabase(); + public ImplementerViewModel? Update(ImplementerBindingModel model) + { + using var context = new FurnitureAssemblyDatabase(); - var res = context.Implementers.FirstOrDefault(x => x.Id == model.Id); + var res = context.Implementers.FirstOrDefault(x => x.Id == model.Id); - if (res != null) - { - res.Update(model); - context.SaveChanges(); - } + if (res != null) + { + res.Update(model); + context.SaveChanges(); + } - return res?.GetViewModel; - } + return res?.GetViewModel; + } - public ImplementerViewModel? Delete(ImplementerBindingModel model) - { - using var context = new FurnitureAssemblyDatabase(); + public ImplementerViewModel? Delete(ImplementerBindingModel model) + { + using var context = new FurnitureAssemblyDatabase(); - var res = context.Implementers.FirstOrDefault(x => x.Id == model.Id); + var res = context.Implementers.FirstOrDefault(x => x.Id == model.Id); - if (res != null) - { - context.Implementers.Remove(res); - context.SaveChanges(); - } + if (res != null) + { + context.Implementers.Remove(res); + context.SaveChanges(); + } - return res?.GetViewModel; - } - } + return res?.GetViewModel; + } + } } diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/20240511234747_InitialCreate.Designer.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/20240518234238_InitialCreate.Designer.cs similarity index 99% rename from FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/20240511234747_InitialCreate.Designer.cs rename to FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/20240518234238_InitialCreate.Designer.cs index d2b2599..954ebb6 100644 --- a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/20240511234747_InitialCreate.Designer.cs +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/20240518234238_InitialCreate.Designer.cs @@ -12,7 +12,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace FurnitureAssemblyDatabaseImplement.Migrations { [DbContext(typeof(FurnitureAssemblyDatabase))] - [Migration("20240511234747_InitialCreate")] + [Migration("20240518234238_InitialCreate")] partial class InitialCreate { /// diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/20240511234747_InitialCreate.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/20240518234238_InitialCreate.cs similarity index 100% rename from FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/20240511234747_InitialCreate.cs rename to FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Migrations/20240518234238_InitialCreate.cs diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Client.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Client.cs index af77220..18af9d6 100644 --- a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Client.cs +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Client.cs @@ -8,20 +8,26 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Runtime.Serialization; namespace FurnitureAssemblyDatabaseImplement.Models { + [DataContract] public class Client : IClientModel { + [DataMember] public int Id { get; private set; } [Required] + [DataMember] public string ClientFIO { get; private set; } = string.Empty; [Required] + [DataMember] public string Email { get; private set; } = string.Empty; [Required] + [DataMember] public string Password { get; private set; } = string.Empty; // Для реализации связи многие-ко-многим с заказами (клиенты могу сделать одинаковый заказ) diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Furniture.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Furniture.cs index b2f1f02..ec7b5d9 100644 --- a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Furniture.cs +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Furniture.cs @@ -7,25 +7,31 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; namespace FurnitureAssemblyDatabaseImplement.Models { + [DataContract] public class Furniture : IFurnitureModel { + [DataMember] public int Id { get; set; } [Required] + [DataMember] public string FurnitureName { get; set; } = string.Empty; [Required] + [DataMember] public double Price { get; set; } public Dictionary? _furnitureWorkPieces = null; // Это поле не будет "мапиться" в бд [NotMapped] + [DataMember] public Dictionary FurnitureWorkPieces { get diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/FurnitureWorkPiece.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/FurnitureWorkPiece.cs index 688440d..65644dd 100644 --- a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/FurnitureWorkPiece.cs +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/FurnitureWorkPiece.cs @@ -2,11 +2,13 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; namespace FurnitureAssemblyDatabaseImplement.Models { + [DataContract] public class FurnitureWorkPiece { public int Id { get; set; } diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Implementer.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Implementer.cs index fc93d8b..03e5610 100644 --- a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Implementer.cs +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Implementer.cs @@ -8,24 +8,31 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Runtime.Serialization; namespace FurnitureAssemblyDatabaseImplement.Models { + [DataContract] public class Implementer : IImplementerModel { - public int Id { get; set; } + [DataMember] + public int Id { get; set; } [Required] - public string ImplementerFIO { get; set; } = string.Empty; + [DataMember] + public string ImplementerFIO { get; set; } = string.Empty; [Required] - public string Password { get; set; } = string.Empty; + [DataMember] + public string Password { get; set; } = string.Empty; [Required] - public int WorkExperience { get; set; } + [DataMember] + public int WorkExperience { get; set; } [Required] - public int Qualification { get; set; } + [DataMember] + public int Qualification { get; set; } // Для реализации связи один ко многим с заказами [ForeignKey("ImplementerId")] diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/MessageInfo.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/MessageInfo.cs index 7a59a32..fe1647e 100644 --- a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/MessageInfo.cs +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/MessageInfo.cs @@ -5,29 +5,30 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading; using System.Threading.Tasks; namespace FurnitureAssemblyDatabaseImplement.Models { + [DataContract] public class MessageInfo : IMessageInfoModel { + public int Id => throw new NotImplementedException(); + [Key] + [DataMember] public string MessageId { get; set; } = string.Empty; public int? ClientId { get; set; } - [Required] public string SenderName { get; set; } = string.Empty; - [Required] public DateTime DateDelivery { get; set; } = DateTime.Now; - [Required] public string Subject { get; set; } = string.Empty; - [Required] public string Body { get; set; } = string.Empty; public virtual Client? Client { get; set; } diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Order.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Order.cs index b47e03f..8b2569b 100644 --- a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Order.cs +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/Order.cs @@ -6,35 +6,46 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; namespace FurnitureAssemblyDatabaseImplement.Models { + [DataContract] public class Order : IOrderModel { + [DataMember] public int Id { get; private set; } [Required] + [DataMember] public int FurnitureId { get; private set; } [Required] + [DataMember] public int ClientId { get; private set; } + [DataMember] public int? ImplementerId { get; private set; } [Required] + [DataMember] public int Count { get; private set; } [Required] + [DataMember] public double Sum { get; private set; } [Required] + [DataMember] public OrderStatus Status { get; private set; } = OrderStatus.Неизвестен; [Required] + [DataMember] public DateTime DateCreate { get; private set; } = DateTime.Now; + [DataMember] public DateTime? DateImplement { get; private set; } // Для передачи названия изделия diff --git a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/WorkPiece.cs b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/WorkPiece.cs index 7bf4529..0620c1c 100644 --- a/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/WorkPiece.cs +++ b/FurnitureAssembly/FurnitureAssemblyDatabaseImplement/Models/WorkPiece.cs @@ -6,19 +6,24 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; namespace FurnitureAssemblyDatabaseImplement.Models { + [DataContract] public class WorkPiece : IWorkPieceModel { + [DataMember] public int Id { get; private set; } [Required] + [DataMember] public string WorkPieceName { get; private set; } = string.Empty; [Required] + [DataMember] public double Cost { get; set; } // для реализации связи многие ко многим с изделиями diff --git a/FurnitureAssembly/FurnitureAssemblyFileImplement/FileImplementationExtension.cs b/FurnitureAssembly/FurnitureAssemblyFileImplement/FileImplementationExtension.cs new file mode 100644 index 0000000..2606f41 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyFileImplement/FileImplementationExtension.cs @@ -0,0 +1,34 @@ +using FurnitureAssemblyContracts.DI; +using FurnitureAssemblyContracts.StoragesContracts; +using FurnitureAssemblyFileImplement.Implements; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyFileImplement +{ + // Для реализации нужных нам зависимостей в данном варианте хранения информации + public class FileImplementationExtension : IImplementationExtension + { + public int Priority => 1; + + public void RegisterServices() + { + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyFileImplement/FurnitureAssemblyFileImplement.csproj b/FurnitureAssembly/FurnitureAssemblyFileImplement/FurnitureAssemblyFileImplement.csproj index c0fa55b..9a3ae31 100644 --- a/FurnitureAssembly/FurnitureAssemblyFileImplement/FurnitureAssemblyFileImplement.csproj +++ b/FurnitureAssembly/FurnitureAssemblyFileImplement/FurnitureAssemblyFileImplement.csproj @@ -1,14 +1,18 @@ - - net6.0 - enable - enable - + + net6.0 + enable + enable + - - - - + + + + + + + + diff --git a/FurnitureAssembly/FurnitureAssemblyFileImplement/Implements/BackUpInfo.cs b/FurnitureAssembly/FurnitureAssemblyFileImplement/Implements/BackUpInfo.cs new file mode 100644 index 0000000..8833636 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyFileImplement/Implements/BackUpInfo.cs @@ -0,0 +1,37 @@ +using FurnitureAssemblyContracts.StoragesContracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyFileImplement.Implements +{ + public class BackUpInfo : IBackUpInfo + { + public List? GetList() where T : class, new() + { + var source = DataFileSingleton.GetInstance(); + + return (List?)source.GetType().GetProperties() + .FirstOrDefault(x => x.PropertyType.IsGenericType && x.PropertyType.GetGenericArguments()[0] == typeof(T)) + ?.GetValue(source); + } + + public Type? GetTypeByModelInterface(string modelInterfaceName) + { + var assembly = typeof(BackUpInfo).Assembly; + var types = assembly.GetTypes(); + + foreach (var type in types) + { + if (type.IsClass && type.GetInterface(modelInterfaceName) != null) + { + return type; + } + } + + return null; + } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyFileImplement/Implements/ImplementerStorage.cs b/FurnitureAssembly/FurnitureAssemblyFileImplement/Implements/ImplementerStorage.cs index 6fe21ff..ac14b08 100644 --- a/FurnitureAssembly/FurnitureAssemblyFileImplement/Implements/ImplementerStorage.cs +++ b/FurnitureAssembly/FurnitureAssemblyFileImplement/Implements/ImplementerStorage.cs @@ -11,102 +11,102 @@ using System.Threading.Tasks; namespace FurnitureAssemblyFileImplement.Implements { - public class ImplementerStorage : IImplementerStorage - { - private readonly DataFileSingleton source; + public class ImplementerStorage : IImplementerStorage + { + private readonly DataFileSingleton source; - public ImplementerStorage() - { - source = DataFileSingleton.GetInstance(); - } + public ImplementerStorage() + { + source = DataFileSingleton.GetInstance(); + } - public ImplementerViewModel? GetElement(ImplementerSearchModel model) - { - if (model.Id.HasValue) - return source.Implementers - .FirstOrDefault(x => x.Id == model.Id)?.GetViewModel; - - if (model.ImplementerFIO != null && model.Password != null) - return source.Implementers.FirstOrDefault(x => x.ImplementerFIO - .Equals(model.ImplementerFIO) && x.Password.Equals(model.Password))?.GetViewModel; - - if (model.ImplementerFIO != null) - return source.Implementers - .FirstOrDefault(x => x.ImplementerFIO.Equals(model.ImplementerFIO))?.GetViewModel; - - return null; - } + public ImplementerViewModel? GetElement(ImplementerSearchModel model) + { + if (model.Id.HasValue) + return source.Implementers + .FirstOrDefault(x => x.Id == model.Id)?.GetViewModel; + + if (model.ImplementerFIO != null && model.Password != null) + return source.Implementers.FirstOrDefault(x => x.ImplementerFIO + .Equals(model.ImplementerFIO) && x.Password.Equals(model.Password))?.GetViewModel; + + if (model.ImplementerFIO != null) + return source.Implementers + .FirstOrDefault(x => x.ImplementerFIO.Equals(model.ImplementerFIO))?.GetViewModel; + + return null; + } - public List GetFullList() - { - return source.Implementers.Select(x => x.GetViewModel).ToList(); - } + public List GetFullList() + { + return source.Implementers.Select(x => x.GetViewModel).ToList(); + } - public List GetFilteredList(ImplementerSearchModel model) - { - if (model == null) - { - return new(); - } + public List GetFilteredList(ImplementerSearchModel model) + { + if (model == null) + { + return new(); + } - if (model.ImplementerFIO != null) - { - return source.Implementers - .Where(x => x.ImplementerFIO.Contains(model.ImplementerFIO)) - .Where(x => x.Id == model.Id) - .Select(x => x.GetViewModel) - .ToList(); - } + if (model.ImplementerFIO != null) + { + return source.Implementers + .Where(x => x.ImplementerFIO.Contains(model.ImplementerFIO)) + .Where(x => x.Id == model.Id) + .Select(x => x.GetViewModel) + .ToList(); + } - return new(); - } + return new(); + } - public ImplementerViewModel? Insert(ImplementerBindingModel model) - { - model.Id = source.Implementers.Count > 0 ? source.Implementers.Max(x => x.Id) + 1 : 1; + public ImplementerViewModel? Insert(ImplementerBindingModel model) + { + model.Id = source.Implementers.Count > 0 ? source.Implementers.Max(x => x.Id) + 1 : 1; - var newImplementer = Implementer.Create(model); + var newImplementer = Implementer.Create(model); - if (newImplementer == null) - { - return null; - } + if (newImplementer == null) + { + return null; + } - source.Implementers.Add(newImplementer); - source.SaveImplementers(); + source.Implementers.Add(newImplementer); + source.SaveImplementers(); - return newImplementer.GetViewModel; - } + return newImplementer.GetViewModel; + } - public ImplementerViewModel? Update(ImplementerBindingModel model) - { - var implementer = source.Implementers.FirstOrDefault(x => x.Id == model.Id); + public ImplementerViewModel? Update(ImplementerBindingModel model) + { + var implementer = source.Implementers.FirstOrDefault(x => x.Id == model.Id); - if (implementer == null) - { - return null; - } + if (implementer == null) + { + return null; + } - implementer.Update(model); - source.SaveImplementers(); + implementer.Update(model); + source.SaveImplementers(); - return implementer.GetViewModel; - } + return implementer.GetViewModel; + } - public ImplementerViewModel? Delete(ImplementerBindingModel model) - { - var element = source.Implementers.FirstOrDefault(x => x.Id == model.Id); + public ImplementerViewModel? Delete(ImplementerBindingModel model) + { + var element = source.Implementers.FirstOrDefault(x => x.Id == model.Id); - if (element != null) - { - source.Implementers.Remove(element); - source.SaveImplementers(); + if (element != null) + { + source.Implementers.Remove(element); + source.SaveImplementers(); - return element.GetViewModel; - } + return element.GetViewModel; + } - return null; - } - } + return null; + } + } } diff --git a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Client.cs b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Client.cs index b5dae44..8e00ade 100644 --- a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Client.cs +++ b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Client.cs @@ -4,20 +4,26 @@ using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; namespace FurnitureAssemblyFileImplement.Models { + [DataContract] public class Client : IClientModel { + [DataMember] public int Id { get; private set; } + [DataMember] public string ClientFIO { get; private set; } = string.Empty; + [DataMember] public string Email { get; private set; } = string.Empty; + [DataMember] public string Password { get; private set; } = string.Empty; public static Client? Create(ClientBindingModel model) diff --git a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Furniture.cs b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Furniture.cs index d428d39..e5b719e 100644 --- a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Furniture.cs +++ b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Furniture.cs @@ -4,6 +4,7 @@ using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; @@ -11,18 +12,23 @@ using System.Xml.Linq; namespace FurnitureAssemblyFileImplement.Models { // Класс, реализующий интерфейс модели изделия + [DataContract] public class Furniture : IFurnitureModel { + [DataMember] public int Id { get; private set; } + [DataMember] public string FurnitureName { get; private set; } = string.Empty; + [DataMember] public double Price { get; private set; } public Dictionary WorkPieces { get; private set; } = new(); private Dictionary? _furnitureWorkPieces = null; + [DataMember] public Dictionary FurnitureWorkPieces { get diff --git a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Implementer.cs b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Implementer.cs index 2d1f696..c812573 100644 --- a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Implementer.cs +++ b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Implementer.cs @@ -4,22 +4,29 @@ using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; namespace FurnitureAssemblyFileImplement.Models { + [DataContract] public class Implementer : IImplementerModel { + [DataMember] public int Id { get; private set; } + [DataMember] public string ImplementerFIO { get; private set; } = string.Empty; + [DataMember] public string Password { get; private set; } = string.Empty; + [DataMember] public int WorkExperience { get; private set; } + [DataMember] public int Qualification { get; private set; } public static Implementer? Create(ImplementerBindingModel model) diff --git a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/MessageInfo.cs b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/MessageInfo.cs index 91aeaf2..acf0db0 100644 --- a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/MessageInfo.cs +++ b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/MessageInfo.cs @@ -4,6 +4,7 @@ using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -11,18 +12,27 @@ using System.Xml.Linq; namespace FurnitureAssemblyFileImplement.Models { + [DataContract] public class MessageInfo : IMessageInfoModel { + public int Id { get; set; } + + [DataMember] public string MessageId { get; private set; } = string.Empty; + [DataMember] public int? ClientId { get; private set; } + [DataMember] public string SenderName { get; private set; } = string.Empty; + [DataMember] public DateTime DateDelivery { get; private set; } = DateTime.Now; + [DataMember] public string Subject { get; private set; } = string.Empty; + public string Body { get; private set; } = string.Empty; public static MessageInfo? Create(MessageInfoBindingModel model) diff --git a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Order.cs b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Order.cs index 4384655..59c79a4 100644 --- a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Order.cs +++ b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/Order.cs @@ -5,6 +5,7 @@ using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; @@ -12,24 +13,34 @@ using System.Xml.Linq; namespace FurnitureAssemblyFileImplement.Models { // Класс, реализующий интерфейс модели заказа + [DataContract] public class Order : IOrderModel { + [DataMember] public int Id { get; private set; } + [DataMember] public int FurnitureId { get; private set; } + [DataMember] public int ClientId { get; private set; } + [DataMember] public int? ImplementerId { get; private set; } + [DataMember] public int Count { get; private set; } + [DataMember] public double Sum { get; private set; } + [DataMember] public OrderStatus Status { get; private set; } = OrderStatus.Неизвестен; + [DataMember] public DateTime DateCreate { get; private set; } = DateTime.Now; + [DataMember] public DateTime? DateImplement { get; private set; } public static Order? Create(OrderBindingModel model) diff --git a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/WorkPiece.cs b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/WorkPiece.cs index 125494d..f8330c8 100644 --- a/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/WorkPiece.cs +++ b/FurnitureAssembly/FurnitureAssemblyFileImplement/Models/WorkPiece.cs @@ -4,6 +4,7 @@ using FurnitureAssemblyDataModels.Models; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; @@ -11,12 +12,16 @@ using System.Xml.Linq; namespace FurnitureAssemblyFileImplement.Models { // Класс, реализующий интерфейс модели заготовки + [DataContract] public class WorkPiece : IWorkPieceModel { + [DataMember] public int Id { get; private set; } + [DataMember] public string WorkPieceName { get; private set; } = string.Empty; + [DataMember] public double Cost { get; set; } public static WorkPiece? Create(WorkPieceBindingModel model) diff --git a/FurnitureAssembly/FurnitureAssemblyListImplement/FurnitureAssemblyListImplement.csproj b/FurnitureAssembly/FurnitureAssemblyListImplement/FurnitureAssemblyListImplement.csproj index c0fa55b..c5df54f 100644 --- a/FurnitureAssembly/FurnitureAssemblyListImplement/FurnitureAssemblyListImplement.csproj +++ b/FurnitureAssembly/FurnitureAssemblyListImplement/FurnitureAssemblyListImplement.csproj @@ -1,14 +1,14 @@ - - net6.0 - enable - enable - + + net6.0 + enable + enable + - - - - + + + + diff --git a/FurnitureAssembly/FurnitureAssemblyListImplement/Implements/BackUpInfo.cs b/FurnitureAssembly/FurnitureAssemblyListImplement/Implements/BackUpInfo.cs new file mode 100644 index 0000000..17649c2 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyListImplement/Implements/BackUpInfo.cs @@ -0,0 +1,22 @@ +using FurnitureAssemblyContracts.StoragesContracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyListImplement.Implements +{ + public class BackUpInfo : IBackUpInfo + { + public List? GetList() where T : class, new() + { + throw new NotImplementedException(); + } + + public Type? GetTypeByModelInterface(string modelInterfaceName) + { + throw new NotImplementedException(); + } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyListImplement/Implements/ImplementerStorage.cs b/FurnitureAssembly/FurnitureAssemblyListImplement/Implements/ImplementerStorage.cs index a6e3d64..dc9d479 100644 --- a/FurnitureAssembly/FurnitureAssemblyListImplement/Implements/ImplementerStorage.cs +++ b/FurnitureAssembly/FurnitureAssemblyListImplement/Implements/ImplementerStorage.cs @@ -11,120 +11,120 @@ using System.Threading.Tasks; namespace FurnitureAssemblyListImplement.Implements { - public class ImplementerStorage : IImplementerStorage - { - // Поле для работы со списком исполнителей - private readonly DataListSingleton _source; + public class ImplementerStorage : IImplementerStorage + { + // Поле для работы со списком исполнителей + private readonly DataListSingleton _source; - public ImplementerStorage() - { - _source = DataListSingleton.GetInstance(); - } + public ImplementerStorage() + { + _source = DataListSingleton.GetInstance(); + } - public List GetFullList() - { - var result = new List(); + public List GetFullList() + { + var result = new List(); - foreach (var implementer in _source.Implementers) - { - result.Add(implementer.GetViewModel); - } + foreach (var implementer in _source.Implementers) + { + result.Add(implementer.GetViewModel); + } - return result; - } + return result; + } - public List GetFilteredList(ImplementerSearchModel model) - { - var result = new List(); + public List GetFilteredList(ImplementerSearchModel model) + { + var result = new List(); - if (string.IsNullOrEmpty(model.ImplementerFIO)) - { - return result; - } + if (string.IsNullOrEmpty(model.ImplementerFIO)) + { + return result; + } - foreach (var implementer in _source.Implementers) - { - if (implementer.ImplementerFIO.Contains(model.ImplementerFIO)) - { - result.Add(implementer.GetViewModel); - } - } + foreach (var implementer in _source.Implementers) + { + if (implementer.ImplementerFIO.Contains(model.ImplementerFIO)) + { + result.Add(implementer.GetViewModel); + } + } - return result; - } + return result; + } - public ImplementerViewModel? GetElement(ImplementerSearchModel model) - { - if (string.IsNullOrEmpty(model.ImplementerFIO) && !model.Id.HasValue) - { - return null; - } + public ImplementerViewModel? GetElement(ImplementerSearchModel model) + { + if (string.IsNullOrEmpty(model.ImplementerFIO) && !model.Id.HasValue) + { + return null; + } - foreach (var implementer in _source.Implementers) - { - if ((!string.IsNullOrEmpty(model.ImplementerFIO) && implementer.ImplementerFIO == model.ImplementerFIO) || - (model.Id.HasValue && implementer.Id == model.Id)) - { - return implementer.GetViewModel; - } - } + foreach (var implementer in _source.Implementers) + { + if ((!string.IsNullOrEmpty(model.ImplementerFIO) && implementer.ImplementerFIO == model.ImplementerFIO) || + (model.Id.HasValue && implementer.Id == model.Id)) + { + return implementer.GetViewModel; + } + } - return null; - } + return null; + } - public ImplementerViewModel? Insert(ImplementerBindingModel model) - { - model.Id = 1; + public ImplementerViewModel? Insert(ImplementerBindingModel model) + { + model.Id = 1; - foreach (var implementer in _source.Implementers) - { - if (model.Id <= implementer.Id) - { - model.Id = implementer.Id + 1; - } - } + foreach (var implementer in _source.Implementers) + { + if (model.Id <= implementer.Id) + { + model.Id = implementer.Id + 1; + } + } - var newImplementer = Implementer.Create(model); + var newImplementer = Implementer.Create(model); - if (newImplementer == null) - { - return null; - } + if (newImplementer == null) + { + return null; + } - _source.Implementers.Add(newImplementer); + _source.Implementers.Add(newImplementer); - return newImplementer.GetViewModel; - } + return newImplementer.GetViewModel; + } - public ImplementerViewModel? Update(ImplementerBindingModel model) - { - foreach (var implementer in _source.Implementers) - { - if (implementer.Id == model.Id) - { - implementer.Update(model); + public ImplementerViewModel? Update(ImplementerBindingModel model) + { + foreach (var implementer in _source.Implementers) + { + if (implementer.Id == model.Id) + { + implementer.Update(model); - return implementer.GetViewModel; - } - } + return implementer.GetViewModel; + } + } - return null; - } + return null; + } - public ImplementerViewModel? Delete(ImplementerBindingModel model) - { - for (int i = 0; i < _source.Implementers.Count; ++i) - { - if (_source.Implementers[i].Id == model.Id) - { - var element = _source.Implementers[i]; - _source.Implementers.RemoveAt(i); + public ImplementerViewModel? Delete(ImplementerBindingModel model) + { + for (int i = 0; i < _source.Implementers.Count; ++i) + { + if (_source.Implementers[i].Id == model.Id) + { + var element = _source.Implementers[i]; + _source.Implementers.RemoveAt(i); - return element.GetViewModel; - } - } + return element.GetViewModel; + } + } - return null; - } - } + return null; + } + } } diff --git a/FurnitureAssembly/FurnitureAssemblyListImplement/ListImplementationExtension.cs b/FurnitureAssembly/FurnitureAssemblyListImplement/ListImplementationExtension.cs new file mode 100644 index 0000000..c913969 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyListImplement/ListImplementationExtension.cs @@ -0,0 +1,33 @@ +using FurnitureAssemblyContracts.DI; +using FurnitureAssemblyContracts.StoragesContracts; +using FurnitureAssemblyListImplement.Implements; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyListImplement +{ + public class ListImplementationExtension : IImplementationExtension + { + public int Priority => 0; + + public void RegisterServices() + { + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + + DependencyManager.Instance.RegisterType(); + } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyListImplement/Models/Implementer.cs b/FurnitureAssembly/FurnitureAssemblyListImplement/Models/Implementer.cs index 7afd835..902a2a0 100644 --- a/FurnitureAssembly/FurnitureAssemblyListImplement/Models/Implementer.cs +++ b/FurnitureAssembly/FurnitureAssemblyListImplement/Models/Implementer.cs @@ -9,58 +9,58 @@ using System.Threading.Tasks; namespace FurnitureAssemblyListImplement.Models { - public class Implementer : IImplementerModel - { - public int Id { get; private set; } + public class Implementer : IImplementerModel + { + public int Id { get; private set; } - public string ImplementerFIO { get; private set; } = string.Empty; + public string ImplementerFIO { get; private set; } = string.Empty; - public string Password { get; private set; } = string.Empty; + public string Password { get; private set; } = string.Empty; - public int WorkExperience { get; private set; } + public int WorkExperience { get; private set; } - public int Qualification { get; private set; } + public int Qualification { get; private set; } - // Метод для создания объекта от класса-компонента на основе класса-BindingModel - public static Implementer? Create(ImplementerBindingModel? model) - { - if (model == null) - { - return null; - } + // Метод для создания объекта от класса-компонента на основе класса-BindingModel + public static Implementer? Create(ImplementerBindingModel? model) + { + if (model == null) + { + return null; + } - return new Implementer() - { - Id = model.Id, - Password = model.Password, - ImplementerFIO = model.ImplementerFIO, - Qualification = model.Qualification, - WorkExperience = model.WorkExperience - }; - } + return new Implementer() + { + Id = model.Id, + Password = model.Password, + ImplementerFIO = model.ImplementerFIO, + Qualification = model.Qualification, + WorkExperience = model.WorkExperience + }; + } - // Метод изменения существующего объекта - public void Update(ImplementerBindingModel? model) - { - if (model == null) - { - return; - } + // Метод изменения существующего объекта + public void Update(ImplementerBindingModel? model) + { + if (model == null) + { + return; + } - Password = model.Password; - ImplementerFIO = model.ImplementerFIO; - Qualification = model.Qualification; - WorkExperience = model.WorkExperience; - } + Password = model.Password; + ImplementerFIO = model.ImplementerFIO; + Qualification = model.Qualification; + WorkExperience = model.WorkExperience; + } - // Метод для создания объекта класса ViewModel на основе данных объекта класса-компонента - public ImplementerViewModel GetViewModel => new() - { - Id = Id, - Password = Password, - ImplementerFIO = ImplementerFIO, - Qualification = Qualification, - WorkExperience = WorkExperience - }; - } + // Метод для создания объекта класса ViewModel на основе данных объекта класса-компонента + public ImplementerViewModel GetViewModel => new() + { + Id = Id, + Password = Password, + ImplementerFIO = ImplementerFIO, + Qualification = Qualification, + WorkExperience = WorkExperience + }; + } } diff --git a/FurnitureAssembly/FurnitureAssemblyListImplement/Models/MessageInfo.cs b/FurnitureAssembly/FurnitureAssemblyListImplement/Models/MessageInfo.cs index af5b220..b86e808 100644 --- a/FurnitureAssembly/FurnitureAssemblyListImplement/Models/MessageInfo.cs +++ b/FurnitureAssembly/FurnitureAssemblyListImplement/Models/MessageInfo.cs @@ -12,6 +12,8 @@ namespace FurnitureAssemblyListImplement.Models { public class MessageInfo : IMessageInfoModel { + public int Id { get; private set; } + public string MessageId { get; private set; } = string.Empty; public int? ClientId { get; private set; } diff --git a/FurnitureAssembly/FurnitureAssemblyRestApi/Controllers/ImplementerController.cs b/FurnitureAssembly/FurnitureAssemblyRestApi/Controllers/ImplementerController.cs index 4e2db8a..183fd38 100644 --- a/FurnitureAssembly/FurnitureAssemblyRestApi/Controllers/ImplementerController.cs +++ b/FurnitureAssembly/FurnitureAssemblyRestApi/Controllers/ImplementerController.cs @@ -7,106 +7,106 @@ using Microsoft.AspNetCore.Mvc; namespace FurnitureAssemblyRestApi.Controllers { - [Route("api/[controller]/[action]")] - [ApiController] - public class ImplementerController : Controller - { - private readonly ILogger _logger; + [Route("api/[controller]/[action]")] + [ApiController] + public class ImplementerController : Controller + { + private readonly ILogger _logger; - private readonly IOrderLogic _order; + private readonly IOrderLogic _order; - private readonly IImplementerLogic _logic; + private readonly IImplementerLogic _logic; - public ImplementerController(IOrderLogic order, IImplementerLogic logic, ILogger logger) - { - _logger = logger; - _order = order; - _logic = logic; - } + public ImplementerController(IOrderLogic order, IImplementerLogic logic, ILogger logger) + { + _logger = logger; + _order = order; + _logic = logic; + } - [HttpGet] - public ImplementerViewModel? Login(string login, string password) - { - try - { - return _logic.ReadElement(new ImplementerSearchModel - { - ImplementerFIO = login, - Password = password - }); - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка авторизации сотрудника"); + [HttpGet] + public ImplementerViewModel? Login(string login, string password) + { + try + { + return _logic.ReadElement(new ImplementerSearchModel + { + ImplementerFIO = login, + Password = password + }); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка авторизации сотрудника"); - throw; - } - } + throw; + } + } - [HttpGet] - public List? GetNewOrders() - { - try - { - return _order.ReadList(new OrderSearchModel - { - Status = OrderStatus.Принят - }); - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка получения новых заказов"); + [HttpGet] + public List? GetNewOrders() + { + try + { + return _order.ReadList(new OrderSearchModel + { + Status = OrderStatus.Принят + }); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка получения новых заказов"); - throw; - } - } + throw; + } + } - [HttpGet] - public OrderViewModel? GetImplementerOrder(int implementerId) - { - try - { - return _order.ReadElement(new OrderSearchModel - { - ImplementerId = implementerId - }); - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка получения текущего заказа исполнителя"); + [HttpGet] + public OrderViewModel? GetImplementerOrder(int implementerId) + { + try + { + return _order.ReadElement(new OrderSearchModel + { + ImplementerId = implementerId + }); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка получения текущего заказа исполнителя"); - throw; - } - } + throw; + } + } - [HttpPost] - public void TakeOrderInWork(OrderBindingModel model) - { - try - { - _order.TakeOrderInWork(model); - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка перевода заказа с №{Id} в работу", model.Id); + [HttpPost] + public void TakeOrderInWork(OrderBindingModel model) + { + try + { + _order.TakeOrderInWork(model); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка перевода заказа с №{Id} в работу", model.Id); - throw; - } - } + throw; + } + } - [HttpPost] - public void FinishOrder(OrderBindingModel model) - { - try - { - _order.FinishOrder(model); - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка отметки о готовности заказа с №{ Id}", model.Id); + [HttpPost] + public void FinishOrder(OrderBindingModel model) + { + try + { + _order.FinishOrder(model); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка отметки о готовности заказа с №{ Id}", model.Id); - throw; - } - } - } + throw; + } + } + } } diff --git a/FurnitureAssembly/FurnitureAssemblyRestApi/FurnitureAssemblyRestApi.csproj b/FurnitureAssembly/FurnitureAssemblyRestApi/FurnitureAssemblyRestApi.csproj index d987301..e347951 100644 --- a/FurnitureAssembly/FurnitureAssemblyRestApi/FurnitureAssemblyRestApi.csproj +++ b/FurnitureAssembly/FurnitureAssemblyRestApi/FurnitureAssemblyRestApi.csproj @@ -1,20 +1,20 @@  - - net6.0 - enable - enable - + + net6.0 + enable + enable + - - - - + + + + - - - - - + + + + + diff --git a/FurnitureAssembly/FurnitureAssemblyView/DataGridViewExtension.cs b/FurnitureAssembly/FurnitureAssemblyView/DataGridViewExtension.cs new file mode 100644 index 0000000..1ba84a8 --- /dev/null +++ b/FurnitureAssembly/FurnitureAssemblyView/DataGridViewExtension.cs @@ -0,0 +1,62 @@ +using FurnitureAssemblyContracts.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FurnitureAssemblyView +{ + public static class DataGridViewExtension + { + public static void FillandConfigGrid(this DataGridView grid, List? data) + { + if (data == null) + { + return; + } + + grid.DataSource = data; + + // Получаем тип + var type = typeof(T); + + // Получаем свойства + var properties = type.GetProperties(); + + foreach (DataGridViewColumn column in grid.Columns) + { + var property = properties.FirstOrDefault(x => x.Name == column.Name); + + if (property == null) + { + throw new InvalidOperationException($"В типе {type.Name} не найдено свойство с именем {column.Name}"); + } + + var attribute = property.GetCustomAttributes(typeof(ColumnAttribute), true)?.SingleOrDefault(); + + if (attribute == null) + { + throw new InvalidOperationException($"Не найден атрибут типа ColumnAttribute для свойства {property.Name}"); + } + + // Ищем нужный нам атрибут + if (attribute is ColumnAttribute columnAttr) + { + column.HeaderText = columnAttr.Title; + column.Visible = columnAttr.Visible; + + if (columnAttr.IsUseAutoSize) + { + column.AutoSizeMode = (DataGridViewAutoSizeColumnMode)Enum.Parse(typeof(DataGridViewAutoSizeColumnMode), + columnAttr.GridViewAutoSize.ToString()); + } + else + { + column.Width = columnAttr.Width; + } + } + } + } + } +} diff --git a/FurnitureAssembly/FurnitureAssemblyView/FormClients.cs b/FurnitureAssembly/FurnitureAssemblyView/FormClients.cs index 0e0fa8d..42b7dea 100644 --- a/FurnitureAssembly/FurnitureAssemblyView/FormClients.cs +++ b/FurnitureAssembly/FurnitureAssemblyView/FormClients.cs @@ -35,19 +35,10 @@ namespace FurnitureAssemblyView private void LoadData() { - _logger.LogInformation("Загрузка клиентов"); - try { - var list = _clientLogic.ReadList(null); - - if (list != null) - { - dataGridView.DataSource = list; - dataGridView.Columns["ClientFIO"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; - } - - _logger.LogInformation("Успешная загрузка клиентов"); + dataGridView.FillandConfigGrid(_clientLogic.ReadList(null)); + _logger.LogInformation("Загрузка клиентов"); } catch (Exception ex) { diff --git a/FurnitureAssembly/FurnitureAssemblyView/FormFurniture.cs b/FurnitureAssembly/FurnitureAssemblyView/FormFurniture.cs index d52ab40..befd832 100644 --- a/FurnitureAssembly/FurnitureAssemblyView/FormFurniture.cs +++ b/FurnitureAssembly/FurnitureAssemblyView/FormFurniture.cs @@ -1,5 +1,6 @@ using FurnitureAssemblyContracts.BindingModels; using FurnitureAssemblyContracts.BusinessLogicsContracts; +using FurnitureAssemblyContracts.DI; using FurnitureAssemblyContracts.SearchModels; using FurnitureAssemblyDataModels.Models; using Microsoft.Extensions.Logging; @@ -35,7 +36,7 @@ namespace FurnitureAssemblyView _logic = logic; _furnitureWorkPieces = new Dictionary(); } - + private void FormFurniture_Load(object sender, EventArgs e) { if (_id.HasValue) @@ -46,7 +47,7 @@ namespace FurnitureAssemblyView { var view = _logic.ReadElement(new FurnitureSearchModel { Id = _id.Value }); - if(view != null) + if (view != null) { textBoxName.Text = view.FurnitureName; textBoxPrice.Text = view.Price.ToString(); @@ -54,7 +55,7 @@ namespace FurnitureAssemblyView LoadData(); } } - catch(Exception ex) + catch (Exception ex) { _logger.LogError(ex, "Ошибка загрузки изделия"); MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); @@ -68,11 +69,11 @@ namespace FurnitureAssemblyView try { - if(_furnitureWorkPieces != null) + if (_furnitureWorkPieces != null) { dataGridView.Rows.Clear(); - foreach(var awp in _furnitureWorkPieces) + foreach (var awp in _furnitureWorkPieces) { dataGridView.Rows.Add(new object[] { awp.Key, awp.Value.Item1.WorkPieceName, awp.Value.Item2 }); } @@ -80,7 +81,7 @@ namespace FurnitureAssemblyView textBoxPrice.Text = CalcPrice().ToString(); } } - catch(Exception ex) + catch (Exception ex) { _logger.LogError(ex, "Ошибка загрузки заготовки для изделия"); MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); @@ -89,30 +90,27 @@ namespace FurnitureAssemblyView private void ButtonAdd_Click(object sender, EventArgs e) { - var service = Program.ServiceProvider?.GetService(typeof(FormFurnitureWorkPiece)); - - if (service is FormFurnitureWorkPiece form) + var form = DependencyManager.Instance.Resolve(); + + if (form.ShowDialog() == DialogResult.OK) { - if (form.ShowDialog() == DialogResult.OK) + if (form.WorkPieceModel == null) { - if (form.WorkPieceModel == null) - { - return; - } - - _logger.LogInformation("Добавление новой заготовки:{WorkPieceName} - {Count}", form.WorkPieceModel.WorkPieceName, form.Count); - - if (_furnitureWorkPieces.ContainsKey(form.Id)) - { - _furnitureWorkPieces[form.Id] = (form.WorkPieceModel, form.Count); - } - else - { - _furnitureWorkPieces.Add(form.Id, (form.WorkPieceModel, form.Count)); - } - - LoadData(); + return; } + + _logger.LogInformation("Добавление новой заготовки:{WorkPieceName} - {Count}", form.WorkPieceModel.WorkPieceName, form.Count); + + if (_furnitureWorkPieces.ContainsKey(form.Id)) + { + _furnitureWorkPieces[form.Id] = (form.WorkPieceModel, form.Count); + } + else + { + _furnitureWorkPieces.Add(form.Id, (form.WorkPieceModel, form.Count)); + } + + LoadData(); } } @@ -120,26 +118,23 @@ namespace FurnitureAssemblyView { if (dataGridView.SelectedRows.Count == 1) { - var service = Program.ServiceProvider?.GetService(typeof(FormFurnitureWorkPiece)); - - if (service is FormFurnitureWorkPiece form) + var form = DependencyManager.Instance.Resolve(); + + int id = Convert.ToInt32(dataGridView.SelectedRows[0].Cells[0].Value); + form.Id = id; + form.Count = _furnitureWorkPieces[id].Item2; + + if (form.ShowDialog() == DialogResult.OK) { - int id = Convert.ToInt32(dataGridView.SelectedRows[0].Cells[0].Value); - form.Id = id; - form.Count = _furnitureWorkPieces[id].Item2; - - if (form.ShowDialog() == DialogResult.OK) + if (form.WorkPieceModel == null) { - if (form.WorkPieceModel == null) - { - return; - } - - _logger.LogInformation("Изменение компонента:{WorkPieceName} - {Count}", form.WorkPieceModel.WorkPieceName, form.Count); - _furnitureWorkPieces[form.Id] = (form.WorkPieceModel, form.Count); - - LoadData(); + return; } + + _logger.LogInformation("Изменение компонента:{WorkPieceName} - {Count}", form.WorkPieceModel.WorkPieceName, form.Count); + _furnitureWorkPieces[form.Id] = (form.WorkPieceModel, form.Count); + + LoadData(); } } } @@ -189,7 +184,7 @@ namespace FurnitureAssemblyView if (_furnitureWorkPieces == null || _furnitureWorkPieces.Count == 0) { MessageBox.Show("Заполните компоненты", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); - + return; } diff --git a/FurnitureAssembly/FurnitureAssemblyView/FormFurnitures.cs b/FurnitureAssembly/FurnitureAssemblyView/FormFurnitures.cs index 1e8b461..98201e8 100644 --- a/FurnitureAssembly/FurnitureAssemblyView/FormFurnitures.cs +++ b/FurnitureAssembly/FurnitureAssemblyView/FormFurnitures.cs @@ -1,5 +1,6 @@ using FurnitureAssemblyContracts.BindingModels; using FurnitureAssemblyContracts.BusinessLogicsContracts; +using FurnitureAssemblyContracts.DI; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -37,15 +38,7 @@ namespace FurnitureAssemblyView { try { - var list = _logic.ReadList(null); - - if (list != null) - { - dataGridView.DataSource = list; - dataGridView.Columns["Id"].Visible = false; - dataGridView.Columns["FurnitureWorkPieces"].Visible = false; - dataGridView.Columns["FurnitureName"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; - } + dataGridView.FillandConfigGrid(_logic.ReadList(null)); _logger.LogInformation("Загрузка изделий"); } @@ -58,14 +51,11 @@ namespace FurnitureAssemblyView private void ButtonAdd_Click(object sender, EventArgs e) { - var service = Program.ServiceProvider?.GetService(typeof(FormFurniture)); + var form = DependencyManager.Instance.Resolve(); - if (service is FormFurniture form) + if (form.ShowDialog() == DialogResult.OK) { - if (form.ShowDialog() == DialogResult.OK) - { - LoadData(); - } + LoadData(); } } @@ -73,16 +63,13 @@ namespace FurnitureAssemblyView { if (dataGridView.SelectedRows.Count == 1) { - var service = Program.ServiceProvider?.GetService(typeof(FormFurniture)); + var form = DependencyManager.Instance.Resolve(); - if (service is FormFurniture form) + form.Id = Convert.ToInt32(dataGridView.SelectedRows[0].Cells["Id"].Value); + + if (form.ShowDialog() == DialogResult.OK) { - form.Id = Convert.ToInt32(dataGridView.SelectedRows[0].Cells["Id"].Value); - - if (form.ShowDialog() == DialogResult.OK) - { - LoadData(); - } + LoadData(); } } } diff --git a/FurnitureAssembly/FurnitureAssemblyView/FormImplementers.cs b/FurnitureAssembly/FurnitureAssemblyView/FormImplementers.cs index b05211a..9f5de17 100644 --- a/FurnitureAssembly/FurnitureAssemblyView/FormImplementers.cs +++ b/FurnitureAssembly/FurnitureAssemblyView/FormImplementers.cs @@ -1,5 +1,6 @@ using FurnitureAssemblyContracts.BindingModels; using FurnitureAssemblyContracts.BusinessLogicsContracts; +using FurnitureAssemblyContracts.DI; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -13,115 +14,113 @@ using System.Windows.Forms; namespace FurnitureAssemblyView { - public partial class FormImplementers : Form - { - private readonly ILogger _logger; + public partial class FormImplementers : Form + { + private readonly ILogger _logger; - private readonly IImplementerLogic _logic; + private readonly IImplementerLogic _logic; - public FormImplementers(ILogger logger, IImplementerLogic logic) - { - InitializeComponent(); + public FormImplementers(ILogger logger, IImplementerLogic logic) + { + InitializeComponent(); - _logger = logger; - _logic = logic; - } + _logger = logger; + _logic = logic; + } - private void FormImplementers_Load(object sender, EventArgs e) - { - LoadData(); - } + private void FormImplementers_Load(object sender, EventArgs e) + { + LoadData(); + } - private void LoadData() - { - try - { - var list = _logic.ReadList(null); + private void LoadData() + { + try + { + dataGridView.FillandConfigGrid(_logic.ReadList(null)); - // Растягиваем колонку Название на всю ширину, колонку Id скрываем - if (list != null) - { - dataGridView.DataSource = list; - dataGridView.Columns["Id"].Visible = false; - dataGridView.Columns["ImplementerFIO"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; - } + _logger.LogInformation("Загрузка исполнителей"); + var list = _logic.ReadList(null); - _logger.LogInformation("Загрузка исполнителей"); - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка загрузки исполнителей"); + // Растягиваем колонку Название на всю ширину, колонку Id скрываем + if (list != null) + { + dataGridView.DataSource = list; + dataGridView.Columns["Id"].Visible = false; + dataGridView.Columns["ImplementerFIO"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; + } - MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } + _logger.LogInformation("Загрузка исполнителей"); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка загрузки исполнителей"); - private void ButtonCreate_Click(object sender, EventArgs e) - { - var service = Program.ServiceProvider?.GetService(typeof(FormImplementer)); + MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } - if (service is FormImplementer form) - { - if (form.ShowDialog() == DialogResult.OK) - { - LoadData(); - } - } - } + private void ButtonCreate_Click(object sender, EventArgs e) + { + var form = DependencyManager.Instance.Resolve(); - private void ButtonChange_Click(object sender, EventArgs e) - { - if (dataGridView.SelectedRows.Count == 1) - { - var service = Program.ServiceProvider?.GetService(typeof(FormImplementer)); + if (form.ShowDialog() == DialogResult.OK) + { + LoadData(); + } + } - if (service is FormImplementer form) - { - form.Id = Convert.ToInt32(dataGridView.SelectedRows[0].Cells["Id"].Value); + private void ButtonChange_Click(object sender, EventArgs e) + { + if (dataGridView.SelectedRows.Count == 1) + { + var form = DependencyManager.Instance.Resolve(); - if (form.ShowDialog() == DialogResult.OK) - { - LoadData(); - } - } - } - } + form.Id = Convert.ToInt32(dataGridView.SelectedRows[0].Cells["Id"].Value); - private void ButtonDelete_Click(object sender, EventArgs e) - { - // Проверяем наличие выделенной строки - if (dataGridView.SelectedRows.Count == 1) - { - if (MessageBox.Show("Удалить запись?", "Вопрос", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) - { - int id = Convert.ToInt32(dataGridView.SelectedRows[0].Cells["Id"].Value); + if (form.ShowDialog() == DialogResult.OK) + { + LoadData(); + } - _logger.LogInformation("Удаление исполнителя"); + } + } - try - { - if (!_logic.Delete(new ImplementerBindingModel - { - Id = id - })) - { - throw new Exception("Ошибка при удалении. Дополнительная информация в логах."); - } + private void ButtonDelete_Click(object sender, EventArgs e) + { + // Проверяем наличие выделенной строки + if (dataGridView.SelectedRows.Count == 1) + { + if (MessageBox.Show("Удалить запись?", "Вопрос", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) + { + int id = Convert.ToInt32(dataGridView.SelectedRows[0].Cells["Id"].Value); - LoadData(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка удаления исполнителя"); - MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - } - } + _logger.LogInformation("Удаление исполнителя"); - private void ButtonUpdate_Click(object sender, EventArgs e) - { - LoadData(); - } - } + try + { + if (!_logic.Delete(new ImplementerBindingModel + { + Id = id + })) + { + throw new Exception("Ошибка при удалении. Дополнительная информация в логах."); + } + + LoadData(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка удаления исполнителя"); + MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + } + + private void ButtonUpdate_Click(object sender, EventArgs e) + { + LoadData(); + } + } } diff --git a/FurnitureAssembly/FurnitureAssemblyView/FormMails.cs b/FurnitureAssembly/FurnitureAssemblyView/FormMails.cs index 62d0f94..3471704 100644 --- a/FurnitureAssembly/FurnitureAssemblyView/FormMails.cs +++ b/FurnitureAssembly/FurnitureAssemblyView/FormMails.cs @@ -12,48 +12,40 @@ using System.Windows.Forms; namespace FurnitureAssemblyView { - public partial class FormMails : Form - { - private readonly ILogger _logger; + public partial class FormMails : Form + { + private readonly ILogger _logger; - private readonly IMessageInfoLogic _messageLogic; + private readonly IMessageInfoLogic _messageLogic; - public FormMails(ILogger logger, IMessageInfoLogic messageLogic) - { - InitializeComponent(); + public FormMails(ILogger logger, IMessageInfoLogic messageLogic) + { + InitializeComponent(); - _logger = logger; - _messageLogic = messageLogic; - } + _logger = logger; + _messageLogic = messageLogic; + } - private void FormMails_Load(object sender, EventArgs e) - { - LoadData(); - } + private void FormMails_Load(object sender, EventArgs e) + { + LoadData(); + } - private void LoadData() - { - _logger.LogInformation("Загрузка писем"); + private void LoadData() + { + _logger.LogInformation("Загрузка писем"); - try - { - var list = _messageLogic.ReadList(null); + try + { + dataGridView.FillandConfigGrid(_messageLogic.ReadList(null)); - if (list != null) - { - dataGridView.DataSource = list; - dataGridView.Columns["MessageId"].Visible = false; - dataGridView.Columns["ClientId"].Visible = false; - dataGridView.Columns["Body"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; - } - - _logger.LogInformation("Успешная загрузка писем"); - } - catch (Exception ex) - { - _logger.LogError(ex, "Ошибка загрузки писем"); - MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - } + _logger.LogInformation("Успешная загрузка писем"); + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка загрузки писем"); + MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } } diff --git a/FurnitureAssembly/FurnitureAssemblyView/FormMain.Designer.cs b/FurnitureAssembly/FurnitureAssemblyView/FormMain.Designer.cs index 346ffc5..6220268 100644 --- a/FurnitureAssembly/FurnitureAssemblyView/FormMain.Designer.cs +++ b/FurnitureAssembly/FurnitureAssemblyView/FormMain.Designer.cs @@ -46,6 +46,7 @@ workWithImplementerToolStripMenuItem = new ToolStripMenuItem(); implementerToolStripMenuItem = new ToolStripMenuItem(); startingWorkToolStripMenuItem = new ToolStripMenuItem(); + createBackUpToolStripMenuItem = new ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit(); menuStrip.SuspendLayout(); SuspendLayout(); @@ -92,12 +93,12 @@ buttonRefresh.TabIndex = 5; buttonRefresh.Text = "Обновить"; buttonRefresh.UseVisualStyleBackColor = true; - buttonRefresh.Click += ButtonRef_Click; + buttonRefresh.Click += ButtonRefresh_Click; // // menuStrip // menuStrip.ImageScalingSize = new Size(20, 20); - menuStrip.Items.AddRange(new ToolStripItem[] { toolStripMenuItem, reportsToolStripMenuItem, workWithClientsToolStripMenuItem, workWithImplementerToolStripMenuItem, startingWorkToolStripMenuItem }); + menuStrip.Items.AddRange(new ToolStripItem[] { toolStripMenuItem, reportsToolStripMenuItem, workWithClientsToolStripMenuItem, workWithImplementerToolStripMenuItem, startingWorkToolStripMenuItem, createBackUpToolStripMenuItem }); menuStrip.Location = new Point(0, 0); menuStrip.Name = "menuStrip"; menuStrip.Padding = new Padding(5, 2, 0, 2); @@ -115,21 +116,21 @@ // workPieceToolStripMenuItem // workPieceToolStripMenuItem.Name = "workPieceToolStripMenuItem"; - workPieceToolStripMenuItem.Size = new Size(180, 22); + workPieceToolStripMenuItem.Size = new Size(130, 22); workPieceToolStripMenuItem.Text = "Заготовки"; workPieceToolStripMenuItem.Click += WorkPieceToolStripMenuItem_Click; // // furnitureToolStripMenuItem // furnitureToolStripMenuItem.Name = "furnitureToolStripMenuItem"; - furnitureToolStripMenuItem.Size = new Size(180, 22); + furnitureToolStripMenuItem.Size = new Size(130, 22); furnitureToolStripMenuItem.Text = "Изделия"; furnitureToolStripMenuItem.Click += FurnitureToolStripMenuItem_Click; // // mailsToolStripMenuItem // mailsToolStripMenuItem.Name = "mailsToolStripMenuItem"; - mailsToolStripMenuItem.Size = new Size(180, 22); + mailsToolStripMenuItem.Size = new Size(130, 22); mailsToolStripMenuItem.Text = "Письма"; mailsToolStripMenuItem.Click += MailsToolStripMenuItem_Click; // @@ -196,6 +197,13 @@ startingWorkToolStripMenuItem.Text = "Запуск работ"; startingWorkToolStripMenuItem.Click += StartingWorkToolStripMenuItem_Click; // + // createBackUpToolStripMenuItem + // + createBackUpToolStripMenuItem.Name = "createBackUpToolStripMenuItem"; + createBackUpToolStripMenuItem.Size = new Size(97, 20); + createBackUpToolStripMenuItem.Text = "Создать бекап"; + createBackUpToolStripMenuItem.Click += CreateBackUpToolStripMenuItem_Click; + // // FormMain // AutoScaleDimensions = new SizeF(7F, 15F); @@ -238,5 +246,6 @@ private ToolStripMenuItem implementerToolStripMenuItem; private ToolStripMenuItem startingWorkToolStripMenuItem; private ToolStripMenuItem mailsToolStripMenuItem; + private ToolStripMenuItem createBackUpToolStripMenuItem; } } \ No newline at end of file diff --git a/FurnitureAssembly/FurnitureAssemblyView/FormMain.cs b/FurnitureAssembly/FurnitureAssemblyView/FormMain.cs index 1d2b862..c0385f1 100644 --- a/FurnitureAssembly/FurnitureAssemblyView/FormMain.cs +++ b/FurnitureAssembly/FurnitureAssemblyView/FormMain.cs @@ -1,5 +1,6 @@ using FurnitureAssemblyContracts.BindingModels; using FurnitureAssemblyContracts.BusinessLogicsContracts; +using FurnitureAssemblyContracts.DI; using FurnitureAssemblyDataModels.Enums; using Microsoft.Extensions.Logging; using System; @@ -24,7 +25,9 @@ namespace FurnitureAssemblyView private readonly IWorkProcess _workProcess; - public FormMain(ILogger logger, IOrderLogic orderLogic, IReportLogic reportLogic, IWorkProcess workProcess) + private readonly IBackUpLogic _backUpLogic; + + public FormMain(ILogger logger, IOrderLogic orderLogic, IReportLogic reportLogic, IWorkProcess workProcess, IBackUpLogic backUpLogic) { InitializeComponent(); @@ -32,6 +35,7 @@ namespace FurnitureAssemblyView _orderLogic = orderLogic; _reportLogic = reportLogic; _workProcess = workProcess; + _backUpLogic = backUpLogic; } private void FormMain_Load(object sender, EventArgs e) @@ -45,20 +49,9 @@ namespace FurnitureAssemblyView try { - var list = _orderLogic.ReadList(null); + dataGridView.FillandConfigGrid(_orderLogic.ReadList(null)); - if (list != null) - { - dataGridView.DataSource = list; - dataGridView.Columns["FurnitureId"].Visible = false; - dataGridView.Columns["ClientId"].Visible = false; - dataGridView.Columns["ImplementerId"].Visible = false; - dataGridView.Columns["FurnitureName"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; - dataGridView.Columns["ClientFIO"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; - dataGridView.Columns["ImplementerFIO"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; - } - - _logger.LogInformation("Загрузка заказов"); + _logger.LogInformation("Успешная загрузка заказов"); } catch (Exception ex) { @@ -69,34 +62,24 @@ namespace FurnitureAssemblyView private void WorkPieceToolStripMenuItem_Click(object sender, EventArgs e) { - var service = Program.ServiceProvider?.GetService(typeof(FormWorkPieces)); + var form = DependencyManager.Instance.Resolve(); - if (service is FormWorkPieces form) - { - form.ShowDialog(); - } + form.ShowDialog(); } private void FurnitureToolStripMenuItem_Click(object sender, EventArgs e) { - var service = Program.ServiceProvider?.GetService(typeof(FormFurnitures)); + var form = DependencyManager.Instance.Resolve(); - if (service is FormFurnitures form) - { - form.ShowDialog(); - } + form.ShowDialog(); } private void ButtonCreateOrder_Click(object sender, EventArgs e) { - var service = Program.ServiceProvider?.GetService(typeof(FormCreateOrder)); - - if (service is FormCreateOrder form) - { - form.ShowDialog(); - LoadData(); - } + var form = DependencyManager.Instance.Resolve(); + form.ShowDialog(); + LoadData(); } private void ButtonIssuedOrder_Click(object sender, EventArgs e) @@ -147,63 +130,73 @@ namespace FurnitureAssemblyView private void WorkPieceFurnituresToolStripMenuItem_Click(object sender, EventArgs e) { - var service = Program.ServiceProvider?.GetService(typeof(FormReportFurnitureWorkPieces)); + var form = DependencyManager.Instance.Resolve(); - if (service is FormReportFurnitureWorkPieces form) - { - form.ShowDialog(); - } + form.ShowDialog(); } private void OrdersToolStripMenuItem_Click(object sender, EventArgs e) { - var service = Program.ServiceProvider?.GetService(typeof(FormReportOrders)); + var form = DependencyManager.Instance.Resolve(); - if (service is FormReportOrders form) - { - form.ShowDialog(); - } + form.ShowDialog(); } - private void ButtonRef_Click(object sender, EventArgs e) + private void ButtonRefresh_Click(object sender, EventArgs e) { LoadData(); } private void ClientsToolStripMenuItem_Click(object sender, EventArgs e) { - var service = Program.ServiceProvider?.GetService(typeof(FormClients)); + var form = DependencyManager.Instance.Resolve(); - if (service is FormClients form) - { - form.ShowDialog(); - } + form.ShowDialog(); } private void StartingWorkToolStripMenuItem_Click(object sender, EventArgs e) { - _workProcess.DoWork((Program.ServiceProvider?.GetService(typeof(IImplementerLogic)) as IImplementerLogic)!, _orderLogic); + _workProcess.DoWork(DependencyManager.Instance.Resolve()!, _orderLogic); MessageBox.Show("Процесс обработки запущен", "Сообщение", MessageBoxButtons.OK, MessageBoxIcon.Information); } private void ImplementerToolStripMenuItem_Click(object sender, EventArgs e) { - var service = Program.ServiceProvider?.GetService(typeof(FormImplementers)); + var form = DependencyManager.Instance.Resolve(); - if (service is FormImplementers form) - { - form.ShowDialog(); - } + form.ShowDialog(); } private void MailsToolStripMenuItem_Click(object sender, EventArgs e) { - var service = Program.ServiceProvider?.GetService(typeof(FormMails)); + var form = DependencyManager.Instance.Resolve(); - if (service is FormMails form) + form.ShowDialog(); + } + + private void CreateBackUpToolStripMenuItem_Click(object sender, EventArgs e) + { + try { - form.ShowDialog(); + if (_backUpLogic != null) + { + var fbd = new FolderBrowserDialog(); + + if (fbd.ShowDialog() == DialogResult.OK) + { + _backUpLogic.CreateBackUp(new BackUpSaveBindingModel + { + FolderName = fbd.SelectedPath + }); + + MessageBox.Show("Бекап создан", "Сообщение", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } diff --git a/FurnitureAssembly/FurnitureAssemblyView/FormWorkPieces.cs b/FurnitureAssembly/FurnitureAssemblyView/FormWorkPieces.cs index 303f88b..4133208 100644 --- a/FurnitureAssembly/FurnitureAssemblyView/FormWorkPieces.cs +++ b/FurnitureAssembly/FurnitureAssemblyView/FormWorkPieces.cs @@ -1,5 +1,6 @@ using FurnitureAssemblyContracts.BindingModels; using FurnitureAssemblyContracts.BusinessLogicsContracts; +using FurnitureAssemblyContracts.DI; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -37,15 +38,7 @@ namespace FurnitureAssemblyView { try { - var list = _logic.ReadList(null); - - // Растягиваем колонку Название на всю ширину, колонку Id скрываем - if (list != null) - { - dataGridView.DataSource = list; - dataGridView.Columns["Id"].Visible = false; - dataGridView.Columns["WorkPieceName"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; - } + dataGridView.FillandConfigGrid(_logic.ReadList(null)); _logger.LogInformation("Загрузка заготовок"); } @@ -59,14 +52,11 @@ namespace FurnitureAssemblyView private void ButtonAdd_Click(object sender, EventArgs e) { - var service = Program.ServiceProvider?.GetService(typeof(FormWorkPiece)); + var form = DependencyManager.Instance.Resolve(); - if (service is FormWorkPiece form) + if (form.ShowDialog() == DialogResult.OK) { - if (form.ShowDialog() == DialogResult.OK) - { - LoadData(); - } + LoadData(); } } @@ -75,15 +65,12 @@ namespace FurnitureAssemblyView { if (dataGridView.SelectedRows.Count == 1) { - var service = Program.ServiceProvider?.GetService(typeof(FormWorkPiece)); + var form = DependencyManager.Instance.Resolve(); - if (service is FormWorkPiece form) + form.Id = Convert.ToInt32(dataGridView.SelectedRows[0].Cells["Id"].Value); + if (form.ShowDialog() == DialogResult.OK) { - form.Id = Convert.ToInt32(dataGridView.SelectedRows[0].Cells["Id"].Value); - if (form.ShowDialog() == DialogResult.OK) - { - LoadData(); - } + LoadData(); } } } diff --git a/FurnitureAssembly/FurnitureAssemblyView/Program.cs b/FurnitureAssembly/FurnitureAssemblyView/Program.cs index 09bede2..4e7a2c8 100644 --- a/FurnitureAssembly/FurnitureAssemblyView/Program.cs +++ b/FurnitureAssembly/FurnitureAssemblyView/Program.cs @@ -4,6 +4,7 @@ using FurnitureAssemblyBusinessLogic.OfficePackage; using FurnitureAssemblyContracts.BusinessLogicsContracts; using FurnitureAssemblyContracts.StoragesContracts; using FurnitureAssemblyDatabaseImplement.Implements; +using FurnitureAssemblyContracts.DI; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -15,10 +16,6 @@ namespace FurnitureAssemblyView { internal static class Program { - private static ServiceProvider? _serviceProvider; - - public static ServiceProvider? ServiceProvider => _serviceProvider; - /// /// The main entry point for the application. /// @@ -29,80 +26,75 @@ namespace FurnitureAssemblyView // see https://aka.ms/applicationconfiguration. ApplicationConfiguration.Initialize(); var services = new ServiceCollection(); - ConfigureServices(services); - _serviceProvider = services.BuildServiceProvider(); + InitDependency(); try { - var mailSender = _serviceProvider.GetService(); - mailSender?.MailConfig(new MailConfigBindingModel - { - MailLogin = System.Configuration.ConfigurationManager.AppSettings["MailLogin"] ?? string.Empty, - MailPassword = System.Configuration.ConfigurationManager.AppSettings["MailPassword"] ?? string.Empty, - SmtpClientHost = System.Configuration.ConfigurationManager.AppSettings["SmtpClientHost"] ?? string.Empty, - SmtpClientPort = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["SmtpClientPort"]), - PopHost = System.Configuration.ConfigurationManager.AppSettings["PopHost"] ?? string.Empty, - PopPort = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["PopPort"]) - }); + var mailSender = DependencyManager.Instance.Resolve(); + mailSender?.MailConfig(new MailConfigBindingModel + { + MailLogin = System.Configuration.ConfigurationManager.AppSettings["MailLogin"] ?? string.Empty, + MailPassword = System.Configuration.ConfigurationManager.AppSettings["MailPassword"] ?? string.Empty, + SmtpClientHost = System.Configuration.ConfigurationManager.AppSettings["SmtpClientHost"] ?? string.Empty, + SmtpClientPort = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["SmtpClientPort"]), + PopHost = System.Configuration.ConfigurationManager.AppSettings["PopHost"] ?? string.Empty, + PopPort = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["PopPort"]) + }); // var timer = new System.Threading.Timer(new TimerCallback(MailCheck!), null, 0, 100000); } catch (Exception ex) { - var logger = _serviceProvider.GetService(); + var logger = DependencyManager.Instance.Resolve(); logger?.LogError(ex, " "); } - Application.Run(_serviceProvider.GetRequiredService()); + Application.Run(DependencyManager.Instance.Resolve()); } - private static void ConfigureServices(ServiceCollection services) + private static void InitDependency() { - services.AddLogging(option => + DependencyManager.InitDependency(); + + DependencyManager.Instance.AddLogging(option => { option.SetMinimumLevel(LogLevel.Information); option.AddNLog("nlog.config"); }); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - services.AddTransient(); - services.AddSingleton(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(true); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); + DependencyManager.Instance.RegisterType(); } - private static void MailCheck(object obj) => ServiceProvider?.GetService()?.MailCheck(); + private static void MailCheck(object obj) => DependencyManager.Instance.Resolve()?.MailCheck(); } } \ No newline at end of file diff --git a/FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyContracts.dll b/FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyContracts.dll new file mode 100644 index 0000000000000000000000000000000000000000..e91b3e41f32ac04fec5f015d4ce92901754d96bf GIT binary patch literal 31744 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 P@(-r}|H=NJZh`*-^EKeb literal 0 HcmV?d00001 diff --git a/FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyDataModels.dll b/FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyDataModels.dll new file mode 100644 index 0000000000000000000000000000000000000000..71d71d0a285a103b072e0678bab4989e209d8b9c GIT binary patch literal 6144 zcmeHLYiu0V6+ZLW_1cLYJ8=?&Nirb>On{9;!Xp%jA8W%VapGj12d$-ec6Z_o%+73Q zX5+Z1;5vb}Dg^|TA_N8c2U<}SMTr`LLX@H)sESxur7cx|AXQaG8>#e1K|n?NojbF; zvv!+G>90z?_WkC(?z!ijd*|-n9s2U4q!5vce*QesNj$mr2)r;%LEW`-Au3pe`x@|kYmNhiDWNW6arM73Zf|ECr&CN|$gsz7Nh_*@!y?E|} za%Hv;=yGkI)J@b1Nj#ALc`cqAdJj5lG@u;B%>s^Jv?(Cu+!PvnKsaGP>`XkX4;Iq* z;CDL{Jw#s65F?9B|1U=Gvi25R|Am8S?qH%08#pnqQQ?w9C zEWC(zx!l!E)I@8tAt5jQ?qaxGy+nED>u{>BxxJ!L=J1GFU4tMqoBO0N0?y~)hGchg zefRox8#$mDS-=$b#j5*=j^de*fzJ4@X^(qs(T+h}rd7K#)B&28ebpVi(kVQ61R@$@Td8v_^&!qKSH_jh%i+b`pu0UrQZ$~7ED2SG$H=uWho%QgAHmoqs z*0;*J;1TH+WdVJPT^6S^(z|k;9+sbkcA3E6Nlbqta8yWsEa)8)dw5MQ0$)%W zEvcw9(IvDOe&!QPB!L}}$LW5B@ht2)f-4!IM?6w1ZIYI#H&nT&;F&qjzm-ae@dnT; zy?}~&G>j4|$dkE^%5{Q61mHfE1FlhUSB1Lyf@=)9R>5_K+!Dck7>-*`62dv9TIvqW zpdrSDdK>WPaxcZ>!<3@kQ)^;(05=KTDzIJP3gEEDIX&3%lF0n7Dz^iv$=XLZ~|b@RPa$30Uw!=Kb>EE7sTGQ%@HKI46&lB`ZcwgFx*Ygr!6I~5#rF8-~3hWh_7Pv#; zT>^DroF;*b$rN+~JM;=M$JM|NN&+vV^+1hohUQXwS6YoDbPF`|=q=zPngMpwN5EC| zDexM)NlIeOUf`D~2kfUJaEp*_(_aXDRM;OA z_`IV*BYOFe9~81C#@6)^|FUyCEB)YMZvIr!yQa-7ovX41kc<- z_OWjtWhOn}C?xwG%QA!`FL{Sy8?Kq7bUGjS2_8d+=jr1{C>$)gw&|DL3Llv)va`~>4ya6)%2B!hh6NRoL^H^l7nCVDp^xhMzCkyo~$Xt@(a0d zW=+fVBig=66n@as$7iipGRz2Ht|-lWLTmu+Wy7L$b@@ZSvJX*_P_o^{ZV2hfJ`5$n zJ`5P%6$1s`w5aN}k_tA9E{wcn-m<~~#Wu>63N&B?c=V2vZkhYdoTy4g6qTPX zpD3R!|FnFpd}8Js(4S!8b2C#Ao|<`NW;!rFjd8EB09Mnmdn7n!6O+$gdHjuKTVF0L z80h)<^9-q)BqbD$q!@^{HfCD{xiN8c)4u!L-fOx=J&z{NX_ZfKmA`qZ3P6c3i^*~P zCzN>$Ptmc`(eJ-47Yw`jC@VXvH6+%_ODyf)DQwk<6sRE^q(7`kz}V@cbP z(uGl77}bSQUG<~DicwuW3ecShByB?p2_J~umh<=Y5qZfTS1)dJ?14i$qsYg~$N|@x z@FdtZh&XSPs3W;;V5Hx1joxDM+VB;awdjKmT%%S4T8qBeE^>t zIJVhrYx{pTL-mo@JPF?u_>)-V2x`#-51k=tXqeY*8vPvZ;OD|SJXm432+ym~ZQNt+ zHkQ^}#8e1(W>T54<3IZ5f!}_#`H6p=Jk$97U0Zmrfm=pLhDW#R*_%h_)Mc)ub{LI1 z*}F$Yp+;@PM`bT$oGj+El)1C_`WtSfFo>^Jf*(I6fQxXOpL{s&OU`?>RQL*(=Fh0RwsfZ9zN+6Nq>O}GJF5N)P9?L=Xf;Ob7g&D zYa?nalIg|8kwnH8{_tB2Ru%^Ye2)vyT+t$`!x@j$0nAE>fIx8^+e1087ROPk6LUf3 z|J!(ibsfe$yecKs-j8IZ{p{1XHPW}*N9 literal 0 HcmV?d00001 diff --git a/FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyDatabaseImplement.dll b/FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyDatabaseImplement.dll new file mode 100644 index 0000000000000000000000000000000000000000..960e2737fc30668535b1d8bf68e20ff0b903897e GIT binary patch literal 76800 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 a>z&X4aSb#qyi-W2UvWae^Z9?Lf&T@(sPHWS literal 0 HcmV?d00001 diff --git a/FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyFileImplement.dll b/FurnitureAssembly/ImplementationExtensions/FurnitureAssemblyFileImplement.dll new file mode 100644 index 0000000000000000000000000000000000000000..86fa6377c9d9874c30059cfba4f513dca59c6af6 GIT binary patch literal 40960 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 NAp8Hx|JP^W{{lgLCMy5{ literal 0 HcmV?d00001