The ASP.NET Core WishList Application is designed to allow users to create their own wishlists, and other users to mark that they are buying those items in such a way the owner of the wish list isn't able to see, while other users are able to see. This application is designed using the Model View Controller design pattern.
Note: This project is the second in a series of four projects, this project will cover taking an existing ASP.NET Core web application and changing it from only supporting one user to being able to support many users with authentication and basic security.
If you want to use Visual Studio (highly recommended) follow the following steps:
- If you already have Visual Studio installed make sure you have .Net Core installed by running the "Visual Studio Installer" and making sure ".NET Core cross-platform development" is checked
- If you need to install visual studio download it at https://www.microsoft.com/net/download/ (If you're using Windows you'll want to check "ASP.NET" and ".NET Core cross-platform development" on the workloads screen during installation.)
- Open the .sln file in visual studio
- To run the application simply press the Start Debug button (green arrow) or press F5
- If you're using Visual Studio on Windows, to run tests open the Test menu, click Run, then click on Run all tests (results will show up in the Test Explorer)
- If you're using Visual Studio on macOS, to run tests, select the WishListTests Project, then go to the Run menu, then click on Run Unit Tests (results will show up in the Unit Tests panel)
(Note: All tests should fail at this point, this is by design. As you progress through the projects more and more tests will pass. All tests should pass upon completion of the project.)
If you would rather use something other than Visual Studio
- Install the .Net Core SDK from https://www.microsoft.com/net/download/core once that installation completes you're ready to roll!
- To run the application go into the WishList project folder and type dotnet run
- To run the tests go into the WishListTests project folder and type dotnet test
- Add support for user authentication
- Create functionality for creating and logging in
- Expand Wishlist functionality to support multiple users
- Implement several basic security practices (validation tokens, user verification, authentication, etc)
Note: this isn't the only way to accomplish this, however; this is what the project's tests are expecting. Implementing this in a different way will likely result in being marked as incomplete / incorrect.
-  Adding Authentication to our existing ASP.NET Core wishlist app
-  Configure Authentication
- Note : We created the model ApplicationUserthat inheritsIdentityUserfor you! (This was done to allow us to more accurately test your code through out this project)
-  Replace ApplicationDbContext's inheritance ofDbContexttoIdentityDbContext<ApplicationUser>(you will need to addusingdirectives forMicrosoft.AspNetCore.Identity.EntityFrameworkCoreandusing WishList.Models)
-  In Startup.cs'sConfigureServicesmethod callAddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();onservices(you will need to addusingdirectives forMicrosoft.AspNetCore.Identityandusing WishList.Models)
-  In Startup.cs'sConfiguremethod Beforeapp.UseMvcWithDefaultRoute();callUseAuthenticationonapp.
 
- Note : We created the model 
-  Create AccountController-  Create new controller AccountControllerin theControllersfolder- The AccountControllerclass should have theAuthorizeattribute (you will need ausingdirective forMicrosoft.AspNetCore.Authorization)
- The AccountControllershould inherit theControllerclass (you will need ausingdirective forMicrosoft.AspNetCore.Mvc)
 
- The 
-  Create private fields in the AccountControllerclass- This should have a private readonly field of type UserManager<ApplicationUser>named_userManager(you will need ausingdirectives forWishList.ModelsandMicrosoft.AspNetCore.Identity)
- This should have a private readonly field of type SignInManager<ApplicationUser>named_signInManager
 
- This should have a private readonly field of type 
-  Create a constructor in the AccountControllerclass- This constructor should accept two parameters, the first of type UserManager<ApplicationUser>, the second of typesignInManager<ApplicationUser>
- This constructor should set each of the private readonly properties using the parameter of the same type
 
- This constructor should accept two parameters, the first of type 
 
-  Create new controller 
-  Create Register Functionality
-  Create RegisterViewModel class
- Inside the Models/AccountViewModelsfolder create a new modelRegisterViewModel(You will need to create the AccountViewModels folder)
- Create a StringProperty Email- Email should have the Required attribute (you will need to add a usingdirective forSystem.ComponentModel.DataAnnotations)
- Email should have the EmailAddress attribute
 
