Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

Лапшекодим валидацию, или запрещаем вводить неправильные данные?

2865  1 2 3 4 5 6 7 8 9 все
alex445 коренной житель01.06.22 12:23
NEW 01.06.22 12:23 
Последний раз изменено 01.06.22 12:27 (alex445)

Попытался тут заюзать Range атрибут для валидации моделей в WPF. А мне сказали, что он сам не заводится, а надо реализовывать интерфейс IDataErrorInfo. Обычно все примеры с ним для веб проектов (типа ASP.NET MVC) приводятся - там типа код из коробки есть, который модель под капотом валидирует, поэтому тебе кажется, что валидация происходит автоматически - достаточно просто добавить атрибутов. При попытке перенести эту "простоту" в тот же WPF ничего из коробки не заводится так же легко, как в веб проектах.


И то верно, когда привязываешь в XAML


Path=(Validation.Errors)[0].ErrorContent}


То там ничего нет без прописывания валидации в IDataErrorInfo. Сам RangeAttribute ничего не валидирует.


Для реализации валидации через IDataErrorInfo предлагается писать тонну лапшекода. Либо через магию рефлексии, либо через совсем уж лапшу с перебором всех пропертей вручную. Я всё думал, что лыжи-то не едут. Либо я тупой, либо лыжи всё же авно? Вспомнил, что я этот вопрос для себя закрыл ещё давно, и решил, что эту лапшу писать не буду. Штука в том, что они в этих статьях как правило на вьюхе используют обычный текстбокс, из которого берут строку, пытаются парсить её в число и валидируют. Ну ладно парсить, но валидировать-то тоже вручную приходится. И я давно от этого дерьма отказался в пользу правильных контролов. Вместо того, чтобы вытаскивать той же рефлексией из модели долбаный атрибут (а более удобного способа доступа к ним в Дотнете нет), потом его свойства и проверять введённые значения по ним, я ввожу прямо в модели обычные свойства типа Value, Min, Max. А потом, ска, тупо привязываю их к правильному контролу, типа NumericUpDown, который из коробки имеет те же свойства Value, Min, Max и не даёт ввести значения вне диапазона. Вуаля - не надо лапшекодить.


А если ещё добавить, что сериализация моделей с кучей валидирующих атрибутов тот ещё квест по сравнению с сериализацией обычных свойств Value, Min, Max... Или есть всё же простые варианты?


Короче, в чём суть. Вместо того, чтобы лапшекодить долбаную валидацию, не проще добавить контролы с ограничениями для вводимых чисел, строк и тому подобному? Текстбокс с проверкой длины введённой строки и фильтру символов, текст бокс с переключателями для числе и заданием диапазона (NumericUpDown), и т.д.

#1 
alex445 коренной житель01.06.22 12:26
NEW 01.06.22 12:26 
в ответ alex445 01.06.22 12:23, Последний раз изменено 01.06.22 13:34 (alex445)

Как вы у себя делаете?


ЗАБЫЛ СКАЗАТЬ - ЭТО ВСЁ ДЛЯ .NET.

#2 
alex445 коренной житель01.06.22 12:33
NEW 01.06.22 12:33 
в ответ alex445 01.06.22 12:26, Последний раз изменено 01.06.22 12:34 (alex445)

О, да, мать-перемать! Городим забор из наследования базовых классов с валидацией и прочим, тонны кода с линком, словарями и делегатами по вытаскиванию атрибутов и пропертей, кастомные поведения, прогресс валидации - о да, конечно, только это бы и делал с утра до вечера! Чел поди месяц пыхтел над этой бадьёй. Статью тиснул, где-то на SO я его ответы видел, где он тоже советовал основательно реализовывать IDataErrorInfo.


Кого-то хлебом не корми - дай усложнить всё до упора. ))


Одно непонятно. Как-то в веб-проектах добились, что разрабу не надо самому эти простыни писать. Ну добавил атрибут в модель и оно само под капотом валидируется. Во вьюхе привязал контрол к сообщению об ошибке, которое туда как-то попало, но мне и пофиг, как - главное, что попало. Почему в других местах, типа того же WPF, нужно всё руками вспахивать?

#3 
alex445 коренной житель01.06.22 13:58
NEW 01.06.22 13:58 
в ответ alex445 01.06.22 12:33, Последний раз изменено 01.06.22 13:59 (alex445)

