How to Consuming an API in ASP.NET Core

How to Consuming an API in ASP.NET Core

In the API Controllers project I Created an API in ASP.NET Core, now I have to consume the API. For this I have to create a new project. So create a new empty project by using the ASP.NET Core Web Application (.NET Core) template, and name the project as ‘APIConsume’.

Remember to select the framework as .NET Core and version as ASP.NET Core 2.0.

Models

Create ‘Models’ folder in your project root folder and add a class ‘Reservation.cs’ to define the following properties:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace APIConsume.Models
{
    public class Reservation
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string StartLocation { get; set; }
        public string EndLocation { get; set; }
    }
}

Bootstrap Package

I will need bootstrap package for giving the HTML of the View some proper layout. For this add bower.json file in your project root folder, and add a dependency of Bootstrap in it:

{
  "name": "asp.net",
  "private": true,
  "dependencies": {
    "bootstrap": "v4.1.3"
  }
}

When you save the bower file the Bootstrap package will automatically download to the ‘wwwroot/lib’ folder.

Layout

Create ‘Views’ folder in the root of the application and create ‘Shared’ folder inside the ‘Views’ folder.

Inside the ‘Shared’ folder create _Layout.cshtml file for all the Views that I will be making.

The Layout file’s code is given below:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link asp-href-include="lib/bootstrap/dist/css/*.min.css" rel="stylesheet" />
</head>
<body>
    <div class="container-fluid">
        @RenderBody()
    </div>
</body>
</html>

View Imports

Next, create _ViewImports.cshtml file inside the ‘Views’ folder and use it to setup the built-in tag helpers and import the model namespace:

@using APIControllers.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Startup Class

Make sure to add the necessary Configuration for the MVC to work. To do it add the following code to the Startup.cs class of your project:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace APIConsume
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseStatusCodePages();
            app.UseDeveloperExceptionPage();
            app.UseStaticFiles();
            app.UseMvcWithDefaultRoute();
        }
    }
}

Controller

Create Controllers folder in the root of your project and add a controller called ‘Home Controller’. In this controller I will be adding action method to invoke action method of the API.

Consuming API

In order to consume my API I have to keep my API Controllers Project in running mode. Just press the F5 key to the project.

Once it run it will show the message – ‘Status Code: 404; Not Found’ on the browser. That’s due to it having no ‘Home Controller’. Just ignore the message, it only means your project is in running state.

To make HTTP Request to the API I will be using a very popular HttpClient() class.

To Deserialize JSON to Reservation object I will use Newtonsoft.Json DLL.

Fetching all the Reservation Records from API

To fetch all the Reservation Records I have to make an HTTP GET Type of Request to my API.

So go to your Home Controller and replace the Index action method with the following version:

public async Task<IActionResult> Index()
{
    List<Reservation> reservationList = new List<Reservation>();
    using (var httpClient = new HttpClient())
    {
        using (var response = await httpClient.GetAsync("http://localhost:8888/api/Reservation"))
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            reservationList = JsonConvert.DeserializeObject<List<Reservation>>(apiResponse);
        }
    }
    return View(reservationList);
}

You will notice that this action is an asynchronous type that returns Task. This is because the HttpClient class makes only asynchronous request which can only happen from an asynchronous action.

