Taking ASP.NET Core MVC further

Now that you've seen the basics of how models, views, and controllers work together to provide a web application, let's look at some common scenarios, such as passing parameters and annotating models.

Passing parameters using a route value

Back in the HomeController class, add the following action method. It uses a class called defaultmodelbinder to automatically match the id passed in the route to the parameter named id in the method.

Note

Model binders are very powerful, and the default one does a lot for you. For advanced scenarios, you can create your own by implementing the IModelBinder interface, but that is beyond the scope of this book.

Inside the method, we check to see whether id is null, and if so, it returns a 404 status code and message. Otherwise, we can connect to the database and try to retrieve a product using the id variable. If we find a product, we pass it to a view; otherwise, we return a different 404 status code and message, as shown in the following code:

    public IActionResult ProductDetail(int? id) 
    { 
      if (!id.HasValue) 
      { 
        return NotFound("You must pass a product ID in the route, for
          example, /Home/ProductDetail/21"); 
      } 
      var model = db.Products.SingleOrDefault(p => p.ProductID == id); 
      if (model == null) 
      { 
        return NotFound($"A product with the ID of {id} was not
          found."); 
      } 
      return View(model); // pass model to view 
    } 

Now, we need to create a view for this request.

In Visual Studio 2017, inside the Views folder, right-click on Home and choose Add | New Item.... Choose MVC  View Page and name it ProductDetail.cshtml.

In Visual Studio Code, inside the Views/Home folder, add a new file named ProductDetail.cshtml.

Modify the contents, as shown in the following markup:

    @model Packt.CS7.Product 
    @{ 
      ViewData["Title"] = "Product Detail - " + Model.ProductName; 
    } 
    <h2>Product Detail</h2> 
    <hr /> 
    <div> 
      <dl class="dl-horizontal"> 
        <dt>Product ID</dt> 
        <dd>@Model.ProductID</dd> 
        <dt>Product Name</dt> 
        <dd>@Model.ProductName</dd> 
        <dt>Category ID</dt> 
        <dd>@Model.CategoryID</dd> 
        <dt>Unit Price</dt> 
        <dd>@Model.UnitPrice.Value.ToString("C")</dd> 
        <dt>Units In Stock</dt> 
        <dd>@Model.UnitsInStock</dd> 
      </dl> 
    </div> 

Run the web application, and when the home page appears with the list of products, click one of them, for example, product 2, Chang. The result should look something like the following screenshot:

Passing parameters using a route value

Passing parameters using a query string

In the HomeController class, import the Microsoft.EntityFrameworkCore namespace.

Add a new action method, as shown in the following code:

    public IActionResult ProductsThatCostMoreThan(decimal? price) 
    { 
      if (!price.HasValue) 
      { 
        return NotFound("You must pass a product price in the query
        string, for example, /Home/ProductsThatCostMoreThan?price=50"); 
      } 
      var model = db.Products.Include(p => p.Category).Include( 
        p => p.Supplier).Where(p => p.UnitPrice > price).ToArray(); 
      if (model.Count() == 0) 
      { 
        return NotFound($"No products cost more than {price:C}."); 
      } 
      ViewData["MaxPrice"] = price.Value.ToString("C"); 
      return View(model); // pass model to view 
    } 

Inside the Views/Home folder, add a new file named ProductsThatCostMoreThan.cshtml.

Modify the contents, as shown in the following code:

    @model IEnumerable<Packt.CS7.Product> 
    @{ 
      ViewData["Title"] =  
        "Products That Cost More Than " + ViewData["MaxPrice"]; 
    } 
    <h2>Products That Cost More Than @ViewData["MaxPrice"]</h2> 
    <table class="table"> 
      <tr> 
        <th> 
          @Html.DisplayNameFor( 
            model => model.Category.CategoryName) 
        </th> 
        <th> 
          @Html.DisplayNameFor(model => model.Supplier.CompanyName) 
        </th> 
        <th> 
          @Html.DisplayNameFor(model => model.ProductName) 
        </th> 
        <th> 
          @Html.DisplayNameFor(model => model.UnitPrice) 
        </th> 
        <th> 
          @Html.DisplayNameFor(model => model.UnitsInStock) 
        </th> 
      </tr> 
      @foreach (var item in Model) 
      { 
      <tr> 
        <td> 
          @Html.DisplayFor(modelItem => item.Category.CategoryName) 
        </td> 
        <td> 
          @Html.DisplayFor(modelItem => item.Supplier.CompanyName) 
        </td> 
        <td> 
          @Html.DisplayFor(modelItem => item.ProductName) 
        </td> 
        <td> 
          @Html.DisplayFor(modelItem => item.UnitPrice) 
        </td> 
        <td> 
          @Html.DisplayFor(modelItem => item.UnitsInStock) 
        </td> 
      </tr> 
      } 
    </table> 

In the Views/Home folder, open Index.cshtml and add the following div element at the bottom of the file. This will provide a form for the user to enter a price. The user can then click on a submit button to call the action method that shows only products that cost more than the entered price:

    <div class="row"> 
      <form asp-action="ProductsThatCostMoreThan" method="get"> 
        <input name="price" placeholder="Enter a product price" /> 
        <input type="submit" /> 
      </form> 
    </div> 

Run the web application, and on the home page, scroll down and enter a price in the form, for example, 50. Then, click Submit Query, as shown in the following screenshot:

Passing parameters using a query string

You will see a table of the products that cost more than the price that you entered, as shown in the following screenshot:

Passing parameters using a query string

Annotating models

You might have noted that the column headings in the table used the names of the properties by default. This means that if the property is multiple words, it won't have spaces. We can use data annotations to improve this.

In the Models folder, open the Product class.

Add the [Display] attributes before each property that you want to have a different label, for example, Product Name, Unit Price, Units in Stock, and so on, like this code example:

    [Display(Name = "Product Name")] 
    public string ProductName { get; set; } 

Apply the [Display] attribute to some of the properties of the other classes, especially Category's Category Name and Supplier's Company Name.

Restart the web application.

Enter a product price and click on Submit Query.

Note that the column headings now reflect the display attributes and not the property names, as shown in the following screenshot:

Annotating models

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.254.61