- Email should have the Required attribute (you will need to add a 
- Create a String Property Password- Passwordshould have the- Requiredattribute
- Passwordshould have a- StringLengthattribute of 100 with a- MinimumLengthof 8 characters
- Passwordshould have the- DataType.Passwordattribute
 
- Create a StringPropertyConfirmPassword- ConfirmPasswordshould have the- DataType.Passwordattribute
- ConfirmPasswordshould have the- Compareattribute with "Password"
 
 
- Inside the 
-  Create the Register View
- Inside the Views/Accountfolder add a new viewRegister(you will need to create theAccountfolder)
- Register.cshtmlshould have a model of- RegisterViewModel(You will need to include the namespace,- WishList.Models.AccountViewModels.RegisterViewModel)
- Add the following HTML to the view (we're providing this to save you from needing to type it all yourself)
<h3>Register New User</h3> <form> <div class="text-danger"></div> <div> <label></label> <input /> </div> <div> <label></label> <input /> </div> <div> <label></label> <input /> </div> <div> <button type="submit">Register User</button> </div> </form>
- Add an attribute asp-actionwith a value of"Register"to theformtag
- Add an attribute asp-validation-summarywith a value of"All"for thedivtag with an attributeclassof value"text-danger"
- Add an attribute asp-forwith a value of"Email"to both the firstlabelandinputtag
- Add an attribute asp-forwith a value of"Password"to both the secondlabelandinputtag
- Add an attribute asp-forwith a value of"ConfirmPassword"to both the thirdlabelandinputtag
 
- Inside the 
-  Create an HttpGetactionRegisterin theAccountControllerclass- This action should have the HttpGetattribute
- This action should have the AllowAnonymousattribute
- This action should have no parameters
- This action should return the Registerview.
 
- This action should have the 
-  Create an HttpPostactionRegisterin theAccountControllerclass- This action should have the HttpPostattribute
- This action should have the AllowAnonymousattribute
- This action should accept a parameter of type RegisterViewModel(you will need to add ausingdirective forWishList.Models.AccountViewModels)
- This action should return a RedirectToActiontoHomeController.Index
 
- This action should have the 
-  Update the HttpPostRegisteraction to check if theModelStateis valid - If not return theRegisterview with the model provided in the parameter as it's model
-  Update the HttpPostRegisteraction to create the new user using the_userManager.CreateAsyncmethod providing it a validApplicationUser(you will need to set theUserandEmailproperties to theEmailfrom theRegisterViewModel) and astringwhich you'll set the thePasswordproperty from theRegisterViewModel
-  Check the Resultproperty from theHttpPostRegister's theCreateAsynccall ifResult.Success- IfResult.Successisfalseforeach error inResult.ErrorsuseModelState.AddModelErrorto add an error with a the first parameter of"Password"and second with the value of the error'sDescriptionproperty. Then return theRegisterview with the model provided byRegister's the parameter.
 
-  Create RegisterViewModel class
-  Create Login / Logout Functionality
-  Create LoginViewModelclass in theModels\AccountViewModelsfolder- Create a StringProperty Email- Email should have the Required attribute
- Email should have the EmailAddress attribute
 
- Create a String Property Password- Passwordshould have the- Requiredattribute
- Passwordshould have the- DataType.Passwordattribute
 
 
- Create a 
-  Create a Login.cshtmlview in theViews/Accountfolder- Add the following HTML to the Loginview@model WishList.Models.AccountViewModels.LoginViewModel <h2>Log in</h2> <form asp-action="Login" method="post"> <div asp-validation-summary="All" class="text-danger"></div> <div> <label asp-for="Email"></label> <input asp-for="Email" /> <span asp-validation-for="Email"></span> </div> <div> <label asp-for="Password"></label> <input asp-for="Password" /> <span asp-validation-for="Password"></span> </div> <div> <button type="submit">Log in</button> </div> </form> <a asp-action="Register">Register new account</a>
 
- Add the following HTML to the 
-  Create an HttpGetactionLoginin theAccountController- This action should have the HttpGetattribute
- This action should have the AllowAnonymousattribute
- This action should have no parameters
- This action should return the Loginview.
 
- This action should have the 
-  Create an HttpPostactionLoginin theAccountController- This action should have the HttpPostattribute
- This action should have the AllowAnonymousattribute
- This action should have the ValidateAntiForgeryTokenattribute
- This action should have a return type of IActionResult
- This action should accept a parameter of type LoginViewModel
- This action should return a RedirectToActionto theHome.Indexaction.
 
- This action should have the 
-  Update HttpPostLoginto check if theModelStateis valid- If not return the Loginview with the model provided in the parameter as it's model
 
- If not return the 
-  Update HttpPostLoginto useSignInManager'sPasswordSignInAsyncmethod with the(string,string,bool,bool)signature to attempt to login the user (Note: you will need to check theResultproperty to see the results, passfalsefor the 3rd and 4th parameters)- if the SignInResultreturned byPasswordSignInAsync'sSucceededproperty isfalseuseModelState'sAddModelErrorwith a key ofstring.Emptyand anerrorMessageof"Invalid login attempt."
 
- if the 
-  CreateanHttpPostactionLogoutin theAccountController- This action should have the HttpPostattribute
- This action should have the ValidateAntiForgeryTokenattribute
- This action should have a return type of IActionResult
- This action should use SignInManager'sSignOutAsyncmethod
- This should return a RedirectToActionto theHome.Indexaction
 
- This action should have the 
 
-  Create 
-  Add Links to Index View
-  Add usingdirectives forMicrosoft.AspNetCore.IdentityandWishList.Modelsto the top ofIndex.cshtml
-  Add an injectdirective forSignInManager<ApplicationUser>with the nameSignInManagerafter theusingdirectives
-  Check if the user is signed in using the injected SignInManager'sIsSignedInmethod (provideUseras the arguement)- If IsSignedInreturnstrueprovide the following HTML<div> <form asp-action="Logout" asp-controller="Account" method="post"> <button type="submit">Logout</button> </form> </div>
- If IsSignedInreturnsfalseprovide the following HTML<div> <a asp-action="Register" asp-controller="Account" >Register</a> </div> <div> <a asp-action="Login" asp-controller="Account" >Log in</a> </div>
 
- If 
 
-  Add 
-  Create Relationship Between Item and ApplicationUser Models
-  Add a virtualproperty of typeApplicationUsernamedUserto theItemmodel
-  Add a virtualproperty of typeICollection<Item>namedItemsto theApplicationUsermodel (you will need to add ausingdirective forSystem.Collections.Generic)
 
-  Add a 
-  Update ItemController actions to consider user
-  Add the Authorizeattribute to theItemControllerclass (you will need to add ausingdirective forMicrosoft.AspNetCore.Authorization)
-  Add a new privatereadonlyfield of typeUserManager<ApplicationUser>named_userManager
-  Update the ItemController's constructor to accept a second parameter of typeUserManager<ApplicationUser>and within the costructor set_userManagerto the providedUserManager<ApplicationUser>paramater.
-  Update the ItemController.Indexaction to only return items with associated with the currently logged in user.- Change the _context.Items.ToList();to include aWherecall that only gets items with the matchingUser.Id. (You can get the current logged in user usingUserManager.GetUserAsync(HttpContext.User))
 
- Change the 
-  Update the HttpPostItemController.Createaction to add the logged in User to theItem- Before adding the Item to set the UserId to the logged in user's Id (You can get the current logged in user using UserManager.GetUserAsync(HttpContext.User))
 
- Before adding the Item to set the UserId to the logged in user's Id (You can get the current logged in user using 
-  Update the ItemController.Deleteaction to prevent deleting items by anyone but the user who owns that item.- Before removing the Itemcheck that it is notnullif it isnullreturnNotFound
- After checking if Itemis null, but before removing theItemcheck te make sure the Item's User is the same as the logged in user, if not returnUnauthorized
 
- Before removing the 
 
-  Add the 
 
-  Configure Authentication
You've completed the tasks of this project, if you want to continue working on this project there will be additional projects added to the ASP.NET Core path that continue where this project left off adding more advanced views and models, as well as providing and consuming data as a web service.
Otherwise now is a good time to continue on the ASP.NET Core path to expand your understanding of the ASP.NET Core framework or take a look at the Microsoft Azure for Developers path as Azure is a common choice for hosting, scaling, and expanding the functionality of ASP.NET Core applications.