I make the HTTP GET request to the API in the line – var response = await httpClient.GetAsync(“http://localhost:8888/api/Reservation”). Notice the URL of the API’s [HttpGet] action is supplied to the GetAsync() method.

Next, the API Response i.e. the return of the API’s [HttpGet] Action is fetched from the code – await response.Content.ReadAsStringAsync();, and stored in the ‘apiResponse’ variable.

You already know that the response is a JSON of all the Reservation objects. So I can easily Deserialize the JSON to a List object by using the Newtonsoft.Json DLL. The Code – reservationList = JsonConvert.DeserializeObject>(apiResponse); does this work.

The list of Reservation objects which are stored to the variable ‘reservationList’ is returned to the View as the Model.

Now you need to Index View, inside the ‘Views/Home’ folder, to show all the reservations in table manner. The Index View code is given below:

@model IEnumerable<Reservation>
@{ Layout = "_Layout"; ViewBag.Title = "All Reservations";}

<h2>All Reservations</h2>
<a asp-action="AddReservation" class="btn btn-sm btn-primary">Add Reservation</a>
<a asp-action="GetReservation" class="btn btn-sm btn-secondary">Get Reservation</a>
<table class="table table-sm table-striped table-bordered m-2">
    <thead><tr><th>ID</th><th>Name</th><th>Start Location</th><th>End Location</th><th>Update</th><th>Delete</th></tr></thead>
    <tbody>
        @foreach (var r in Model)
        {
            <tr>
                <td>@r.Id</td>
                <td>@r.Name</td>
                <td>@r.StartLocation</td>
                <td>@r.EndLocation</td>
                <td>
                    <a asp-action="UpdateReservation" asp-route-id="@r.Id"><img src="/icon/edit.png" /></a>
                </td>
                <td>
                    <form asp-action="DeleteReservation" method="post">
                        <input type="hidden" value="@r.Id" name="ReservationId" />
                        <input type="image" src="/icon/close.png" />
                    </form>
                </td>
            </tr>
        }
    </tbody>
</table>

This view is a strongly typed receiving an IEnumerable type as its model and uses a Razor foreach loop to populate a table with them.

Now run your API Consume project which will open a browser window to show all the Reservations that are sent by the API Controllers project. The image below shows all the Reservations:

all reservations from api

Ignore the ‘Add Reservation’ and ‘Get Reservation’ links, and the ‘Update’ and ‘Delete’ column. I will be adding there functionality later.

Fetching a Reservation Records by Id from API

In the Index View I have created a link to ‘Get Reservation, now I will all its functionality. So go to the Home Controller and add the GetReservation actions to it:

public ViewResult GetReservation() => View();

[HttpPost]
public async Task<IActionResult> GetReservation(int id)
{
    Reservation reservation = new Reservation();
    using (var httpClient = new HttpClient())
    {
        using (var response = await httpClient.GetAsync("http://localhost:8888/api/Reservation/" + id))
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            reservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
        }
    }
    return View(reservation);
}

The GET version of the Action simply returns to the View. While the POST version of the ‘GetReservation’ Action method makes an API request to fetch the Reservation record by providing an ‘Id’ to the API.

The API request is made by HttpClient class and the response, which is the Reservation object in JSON, is deserialized into the Reservation class object. The Reservation class object is then returned with the View as Model.

Next, add ‘GetReservation’ View inside the ‘Views/Home’ folder, and add the following code to it:

@model Reservation
@{ Layout = "_Layout"; ViewBag.Title = "Get Reservation by Id";}

<h2>Get Reservation by Id <a asp-action="Index" class="btn btn-sm btn-primary">Back</a></h2>
<form method="post">
    <div class="form-group">
        <label for="id">Id:</label>
        <input class="form-control" name="id" />
    </div>
    <div class="text-center panel-body">
        <button type="submit" class="btn btn-sm btn-primary">Get Reservation</button>
    </div>
</form>

@if (Model != null)
{	
    <h2>Reservation</h2>
    <table class="table table-sm table-striped table-bordered m-2">
        <thead><tr><th>ID</th><th>Name</th><th>Start Location</th><th>End Location</th></tr></thead>
        <tbody>
            <tr>
                <td>@Model.Id</td>
                <td>@Model.Name</td>
                <td>@Model.StartLocation</td>
                <td>@Model.EndLocation</td>
            </tr>
        </tbody>
    </table>
}

The View has a form which is where you put a Reservation ‘Id’, and on clicking the button the API request is made.

The expression – @if (Model != null) check if the Model is not null. In that case it will show the Model data (which is Reservation data fetched from the API).

Now run your project and on the main page click the ‘Get Reservation’ link. Add the Id as 3 and click the button. You will see the 3rd Reservation details will be shown, see the image below:

3rd reservation from api

Adding a Reservation Records through the API

To add a new Reservation you have to make a HTTP POST request to the API. This is done by the PostAsync() method of the HttpClient class.

So add the below actions to the Home controller:

public ViewResult AddReservation() => View();