Эта же проблема с долбаными атрибутами возникает, когда делаешь MVVM в WPF и вообще подобные многослойки. Прописываешь в самом нижнем слое (типа модель) валидирующие атрибуты. А теперь нужно всю эту валидацию поднять на уровень выше - скажем, модель представления. Что делать будете? Лапшекодить-рефлексировать, вытаскивая атрибуты из модели? А как в атрибуты вью модели это всё поместите? Атрибуты-то во время выполнения кода не задаются - только при написании. Ну я обычно во вью модели и делаю валидирующие ограничения (типа Min и Max) в виде обычных свойств. А если их уже во втором слое в виде обычных свойств делаешь, то почему бы сразу в первом же слое их такими не сделать? К чему возьба с атрибутами и потом с рефлексией по их вытаскиванию?


Навеяло, как один знакомый сходил в одну крутую новосибскую контору лет 12-15 назад. Там ему код показали - он сказал, что они теперь всё на атрибутах делают - валидацию, шмалидацию. Модно типа теперь так. Правда, не сказал, как они теперь с этим всем ипуца и стоило ли оно того. Но я тогда зелёный был и про атрибуты лишь мельком слышал. Подумал, ну раз у них всё на атрибутах теперь, значит контора точно крутая. Ну не будет же одна из самых крутых контор Новосиба веников вязать?

#4 
alex445 коренной житель01.06.22 14:32
NEW 01.06.22 14:32 
в ответ alex445 01.06.22 13:58

Ещё доводы за перенос валидации ввода в контролы, а не в классы бизнес-логики. Начинаете новый класс модели. Если реализовывать валидацию в базовом классе, то каждый раз надо унаследоваться от него. Не задолбает ли? А вот если валидация в контролах, то ничего дополнительного сверх обычного делать не надо.


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


Естественно, это для простых проектов - модель плюс вью модель. Если у вас там десятки слоёв, и на каждом своя валидация, то там другой подход может быть. Но суть та же - вместо гоняния данных из верхних слоёв в самые нижние и обратно, лучше всё делать на как можно более верхнем слое, где вводятся данные.

#5 
AlexNek патриот01.06.22 18:03
AlexNek
NEW 01.06.22 18:03 
в ответ alex445 01.06.22 14:32
Ещё доводы за

Не нужно искать универсальное решение. Для каждого проекта будет свое наиболее подходящее

https://docs.devexpress.com/WPF/7076/controls-and-librarie...

https://docs.devexpress.com/WPF/6945/controls-and-librarie...

https://docs.devexpress.com/WPF/6933/controls-and-librarie...


https://github.com/EmmanuelDURIN/wpf-attribute-validation

#6 
alex445 коренной житель01.06.22 18:31
NEW 01.06.22 18:31 
в ответ AlexNek 01.06.22 18:03, Последний раз изменено 01.06.22 18:33 (alex445)

Вот этого дядьку с его лапшевалидацией

https://github.com/EmmanuelDURIN/wpf-attribute-validation/...


я тоже встречал на SO по этой теме.


Хорошо, конечно, иметь кучу умных контролов вместо стандартной куцей поставки, в которой всё надо из текстбоксов брать.


Как будете сериализовывать и десериализовывать объект с атрибутами валидации? Или атрибуты не сериализуются?

#7 
AlexNek патриот01.06.22 21:29
AlexNek
NEW 01.06.22 21:29 
в ответ alex445 01.06.22 18:31
Вот этого дядьку с его лапшевалидацией

А чем не нравится то?

public class Contact : ValidatorBase
{
      [Required(ErrorMessage = " Name is required.")]
      [StringLength(50, ErrorMessage = "No more than 50 characters")]
      [Display(Name = "Name")]
      public string Name { get; set; }
}


#8 
alex445 коренной житель01.06.22 21:51
NEW 01.06.22 21:51 
в ответ AlexNek 01.06.22 21:29, Последний раз изменено 01.06.22 22:14 (alex445)

Вот если бы это так и работало, без той лапши, на которую я ссылку дал.


А теперь скажите, зачем нужен валидатор StringLength, если я могу использовать контрол с ограничением по длине строки?


По мне, луче иметь такую модель (проперти для примера)


Name

NameMaxLength

DisplayName

Age

AgeMin

AgeMax


чем такую


[StringLength]

[Display]

Name


[Range]

Age


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


