CRUD Class Library Design, чтобы возвращать полезные сообщения о сбое бизнес-логики, что не является исключением - PullRequest
6 голосов
/ 27 октября 2009

Я создаю базовую библиотеку CRUD, которую я ожидаю использовать как в локальной (добавить ссылку), так и в wcf (добавить ссылку на службу).

Каковы наилучшие типы возврата для частей Create, Uupdate и Delete (которые имеют более сложные бизнес-правила) установки CRUD?

Я хочу иметь возможность свести к минимуму время от времени по проводной связи, но я также хочу предоставить своим клиентам значимую информацию о том, когда операция терпит неудачу в моей бизнес-логике, но технически обоснована (таким образом, это не исключение) .

Возьмем, к примеру, CRUD для класса Person, который имеет следующие поля: FirstName, MiddleName LastName и Date of Brith. First, Last и DOB требуются, но Middle нет.

Как мне сообщить клиенту о сбоях бизнес-логики? И.Е. «Вы должны указать значение для FirstName.»

  1. Это где я должен бросать исключения? (это не похоже на исключительный случай, так что я думаю нет, но я могу ошибаться).
  2. Должен ли я использовать void и параметр "out"? Если да, то какой это должен быть тип?
  3. Должен ли я использовать тип возвращаемого объекта и поместить туда данные о том, что происходит?
  4. Какой-то другой вариант, который я полностью пропустил?

Ответы [ 6 ]

3 голосов
/ 03 ноября 2009

По соображениям производительности начальная проверка ввода должна выполняться на уровне клиента. (т. е. не пытайтесь отправлять неверные данные по сети.) На уровне клиента сбой проверки входных данных, на самом деле, является весьма ожидаемой проблемой, которая не должна вызывать исключения. Однако, если вы поместите эту «раннюю» проверку на уровне клиента, сбой проверки данных, обнаруженный на любом более глубоком уровне, может быть разумно рассмотрен как неожиданная проблема, поэтому создание исключений для ошибок проверки данных на этих уровнях не будет неуместным.

1 голос
/ 05 ноября 2009

1. Это где я должен бросать исключения? (это не похоже на исключительный случай, поэтому я думаю, что нет, но я могу ошибаться).

Лично я считаю, что вы должны вернуть объект с результатом, а также с любыми ошибками проверки, и не выдавать исключение для проверки данных, будь то из-за отсутствия информации (проверка формата) или проверки бизнес-логики. Тем не менее, я предлагаю выдать исключение для ошибок, которые не связаны с самими данными, т.е. если происходит сбой фиксации базы данных с действительными данными и т. Д.

Я думаю, что провал проверки не является «исключительным случаем». Я лично чувствую, что все, что пользователь может испортить, просто не введя достаточное количество / правильных данных и т. Д., Является чем-то, что не является исключением - это стандартная практика и должна обрабатываться непосредственно API.

То, что не связано с тем, что делает пользователь (например, проблемы с сетью, проблемы с сервером и т. Д.), Является исключительным происшествием и требует исключения.

2.Могу ли я использовать void и параметр "out"? Если да, то какой это должен быть тип?

3.Могу ли я использовать возвращаемый тип объекта и помещать туда данные о том, что происходит?

Я лично предпочитаю третий вариант. «out» параметры не очень значимы. Кроме того, вы захотите вернуть более одной информации о состоянии из этого вызова - вам нужно будет вернуть достаточно информации, чтобы пометить соответствующие свойства как недействительные, а также любую полную информацию по всей операции.

Вероятно, для этого потребуется класс, который содержит, как минимум, статус фиксации (успех / неудачный формат / неудачная бизнес-логика / и т. Д.), Список сопоставлений для свойств-> ошибок (т. Е. IDataErrorInfo информация о стиле) и, возможно, список ошибок, которые не привязаны к определенному свойству, а скорее касаются бизнес-логики операции в целом или комбинации предлагаемых значений свойств.

4.Некоторые другие варианты, которые я полностью пропустил?

Другой вариант, который мне очень нравится, - это проверка в отдельной сборке от уровня бизнес-обработки. Это позволяет повторно использовать логику проверки на стороне клиента.