[HttpPost]
public async Task<IActionResult> AddReservation(Reservation reservation)
{
    Reservation receivedReservation = new Reservation();
    using (var httpClient = new HttpClient())
    {
        StringContent content = new StringContent(JsonConvert.SerializeObject(reservation), Encoding.UTF8, "application/json");

        using (var response = await httpClient.PostAsync("http://localhost:8888/api/Reservation", content))
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
        }
    }
    return View(receivedReservation);
}

Since the API will need the new Reservation data in JSON format therefore I am serializing the Reservation class data into JSON and then converting it to a StringContent object:

StringContent content = new StringContent(JsonConvert.SerializeObject(reservation), Encoding.UTF8, "application/json");

The StringContent object is then added to the API request by adding it to the 2nd parameter of the PostAsync() method.

The API will add the New Reservation to its Repository and then send back that Reservation object, along with the Reservation Id, as the response.

The Response is deserialized into the Reservation class and is sent to the View as model.

Next, create the ‘AddReservation’ View inside the ‘Views/Home’ folder with the following code:

@model Reservation
@{ Layout = "_Layout"; ViewBag.Title = "Add a Reservation";}

<h2>Add a Reservation <a asp-action="Index" class="btn btn-sm btn-secondary">Back</a></h2>
<form asp-action="AddReservation" method="post">
    <div class="form-group">
        <label for="Name">Name:</label>
        <input class="form-control" name="Name" />
    </div>
    <div class="form-group">
        <label for="StartLocation">Start Location:</label>
        <input class="form-control" name="StartLocation" />
    </div>
    <div class="form-group">
        <label for="EndLocation">End Location:</label>
        <input class="form-control" name="EndLocation" />
    </div>
    <div class="text-center panel-body">
        <button type="submit" class="btn btn-sm btn-primary">Add</button>
    </div>
</form>

@if (Model != null)
{
    <h2>Reservation</h2>
    <table class="table table-sm table-striped table-bordered m-2">
        <thead><tr><th>ID</th><th>Name</th><th>Start Location</th><th>End Location</th></tr></thead>
        <tbody>
            <tr>
                <td>@Model.Id</td>
                <td>@Model.Name</td>
                <td>@Model.StartLocation</td>
                <td>@Model.EndLocation</td>
            </tr>
        </tbody>
    </table>
}

The View has a form for adding a new reservation.

The View Model is of type Reservation. Once the API response is received the Model gets that response, and I check if the Model is not null from the code – @if (Model != null).

If the Model contains the reservation details then it is shown in the HTML table.

You can now run your project and go to the URL – ‘/Home/AddReservation’. There fill the form and click the add button.

The reservation will be added and its details are shown in a table.

See the image below:

adding a reservation through api

Updating a Reservation Records through the API

Notice the Index view has an Update column, showing a pen icon, in the table which shows all the Reservations. If you click on the icon (see the below image) then you can update the clicked reservation record.

update icon in reservation table

Now I will create the Update Reservation functionality. For this add the following actions called ‘UpdateReservation’ to the Home controller:

public async Task<IActionResult> UpdateReservation(int id)
{
    Reservation reservation = new Reservation();
    using (var httpClient = new HttpClient())
    {
        using (var response = await httpClient.GetAsync("http://localhost:8888/api/Reservation/" + id))
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            reservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
        }
    }
    return View(reservation);
}

[HttpPost]
public async Task<IActionResult> UpdateReservation(Reservation reservation)
{
    Reservation receivedReservation = new Reservation();
    using (var httpClient = new HttpClient())
    {
        var content = new MultipartFormDataContent();
        content.Add(new StringContent(reservation.Id.ToString()), "Id");
        content.Add(new StringContent(reservation.Name), "Name");
        content.Add(new StringContent(reservation.StartLocation), "StartLocation");
        content.Add(new StringContent(reservation.EndLocation), "EndLocation");

        using (var response = await httpClient.PutAsync("http://localhost:8888/api/Reservation", content))
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            ViewBag.Result = "Success";
            receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
        }
    }
    return View(receivedReservation);
}

The Get Version simply makes a HTTP GET request to the API and provides it with the reservation Id. The API will send it the reservation record which is then binded to the Form on the ‘UpdateReservation’ View.

The Post version of this action does the Update of the Reservation object. The Reservation type argument which it has is binded from the form in the ‘UpdateReservation’ View.

