Курс. NET
Хорошая книга • ASP. NET MVC Framework • Гайдар Магдануров, Владимир Юнев
Хорошая книга • Предметноориентированное проектирование (DDD). Структуризация сложных программных систем • Эрик Эванс
Орг. вопросы • Включить камеру • Отметить присутствующих • След. Занятие – 16 июля (вторник)
Дом. задание • Реализовать приложение для CRUD с бизнесобъектами. Необходимо реализовать через тесты валидацию моделей, использовать ninject, использовать ORM. Для тестов необходимо реализовать замену сервиса на что-то другое.
Использование Ninject в ASP MVC
Io. C - Inversion of Control (инверсия управления) Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракции. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций. Суть - каждый компонент системы должен быть как можно более изолированным от других, не полагаясь в своей работе на детали конкретной реализации других компонентов. Следствие 1 – появление интерфейсов
Суть проблемы • Пусть есть задача интеграции с платежным шлюзом банка. • Пусть у нас есть 100 тестов, которые проверяют работу с платежным шлюзом и в среднем делают с ним 5 операций. • Тогда когда мы запускаем тесты идет маленькая DOS атака на шлюз – 500 обращений за 5 -10 секунд • Банк не доволен. • Если учесть, что в среднем тесты запускаются каждые 30 минут у 5 -6 разработчиков банк ОЧЕНЬ не доволен
Суть решения • В тестах заменить реализацию интерфейса взаимодействия с платежным шлюзом на «заглушку» (mock)
Решение ( «закат солнца в ручную)» • Выделяем интерфейс взаимодействия с платежным шлюзом • Делаем фабрику, которая возвращает экземпляр класса, который реализует интерфейс • Получаем экземпляры интерфейса только через фабрику
Минусы решения • Надо программировать • А что если одна заглушка зависит от другой, т. е. в параметрах конструктора есть интерфейс? • Решение – сделать жестокую рефлексию с использованием теории графов (при этом развести циклические зависимости)
Нормальное решение • Взять гугл • Поискать Io. C контейнер для. NET (их несколько) • Для примера использовать ninject
Что надо сделать, что бы использовать Ninject • Добавить ссылку на ninject • Перегрузить стандартную фабрику контроллеров • Инициализировать ninject • Добавить конструкторы серверов + в них в параметры добавить зависимости через интерфейс
Что такое приложение • Приложение – графический интерфейс над бизнес-логикой (с точки зрения пользователя). • А бизнес-логика принимает модели. А что делать, если модель не корректная? • Проверять корректность модели
MVC – валидация моделей
Валидация модели • По хорошему в любом методе, который принимает модель первой строкой должно быть • If (Model. State. Is. Valid == false) { – Обработка не корректного состояния модели • }
Возможности контроля валидности модели • 1) Атрибутивный – Атрибуты над свойствами – Соотнесение класса с атрибутами классумодели • 2) Программный • Но первый вопрос – как валидировать в тестах?
Валидация в тестах
Стандартные атрибуты валидации • [Required] – то, что поле обязательно • [Data. Type(Data. Type. Date)] – не получилось запустить • [Range(1, 100)] - в диапазоне от 1 до 100 • [String. Length(5)] – ограничение на размер строки • [Regular. Expression(@"^$? d+(. (d{2}))? $")] • [Display. Name("Price")] - не валидация
Что такое модель • Модель – некоторое отображение БД (или наоборот, если работать с «моделями предметной области» ) • В любом случае валидация связана напрямую или нет с добавлением в БД • Казалось бы с учетом того, что «классымапперы» генерируются автоматически, их хорошо использовать • (Вставка из презентации Model. Valid 2)
Валидация по сложной бизнеслогике • Интерфейс IValidatable. Object
Нечто промежуточное – по простой логике, но без реализации IValidatable. Object • Реализация пользовательского атрибута проверки
Для чего нужна валидация? • Для того, что бы быть уверенным, что пришедшие данные верны (вернее единообразная проверка) • Для того, что бы выводить пользователю сообщение об ошибке/ошибках • Клиентская валидация – блок кода на Java. Script, который позволяет делать часть проверки на клиенте ( «на грубые ошибки» ). Следует отметить, что клиентская валидация может быть отключена, поэтому это только дополнение к серверной валидации, а не замена.
Создание места для вывода ошибок • Перейти на Validation. Test в Home • Что получилось? • Создается два метода с одинаковым названием, но один из них POST • Если есть ошибка, то в Post методе идет возврат с той же самой ошибкой (следует заметить, что сообщения об ошибках к этому времени уже заполнятся) • Validation. Message - сообщение об ошибке
Включение Ajax валидации (клиентской) • В пред. примере было обращение на сервер, даже если имя было не заполнено. • Этого можно избежать (Home/Validation. Test) • Подключить jquery. validate. min. js и jquery. validate. unobtrusive. min. js • Проверить, что бы в конфиге было
Соотнесение валидационных атрибутов объектам БД
Куда поместить атрибуты валидации? • Первый вариант – в автогенерируемый код. Это будет работать. По первой перегенерации кода. • Второй вариант – за счет того, что генерируемый класс partial, вынести объявление свойства из автогенерируемого файла и там навесить на него атрибут. Но при следующей автогенерации появится два атрибута, что приведет к ошибке. • Все плохо
Решение проблемы • Использование атрибута Metadata. Type • Однако при Unit тестировании придется «слегка» покрутить что бы все заработало, попутно разобравшись, как это работает
Однотипные операции
Проблема (часть 1) • Есть заказчик, у него N баз данных. В каждой базе данных K таблиц. 10% из них «справочники» , поэтому с к ним операции CRUD не нужны. • Остается N*K*0. 9 таблиц, к которым нужны CRUD, при этом выборка часто не одна, а всех записей, по ID, по условию. Т. е. 6 операций – 3 операции чтения и удаления, обновления, создания
Проблема (часть 2) • Для выполнения одной операции надо 4 -6 строк дополнительного кода – открытие контекста, получение таблицы, добавления записи (для примера), сохранения изменений. • N*K*0. 9*6*5 строк дополнительного кода • В самой маленькой БД 20 таблиц – 600 строк кода и это для самой маленькой БД. А с учетом того, что есть базы данных с номером 20 общее количество «сэкономленого» кода большое.
Решение проблемы • Изучить автогенерируемый код • Вспомнить, что в. NET шаблоны намного лучше, чем в Java • Шаблонизировать все. • Выпить чая после шаблонизации и радоваться
Pre и post Build Event
Суть проблемы • Все программисты – люди. • Все ORM не имеют возможности контроля «актуальности» соответствия БД «без костылей» . • Хочется что бы ORM была всегда актуальна при Build
Суть решения • Генерация ORM через VS – на самом деле запуск специальной утилиты через интерфейс. • Все эти утилиты как правило входят в состав. NET • Надо что бы до каждого Build запускалась генерация ORM и тогда у нас всегда будет актуальный Build. • Любой проект в VS (csproj) имеет довольно простую структуру
Ограничения • По сути event – это скрипт со всеми проблемами в виде пробелов в именах файлах, русских букв и т. д. • Поэтому надо сделать скрипт из одной строки и в эту строку запихнуть какую-то логику • Поэтому придется еще написать приложение, которое будет лежать около проекта, запускаться автоматически и работать согласно нужной логике.
Пример использования • Подключение к БД хранится в конфиге, поэтому этим можно воспользоваться • Следует учитывать, что «строка подключения» в Entity содержит больше информации, чем надо, поэтому собственно строку подключения надо от туда вытащить • А для запуска приложения генерации ORM можно использовать bat файл, который можно создать в нашей программе. А после запуска нашей программы запустить bat файл • Так же существуют переменные, которые указывают на нужные данные • call "$(Project. Dir)getcs. Console. Application. exe" • call "$(Project. Dir)update_model. cmd" "$(Project. Dir)Entities"