В настоящее время у меня есть сервисный уровень, основанный на статье Проверка с сервисным уровнем с сайта ASP.NET.
Согласно этому ответу, это плохой подход, потому что логика обслуживания смешана с логикой валидации, которая нарушает принцип единой ответственности.
Мне действительно нравится альтернатива, которая предоставляется, но во время перефакторинга моего кода я столкнулся с проблемой, которую не могу решить.
Рассмотрим следующий интерфейс сервиса:
interface IPurchaseOrderService
{
void CreatePurchaseOrder(string partNumber, string supplierName);
}
со следующей конкретной реализацией, основанной на связанном ответе:
public class PurchaseOrderService : IPurchaseOrderService
{
public void CreatePurchaseOrder(string partNumber, string supplierName)
{
var po = new PurchaseOrder
{
Part = PartsRepository.FirstOrDefault(p => p.Number == partNumber),
Supplier = SupplierRepository.FirstOrDefault(p => p.Name == supplierName),
// Other properties omitted for brevity...
};
validationProvider.Validate(po);
purchaseOrderRepository.Add(po);
unitOfWork.Savechanges();
}
}
Для объекта PurchaseOrder
который передается в валидатор, также требуются две другие сущности, Part
и Supplier
(для этого примера предположим, что PO имеет только одну деталь).
Объекты Part
и Supplier
могут быть нулевыми, если предоставленные пользователем подробности не соответствуют объектам в базе данных, которые требуют, чтобы валидатор выдал исключение.
У меня проблема в том, что на этом этапе валидатор потерял контекстную информацию (номер детали и имя поставщика), поэтому не может сообщить точную ошибку пользователю. Лучшая ошибка, которую я могу предоставить, - это "заказ на поставку должен иметь связанную деталь", который не имеет смысла для пользователя, потому что он предоставил номер детали (он просто не существует в базе данных).
Используя класс обслуживания из статьи ASP.NET, я делаю что-то вроде этого:
public void CreatePurchaseOrder(string partNumber, string supplierName)
{
var part = PartsRepository.FirstOrDefault(p => p.Number == partNumber);
if (part == null)
{
validationDictionary.AddError("",
string.Format("Part number {0} does not exist.", partNumber);
}
var supplier = SupplierRepository.FirstOrDefault(p => p.Name == supplierName);
if (supplier == null)
{
validationDictionary.AddError("",
string.Format("Supplier named {0} does not exist.", supplierName);
}
var po = new PurchaseOrder
{
Part = part,
Supplier = supplier,
};
purchaseOrderRepository.Add(po);
unitOfWork.Savechanges();
}
Это позволяет мне предоставлять пользователю намного лучшую информацию о проверке, но означает, что логика проверки содержится непосредственно в классе обслуживания, что нарушает принцип единой ответственности (код также дублируется между классами обслуживания).
Есть ли способ получить лучшее из обоих миров? Могу ли я отделить уровень обслуживания от уровня проверки, в то же время предоставляя информацию об ошибках того же уровня?