Since the PUT method of the API has [FromForm] attribute in its argument therefore I am creating form data using the MultipartFormDataContent class which will be sent to the API as:

var content = new MultipartFormDataContent();
content.Add(new StringContent(reservation.Id.ToString()), "Id");
content.Add(new StringContent(reservation.Name), "Name");
content.Add(new StringContent(reservation.StartLocation), "StartLocation");
content.Add(new StringContent(reservation.EndLocation), "EndLocation");

The API updated the reservation record of the Id which is sent it through the Form data.

The API response which is the updated reservation record is shown on the ‘AddReservation’ View.

Now add the ‘UpdateReservation’ View inside the ‘Views/Home’ folder with the following code:

@model Reservation
@{ Layout = "_Layout"; ViewBag.Title = "Update a Reservation";}

<h2>Update a Reservation <a asp-action="Index" class="btn btn-sm btn-secondary">Back</a></h2>
<form method="post">
    <div class="form-group">
        <label asp-for="Id"></label>
        <input class="form-control" asp-for="Id" readonly/>
    </div>
    <div class="form-group">
        <label asp-for="Name"></label>
        <input class="form-control" asp-for="Name" />
    </div>
    <div class="form-group">
        <label asp-for="StartLocation"></label>
        <input class="form-control" asp-for="StartLocation" />
    </div>
    <div class="form-group">
        <label asp-for="EndLocation"></label>
        <input class="form-control" asp-for="EndLocation" />
    </div>
    <div class="text-center panel-body">
        <button type="submit" class="btn btn-sm btn-primary">Update</button>
    </div>
</form>

@if (ViewBag.Result == "Success")
{
    <h2>Reservation</h2>
    <table class="table table-sm table-striped table-bordered m-2">
        <thead><tr><th>ID</th><th>Name</th><th>Start Location</th><th>End Location</th></tr></thead>
        <tbody>
            <tr>
                <td>@Model.Id</td>
                <td>@Model.Name</td>
                <td>@Model.StartLocation</td>
                <td>@Model.EndLocation</td>
            </tr>
        </tbody>
    </table>
}

The View has a form to update a particular reservation record.

The API response is shown inside the HTML table.

Now it’s time to check the update functionality, so run your project and on the reservation table click on the pen icon against any of the reservation.

The reservation will be shown in a form which you can then update.

The below image shows that I have updated the 2nd reservation record’s start location to New York and end location to Barcelona.

update record through api

Updating a Reservation Record with PATCH through the API

To invoke the PATCH method of the API, I will have to use the HttpRequestMessage class to initialize 3 properties:

1. RequestUri – the URL to make the PATCH request.
2. Method – for specifying the HTTP method as PATCH.
3. Content – To specify the JSON, Encoding and media type.

In PATCH method I don’t have to send all the Reservation fields, I only have to send the fields that are need to change along with their new values. This makes the PATCH request light weight and more secure.

The JSON format which I will be using is given below. You can see I have use ‘replace’ for the ‘op’ argument, which specifies that I will be doing the update for the record. I will only be updating the Name and the StartLocation fields:

[
{ "op": "replace", "path": "Name", "value": "Ram"},
{ "op": "replace", "path": "StartLocation", "value": "Moscow"}
]

To make the PATCH request I will use the SendAsync method of the HttpClient class.

So go to the Home Controller and add the 2 actions called ‘UpdateReservationPatch’:

public async Task<IActionResult> UpdateReservationPatch(int id)
{
    Reservation reservation = new Reservation();
    using (var httpClient = new HttpClient())
    {
        using (var response = await httpClient.GetAsync("http://localhost:8888/api/Reservation/" + id))
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            reservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
        }
    }
    return View(reservation);
}

[HttpPost]
public async Task<IActionResult> UpdateReservationPatch(int id, Reservation reservation)
{
    using (var httpClient = new HttpClient())
    {
        var request = new HttpRequestMessage
        {
            RequestUri = new Uri("http://localhost:8888/api/Reservation/" + id),
            Method = new HttpMethod("Patch"),
            Content = new StringContent("[{ \"op\": \"replace\", \"path\": \"Name\", \"value\": \"" + reservation.Name + "\"},{ \"op\": \"replace\", \"path\":
\"StartLocation\", \"value\": \"" + reservation.StartLocation + "\"}]", Encoding.UTF8, "application/json")
        };

        var response = await httpClient.SendAsync(request);
    }
    return RedirectToAction("Index");
}