Всё! Не надо лапши, рефлексии, обязательного базового класса с реализацией допотопных неудобных интерфейсов, и трахания с сериализацией. Вам только кажется, что атрибуты это красиво и удобно. Оно красиво толкьо когда их один-два и они коротко объявлены. А когда каша из атрибутов с кучей установок их свойств (типа притаранить локализованное сообщение об ошибке - укажи словарь, укажи ключ, укажи собственно свойства атрибута), то вся красота и лаконичность быстро исчезают. Вот это что, читаемо (смотри ниже)? А я тут всего два атрибута написал. Некоторые навешивают по пять-шесть. Можно и в одну строку написать - будете скроллить экран по горизонтали. Особенно если у вас ноутбук с маленьким экраном. Писал, писал я подобную фигню, вытаскивал данные из атрибутов рефлексией... а потом подумал - а нафига оно надо? И стал всё в обычных пропертях писать.


[NameDescription(
    resourceType: typeof(Namespace1.Namespace2.Namespace3.Namespace4.Strings),
    name: "AAAName",
    description: "AAADescription")]
[Range(
    1.0,
    20.0,
    ErrorMessageResourceType: typeof(Namespace1.Namespace2.Namespace3.Namespace4.Strings),
    ErrorMessageResourceName : "AAAErrorMessage")]
public double AAA { get; set; } = 1.6;
#9 
alex445 коренной житель01.06.22 22:12
NEW 01.06.22 22:12 
в ответ alex445 01.06.22 21:51

Чем мне не нравятся атрибуты и прочие данные, запиханные в рефлексию - они скрытые. Вот приходит к тебе объект класса, у него свойтсва - вот его данные. А нифига - у него ещё глобальные данные класса есть. Просканируй через рефлексию на наличие атрибутов. Т.е. ты должен изучить исходные код класса, чтобы знать, как с ним работать, чтобы увидеть, что там в глобальных данных куча инфы запрятана, которую ты тоже должен знать и как-то её достать.


Это, лять, как с ссылками на файлы с кодом.


Какого хрена мне талдычат, что всё должно быть прозрачно и меньше связано, а сами пихают данные в скрытые хранилища и вводят неявные связи между проектами?

#10 
uscheswoi_82 старожил01.06.22 22:40
NEW 01.06.22 22:40 
в ответ AlexNek 01.06.22 21:29

А если пользователь захочет сделать кастомный интерфейс и на нескольких языках? У нас для гостиницы и ресторанов можно было визуально весь интерфейс настраивать - формы, меню, горячие клавиши, для этого сделали специальный инструмент, спомощью которого можно было создавать кастомный формы и отчёты, как это было в Visual FoxPro, и в Microsoft Access.

Если я кому-то отвечаю, это не значит что я ему симпатизирую, каждый остаётся при своём мнение
#11 
alex445 коренной житель02.06.22 00:33
02.06.22 00:33 
в ответ uscheswoi_82 01.06.22 22:40, Последний раз изменено 02.06.22 00:34 (alex445)

А какая разница? Для разных культур так же вытаскиваете из словарей по ключам нужное значение и присваиваете свойству. Просто атрибут это делает за вас - само присваивание. Но прописываете всё (класс со словарём, ключ) вы всё равно сами. В конечном счёте с атрибутом даже больше возни - сам атрибут ещё надо оформить.


К настраиваемому виду интерфейса атрибуты вообще не относятся, по-моему. Разве что вы через них как-то эти настройки реализуете? Ну так это явно не обязательный и не единственный путь.

#12 
7495 местный житель02.06.22 17:10
7495
NEW 02.06.22 17:10 
в ответ alex445 01.06.22 22:12
Какого хрена мне талдычат, что всё должно быть прозрачно и меньше связано, а сами пихают данные в скрытые хранилища и вводят неявные связи между проектами?

я не сишарпист и даже не программист, но могу предположить два варианта:


1. Кто программировал усложнял не специально, он просто по другому не мог, так научили работать с "паттернами",

Гдето читал, китайцы так программируют, заучивают код целыми страницами, и потом решают проблему - подходящим куском.


2. Кто программировал усложнял СПЕЦИАЛЬНО.

Вот ты сколько раз уже залетаешь с шашкой наголо - все дураки, ты Д'Артаньян? а потом разбираешься и признаёшь свою ошибку.

Теперь представь, тебе доверили доработать и обновить систему, ты лезешь и лепишь код простой как ситцевые трусы, документация, комментарии...

Что произойдёт? Если каждый школьник может понять и сопровождать - то спрашивается, зачем платить больше? Тебя выпнут и посадят практиканта,

А умные семизнаки как делают? Правильно, наваяют хитроумно, сам шеф не понимает, а семизнак такой - эта конструкция повысит производительность на 30 процентов!


И пофиг что функция вызывается раз в месяц, а код перелопачивать и понимать никто не будет, так семизнак остаётся при деле, и ещё идёт на повышение, незаменим ценный сотрудник. glass

