January 2018 : Instructor-led Online Course in ASP.NET Core 2.0. Conducted by Bipin Joshi. Read more...
Registration for January 2018 batch of ASP.NET Core 2.0 instructor-led online course has already started. Conducted by Bipin Joshi. Register today ! Click here for more details.

Call Controller Actions using HttpClient

A few months ago I wrote Use ASP.NET MVC Controller as API wherein I discussed how MVC controller can be treated as a service. In that example the client used jQuery Ajax to call the controller actions. Some readers asked whether such actions can be called by HttpClient instead of jQuery. To that end this article explains how that can be donw.

The HttpClient component is typically used to call a Web API. The overall design of HttpClient component is geared towards REST services. Its methods such as GetAsync(), PostAsJsonAsync(), PutAsJsonAsync() and DeleteAsync() use the GET, POST, PUT and DELETE verbs to invoke the respective Web API actions. However, you can also use the HttpClient to call ordinary MVC actions. Of course, the actions to be called must follow the pattern as expected by the HttpClient.

This article shows how HttpClient can be used to invoke MVC actions. We will use the same CustomerController and Customer model explained at the above link. So, make sure you have the code ready before you go any further.

Since we wish to call the actions of CustomerController through HttpClient we need to add a reference to System.Net.Http assembly. This assembly provides the HttpClient component. Once referenced add HomeController to the Controllers folder. The HomeController will have six action methods:

  • Index()
  • Insert()
  • Insert(obj)
  • Update(id)
  • Update(obj)
  • Delete(id)

The Index() action will invoke the GetAll() action on the CustomerController to retrieve a List of Customer objects. The Insert() method will simply display a blank view to accept new Customer details. The Insert(obj) method calls the Post() action of the CustomerController and inserts the new customer into the database. The Update(id) method retrieves a Customer whose CustomerID is specified by calling GetByID() action of CustomerController. It then displays the existing Customer details for editing. The Update(obj) action calls the Put() action of the CustomerController and saves the modified Customer to the database. The Delete() action calls the Delete() action of the CustomerController and deletes a Customer.

The complete code of HomeController is given below:

public class HomeController : Controller
{
    private HttpClient client = new HttpClient();

    public HomeController()
    {
        client.BaseAddress = new Uri("http://localhost:49277");
        client.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/json"));
    }

    public ActionResult Index()
    {
        HttpResponseMessage response = client.
                     GetAsync("/Customer/GetAll").Result;
        List<Customer> data = response.Content.
                     ReadAsAsync<List<Customer>>().Result;
        return View(data);
    }

    public ActionResult Update(string id)
    {
        HttpResponseMessage response = client.
              GetAsync("/Customer/GetById" + $"/{id}").Result;
        Customer data = response.Content.
              ReadAsAsync<Customer>().Result;
        return View(data);
    }

    [HttpPost]
    public ActionResult Update(Customer obj)
    {
        if (ModelState.IsValid)
        {
            HttpResponseMessage response = client.
                PutAsJsonAsync<Customer>("/Customer/Put" + 
                $"/{obj.CustomerID}", obj).Result;
            TempData["Message"] = "Customer modified successfully!";
            return RedirectToAction("Index");
        }
        else
        {
            return View(obj);
        }
    }

    public ActionResult Insert()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Insert(Customer obj)
    {
        if (ModelState.IsValid)
        {
            HttpResponseMessage response = client.
               PostAsJsonAsync<Customer>
               ("/Customer/Post", obj).Result;
            TempData["Message"] = "Customer added successfully!";
            return RedirectToAction("Index");
        }
        else
        {
            return View(obj);
        }
    }


    public ActionResult Delete(string id)
    {
        HttpResponseMessage response = client.
               DeleteAsync("/Customer/Delete" + $"/{id}").Result;
        TempData["Message"] = "Customer deleted successfully!";
        return RedirectToAction("Index");
    }
}

When you call a Web API using HttpClient the URL is a REST based end point of the Web API (for example, http://localhost/api/customer). However, you can't use this pattern with the normal MVC controllers. If you observe the URLs in the above code you will find that they point to the actual action such as GetAll and Post. But apart from this difference the rest of the code is quite similar to the Web API based application.

You will also need to add three views - Index, Insert and Update. These views are given below:

Index view

@model List<MVCControllerViaHttpClient.Models.Customer>

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <h1>List of Customers</h1>
    <a href="/home/insert">Add New Customer</a>
    <br />
    @TempData["Message"]
    <br />
    <table border="1" cellpadding="10">
        @foreach (var item in Model)
        {
            <tr>
                <td>@item.CustomerID</td>
                <td>@item.CompanyName</td>
                <td><a href="/home/update/
                      @item.CustomerID">Edit</a></td>
                <td><a href="/home/delete/
                      @item.CustomerID">Delete</a></td>
            </tr>
        }
    </table>
</body>
</html>

Insert view

@model MVCControllerViaHttpClient.Models.Customer

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>New</title>
</head>
<body>
    <h1>Add New Customer</h1>

    @using (Html.BeginForm("insert", "home", FormMethod.Post))
    {
        <table border="1" cellpadding="10">
            <tr>
                <td>Customer ID :</td>
                <td>@Html.TextBoxFor(m => m.CustomerID)</td>
            </tr>
            <tr>
                <td>Company Name :</td>
                <td>@Html.TextBoxFor(m => m.CompanyName)</td>
            </tr>
            <tr>
                <td>Contact Name :</td>
                <td>@Html.TextBoxFor(m => m.ContactName)</td>
            </tr>
            <tr>
                <td>Country :</td>
                <td>@Html.TextBoxFor(m => m.Country)</td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="Insert" />
                </td>
            </tr>
        </table>
    }

    @ViewBag.Message
</body>
</html>

Update view

@model MVCControllerViaHttpClient.Models.Customer

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Edit</title>
</head>
<body>
    <h1>Edit Existing Customer</h1>

    @using (Html.BeginForm("update", "home", FormMethod.Post))
    {
        <table border="1" cellpadding="10">
            <tr>
                <td>Customer ID :</td>
                <td>@Html.TextBoxFor(m => m.CustomerID, 
                    new { @readonly="readonly" })</td>
            </tr>
            <tr>
                <td>Company Name :</td>
                <td>@Html.TextBoxFor(m => m.CompanyName)</td>
            </tr>
            <tr>
                <td>Contact Name :</td>
                <td>@Html.TextBoxFor(m => m.ContactName)</td>
            </tr>
            <tr>
                <td>Country :</td>
                <td>@Html.TextBoxFor(m => m.Country)</td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="Update" />
                </td>
            </tr>
        </table>
    }

    @ViewBag.Message
</body>
</html>

Make sure to change the model namespace in the @model directive of all the views as per your setup.

That's it! Run the Index view and test the insert, update and delete operations.

 


Bipin Joshi is a software consultant, an author and a yoga mentor having 22+ years of experience in software development. He also conducts online courses in ASP.NET MVC / Core and Design Patterns. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 24 August 2015


Tags : ASP.NET Data Access MVC C#