The GET action will just fetch the reservation object who’s Id it is supplied.

The POST action will make the PATCH request. The JSON which is provided to the StringContent class contains the new values of the name and start location fields and are added by using the ‘reservation.Name’ and ‘reservation.StartLocation’. In the end the action is redirecting to the Index View.

Now, add the ‘UpdateReservationPatch’ View inside the ‘Views/Home’ folder with the following code:

@model Reservation
@{ Layout = "_Layout"; ViewBag.Title = "Update a Reservation from PATCH request";}

<h2>Update a Reservation from Patch request<a asp-action="Index" class="btn btn-sm btn-secondary">Back</a></h2>
<form method="post">
    <div class="form-group">
        <label asp-for="Name"></label>
        <input class="form-control" asp-for="Name" />
    </div>
    <div class="form-group">
        <label asp-for="StartLocation"></label>
        <input class="form-control" asp-for="StartLocation" />
    </div>
    <div class="text-center panel-body">
        <button type="submit" class="btn btn-sm btn-primary">Update</button>
    </div>
</form>

In the form I am only binding the ‘Name’ and the ‘StartLocation’ field so that the user can update these 2 fields only.

I also need to create a link to the ‘UpdateReservationPatch’ action from the ‘Index’ View. I can do this thing by changing the asp-action attribute from ‘UpdateReservation’ to ‘UpdateReservationPatch’.

This is shown by the below code:

...
<tbody>
    @foreach (var r in Model)
    {
        <tr>
            ...
            <td>
                <a asp-action="UpdateReservationPatch" asp-route-id="@r.Id"><img src="/icon/edit.png" /></a>
            </td>
            ...
        </tr>
    }
...

</tbody>

Now it’s time to test the Patch functionality, so run your project and click any of the reservation’s update icon, you will see the Name and StartLocation fields on the form, as shown on the image below. Now change the name and start location field values and click the Update button to update the records by PATCH request.

update reservation patch view

Deleting a Reservation Records through the API

Add ‘DeleteReservation’ action method to the Home Controller which will delete a reservation record, from the repository, by calling the API’s delete method:

[HttpPost]
public async Task<IActionResult> DeleteReservation(int ReservationId)
{
    using (var httpClient = new HttpClient())
    {
        using (var response = await httpClient.DeleteAsync("http://localhost:8888/api/Reservation/" + ReservationId))
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
        }
    }

    return RedirectToAction("Index");
}

This action has an argument of ‘ReservationId’ which contains the id of the reservation to be deleted.

The reservation is deleted by making the HTTP DELETE request by using the DeleteAsync method.

In the end the user is redirected to the Index view.

On the Index view there is a Delete column, showing a cross icon (see below image), in the table which shows all the Reservations. If you click on the icon then you can delete the clicked reservation record through the API.

delete icon in reservation table

The Index view has a form which invokes ‘DeleteReservation’ action method:

<form asp-action="DeleteReservation" method="post">
    <input type="hidden" value="@r.Id" name="ReservationId" />
    <input type="image" src="/icon/close.png" />
</form>

Inside the form there is an image button and a hidden field which contains the reservation id for the particular record.

You can delete a reservation by clicking on the cross icon against it.

The below images shows the 3rd reservation deleted from the repository:

delete reservation with api

Testing API through PowerShell

You can test your API method by using PowerShell which makes it easy to create HTTP requests using command line. PowerShell commands can be executed using Visual Studio Package Manager Console window which can be opened by Tools ➤ NuGet Package Manager ➤ Package Manager Console.

So open the Package Manager Console window of your API Controllers project (API consume project) and execute the commands listed below:

Making HTTP GET Request

The command for making HTTP GET Request is:

Invoke-RestMethod http://localhost:8888/api/reservation -Method GET

The command will show all the reservations returned from the API as shown by the image given below:

powershell http get request

The command for making HTTP GET Request to fetch the 2nd reservation:

