Skip to content

itayG98/Zoo-Catalog-App

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Monolith Zoo-Blog web app

Asp Net.Core MVC web app using MSSQL Docker image EF7 , Identity and Boostrap

This web application is built using Asp.Net Core MVC and utilizes an MSSQL Docker image with Entity Framework 7, Identity, and Bootstrap. The app allows users to scroll through and choose animals to explore and leave comments.

Main catalog where you can scroll choose animel and comment

About

The app demonstrates the use of the MVC pattern and including:

  • Asp.NetCore MVC server which is animel catalog web application
  • MSSQL server runs on docker images from microsoft using this command :
    docker run -e "ACCEPT_EULA=Y" --name db --network petshop-bridge -e "MSSQL_SA_PASSWORD=1234ABCD@" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-CU14-ubuntu-20.04
  • netwrok bridge called db-bridge

This app includes Docker-file and Docker-Compose which works with images that i already published

application Server :

docker pull itayg98/zoo-app:1.2

The DB :

docker pull itayg98/zoo-db:1.2
It is very important to add an apropriate connection string using the MSSQL containers name , port and add TCP :

"ConnectionStrings": {
"DefaultConnectionString": "Server=tcp:db,1433;Initial Catalog=Zoo;Persist Security Info=False;User ID=sa;Password=1234ABCD@;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;",
"IdentityUsersConnectionString": "Server=tcp:db,1433;Initial Catalog=ZooIdentity;Persist Security Info=False;User ID=sa;Password=1234ABCD@;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;"
}

Docker-Compose.yml file

version: '3.3'
services:
app:
container_name: app
image: itayg98/zoo-app:1.2
restart: always
depends_on:
- db
ports:
- "3000:80"
- "3001:433"
networks:
- db-bridge
db:
container_name: db
environment:
ACCEPT_EULA : Y
MSSQL_SA_PASSWORD : 1234ABCD@
image: itayg98/zoo-db:1.2
restart: always
ports:
- "1433:1433"
networks:
- db-bridge
networks:
db-bridge: {}

Model (Entity Framwork Core)

MSSQL Diagram

My model contain 3 objects : Category ,Animal and Comment. I gave each of them several propetries and fitting validation attributes including Regex patterns, Data type custom messege errors etc.. I created two custom Vlidation Attributes:

  1. Birthdate to validate the animal is less than 150 years and was born in the current day or earlier
  2. File validator to check wether if the file's content Type include the word "Image" and the size of the file limited to 10MB

public class ImageFileValidationAttribute : ValidationAttribute
{
const int Max_File_Size = 10 * 1024 * 1024; // 10MB
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (value is IFormFile file != default)
{
if (file.Length > Max_File_Size)
return new ValidationResult("This file's size is bigger than the 10MB limitation");
if (file.ContentType.Contains("image"))
return ValidationResult.Success;
return new ValidationResult("This is not a valid file ");
}
return new ValidationResult("Please enter a valid image file");
}
}

In order to generate the categories i made an Enum helper model which is not mapped in to the DataBase but i use to generate apropriate select tag

The model project contains also the data access layer Generic base Repsoitory class for each entity whom id is of type Guid and one service of image formating which help me to save the images files as bytes array and generate the image back on the client side

public static byte[] FormFileToByteArray(FormFile formFile)
{
if (formFile != null)
{
MemoryStream memoryStream = new MemoryStream();
formFile.OpenReadStream().CopyTo(memoryStream);
byte[] rawData= memoryStream.ToArray();
return rawData;
}
return default;
}
public static string FormatRawDataToImage(byte[] imagesFileData)
{
if (imagesFileData != null)
return "data:image;base64," + Convert.ToBase64String(imagesFileData);
return default;
}
}

View

I've created several views for the controllers, one view component and 3 usefull partial view for layout styles and scripts and nav bar The nav bar is used to navigate between the diffrent views and actions

The app's nav bar

