Aplicación web de Blog-Blog
ASP Net.Core MVC Aplicación web utilizando MSSQL EF6 Identity and Boostrap
Página del catálogo principal donde puede desplazar y elegir Animel para explorar y comentar

Acerca de
Esta aplicación web ASP.netcore demuestra un patrón MVC con una vista de diseño contiene barra de navegación y cuerpo de renderizado con vistas y controladores diferentes. Incluí un componente de visión para mantener los animales explorando los divs más comunes entre páginas y el estilo usando boostrap Libary
Modelo (núcleo de marco de entidad)
Diagrama MSSQL

Mi modelo contiene 3 objetos: categoría, animal y comentarios. Le di a cada una de ellas varias propectias y atributos de validación de ajuste, incluidos patrones regex, tipos de datos, errores de messege personalizados, etc. Creé dos atributos de vlidación personalizados:
- La fecha de nacimiento para validar al animal es inferior a 150 años y nació en el día actual o antes
- Validador de archivo para verificar si el tipo de contenido del archivo incluye la palabra "imagen" y el tamaño del archivo limitado a 10mb
| clase pública ImageFeValidationAttribute : ValidationAttribute |
| { |
| const int max_file_size = 10 * 1024 * 1024 ; // 10 MB |
| ¿ Validación de anulación protegida ? ISVALID ( Object ? Value , ValidationContext ValidationContext ) |
| { |
| if ( el valor es el archivo iformfile ! = predeterminado ) |
| { |
| if ( archivo . longitud > max_file_size ) |
| devolver nuevo ValidationResult ( "El tamaño de este archivo es más grande que la limitación de 10 MB" ) ; |
| if ( file . ContentType . Contiene ( "Imagen" ) ) |
| Devolver ValidationResult . Éxito ; |
| devolver nuevo ValidationResult ( "Este no es un archivo válido" ) ; |
| } |
| devolver nuevo ValidationResult ( "Ingrese un archivo de imagen válido" ) ; |
| } |
| } |
Para generar las categorías, hice un modelo enum auxiliar que no está asignado a la base de datos, pero uso para generar etiqueta de selección apropiada
El proyecto Model contiene también la clase de Repsoitor de base genérica de la capa de acceso de datos para cada entidad que ID es de tipo GUID y un servicio de imagen que forman que me ayudan a guardar los archivos de imágenes como la matriz de bytes y generar la imagen en el lado del cliente
| Byte estático público [ ] FormfiletobyTearray ( Formfile Formfile ) |
| { |
| if ( formfile ! = null ) |
| { |
| MemoryStream MemoryStream = new MemoryStream ( ) ; |
| Formfile . OpenReadStream ( ) . Copyto ( MemoryStream ) ; |
| byte [ ] rawData = MemoryStream . ToArray ( ) ; |
| devolver rawdata ; |
| } |
| devolver el valor predeterminado ; |
| } |
| Cadena estática pública FormatrawDatatoimage ( byte [ ] Imagesfiledata ) |
| { |
| if ( ImageFileData ! = NULL ) |
| Devuelve "Datos: Imagen; Base64," + Convertir . TOBASE64String ( ImagesFileData ) ; |
| devolver el valor predeterminado ; |
| } |
| |
| } |
Vista
He creado varias vistas para los controladores, un componente de una visión y 3 vistas parciales útiles para estilos de diseño y scripts y barra de navegación La barra de navegación se usa para navegar entre las diferentes vistas y acciones
La barra de navegación de la aplicación

La vista del administrador de Crear y Actualizar contiene una validación de Vannila JS del tipo de archivo y su tamaño para evitar que el navegador arroje un error
| FileInput . addEventListener ( "Change" , function ( ) { |
| Deje que fileSize = esto . archivos [ 0 ] . tamaño ; |
| if ( this . archivos [ 0 ] === Undefined || filesize === Undefined ) { |
| este . setCustomValidity ( "Ingrese el archivo" ) ; |
| este . reportValidity ( ) ; |
| devolver ; |
| } |
| if ( filesize > maxfilesize ) { |
| este . setCustomValidity ( "Este archivo es mayor que 10 MB" ) ; |
| este . valor = "" ; |
| este . reportValidity ( ) ; |
| devolver ; |
| } |
| if ( ! ValidFileType ( this . archivos [ 0 ] ) ) { |
| este . setCustomValidity ( "Esto no es archivo de imagen" ) ; |
| este . valor = "" ; |
| este . reportValidity ( ) ; |
| devolver ; |
| } |
| if ( filesize < maxfilesize ) { |
| este . setCustomValidity ( "" ) ; |
| este . reportValidity ( ) ; |
| } |
| } ) ; |
Controladores
Este proyecto contiene 4 controladores:
- Inicio - Mostrar los dos animales más comentados
- Gerente - Manejo de la operación CRUD en los datos de los animales
- Catálogo: vea los animales en el blog y puede ordenarlos por categoría
- Datos de Animel: explore los detalles de los animales y permita al usuario dejar un comentario. La publicación de comentarios utiliza la API de Fetch para evitar que la página vuelva a llorar cada vez que el usuario publique un comentario.
| Async Función AddComment ( evento ) { |
| Let Comment = { |
| CommentId : indefinido , |
| Contenido : ContentTextArea . valor , |
| Animelid : ID , |
| } |
| Comentario = JSON . Stringify ( comentario ) ; |
| esperar fetch ( ` $ { BaseUrl } /index` , { |
| Método : 'Post' , |
| Cuerpo : Comentario , |
| Encabezados : { |
| "Tipo de contenido" : "Aplicación/JSON" |
| } |
| } ) . entonces ( ( ) => { getAllcomments ( ) ; } ) ; |
| } |
Hola comentario mundial