Invoke-RestMethod http://localhost:8888/api/reservation/2 -Method GET

It will show the 2nd reservation. See the below image:

powershell http get request by reservation id

Making HTTP POST Request

To make the POST request you have to execute the following command:

Invoke-RestMethod http://localhost:8888/api/Reservation -Method POST -Body (@{Name="Jenny"; StartLocation="Moscow"; EndLocation="New Delhi"} | ConvertTo-Json) -ContentType "application/json"

The command adds a new reservation to the repository.

powershell http post request

The -Body argument specifies the body for the request which is encoded to JSON by using the ConvertTo-Json argument.

The -ContentType argument is used to set the Content-Type header for the request, which in my case is ‘application/json’.

Making HTTP PUT Request

The command to make PUT request is similar to the POST command and is given below:

Invoke-RestMethod http://localhost:8888/api/Reservation -Method PUT -Body (@{Id="5"; Name="Mary"; StartLocation="Tokyo"; EndLocation="Abu Dhabi"}) -ContentType "application/x-www-form-urlencoded"

Since I have to send the reservation object in Form data therefore I have removed the ConvertTo-Json argument from the command. Also, I have set the –’ContentType’ to “application/x-www-form-urlencoded”

Once the command executes the 5th reservation record is updated to Mary for name, Tokyo for start location and Abu Dhabi for end location.

The below image illustrates this:

powershell http put request

Making HTTP PATCH Request

Here I am making a PATCH request to update a reservation record. So in the JSON I will send the ‘op’ argument as ‘replace’.

The below PATCH command will update the 2nd reservation’s name field to ‘Bob’ and start location field to ‘San Francisco’.

Invoke-RestMethod http://localhost:8888/api/Reservation/2 -Method PATCH -Body (@{ op="replace"; path="Name"; value="Bob"},@{ op="replace"; path="StartLocation";value="San Francisco"} | ConvertTo-Json) -ContentType "application/json"

The image below illustrates the change made to the 2nd reservation by the command:

powershell http patch request

Making HTTP DELETE Request

To Powershell command to make HTTP DELETE request is:

Invoke-RestMethod http://localhost:8888/api/Reservation/3 -Method DELETE

The above command will delete the 3rd reservation by invoking the API’s Delete Action method.

Securing API by KEYS

You do not want to allow API access to everyone. That means you will need to secure your API with Keys. The client will have to send the API Key along with the request, the keys are checked in the API Controller and if they are correct then only the response is sent to the client.

The best way to send the API Key is through the Http Request Header.

I create a situation where only authorized clients can add a reservation through the API. I have to change the Post action of the API Controllers to create a manual check for the Key provided in the header.

If the key is correct only then the Reservation is added, else unauthorized result 401 response is sent.

So change the POST action as shown below:

[HttpPost]
public IActionResult Post([FromBody] Reservation res)
{
    if (!Authenticate())
        return Unauthorized();
    return Ok(repository.AddReservation(new Reservation
    {
        Name = res.Name,
        StartLocation = res.StartLocation,
        EndLocation = res.EndLocation
    }));
}

This action method return type is ‘IActionResult’ since it will be returning both a status code and a reservation object.

Unauthorized Status code 401 is returned if Authenticate() method returns false, else success 200 status code is returned along with the newly created reservation object.

Note that I have used the Ok() method to send both 200 status code with the reservation object

You also need to add an Authenticate() method to the controller which checks the key placed in the header of the http request:

bool Authenticate()
{
    var allowedKeys = new[] { "[email protected]", "Secret#12", "SecretABC" };
    StringValues key = Request.Headers["Key"];
    int count = (from t in allowedKeys where t == key select t).Count();
    return count == 0 ? false : true;
}

There are 3 valid keys given in the ‘allowedKeys’ variable. Inside this method I check if the Key in the header matches from these 3 keys, only then I return true.

Now go to the API Consume project and inside the ‘AddReservation’ action method add a key in the Header of the HTTP request with this code – httpClient.DefaultRequestHeaders.Add(“Key”, “[email protected]”);.

Also add a try catch block to deserialize the response to a reservation object. If the deserialization fails then it is because the response does not contain the reservation object. This is a case where the key did not match and 401 status code is returned by the API.

