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

  1. Home page. Change HomeController.Index to 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.
  2. Books. Add a BooksController. /Books shows every book in a table, each title a link to its details page.
  3. 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.
  4. Search. /Books/Search?title=SQL shows a search box that sends a GET (an input named title, so the action's parameter is string? title), and under it the books whose titles contain the text.
  5. Add a book. /Books/Create shows 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.
  6. 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 IConfiguration in each controller's constructor, and create the DAO with new 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 active class: class="carousel-item @(i == 0 ? "active" : "")" in a @for loop 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-for on every field, a POST form tag helper, [HttpGet] and [HttpPost] on the two Create actions, 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.

  1. 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.

  2. 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 main
    

    If 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 main
    
  3. Paste 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

Related