Приложение зоопарка
ASP Net.core MVC Web App с использованием MSSQL EF6 Identity и Boostrap
Основная страница каталога, где вы можете прокрутить и выбрать анимел, чтобы исследовать и прокомментировать

О
Это веб -приложение ASP.NetCore демонстрирует шаблон MVC с одним представлением макета содержит навигационную плату и корпус рендеринга с разными представлениями и контроллерами. Я включил один компонент для просмотра, чтобы анимели изучали DIVS чаще между страницами и стилизованием с использованием Boostrap Libary
Модель (ядро предприятия Framwork)
Диаграмма MSSQL

Моя модель содержит 3 объекта: категория, животное и комментарий. Я дал каждому из них несколько атрибутов проверки пропасти и подгонки, включая шаблоны режима, тип данных пользовательские ошибки Messege и т. Д. Я создал два пользовательских атрибута Vlidation:
- Дата рождения для проверки животного составляет менее 150 лет и родилась в текущий день или ранее
- Валидатор файла, чтобы проверить, если тип содержимого файла включает слово «изображение» и размер файла, ограниченный 10 МБ.
| Public Class ImageFileValidationAttribute : ValidationAttribute |
| { |
| const int max_file_size = 10 * 1024 * 1024 ; // 10 МБ |
| Защищенная проверка валидации ? Isvalid ( объект ? Value , ValidationContext ValidationContext ) |
| { |
| if ( значение iformfile file ! = по умолчанию ) |
| { |
| if ( file . Length > max_file_size ) |
| вернуть New ValidationResult ( «Размер этого файла больше, чем ограничение 10 МБ» ) ; |
| if ( file . ContentType . Содержит ( "Image" ) ) |
| вернуть валидацию . Успех ; |
| вернуть New ValidationResult ( «Это недопустимый файл» ) ; |
| } |
| вернуть New ValidationResult ( «Пожалуйста, введите действительный файл изображения» ) ; |
| } |
| } |
Чтобы генерировать категории, я сделала вспомогательную модель Enum, которая не сопоставлена в базу данных, но я использую для генерации апроприированного тега Select
Проект модели содержит также класс общего уровня доступа к данным общий базовый репсотерий для каждого объекта, который имеет идентификатор типа, и одна услуга формирования изображений, которые помогают мне сохранить файлы изображений в качестве массива байтов и сгенерировать изображение на стороне клиента
| Общественный статический байт [ ] formfiletobytearray ( formfile formfile ) |
| { |
| if ( formfile ! = null ) |
| { |
| MemoryStream MemoryStream = new MemoryStream ( ) ; |
| Formfile . OpenReadStream ( ) . Copyto ( memoreStream ) ; |
| byte [ ] rawdata = memorystream . Toarray ( ) ; |
| вернуть Rawdata ; |
| } |
| вернуть по умолчанию ; |
| } |
| Общественная статическая строка FormatrawDatataTatoImage ( Byte [ ] Imagesfiledata ) |
| { |
| if ( imagesfiledata ! = null ) |
| Вернуть "Данные: Image; Base64", + конвертировать . Tobase64String ( ImagesfileData ) ; |
| вернуть по умолчанию ; |
| } |
| |
| } |
Вид
Я создал несколько представлений для контроллеров, одного компонента представления и 3 полезного частичного представления для стилей макета, сценариев и навигационной панели. Навигация используется для навигации между разными представлениями и действиями
Батончик навигации приложения

