Skip to content

Asp Net.Core MVC web app using MSSQL as database and EF6 and Identity | Include Xunit

Notifications You must be signed in to change notification settings

itayG98/Zoo-Blog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

58 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Zoo-Blog web app

Asp Net.Core MVC web app using MSSQL EF6 Identity and Boostrap

Main catalog page where you can scroll and choose animel to explore and comment

About

This Asp.NetCore web app demonstrates MVC pattern with one Layout view contains nav bar and renderend body with difrrent views and controllers. I included one View-Component in order to keep the animels exploring divs more common between pages and styled using boostrap libary

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,
AnimelID: 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)); });
}

Releases

No releases published

Packages

No packages published

Languages