Exercise: BooksPlus
Turn a new ASP.NET Core MVC project into a small bookstore website for BooksPlus, with featured books, a list, details, search and a form that adds a book, and run tests that request every page.
Journeyman · ASP.NET Core · Razor · C# · Updated
The BooksPlus bookstore wants its first website. The data access is ready, from a DAO much like the ones you wrote in Exercise: Connecting an App. The pages are yours to build: controllers, views and forms.
Before you start
The tests start your website and read your own BooksPlus database, so SQL Server must be running, and BooksPlus created. If you haven't created it yet, run BooksPlus.sql from the course's sample databases in SSMS.
Get the exercise code
Open this lesson's GitHub repository, github.com/ask-codey/exercise-booksplus, also linked from the Exercise box beside the lesson. Click Code, then Download ZIP, and unzip it into your bootcamp folder. Or clone it with Git. Then open BooksPlusWeb.slnx in Visual Studio.
| Folder | What's in it |
|---|---|
BooksPlusWeb |
The project dotnet new mvc makes, with Bootstrap 5.3 loaded from a CDN. HomeController and its views are still the template's. |
BooksPlusWeb/Models |
Book and Category, ready to use |
BooksPlusWeb/Data/BookDao.cs |
Every query the site needs, ready to use |
BooksPlusWeb.Tests |
Tests that request your pages the way a browser would |
BookDao has these methods; the comment above each says what it returns:
| Method | Returns |
|---|---|
GetFeatured(int count) |
The newest books, newest first |
GetAll() |
Every book, by title |
GetById(int bookId) |
One book, or null |
SearchByTitle(string text) |
The books whose titles contain the text |
Add(Book book) |
Adds a book and returns its new BookId |
GetCategories() |
Every category, by name |
What to do
- Home page. Change
HomeController.Indexto pass the five newest books to its view. Under a Featured Books heading, show them in a Bootstrap carousel: each slide shows the title, the price and a link to the book's details page. - Books. Add a
BooksController./Booksshows every book in a table, each title a link to its details page. - Details.
/Books/Details/{id}shows one book: its title, publish date, price as money ($36.58) and summary. A book that doesn't exist is Not Found. - Search.
/Books/Search?title=SQLshows a search box that sends a GET (an input namedtitle, so the action's parameter isstring? title), and under it the books whose titles contain the text. - Add a book.
/Books/Createshows a form for a new book's title, category (a drop-down of every category), publish date, price and summary. Posting it adds the book and redirects to the new book's details page. - Menu. Add Books, Search and Add a Book links to the menu in
_Layout.cshtml.
Run the website with Ctrl+F5, and try every page in the browser as you go. Then run the tests with Test > Run All Tests (or dotnet test): each page you finish turns its tests green.
Hints
- The connection string. Take
IConfigurationin each controller's constructor, and create the DAO withnew BookDao(configuration.GetConnectionString("BooksPlus")!). - One step at a time. Write the action, run it, see the "view was not found" error, add the view, run it again.
- The carousel. Bootstrap's documentation has a carousel to copy. Give the first slide the
activeclass:class="carousel-item @(i == 0 ? "active" : "")"in a@forloop does it. - Money and dates.
@book.Price?.ToString("C")and@book.PublishDate.ToString("MMMM d, yyyy"). - Links with tag helpers:
asp-controller="Books" asp-action="Details" asp-route-id="@book.BookId". - The form.
asp-foron every field, a POST form tag helper,[HttpGet]and[HttpPost]on the twoCreateactions, and[ValidateAntiForgeryToken]on the POST. A date field:<input asp-for="PublishDate" type="date">. - The test that adds a book deletes it again afterward, so your database stays as it was.
When you're done
Every test is green, and every page works in the browser. Try the Add a Book form with an empty title: what happens? Add a ModelState.IsValid check, as in Model Binding a Form, so the form comes back instead.
Submit your exercise
The exercise is how you finish this lesson. When your work is done, put it on GitHub in a repo of your own, then submit that repo's address here.
On GitHub, click +, then New repository. Name it (for example
exercise-booksplus), choose Public, and click Create repository. Leave out the README: your folder already has one.In a terminal in your exercise folder (Git Bash on Windows), send your work to your new repo. If you downloaded the ZIP:
git init -b main git add . git commit -m "My solution" git remote add origin https://github.com/your-name/exercise-booksplus.git git push -u origin mainIf you cloned the starter instead, point your copy at your own repo, then commit and push:
git remote set-url origin https://github.com/your-name/exercise-booksplus.git git add . git commit -m "My solution" git push -u origin mainPaste your repo's address, such as
https://github.com/your-name/exercise-booksplus, into Submit your exercise on this page. The site checks that the repo is public and holds your commits, and then the lesson is complete.
Changed something after you submitted? Push it, and submit again: your latest submission is the one that counts.
So what
That's a real database-backed website: a home page, a list, details, search and a form, each a controller action and a view. Every MVC app is more of the same, and in ASP.NET Core MVC in Depth you'll add routing, validation and sign-in to it.
Key terms
- Controller
- Action Method
- Tag Helper
- Model Binding