Вопросы и Ответы - Программируем калькулятор пособий для беженцев вместе.
#13 
AlexNek патриот02.06.22 17:57
AlexNek
NEW 02.06.22 17:57 
в ответ alex445 01.06.22 21:51
Вот если бы это так и работало

Как это все реализуется вроде бы должно быть безразлично. Подключили либу и работаем.


А теперь скажите, зачем нужен валидатор StringLength, если я могу использовать контрол с ограничением по длине строки?

Ну давайте в проперти грид засуньте подобный контрол, да и контролов на все случаи не наберёте, когда нужно может и это, а может и это еще проверить, да и пользователю сообщить об ошибке.


По мне, лучше иметь такую модель

Опять таки в каком то частом случае. А если иметь хотя-бы пяток полей с мин и мах, то получаем уже 15 пропертей которые нужно все не забыть использовать правильно.


не надо никаких сообщений об ошибках

Очень даже надо. Вот помню где то было поле с 1000 символами. Так во первых, знаешь это заранее, а во вторых видно сколько еще можно дописать.


и сериализуется тоже без проблем

Это вообще клёво. Записали с ограничением в 16 лет, а после изменили на 18, и вдруг оказывается, что после чтения будет всё равно на 16

#14 
alex445 коренной житель02.06.22 20:41
NEW 02.06.22 20:41 
в ответ 7495 02.06.22 17:10, Последний раз изменено 02.06.22 20:41 (alex445)
И пофиг что функция вызывается раз в месяц, а код перелопачивать и понимать никто не будет, так семизнак остаётся при деле, и ещё идёт на повышение, незаменим ценный сотрудник.

Вы правы пожалуй. Только так семь знаков и домик во Флориде и зарабатываются.

#15 
alex445 коренной житель02.06.22 20:43
NEW 02.06.22 20:43 
в ответ AlexNek 02.06.22 17:57, Последний раз изменено 02.06.22 20:45 (alex445)
да и пользователю сообщить об ошибке.

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


И я говорю не про контролы на все случаи жизни, а на 99% этих случаев. NumericUpDown и всякие маскированные текстбоксы с прочими ограничениями - давно уже само собой разумеющееся для любого набора контролов должно быть. У нормальных поставщиков контролов оно уже давно так и есть.

#16 
alex445 коренной житель02.06.22 20:46
NEW 02.06.22 20:46 
в ответ AlexNek 02.06.22 17:57
и сериализуется тоже без проблем

Это вообще клёво. Записали с ограничением в 16 лет, а после изменили на 18, и вдруг оказывается, что после чтения будет всё равно на 16

Не понял.

#17 
AlexNek патриот02.06.22 22:47
AlexNek
NEW 02.06.22 22:47 
в ответ alex445 02.06.22 20:43
пользователю не нужно будет сообщать об ошибке

Не во всех случаях это хорошо.


У нормальных поставщиков контролов оно уже давно так и есть.

А кто сказал что МС - нормальный поставщик контролов? Они делают только то что нужно лично им.

#18 
AlexNek патриот02.06.22 22:50
AlexNek
02.06.22 22:50 
в ответ alex445 02.06.22 20:46
Не понял.

Хочется ведь сериализовывать данные с полями валидации.

Сохранили вот данные пользователя, а затем восстановили. А между этим в программе ограничения изменились.

#19 
alex445 коренной житель03.06.22 00:32
NEW 03.06.22 00:32 
в ответ AlexNek 02.06.22 22:50, Последний раз изменено 03.06.22 00:33 (alex445)
Хочется ведь сериализовывать данные с полями валидации.
Сохранили вот данные пользователя, а затем восстановили. А между этим в программе ограничения изменились.

Если такая проблема, то не сериализуйте поля валидации. Или при десериализации полей валидации ранее сериализованных объектов считайте их устаревшими относительно данных в текущей запущенной сборке.


Возможно, что для атрибутов просто свой механизм сериализации будет - не пересекающийся с механизмом для простых данных. Т.е. отдельно сохраняем модель, и отдельно - данные атрибутов этой модели.


Суть-то в том, что когда сериализовать не надо, то проблем нет в любом случае, а когда надо, то с атрибутами приходится возиться. А как их сериализовать? А обычно создаёшь модель для сериализации, куда атрибуты выводишь в виде обычных свойств, или пишешь для сериализатора всякие конвертеры, которые делают примерно то же самое - вытаскивают данные из атрибутов и сериализуют их.


И да, пачка свойств выглядит читаемее, чем пачка атрибутов с кучей параметров.

#20 
1 2 3 4 5 6 7 8 9 все