Inside the catch block set ViewBag.Result variable to contain this 401 response sent by the API.

The updated AddReservation Action method code is given below:

[HttpPost]
public async Task<IActionResult> AddReservation(Reservation reservation)
{
    Reservation receivedReservation = new Reservation();
    using (var httpClient = new HttpClient())
    {
        httpClient.DefaultRequestHeaders.Add("Key", "[email protected]");
        StringContent content = new StringContent(JsonConvert.SerializeObject(reservation), Encoding.UTF8, "application/json");

        using (var response = await httpClient.PostAsync("http://localhost:8888/api/Reservation", content))
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            try
            {
                receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
            }
            catch(Exception ex)
            {
                ViewBag.Result = apiResponse;
                return View();
            }
        }
    }
    return View(receivedReservation);
}

Now run your API Consume project and add a new reservation from the URL ‘/Home/AddReservation’. You will be able to add the new reservation because your key in the Header is correct.

Now Change the key to a wrong one like – httpClient.DefaultRequestHeaders.Add(“Key”, “wrongkey”);, and try one again to add a new reservation. This time you will fail to do so and will see a message – ‘Status Code: 401; Unauthorized’.

This is shown by the image given below:

401 status message received for wrong key

Uploading Files through API

You can also upload files through API, this is done by using the IFormFile Class as the parameter of the API’s action method. The IFormFile class represents the file sends through the HttpRequest.

You will have to add ‘Images’ folder inside the ‘wwwroot’ folder of the API Controllers project. In that folder images sent by the client will be uploaded.

The below image illustrates the images folder location:

images folder location

For saving files on an application folder, I will need the information about the web hosting environment. So I will need to use the dependency injection feature to get the object of the IHostingEnvironment class.

Go to the Reservation controller of the API Controllers project and add a new private property of IHostingEnvironment type, and then set its value in the Constructor of the Controller.

You need to add the following code to your controller.

private IHostingEnvironment hostingEnvironment;

public ReservationController(IRepository repo, IHostingEnvironment environment)
{
    repository = repo;
    hostingEnvironment = environment;
}

Now you are ready to use the ‘hostingEnvironment’ variable which contains the hosting environment details.

Next, add a new action method which is given below:

[HttpPost("UploadFile")]
public async Task<string> UploadFile([FromForm] IFormFile file)
{
    string path = Path.Combine(hostingEnvironment.WebRootPath, "Images/" + file.FileName);
    using (var stream = new FileStream(path, FileMode.Create))
    {
        await file.CopyToAsync(stream);
    }
    return "http://localhost:8888/Images/" + file.FileName;
}

The ‘UploadFile’ string given for the HttpPost attribute specifies that this action method will be accessed with the URL – ‘/api/Reservation/UploadFile’.

The Client will be sending the file from HttpRequest and the file will be saved in the ‘wwwroot/Images’ folder of the API Controllers project.

The WebRootPath method of the IHostingEnvironment class gives the absolute path of the applications content file (i.e the absolute path of ‘wwwroot’ folder).

So I can use the Path.Combine() method of the System.IO class to create an absolute path where the file will be saved. I have also added the file name to this path, by using the FileName property of the IFormFile class.

The FileStream class code which saves the file is given below:

using (var stream = new FileStream(path, FileMode.Create))
{
    await file.CopyToAsync(stream);
}

In the end my action method is returning back the full path of the saved file in the API response.

Now on the Client side, which is the API Consume application, I will add a new action method that will upload the file from the API.

This action method is given below:

[HttpPost]
public async Task<IActionResult> AddFile(IFormFile file)
{
    string apiResponse = "";
    using (var httpClient = new HttpClient())
    {
        var form = new MultipartFormDataContent();
        using (var fileStream = file.OpenReadStream())
        {
            form.Add(new StreamContent(fileStream), "file", file.FileName);
            using (var response = await httpClient.PostAsync("http://localhost:8888/api/Reservation/UploadFile", form))
            {
                response.EnsureSuccessStatusCode();
                apiResponse = await response.Content.ReadAsStringAsync();
            }
        }
    }
    return View((object)apiResponse);
}

This action method has a parameter of type ‘IFormFile’, which means I can get the file which is uploaded from the input control of type file from the View. This is a simple Model Binding feature.

Next I am reading the file from the OpenReadStream() method, and adding it to the form data by using the MultipartFormDataContent Class.

The reason for adding the file to form data is because the API action is binding the parameter using form data ([FromForm]).

Next, I am making the API call to the URL – ‘http://localhost:8888/api/Reservation/UploadFile’ with the POST request and the API response is returned to the View as Model.

The API returns a string which contains the full location of the File. I have casted the response string to an object, (object)apiResponse to call the default view. Otherwise the Core MVC will search for the View having name as the string.

Now create the View called ‘AddFile’ inside the ‘Views/Home’ folder with the code given below:

@model string
@{ Layout = "_Layout"; ViewBag.Title = "Add File";}

<h2>Add File</h2>
<a asp-action="Index" class="btn btn-sm btn-primary">Back</a>
<form method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <div class="text-center panel-body">
        <button type="submit" class="btn btn-sm btn-primary">Add</button>
    </div>
</form>

@if (Model != null)
{
    <h2>Uploaded File</h2>
    <img src="@Model" />
}

The form should have the attribute – enctype=”multipart/form-data” with an input control of type file to upload files.

The View has a model of type string so that I can show the API response inside an img tag.

Now let us try uploading a file, so run the application and go to the URL – ‘/Home/AddFile’. Select a image file from the file control and click the ‘Add’ button. You will see the image uploaded to the API Controllers and will display in the View.

The image below illustrates this:

file upload through api

You can now find this file uploaded in the Images folder of the API Controllers project:

file uploaded

Returning Data from API in XML instead of JSON

I told earlier that ASP.NET Core MVC returns data in JSON to the Client if the Action method has the return type of anything other than string.

You may have noticed that if you run your API Controllers project and go to the URL – ‘/api/Reservation’, then you will get a JSON data containing all the reservations.

If you check the ‘Response Headers’, in your Chrome Developers Tools, then you will find the Content-Type as ‘application/json’. This is shown in the below image:

API response in json

You can change this and make the API to return the data in XML. For this you will have to add the AddXmlDataContractSerializerFormatters() method in the Startup class:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IRepository, Repository>();
    services.AddMvc().AddXmlDataContractSerializerFormatters();
}

Then in your action method add the [Produces(“application/xml”)] attribute which forces the format used by the response to XML.

See the below code where I have used this attribute on the GET action method:

[HttpGet]
[Produces("application/xml")]
public IEnumerable<Reservation> Get() {
    Authenticate();
    return repository.Reservations;
}

Now rerun your application and go to the same URL again. This time you will see the data in XML format and the Content-Type set as ‘application/json’. See the below image:

API response in xml

Receiving Data in Different Formats

You can specify different action methods to handle specific data formats using the [Consumes] attribute.

In your API controllers project change the Post method to include 2 actions with the Consume attribute as shown below:

[HttpPost]
[Consumes("application/json")]
public Reservation PostJson([FromBody] Reservation res) =>
repository.AddReservation(new Reservation
{
    Name = res.Name,
    StartLocation = res.StartLocation,
    EndLocation = res.EndLocation
});

[HttpPost]
[Consumes("application/xml")]
public Reservation PostXml([FromBody] Reservation res) =>
repository.AddReservation(new Reservation
{
    Name = res.Name,
    StartLocation = res.StartLocation,
    EndLocation = res.EndLocation
});

The PostJson and PostXml actions both accept POST requests, but the difference between them is the data format which is specified with the Consumes attribute.

The Consume attribute examines the Content-Type header in the HTTP Request from the clients and decides whether the action method can process the request.

When there is a request whose Content-Type is set to application/json, the PostJson method is be used, and if the Content-Type header is application/xml, then the PostXml method will be used.

The link to download the full source code of this tutorial is given below:

Download

Conclusion

In this tutorial I explained working with APIs in ASP.NET Core MVC. I hope you find it useful, do check other ASP.NET Core tutorial on the site to.

Share this article -

yogihosting

ABOUT THE AUTHOR

This article has been written by the Technical Staff of YogiHosting. Check out other articles on "ASP.NET Core, jQuery, EF Core, SEO, jQuery, HTML" and more.