diff --git a/LawFirm/LawFirm.sln b/LawFirm/LawFirm.sln index a563901..b351967 100644 --- a/LawFirm/LawFirm.sln +++ b/LawFirm/LawFirm.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LawFirmView", "LawFirm\LawF EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LawFirmContracts", "LawFirmContracts\LawFirmContracts.csproj", "{E2306BF5-FCE9-4195-85BF-22C35495A8D0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LawFirmBusinessLogic", "LawFirmBusinessLogic\LawFirmBusinessLogic.csproj", "{08E0AB8D-1F53-4757-BA64-D76A2EB866C0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {E2306BF5-FCE9-4195-85BF-22C35495A8D0}.Debug|Any CPU.Build.0 = Debug|Any CPU {E2306BF5-FCE9-4195-85BF-22C35495A8D0}.Release|Any CPU.ActiveCfg = Release|Any CPU {E2306BF5-FCE9-4195-85BF-22C35495A8D0}.Release|Any CPU.Build.0 = Release|Any CPU + {08E0AB8D-1F53-4757-BA64-D76A2EB866C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {08E0AB8D-1F53-4757-BA64-D76A2EB866C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08E0AB8D-1F53-4757-BA64-D76A2EB866C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {08E0AB8D-1F53-4757-BA64-D76A2EB866C0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/LawFirm/LawFirm/LawFirmView.csproj b/LawFirm/LawFirm/LawFirmView.csproj index b57c89e..7eec60b 100644 --- a/LawFirm/LawFirm/LawFirmView.csproj +++ b/LawFirm/LawFirm/LawFirmView.csproj @@ -8,4 +8,19 @@ enable + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + \ No newline at end of file diff --git a/LawFirm/LawFirmBusinessLogic/BusinessLogics/CaseLogic.cs b/LawFirm/LawFirmBusinessLogic/BusinessLogics/CaseLogic.cs new file mode 100644 index 0000000..aff1b6d --- /dev/null +++ b/LawFirm/LawFirmBusinessLogic/BusinessLogics/CaseLogic.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LawFirmContracts.BindingModels; +using LawFirmContracts.BusinessLogicsContracts; +using LawFirmContracts.SearchModels; +using LawFirmContracts.StorageContracts; +using LawFirmContracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace LawFirmBusinessLogic.BusinessLogics +{ + public class CaseLogic : ICaseLogic + { + private readonly ILogger _logger; + private readonly ICaseStorage _caseStorage; + + public CaseLogic(ILogger logger, ICaseStorage caseStorage) + { + _logger = logger; + _caseStorage = caseStorage; + } + + public List? ReadList(CaseSearchModel? model) + { + _logger.LogInformation("ReadList. Id:{Id}", model?.Id); + var list = model == null ? _caseStorage.GetFullList() : _caseStorage.GetFilteredList(model); + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + _logger.LogInformation("ReadList. Count:{Count}", list.Count); + return list; + } + + public CaseViewModel? ReadElement(CaseSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + _logger.LogInformation("ReadElement. Id:{Id}", model.Id); + var element = _caseStorage.GetElement(model); + if (element == null) + { + _logger.LogWarning("ReadElement element not found"); + return null; + } + _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); + return element; + } + + public bool Create(CaseBindingModel model) + { + CheckModel(model); + if (_caseStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + return true; + } + public bool Update(CaseBindingModel model) + { + CheckModel(model); + if (_caseStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + return true; + } + + public bool Delete(CaseBindingModel model) + { + CheckModel(model, false); + _logger.LogInformation("Delete. Id:{Id}", model.Id); + if (_caseStorage.Delete(model) == null) + { + _logger.LogWarning("Delete operation failed"); + return false; + } + return true; + } + + private void CheckModel(CaseBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + if (model.CustomerId < 0) + { + throw new InvalidOperationException("Неверный ID клиента"); + } + _logger.LogInformation("Case. DateCreated:{DateCreated}. CustomerId:{CustomerId}. Id:{Id}", model.DateCreated, model.CustomerId, model.Id); + } + } +} + diff --git a/LawFirm/LawFirmBusinessLogic/BusinessLogics/CustomerLogic.cs b/LawFirm/LawFirmBusinessLogic/BusinessLogics/CustomerLogic.cs new file mode 100644 index 0000000..de21f31 --- /dev/null +++ b/LawFirm/LawFirmBusinessLogic/BusinessLogics/CustomerLogic.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LawFirmContracts.BindingModels; +using LawFirmContracts.BusinessLogicsContracts; +using LawFirmContracts.SearchModels; +using LawFirmContracts.StorageContracts; +using LawFirmContracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace LawFirmBusinessLogic.BusinessLogics +{ + public class CustomerLogic : ICustomerLogic + { + private readonly ILogger _logger; + private readonly ICustomerStorage _customerStorage; + public CustomerLogic(ILogger logger, ICustomerStorage customerStorage) + { + _logger = logger; + _customerStorage = customerStorage; + } + public bool Create(CustomerBindingModel model) + { + CheckModel(model); + if (_customerStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + return true; + } + + public bool Delete(CustomerBindingModel model) + { + CheckModel(model, false); + _logger.LogInformation("Delete. Id: {Id}", model.Id); + if (_customerStorage.Delete(model) == null) + { + _logger.LogWarning("Delete operation failed"); + return false; + } + return true; + } + + public CustomerViewModel ReadElement(CustomerSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + _logger.LogInformation("ReadElement. Id: {Id}", model.Id); + var element = _customerStorage.GetElement(model); + if (element == null) + { + _logger.LogWarning("ReadElement element not found"); + return null; + } + _logger.LogInformation("ReadElement found. Id: {Id}", element.Id); + return element; + } + + public bool Update(CustomerBindingModel model) + { + CheckModel(model); + if (_customerStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + return true; + } + + public List? ReadList(CustomerSearchModel? model) + { + _logger.LogInformation("ReadList. Id: {Id}", model?.Id); + var list = model == null ? _customerStorage.GetFullList() : _customerStorage.GetFilteredList(model); + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + _logger.LogInformation("ReadList. Count: {Count}", list.Count); + return list; + } + + private void CheckModel(CustomerBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentException(nameof(model)); + } + if (!withParams) + { + return; + } + if (string.IsNullOrEmpty(model.Login)) + { + _logger.LogWarning("Login is empty"); + throw new ArgumentNullException("Не заполнен логин"); + } + if (string.IsNullOrEmpty(model.Name)) + { + _logger.LogWarning("Name is empty"); + throw new ArgumentNullException("Не заполнено имя"); + } + if (string.IsNullOrEmpty(model.Surname)) + { + _logger.LogWarning("Surname is empty"); + throw new ArgumentNullException("Не заполнена фамилия"); + } + if (string.IsNullOrEmpty(model.Password)) + { + _logger.LogWarning("Password is empty"); + throw new ArgumentNullException("Не заполнен пароль"); + } + var ExistingCustomer = _customerStorage.GetElement + (new CustomerSearchModel() { Login = model.Login }); + if (ExistingCustomer != null) + { + _logger.LogWarning("There is already a user with this login"); + throw new ArgumentException("Пользователь с таким логином уже есть"); + } + _logger.LogInformation("Customer. Id: {Id}", model.Id); + } + } +} diff --git a/LawFirm/LawFirmBusinessLogic/BusinessLogics/ItemLogic.cs b/LawFirm/LawFirmBusinessLogic/BusinessLogics/ItemLogic.cs new file mode 100644 index 0000000..04fc3e3 --- /dev/null +++ b/LawFirm/LawFirmBusinessLogic/BusinessLogics/ItemLogic.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LawFirmContracts.BindingModels; +using LawFirmContracts.BusinessLogicsContracts; +using LawFirmContracts.SearchModels; +using LawFirmContracts.StorageContracts; +using LawFirmContracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace LawFirmBusinessLogic.BusinessLogics +{ + public class ItemLogic : IItemLogic + { + private readonly ILogger _logger; + private readonly IItemStorage _paymentStorage; + public ItemLogic(ILogger logger, IItemStorage paymentStorage) + { + _logger = logger; + _paymentStorage = paymentStorage; + } + public List? ReadList(ItemSearchModel? model) + { + _logger.LogInformation("ReadList. Id: {Id}", model?.Id); + var list = model == null ? _paymentStorage.GetFullList() : _paymentStorage.GetFilteredList(model); + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + _logger.LogInformation("ReadList. Count: {Count}", list.Count); + return list; + } + public ItemViewModel? ReadElement(ItemSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + _logger.LogInformation("ReadElement. Id: {Id}", model.Id); + var element = _paymentStorage.GetElement(model); + if (element == null) + { + _logger.LogWarning("ReadElement element not found"); + return null; + } + _logger.LogInformation("ReadElement found. Id: {Id}", element.Id); + return element; + } + public bool Create(ItemBindingModel model) + { + CheckModel(model); + if (_paymentStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + return true; + } + public bool Update(ItemBindingModel model) + { + CheckModel(model); + if (_paymentStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + return true; + } + public bool Delete(ItemBindingModel model) + { + CheckModel(model, false); + _logger.LogInformation("Delete. Id:{Id}", model.Id); + if (_paymentStorage.Delete(model) == null) + { + _logger.LogWarning("Delete operation failed"); + return false; + } + return true; + } + private void CheckModel(ItemBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + _logger.LogInformation("Item. Id: {Id}", model.Id); + } + } +} \ No newline at end of file diff --git a/LawFirm/LawFirmBusinessLogic/BusinessLogics/PaymentLogic.cs b/LawFirm/LawFirmBusinessLogic/BusinessLogics/PaymentLogic.cs new file mode 100644 index 0000000..0e0faf8 --- /dev/null +++ b/LawFirm/LawFirmBusinessLogic/BusinessLogics/PaymentLogic.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LawFirmContracts.BindingModels; +using LawFirmContracts.BusinessLogicsContracts; +using LawFirmContracts.SearchModels; +using LawFirmContracts.StorageContracts; +using LawFirmContracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace LawFirmBusinessLogic.BusinessLogics +{ + public class PaymentLogic : IPaymentLogic + { + private readonly ILogger _logger; + private readonly IPaymentStorage paymentStorage; + public PaymentLogic(ILogger logger, IPaymentStorage paymentStorage) + { + _logger = logger; + this.paymentStorage = paymentStorage; + } + public List? ReadList(PaymentSearchModel? model) + { + _logger.LogInformation("ReadList. Id: {Id}", model?.Id); + var list = model == null ? paymentStorage.GetFullList() : paymentStorage.GetFilteredList(model); + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + _logger.LogInformation("ReadList. Count: {Count}", list.Count); + return list; + } + public PaymentViewModel? ReadElement(PaymentSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + _logger.LogInformation("ReadElement. Id: {Id}", model.Id); + var element = paymentStorage.GetElement(model); + if (element == null) + { + _logger.LogWarning("ReadElement element not found"); + return null; + } + _logger.LogInformation("ReadElement found. Id: {Id}", element.Id); + return element; + } + public bool Create(PaymentBindingModel model) + { + CheckModel(model); + if (paymentStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + return true; + } + public bool Update(PaymentBindingModel model) + { + CheckModel(model); + if (paymentStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + return true; + } + public bool Delete(PaymentBindingModel model) + { + CheckModel(model, false); + _logger.LogInformation("Delete. Id:{Id}", model.Id); + if (paymentStorage.Delete(model) == null) + { + _logger.LogWarning("Delete operation failed"); + return false; + } + return true; + } + private void CheckModel(PaymentBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + _logger.LogInformation("Payment. Id: {Id}", model.Id); + } + } +} diff --git a/LawFirm/LawFirmBusinessLogic/BusinessLogics/ServiceLogic.cs b/LawFirm/LawFirmBusinessLogic/BusinessLogics/ServiceLogic.cs new file mode 100644 index 0000000..0b79c45 --- /dev/null +++ b/LawFirm/LawFirmBusinessLogic/BusinessLogics/ServiceLogic.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LawFirmContracts.BindingModels; +using LawFirmContracts.BusinessLogicsContracts; +using LawFirmContracts.SearchModels; +using LawFirmContracts.StorageContracts; +using LawFirmContracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace LawFirmBusinessLogic.BusinessLogics +{ + public class ServiceLogic : IServiceLogic + { + private readonly ILogger _logger; + private readonly IServiceStorage _serviceStorage; + public ServiceLogic(ILogger logger, IServiceStorage serviceStorage) + { + _logger = logger; + _serviceStorage = serviceStorage; + } + public List? ReadList(ServiceSearchModel? model) + { + _logger.LogInformation("ReadList. Id: {Id}", model?.Id); + var list = model == null ? _serviceStorage.GetFullList() : _serviceStorage.GetFilteredList(model); + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + _logger.LogInformation("ReadList. Count: {Count}", list.Count); + return list; + } + public ServiceViewModel? ReadElement(ServiceSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + _logger.LogInformation("ReadElement. Id: {Id}", model.Id); + var element = _serviceStorage.GetElement(model); + if (element == null) + { + _logger.LogWarning("ReadElement element not found"); + return null; + } + _logger.LogInformation("ReadElement found. Id: {Id}", element.Id); + return element; + } + public bool Create(ServiceBindingModel model) + { + CheckModel(model); + if (_serviceStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + return true; + } + public bool Update(ServiceBindingModel model) + { + CheckModel(model); + if (_serviceStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + return true; + } + public bool Delete(ServiceBindingModel model) + { + CheckModel(model, false); + _logger.LogInformation("Delete. Id: {Id}", model.Id); + if (_serviceStorage.Delete(model) == null) + { + _logger.LogWarning("Delete operation failed"); + return false; + } + return true; + } + private void CheckModel(ServiceBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentException(nameof(model)); + } + if (!withParams) + { + return; + } + if (string.IsNullOrEmpty(model.Name)) + { + _logger.LogWarning("Service name is empty"); + throw new ArgumentException("Укажите название услуги"); + } + _logger.LogInformation("Service. Id: {Id}", model.Id); + } + } +} diff --git a/LawFirm/LawFirmBusinessLogic/LawFirmBusinessLogic.csproj b/LawFirm/LawFirmBusinessLogic/LawFirmBusinessLogic.csproj new file mode 100644 index 0000000..6f20f1a --- /dev/null +++ b/LawFirm/LawFirmBusinessLogic/LawFirmBusinessLogic.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/LawFirm/LawFirmContracts/LawFirmContracts.csproj b/LawFirm/LawFirmContracts/LawFirmContracts.csproj index 453d908..922df1c 100644 --- a/LawFirm/LawFirmContracts/LawFirmContracts.csproj +++ b/LawFirm/LawFirmContracts/LawFirmContracts.csproj @@ -7,7 +7,18 @@ - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/LawFirm/LawFirmContracts/SearchModels/CustomerSearchModel.cs b/LawFirm/LawFirmContracts/SearchModels/CustomerSearchModel.cs index 4477c85..c6f34ed 100644 --- a/LawFirm/LawFirmContracts/SearchModels/CustomerSearchModel.cs +++ b/LawFirm/LawFirmContracts/SearchModels/CustomerSearchModel.cs @@ -9,5 +9,6 @@ namespace LawFirmContracts.SearchModels public class CustomerSearchModel { public int? Id { get; set; } + public string? Login { get; set; } } } diff --git a/LawFirm/LawFirmContracts/StorageContracts/ICaseStorage.cs b/LawFirm/LawFirmContracts/StorageContracts/ICaseStorage.cs new file mode 100644 index 0000000..702a797 --- /dev/null +++ b/LawFirm/LawFirmContracts/StorageContracts/ICaseStorage.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LawFirmContracts.BindingModels; +using LawFirmContracts.SearchModels; +using LawFirmContracts.ViewModels; + +namespace LawFirmContracts.StorageContracts +{ + public interface ICaseStorage + { + List GetFullList(); + List GetFilteredList(CaseSearchModel model); + CaseViewModel? GetElement(CaseSearchModel model); + CaseViewModel? Insert(CaseBindingModel model); + CaseViewModel? Update(CaseBindingModel model); + CaseViewModel? Delete(CaseBindingModel model); + } +} diff --git a/LawFirm/LawFirmContracts/StorageContracts/ICustomerStorage.cs b/LawFirm/LawFirmContracts/StorageContracts/ICustomerStorage.cs new file mode 100644 index 0000000..1c642ec --- /dev/null +++ b/LawFirm/LawFirmContracts/StorageContracts/ICustomerStorage.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LawFirmContracts.BindingModels; +using LawFirmContracts.SearchModels; +using LawFirmContracts.ViewModels; + +namespace LawFirmContracts.StorageContracts +{ + public interface ICustomerStorage + { + List GetFullList(); + List GetFilteredList(CustomerSearchModel model); + CustomerViewModel? GetElement(CustomerSearchModel model); + CustomerViewModel? Insert(CustomerBindingModel model); + CustomerViewModel? Update(CustomerBindingModel model); + CustomerViewModel? Delete(CustomerBindingModel model); + } +} diff --git a/LawFirm/LawFirmContracts/StorageContracts/IItemStorage.cs b/LawFirm/LawFirmContracts/StorageContracts/IItemStorage.cs new file mode 100644 index 0000000..4e38871 --- /dev/null +++ b/LawFirm/LawFirmContracts/StorageContracts/IItemStorage.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LawFirmContracts.BindingModels; +using LawFirmContracts.SearchModels; +using LawFirmContracts.ViewModels; + +namespace LawFirmContracts.StorageContracts +{ + public interface IItemStorage + { + List GetFullList(); + List GetFilteredList(ItemSearchModel model); + ItemViewModel? GetElement(ItemSearchModel model); + ItemViewModel? Insert(ItemBindingModel model); + ItemViewModel? Update(ItemBindingModel model); + ItemViewModel? Delete(ItemBindingModel model); + } +} diff --git a/LawFirm/LawFirmContracts/StorageContracts/IPaymentStorage.cs b/LawFirm/LawFirmContracts/StorageContracts/IPaymentStorage.cs new file mode 100644 index 0000000..a510469 --- /dev/null +++ b/LawFirm/LawFirmContracts/StorageContracts/IPaymentStorage.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LawFirmContracts.BindingModels; +using LawFirmContracts.SearchModels; +using LawFirmContracts.ViewModels; + +namespace LawFirmContracts.StorageContracts +{ + public interface IPaymentStorage + { + List GetFullList(); + List GetFilteredList(PaymentSearchModel model); + PaymentViewModel? GetElement(PaymentSearchModel model); + PaymentViewModel? Insert(PaymentBindingModel model); + PaymentViewModel? Update(PaymentBindingModel model); + PaymentViewModel? Delete(PaymentBindingModel model); + } +} diff --git a/LawFirm/LawFirmContracts/StorageContracts/IServiceStorage.cs b/LawFirm/LawFirmContracts/StorageContracts/IServiceStorage.cs new file mode 100644 index 0000000..caac867 --- /dev/null +++ b/LawFirm/LawFirmContracts/StorageContracts/IServiceStorage.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LawFirmContracts.BindingModels; +using LawFirmContracts.SearchModels; +using LawFirmContracts.ViewModels; + +namespace LawFirmContracts.StorageContracts +{ + public interface IServiceStorage + { + List GetFullList(); + List GetFilteredList(ServiceSearchModel model); + ServiceViewModel? GetElement(ServiceSearchModel model); + ServiceViewModel? Insert(ServiceBindingModel model); + ServiceViewModel? Update(ServiceBindingModel model); + ServiceViewModel? Delete(ServiceBindingModel model); + } +}