Autenticación && Autorización (identidad)
Utilicé Identity Nuget y contexto separado para autenticar y autorizar a los usuarios en mi aplicación web y registrar e iniciar sesión en Handels por ayudantes de modelos llamados LoginModel y SignupModel en la aplicación. Hay 3 tipos de usuarios "Administrador", "Usuario" anónimo. El rol del administrador puede usar el controlador del administrador y tiene un ancla navegación de navegación para la creación y actualización. Cada usuario firmado puede comentar sobre animales en la aplicación (incluidos los gerentes). El usuario anónimo solo puede desplazarse a través de la página del catálogo de Animels o registrarse/iniciar sesión.
Acción de registro:
| [ Httppost ] |
| [ ValidateAntiforgeryToken ] |
| Tarea de async pública <IaCactionResult> Register ( Usuario de SegidUsModel ) |
| { |
| if ( ModelState . IsValid ) |
| { |
| IdentityUser Iduser = New IdentityUser |
| { |
| Nombre de usuario = usuario . Nombre de usuario , |
| PhoneNumber = usuario . PhoneNumber , |
| Correo electrónico = usuario . Correo electrónico |
| } ; |
| var crereaterSult = espera _Usermanager . Createeasync ( iduser , usuario . Password ) ; |
| var addrole = espera _Usermanager . AddToroleAsync ( iduser , "usuario" ) ; |
| if ( crereaterSult . sucedido ) |
| { |
| var firmesult = espera _signinManager . PasswordSigninasync ( usuario . Nombre de usuario , usuario . Contraseña , falso , falso ) ; |
| if ( Signupresult . Sucedió ) |
| { |
| return redirectToAction ( "índice" , "inicio" ) ; |
| } |
| return login ( ) ; |
| } |
| } |
| Vista de retorno ( ) ; |
| } |
Prueba unitaria
Esta solución de aplicación web incluye un proyecto XUnit de prueba para la comprobación de la capa del repositorio y la validación de la clase ReposiroEyBase para los métodos de sincronización y async.
Ejemplo de prueba:
| [ Prueba , RequastEsthread ] |
| Public void findByidasync ( ) |
| { |
| _CategoryRepository ? . Crear ( ¡CategoryTest ! ) ; |
| _AnimelRepository ? . Crea ( ¡Animeltest ! ) ; |
| _commentRepository ? . Crear ( commenttest ! ) ; |
| |
| Tarea <MINIMA> ANIMELFOUND = _AnimElRepository ! . Findbyidasync ( ¡ Animeltest !. Id ) ; |
| animalfound . Continuar con ( _ => { afirmar . Que ( animelfound . Result , is . Igual a ( animeltest ) ) ; } ) ; |
| Tarea <MINIMY> AnimelNotFound = _AnimElRepository . FindByidasync ( do_not_insret_animel !. Id ) ; |
| animelnotfound . Continuar con ( _ => { afirmar . Que ( animelfound . Result , is . Null ) ; } ) ; |
| Tarea <MOMENT> CommentFound = _comMentRepository ! . Findbyidasync ( CommentTest !. CommentId ) ; |
| commentfound . Continuar con ( _ => { afirmar . Que ( commentfound . Result , is . Igualto ( commenttest ) ) ; } ) ; |
| Tarea <Category> CategyFound = _CategoryRepository ! . FindByidasync ( CategoryTest !. CategoryId ) ; |
| CategoryFound . Continuar con ( _ => { afirmar . Que ( categoryFound . Result , is . Equalto ( categoryTest ) ) ; } ) ; |
| } |