The manager view of Create and update contain a vannila JS validation of the file type and it size in order to prevent the browser to throw an error

fileInput.addEventListener("change", function () {
let fileSize = this.files[0].size;
if (this.files[0] === undefined || fileSize === undefined) {
this.setCustomValidity("Please enter file");
this.reportValidity();
return;
}
if (fileSize > maxFileSize) {
this.setCustomValidity("This file is greater than 10mb");
this.value = "";
this.reportValidity();
return;
}
if (!validFileType(this.files[0])) {
this.setCustomValidity("This is not image file");
this.value = "";
this.reportValidity();
return;
}
if (fileSize < maxFileSize) {
this.setCustomValidity("");
this.reportValidity();
}
});

Controllers

This project contain 4 controllers :

  1. Home - displaying the two most commented animals
  2. Manager - Handling the CRUD operation on the animals data
  3. Catalog - view the animals in the blog and can sort them by category
  4. Animel Data - Explore the animals details and allow the user to leave a comment. The comment posting uses Fetch api in order to prevent the page to relload each time the user post a comment.

async function addComment(event) {
let comment = {
CommentId: undefined,
Content: contentTextArea.value,
AnimalID: id,
};
comment = JSON.stringify(comment);
await fetch(`${BaseUrl}/Index`, {
method: "POST",
body: comment,
headers: {
"content-type": "application/json",
},
}).then(() => {
getAllComments();
});
}

Hello world comment

Authentication && Authorization (Identity)

I used Identity Nuget and seperate context in order to authenticate and authorize users in my web application and registering and loging in handels by model helpers named LoginModel and SignUpModel In the app there are 3 types of users "Admin" , "User" adn Anonymous . The manager role can use the Manager controller and has anchor nav-link to creation and update . every signed user can comment on animals in the application (including managers). Anonymous user can only scroll through the animels catalog page or Register/Log In.

Registering action :

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(SignUpModel user)
{
if (ModelState.IsValid)
{
IdentityUser IDuser = new IdentityUser
{
UserName = user.Username,
PhoneNumber = user.PhoneNumber,
Email = user.Email
};
var createResult = await _userManager.CreateAsync(IDuser, user.Password);
var addRole = await _userManager.AddToRoleAsync(IDuser, "User");
if (createResult.Succeeded)
{
var signUpResult = await _signInManager.PasswordSignInAsync(user.Username, user.Password, false, false);
if (signUpResult.Succeeded)
{
return RedirectToAction("Index", "Home");
}
return Login();
}
}
return View();
}

Unit Testing

This web app solution includes one Xunit project of testing for the repository layer checking and validating the ReposiroeyBase class for both sync and async methods .

Test example :

[Test, RequiresThread]
public void FindByIdAsync()
{
_categoryRepository?.Create(categoryTest!);
_animelRepository?.Create(animelTest!);
_commentRepository?.Create(commentTest!);
Task<Animal> animelFound = _animelRepository!.FindByIDAsync(animelTest!.ID);
animelFound.ContinueWith(_ => { Assert.That(animelFound.Result, Is.EqualTo(animelTest)); });
Task<Animal> animelNotFound = _animelRepository.FindByIDAsync(Do_Not_Insret_Animel!.ID);
animelNotFound.ContinueWith(_ => { Assert.That(animelFound.Result, Is.Null); });
Task<Comment> commentFound = _commentRepository!.FindByIDAsync(commentTest!.CommentId);
commentFound.ContinueWith(_ => { Assert.That(commentFound.Result, Is.EqualTo(commentTest)); });
Task<Category> categoryFound = _categoryRepository!.FindByIDAsync(categoryTest!.CategoryID);
categoryFound.ContinueWith(_ => { Assert.That(categoryFound.Result, Is.EqualTo(categoryTest)); });
}

About

Asp Net.Core MVC web app using MSSQL Dockerfile Docker-Compose EF7 and Identity | Include Xunit

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages