Zoo-Blog-Web-App
ASP net.core MVC -Web -App mit MSSQL EF6 Identity und Boostrap
Hauptkatalogseite, auf der Sie scrollen und Animel auswählen können, um zu erkunden und zu kommentieren

Um
Diese ASP.NetCore -Web -App zeigt das MVC -Muster mit einer Layout -Ansicht und enthält Navigationsleiste und Renderend -Körper mit verschiedenen Ansichten und Controllern. Ich habe eine Ansichtskomponente eingeschlossen, um die Animelle zu halten, die Divs häufiger zwischen Seiten erforschen, und mit Boostrap Libary gestylt
Modell (Entity Framwork Core)
MSSQL -Diagramm

Mein Modell enthält 3 Objekte: Kategorie, Tier und Kommentar. Ich gab jedem von ihnen mehrere Propetrien und Anpassungsvalidierungsattribute, einschließlich Regex -Muster, Datentyp benutzerdefinierte Messenge -Fehler usw. Ich habe zwei benutzerdefinierte Vlidationsattribute erstellt:
- Geburtsdatum, um das Tier zu validieren, ist weniger als 150 Jahre und wurde am aktuellen Tag oder früher geboren
- Datei -Validator überprüft, ob der Inhaltstyp der Datei das Wort "Bild" und die Größe der auf 10 MB beschränkten Datei enthalten
| öffentliche Klasse ImageFilevalidationAttribute : validationAttribute |
| { |
| const int max_file_size = 10 * 1024 * 1024 ; // 10mb |
| geschützte Überschreibung validationResult ? Isvalid ( Objekt ? Wert , ValidationContext ValidationContext ) |
| { |
| if ( Wert ist iFormFile -Datei ! = Standard ) |
| { |
| if ( Datei . Länge > max_file_size ) |
| Neue ValidationResult zurückgeben ( "Die Größe dieser Datei ist größer als die 10 -MB -Begrenzung" ) ; |
| if ( Datei . contentType . Enthält ( "Bild" ) ) |
| Return ValidationResult . Erfolg ; |
| Neue ValidationResult zurückgeben ( "Dies ist keine gültige Datei" ) ; |
| } |
| Neue ValidationResult zurückgeben ( "Bitte geben Sie eine gültige Bilddatei ein" ) ; |
| } |
| } |
Um die Kategorien zu generieren, habe ich ein Enum -Helfer -Modell erstellt, das nicht in die Datenbank zugeordnet ist, aber ich benutze, um Aprit -Auswahl -Tag zu generieren
Das Modellprojekt enthält auch die Datenzugriffsschicht generische Basis -Repsoitory -Klasse für jede Entität, die ID vom Typ GUID und ein Bild von Bildformating ist, die mir helfen, die Bilderdateien als Bytes -Array zu speichern und das Bild wieder auf der Client -Seite zu generieren
| öffentliches statisches Byte [ ] Formfiletobytearray ( Formfile Formalfile ) |
| { |
| if ( formFile ! = null ) |
| { |
| MemoryStream memorStream = new memorystream ( ) ; |
| Formalfile . OpenReadstream ( ) . CopyTo ( MemoryStream ) ; |
| byte [ ] rawdata = memoryStream . ToArray ( ) ; |
| kehren Sie Rawdata zurück ; |
| } |
| Versäumnis zurückgeben ; |
| } |
| öffentliches statisches String -Formatrawdatatoimage ( Byte [ ] ImagesFiledata ) |
| { |
| if ( ImagesFiledata ! = NULL ) |
| Return "Data: Image; Base64," + konvertieren . Tobase64String ( ImagesFiledata ) ; |
| Versäumnis zurückgeben ; |
| } |
| |
| } |
Sicht
Ich habe mehrere Ansichten für die Controller, eine Ansichtskomponente und 3 nützliche Teilansicht für Layoutstile und -Skripte und Navigationsleiste erstellt. Mit der NAV -Leiste wird zwischen den verschiedenen Ansichten und Aktionen navigiert
Die Navigationsleiste der App

Die Manager -Ansicht von Erstellen und Update enthält eine Vannila JS -Validierung des Dateityps und der IT -Größe, um zu verhindern, dass der Browser einen Fehler auslöst
| DateiInput . AddEventListener ( "Change" , function ( ) { |
| lass ateaSize = this . Dateien [ 0 ] . Größe ; |
| if ( this . Dateien [ 0 ] === undefined || FileSize === undefined ) { |
| Das . setCustomvality ( "Bitte eingeben" ) ; |
| Das . ReportVality ( ) ; |
| zurückkehren ; |
| } |
| if ( filesize > maxFileSize ) { |
| Das . setCustomvality ( "Diese Datei ist größer als 10 MB" ) ; |
| Das . value = "" ; |
| Das . ReportVality ( ) ; |
| zurückkehren ; |
| } |
| if ( ! validFileType ( this . Dateien [ 0 ] ) ) { |
| Das . setCustomvality ( "Dies ist keine Bilddatei" ) ; |
| Das . value = "" ; |
| Das . ReportVality ( ) ; |
| zurückkehren ; |
| } |
| if ( FileSize < maxFileSize ) { |
| Das . setCustomvality ( "" ) ; |
| Das . ReportVality ( ) ; |
| } |
| } ) ; |
Controller
Dieses Projekt enthält 4 Controller:
- Home - Zeigen Sie die beiden am meisten kommentierten Tiere aus
- Manager - Umgang mit dem CRUD -Betrieb auf den Tieren Daten
- Katalog - Sehen Sie sich die Tiere im Blog an und können Sie sie nach Kategorie sortieren
- Animel -Daten - Erforschen Sie die Details der Tiere und erlauben Sie dem Benutzer, einen Kommentar zu hinterlassen. In der Kommentarveröffentlichung wird die API -Fetch -API verwendet, um zu verhindern, dass die Seite jedes Mal, wenn der Benutzer einen Kommentar veröffentlicht.
| asynchrische Funktion addCompment ( Ereignis ) { |
| lass comment = {{ |
| Kommentar : undefiniert , |
| Inhalt : ContentTextArea . Wert , |
| Animelid : id , |
| } |
| Kommentar = JSON . Stringify ( Kommentar ) ; |
| Warten Sie auf Fetch ( ` $ { BaseUrl } /index` , { |
| Methode : 'Post' , |
| Körper : Kommentar , |
| Header : { |
| "Inhaltstyp" : "Anwendung/JSON" |
| } |
| } ) . dann ( ( ) => { getAllComments ( ) ; } ) ; |
| } |
Hallo Weltkommentar

Authentifizierung && Autorisierung (Identität)
Ich habe Identitätsnuget und separaten Kontext verwendet, um Benutzer in meiner Webanwendung zu authentifizieren und zu autorisieren, und registrieren und loggen in Handels nach Modellhelfern mit dem Namen LoginModel und SignUpModel in der App zu 3 Arten von Benutzern "admin", "Benutzer" ADN Anonymous. Die Manager-Rolle kann den Manager-Controller nutzen und verfügt über einen Anker-Nav-Link zur Erstellung und Aktualisierung. Jeder unterschriebene Benutzer kann Tiere in der Anwendung (einschließlich Managern) kommentieren. Anonymous Benutzer können nur durch die Animels -Katalogseite scrollen oder sich registrieren/anmelden.
Aktion registrieren:
| [ Httppost ] |
| [ Validateantiforgerytoken ] |
| öffentliche asynchronisierte Aufgabe <IActionResult> Register ( SignUpModel -Benutzer ) |
| { |
| if ( modelState . isvalid ) |
| { |
| IdentityUser iduser = new identityUser |
| { |
| Benutzername = Benutzer . Benutzername , |
| PhonNumber = Benutzer . PhoneNumber , |
| E -Mail = Benutzer . E-Mail |
| } ; |
| var createResult = warte _userManager . Createasync ( Iduser , Benutzer . Passwort ) ; |
| var addrole = warte _userManager . AddToroleAsync ( Iduser , "Benutzer" ) ; |
| if ( createuresult . erfolgreich ) |
| { |
| var signuPresult = warte _signinManager . PasswordSigninaSync ( Benutzer . Benutzername , Benutzer . Passwort , false , false ) ; |
| if ( significsult . erfolgreich ) |
| { |
| return reutirectToAction ( "Index" , "Home" ) ; |
| } |
| return login ( ) ; |
| } |
| } |
| return view ( ) ; |
| } |
Unit -Tests
Diese Web -App -Lösung enthält ein Xunit -Testprojekt für die Überprüfung und Validierung der RepoSiroeyBase -Klasse für die Synchronisierungs- und Async -Methoden.
Testbeispiel:
| [ Test , Bedarfsread ] |
| öffentliche void findbyidasync ( ) |
| { |
| _categoryRepository ? . Create ( categoryTest ! ) ; |
| _AnimelRepository ? . Create ( animeltest ! ) ; |
| _ComentRepository ? . Create ( commentest ! ) ; |
| |
| Aufgabe <Timals> Animelfound = _AnimelRepository ! . FindByIdasync ( animeltest !. Id ) ; |
| Animfund . Fortsetzung ( _ => { assert . Das ( AnimFound . Ergebnis , is . Equalto ( animeltest ) ) ; } ) ; |
| Aufgabe <Timals> AnimelnotFound = _animelRepository . FindByIdasync ( do_not_insret_animel !. Id ) ; |
| Animelnotfound . Fortsetzung ( _ => { assert . Das ( AnimFound . Ergebnis , ist . Null ) ; } ) ; |
| Aufgabe <Kommentare> commentFound = _CompommentRepository ! . FindByIdasync ( commentest !. Commentid ) ; |
| Kommentar . Fortsetzung ( _ => { assert . Das ( commentFound . Ergebnis , is . Equalto ( commentest ) ) ; } ) ; |
| Task <Gategorie> categoryFound = _categoryRepository ! . FindByIdasync ( CategoryTest !. CategoryId ) ; |
| Kategorie . Fortsetzung ( _ => { assert . Das ( Kategoriefund . Ergebnis , is . Equalto ( categoryTest ) ) ; } ) ; |
| } |