- Notifications
You must be signed in to change notification settings - Fork0
BloodShop/pet-shop
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Asp.Net Core MVC web appplication using mssql, ef6, docker, jquery, sass, CORS, restAPI, socket, hubs & signalR, vanilla js, bootstrap library
Main catalog page where you can scroll and choose animel to explore and comment
pulling images to your local device:$dockerpullbloodshop/petshopapp:1.0 #https://hub.docker.com/repository/docker/bloodshop/petshopapp$dockerpullbloodshop/petshopdb:1.0 #https://hub.docker.com/repository/docker/bloodshop/petshopdb$docker-composeup-d
version:'3.3'services:db:image:bloodshop/petshopdb:1.0restart:alwaysapp:depends_on:-dbimage:bloodshop/petshopapp:1.0ports:-"3000:80"-"3001:433"networks:-db-bridgerestart:always
Lines 15 to 17 inbcf9df3
builder.Services.InstallerServices( | |
builder.Configuration, | |
typeof(IServiceInstaller).Assembly); |
publicclass InfrastuctureServiceInstaller :IServiceInstaller{publicvoidInstall(IServiceCollectionservices,IConfigurationconfiguration){services.AddTransient<IRepository,PetRepository>();stringconnectionString=configuration["ConnectionStrings:DefaultConnection"];services.AddDatabaseDeveloperPageExceptionFilter();services.AddControllersWithViews().AddJsonOptions(options=>{options.JsonSerializerOptions.PropertyNamingPolicy=null;});services.AddDbContext<ICallCenterContext,PetDbContext>(options=>options.UseLazyLoadingProxies().UseSqlServer(connectionString));}}publicinterfaceIServiceInstaller{voidInstall(IServiceCollectionservices,IConfigurationconfiguration);}
- ViewModels & models
Models - pure models which are used in our database and repositories- Animal
- Category
- Comment
- AddAnimalViewModel
- AddCategoryViewModel
- AddCommentViewModel
- EditAnimalViewModel
- LoginViewModel
- ManageUsersViewModel
- RegisterViewModel
- SearchAnimalViewModel
examlpe viewmodel binded with form/view
ViewmodelViewpet-shop/ViewModels/SearchAnimalViewModel.cs
Lines 5 to 11 inbca1335
publicclassSearchAnimalViewModel { [Required] [MaxLength(25,ErrorMessage="{0} cannot exceed 25 characters.")] [RegularExpression(@"^[a-zA-Z\s]+$")] publicstringContent{get;set;}=null!; } @{varsearchModel=newSearchAnimalViewModel();}
pet-shop/Views/Shared/_Layout.cshtml
Lines 87 to 91 inbca1335
<formenctype="multipart/form-data"method="post"class="d-flex"asp-controller="Home"asp-action="Search"> @*asp-validation-for="Content"*@ <spanasp-validation-for="@searchModel.Content"class="text-danger"></span> @*asp-for="Content"*@ <inputname="text"asp-for="@searchModel.Content"class=" form-control me-2"type="search"placeholder="Search"aria-label="Search"> <buttonclass="btn btn-outline-success"type="submit">Search</button> </form> - Initialize ASP.NET Identity You can initialize ASP.NET Identity when the application starts. Since ASP.NET Identity is Entity Framework based in this sample, you can create DatabaseInitializer which is configured to get called each time the app starts.Please look in Program.csThis code shows the following
Lines 16 to 29 inbca1335
builder.Services.AddIdentity<IdentityUser,IdentityRole>(options=> { options.Password.RequiredUniqueChars=0; options.Password.RequireNonAlphanumeric=false; options.Password.RequireLowercase=false; options.Password.RequireUppercase=false; options.Password.RequireDigit=false; }).AddEntityFrameworkStores<PetDbContext>(); builder.Services.AddControllersWithViews(); builder.Services.Configure<PasswordHasherOptions>(options=> options.CompatibilityMode=PasswordHasherCompatibilityMode.IdentityV2 ); builder.Services.ConfigureApplicationCookie(config=>config.LoginPath="/Login"); - Create user
- Create user with password
- Create Roles
- Add Users to Roles
- Validation When you create a User using a username or password, the Identity system performs validation on the username and password, and the passwords are hashed before they are stored in the database. You can customize the validation by changing some of the properties of the validators such as Turn alphanumeric on/off, set minimum password length or you can write your own custom validators and register them with the Administrator. You can use the same approach for UserManager and RoleManager.
- Look at Controllers\AccountController.cs Default Action on how to tweak the default settings for the Validators
- Look at Models\DataAnnotations\ValidateFileAttribute.cs to see how you can implement the different validators
- Look at Controllers\AccountController.cs Cutomize Action on how you can use the custom validators with the Managers
pet-shop/Models/DataAnnotations/ValidateFileAttribute.cs
Lines 5 to 38 inbca1335
[AttributeUsage(AttributeTargets.Field|AttributeTargets.Property,AllowMultiple=false,Inherited=true)] publicclassValidateFileAttribute:ValidationAttribute { double_maxContent=1*1024*1024;//1 MB string[]_sAllowedExt=newstring[]{".jpg",".gif",".png",".jpeg",".jpeg2000"}; publicValidateFileAttribute(longmaxContent)=>_maxContent=maxContent; publicValidateFileAttribute(longmaxContent,paramsstring[]extentions) { _maxContent=maxContent; _sAllowedExt=extentions; } publicoverrideboolIsValid(object?value) { varfile=valueasIFormFile; if(file==null) returntrue; if(!_sAllowedExt.Contains(file.FileName.Substring(file.FileName.LastIndexOf('.')))) { ErrorMessage="Please upload Your Photo of type: "+string.Join(" / ",_sAllowedExt); returnfalse; } if(file.Length>_maxContent) { ErrorMessage="Your Photo is too large, maximum allowed size is : "+(_maxContent/1024).ToString()+"MB"; returnfalse; } returntrue; } - Register a user, Login Click Register and see the code in AccountController.cs and Register Action. Click Login and see the code in AccountController.cs and Login Action.
- Basic Role Management Do Create, Update, List and Delete Roles. Only Users In Role Admin can access this page. This uses the [Authorize] on the controller.
- Basic User Management Do Create, Update, List and Delete Users. Assign a Role to a User. Only Users In Role Admin can access this page. This uses the [Authorize] on the controller.
pet-shop/Hubs/CallCenterHub.cs
Lines 6 to 19 in7948044
publicclassCallCenterHub:Hub<ICallCenterHub> | |
{ | |
publicasyncTaskNewCallReceivedAsync(CallnewCall)=> | |
awaitClients.Group("CallCenters").NewCallReceivedAsync(newCall); | |
publicasyncTaskCallDeletedAsync()=> | |
awaitClients.Group("CallCenters").CallDeletedAsync(); | |
publicasyncTaskCallEditedAsync(CalleditCall)=> | |
awaitClients.Group("CallCenters").CallEditedAsync(editCall); | |
publicasyncTaskJoinCallCenters()=> | |
awaitGroups.AddToGroupAsync(Context.ConnectionId,"CallCenters"); | |
} |
!!Importent!! -- Providing the CallsController that Hub implementing the `ICallCenterHub` interface inorder to get the dependencies (Dependency Injection).
$(()=>{LoadCallsData();let$theWarning=$("#theWarning");$theWarning.hide();varconnection=newsignalR.HubConnectionBuilder().withUrl("/callcenter").build();connection.start().then(()=>connection.invoke("JoinCallCenters")).catch(err=>console.error(err.toString()));connection.on("NewCallReceivedAsync",()=>LoadCallsData());connection.on("CallDeletedAsync",()=>LoadCallsData());connection.on("CallEditedAsync",()=>LoadCallsData());functionLoadCallsData(){vartr='';$.ajax({url:'/Calls/GetCalls',method:'GET',success:(result)=>{$.each(result,(k,v)=>{tr+=`<tr> <td>${v.Name}</td> <td>${v.Email}</td> <td>${moment(v.CallTime).format("llll")}</td> <td> <a href="../Calls/Details?id=${v.Id}" data-id="${v.Id}">Details</a> <a href="../Calls/Edit?id=${v.Id}" data-id="${v.Id}">Edit</a> <a href="../Calls/Delete?id=${v.Id}" data-id="${v.Id}">Delete</a> </td> </tr>`;})$("#logBody").html(tr);},error:(error)=>{$theWarning.text("Failed to get calls...");$theWarning.show();console.log(error)}});}});
pet-shop/wwwroot/js/theme-mode.js
Lines 1 to 33 inbca1335
document.addEventListener('DOMContentLoaded',()=>{ | |
constbody=document.querySelector('body'); | |
constinputs=document.querySelectorAll('input'); | |
constcontainers=document.querySelectorAll('.container'); | |
constdropdown=document.querySelector('.dropdown-menu'); | |
constulss=document.querySelectorAll('li.list-group-item.d-flex.justify-content-between.align-items-start'); | |
constnavBar=document.querySelector('body>nav'); | |
constaas=document.querySelectorAll('body div.container-fluid a, form>button.nav-link.btn.btn-link.py-0').forEach(a=>{ | |
a.classList.toggle('text-light'); | |
}); | |
consttoggle=document.getElementById('toggle'); | |
toggle.onclick=function(){ | |
toggle.classList.toggle('active'); | |
body.classList.toggle('active'); | |
containers.forEach(e=>{ | |
e.classList.toggle('active'); | |
//let children = e.children; | |
//for (let i = 0; i < children.length; i++) { | |
// children[i].classList.toggle('active'); | |
}); | |
dropdown.classList.toggle('bg-dark'); | |
dropdown.querySelectorAll('a').forEach(a=>{ | |
a.classList.toggle('text-dark'); | |
}); | |
navBar.classList.toggle('bg-opacity-25'); | |
inputs.forEach(i=>{ | |
i.classList.toggle('bg-black'); | |
}); | |
ulss.forEach(li=>{ | |
li.classList.toggle('bg-dark'); | |
}); | |
}; | |
}); |