Приятно то, что вы можете значительно упростить и уменьшить сетевой трафик. Клиент может предварительно проверить информацию и отправлять данные по сети только в том случае, если она действительна.

Сервер может получать достоверные данные, проверять их и ничего не возвращать, кроме одного результата коммита. Я считаю, что это должно иметь как минимум три ответа - успех, неудача из-за бизнес-логики или неудача из-за форматирования. Это обеспечивает безопасность (вам не нужно доверять клиенту) и предоставляет клиенту информацию о том, что не обрабатывается должным образом, но избегает передачи как неверной информации из client-> server, так и информации о проверке из server-> client, поэтому может резко сократить трафик.

Уровень проверки затем может (безопасно) отправить информацию на уровень CRUD для отправки.

1 голос
/ 03 ноября 2009

Дискуссия между возвратом структуры результата с подробностями об ошибке и выдачей исключения может быть обобщена на «Могу ли я успешно выполнить запрошенное действие?» Вы проектируете библиотеку, и то, как библиотека передает режимы сбоев, является частью этого.

Если библиотека просит создать объект User, но не может этого сделать, потому что имя пользователя не прошло проверку, вы можете передать обратно пустого пользователя вместе с сообщениями об ошибках проверки и надеяться, что код клиента проверяет возвращаемое значение. Мой опыт (воспоминания DCOM pre ATL) о необходимости проверять возвращаемые значения для кодов ошибок заключается в том, что легко получить удовлетворение (или ленивость) и пропустить его.

Из того, что вы описали, об исключениях не может быть и речи. Определите родительское исключение для всех типов исключений, которые может генерировать ваша библиотека. Таким образом, клиентам не нужно включать большой список исключений, если они этого не хотят. Примером этого является SqlException.

1 голос
/ 30 октября 2009

Редактировать: я должен заметить, что у меня обычно бывают элементы проверки, абстрагированные в бизнес-уровень, которые будут обрабатывать проверку и вызывать методы CRUD после успешной проверки.

Один из способов сделать это - вернуть класс «response», содержащий всю информацию, которая понадобится потребителю вашей библиотеки для оценки того, что произошло и что делать дальше. Очень простой пример класса, который вы могли бы использовать, будет выглядеть примерно так:

public class Response<T> where T:BusinessObject
{
    public Response(T oldOriginalValue, T newValue)
    {
    }

    /// <summary>
    /// List of Validation Messages
    /// </summary>
    public List<ValidationMessage> ValidationMessages { get; set; }

    /// <summary>
    /// Object passed into the CRUD method
    /// </summary>
    public T OldValue { get; private set; }

    /// <summary>
    /// Object passed back from the CRUD method, with values of identity fields, etc populated
    /// </summary>
    public T NewValue { get; private set; }

    /// <summary>
    /// Was the operation successful
    /// </summary>
    public bool Success { get; set; }
}

public class ValidationMessage
{
    /// <summary>
    /// Property causing validation message (i.e. FirstName)
    /// </summary>
    string Property { get; set; }

    /// <summary>
    /// Validation Message text
    /// </summary>
    string Message { get; set; }
}
1 голос
/ 27 октября 2009

Вы действительно должны проверить реализацию правил валидации Роки Лхоткой в ​​его CSLA framework .

ПРИМЕЧАНИЕ: Я не сказал, что массово использовал его фреймворк, поскольку у него есть некоторые проблемы со связыванием, которые нарушают некоторые усилия SRP в последних тенденциях развития .NET. *

Но его среда использует «автоматическое» уведомление до уровня пользовательского интерфейса и интеграцию с сообщениями об ошибках валидации с поддержкой элементов управления Web / Winforms.

1 голос
/ 27 октября 2009

Вы можете найти этот пост Роба Бэгби интересным; он описывает, как реализовать хранилище для обработки операций CRUD, и, на ваш взгляд, в частности, как реализовать проверку, возвращая клиенту коллекцию «RuleViolation» в случае возникновения проблемы.

http://www.robbagby.com/silverlight/patterns-based-silverlight-development-part-ii-repository-and-validation/

[edit] Для меня это случай исключения: если при создании пользователя требуется имя, а имя не указано, вызывающая сторона не использовала правильные аргументы и не использует метод в намеченном пути. InvalidArgumentException звучит адекватно.

...