0

In ASP.NET MVC, I have a BooksController which provides functionality for viewing books. I want www.mydomain.com/books to return a list of all my books (and it's associated "All books" html page), while www.domain.com/books/c-sharp-for-dummies to fetch all information for the "C# for dummies" book (again, with it's "Single book" html page).

It's trivial to create an Index method with a bookName parameter.

public class BooksController
{
     public ActionResult Index(string bookName)
     {
         if (string.IsNullOrEmpty(bookName)
         {
           //return all books here
         }
         else
         {
            //return single book here 
         }
     }
}

Index has it's associated Index.cshtml view page, but then I'd have to do a Razor check in the view to ascertain whether to load the "all books" HTML/CSS, or "single book" HTML/CSS - it's like the view contains two pages in one, which I find counter-intuitive.

What is a good (or even conventional) approach to such scenarios? Do I just create two cshtml files, one for "all books" and one for "single book", and just return the appropriate view depending on whether a bookName parameter was provided or not?

public class BooksController
{
     public ActionResult Index(string bookName)
     {
         if (string.IsNullOrEmpty(bookName)
         {
           //return all books viewmodel and related  view             
         }
         else
         {
            //return single book viewmodel and related view 
         }
     }
}
Heimi
  • 126
  • 1
  • 12
globetrotter
  • 997
  • 1
  • 16
  • 42
  • 2
    And `Index` method is typically used for displaying a collection of items associated with a controller, and a separate `Details(string bookName)` method is used for displaying the details of a single item –  Nov 24 '17 at 21:56
  • I would default the view with All books data and have a partial view loaded async to overwrite that data when a book is chosen – Lotok Nov 24 '17 at 21:58
  • Two views (and optionally two actions) would be a more common approach than a single view. – mjwills Nov 24 '17 at 22:00
  • @StephenMuecke thanks - if we assume that I didn't want `/details/` as part of my URL (let's say `/books` for all books and `/books/{bookId}/{bookName}` for a single book) - how would you approach that? I can't think of a "better" solution that the one proposed by @Shyju in his answer. – globetrotter Nov 24 '17 at 22:08
  • Shyju's answer does show how to do that (using attribute routing although you can also just defines routes in your `RouteConfig` file as well). You would just use `[Route("books/{bookId}/{bookName}")]` if you want the ID in the route as well (but that suggest you might want slug routing as per [this answer](https://stackoverflow.com/questions/30349412/how-to-implement-url-rewriting-similar-to-so/30363600#30363600) –  Nov 24 '17 at 22:15

1 Answers1

3

You should create 2 separate action methods in your controller. One for returning the view with all the books and one to return the details of a single book.

You can define routing definition in such a way, so that the request comes for yourSite/books, it will be handled by the index action and yourSite/books/somebookname, it will be handled by the Details action method. Here is how you will do it with attribute routing.

public class BooksController : Controller
{
    [Route("books")]
    public ActionResult Index()
    {
        // to do : Get all the books and pass it to the view.
        return View();
    }
    [Route("books/{bookName}")]
    public ActionResult Details(string bookName)
    {
       // to do : Get single book using the bookName parameter
       // and pass that to the view.
       return View();
    }
}

Now in your index.cshtml view, you can display all the books and in the Details.cshtml view, you can display the details of a specific book.

Shyju
  • 214,206
  • 104
  • 411
  • 497
  • thanks @Shyju, does that mean that I would have to define `Route` on top of each method? Can a similar effect be achieved using `RouteConfig` instead? – globetrotter Nov 24 '17 at 22:03
  • Yes. You can achieve the same with conventional routing as well (check the same link). But IMHO, attribute routing is more readable – Shyju Nov 24 '17 at 22:03