Просмотр менеджера создания и обновления содержит валидацию типа файла Vannila JS и его размер, чтобы не допустить ошибки.
| FileInput . addEventListener ( "change" , function ( ) { |
| Пусть файлы лярнится = это . файлы [ 0 ] . размер ; |
| if ( this . files [ 0 ] === не определено |
| этот . SetCustomVality ( «Пожалуйста, введите файл» ) ; |
| этот . reportVality ( ) ; |
| возвращаться ; |
| } |
| if ( filesize > maxfilesize ) { |
| этот . SetCustomVality ( «Этот файл превышает 10 МБ» ) ; |
| этот . value = "" ; |
| этот . reportVality ( ) ; |
| возвращаться ; |
| } |
| if ( ! validfileType ( this . files [ 0 ] ) ) { |
| этот . SetCustomVality ( «Это не файл изображения» ) ; |
| этот . value = "" ; |
| этот . reportVality ( ) ; |
| возвращаться ; |
| } |
| if ( filesize < maxfilesize ) { |
| этот . SetCustomVality ( "" " ) ; |
| этот . reportVality ( ) ; |
| } |
| } ) ; |
Контроллеры
Этот проект содержит 4 контроллера:
- Главная - показать двух наиболее прокомментированных животных
- Менеджер - Обработка операции CRUD по данным животных
- КАТАЛОГ - Посмотреть животных в блоге и может сортировать их по категории
- Данные Animel - исследуйте детали животных и позвольте пользователю оставить комментарий. В публикации комментариев используется API Fetch для предотвращения перезагрузки страницы каждый раз, когда пользователь публикует комментарий.
| Async function addComment ( event ) { |
| Пусть комментарий = { |
| Комментарий : не определен , |
| Контент : ContentTextarea . ценить , |
| Animelid : id , |
| } |
| Комментарий = JSON . stringify ( comment ) ; |
| ждать fetch ( ` $ { baseurl } /index` , { |
| Метод : 'post' , |
| тело : комментарий , |
| Заголовки : { |
| "Контент-тип" : "Приложение/json" |
| } |
| } ) . затем ( ( ) => { getallComments ( ) ; } ) ; |
| } |
Привет, мир комментарий

Аутентификация && Авторизация (Identity)
Я использовал идентификацию Nuget и отдельный контекст, чтобы аутентифицировать и авторизовать пользователей в моем веб -приложении, а также регистрацию и регистрацию в руках по моделям с именем loginmodel и invicupmodel в приложении есть 3 типа пользователей «администратор», «пользователь» Adn Anonymous. Роль менеджера может использовать контроллер менеджера и имеет привязку NAV-Link для создания и обновления. Каждый подписанный пользователь может комментировать животных в приложении (включая менеджеров). Анонимный пользователь может прокручивать только страницу каталога анимелей или регистрацию/войти в систему.
Регистрация действия:
| [ Httppost ] |
| [ ValidateAntiforgyToken ] |
| Public Async Task <IaCtionResult> регистр ( пользователь signupModel ) |
| { |
| if ( modelstate . isvalid ) |
| { |
| IdentityUser идузер = новый идентификатор |
| { |
| Имя пользователя = пользователь . Имя пользователя , |
| Phonenumber = пользователь . Номер телефона , |
| Электронная почта = пользователь . Электронная почта |
| } ; |
| var createresult = wait _usermanager . CreateEasync ( идуман , пользователь . Пароль ) ; |
| var addrole = wait _usermanager . AddToroLeasync ( идузер , «пользователь» ) ; |
| if ( seateresult . |
| { |
| var signupresult = wait _signinmanager . PasswordSignInasync ( пользователь . Имя пользователя , пользователь . Пароль , false , false ) ; |
| if ( signupresult . преуспел ) |
| { |
| return redirecttoaction ( «index» , «Home» ) ; |
| } |
| return login ( ) ; |
| } |
| } |
| return view ( ) ; |
| } |
ЕДИНЦИОННЫЕ Тестирование
Это решение для веб -приложения включает в себя один проект XUNIT тестирования для проверки уровня репозитория и проверки класса Reposiroeybase как для синхронизации, так и для асинхронных методов.
Пример теста:
| [ Тест , repteSthread ] |
| public void findbyIdasync ( ) |
| { |
| _categoryRepository ? Полем Создать ( CategoryStest ! ) ; |
| _animelRepository ? Полем Создать ( animeltest ! ) ; |
| _commentRepository ? Полем Создать ( CommentTest ! ) ; |
| |
| Задача <Animal> animelfound = _animelRepository ! Полем FindByIdasync ( animeltest !. Id ) ; |
| анимация . Продолжить ( _ => { assert . That ( animelfound . Результат , is . Evalto ( animeltest ) ) ; } ) ; |
| Задача <Animal> animelnotFound = _animelRepository . FindByIdasync ( do_not_insret_animel !. Id ) ; |
| animelnotfound . Продолжить ( _ => { assert . That ( animelfound . Результат , is . Null ) ; } ) ; |
| Задача < Комментарий > Комментарий FOUND = _commentRepository ! Полем FindByIdasync ( CommentTest !. Комментарий ) ; |
| Комментарий . Продолжить with ( _ => { assert . That ( commentfound . Result , is . Evalto ( commenttest ) ) ; } ) ; |
| Задача < Категория > CategoryFound = _CategoryRepository ! Полем FindByIdasync ( CategoryTest ! .. CategoryId ) ; |
| Категория . Продолжить ( _ = > { assert . Что ( категория . |
| } |