Asp.net Core 2.1 Web Api Upload File Httpclient

On my previous tutorial called How to Create Web APIs in ASP.NET Core [RESTful pattern] I created a Web API. Now I will call this API (i.e. consume the API) in another project known as client.

What is an API?

API stands for (Application Programming Interface) is an interface which allows multiple applications to communicate with one another. We use multiple APIs daily for getting the electric current weather condition update of our area on our phone, current stock prices of a company we invested in, and and so on.

The Operating organization (Bone) of our computer constitutes a large number of APIs. For case, on double clicking a folder, the Os calls a specific API which displays the content of the binder.

The APIs which can be called or accessed by a URL are known equally Web APIs.

What are some API examples?

The most popular API are the ones which the people use daily, 3 of such APIs are:

  • i. Skyscanner which is travel site which lets people enquiry and volume travel options for their trips. On their website, when you perform a search, the website calls a bunch of external APIs to fetch the current state of flights, hotels, etc. This is then displayed to you lot on the browser.
  • two. OpenWeatherMap which provides global weather data via API.
  • 3. Yahoo Finance provides current stock prices and market news.

What is an API call?

We call an API and so that it performs the work for which it is designed. When API completes the work it will send dorsum the status of the completed work, in instance of an fault the appropriate error lawmaking and message is returned back.

The question arises is How to phone call an API? – We tin call an API by using the advisable software which is designed to work with the API, example an Operating Organization, a browser or an APP in your iPhone. If the API has a URL then this URL can be chosen with HTTP protocols.

The Web APIs works with methods which are chosen by HTTP protocols. They are ordinarily called equally Verbs, Become, PUT, POST, and DELETE are the most mutual ones.

Consume (Call) Web API in ASP.Net Cadre

So create a new empty project by using the ASP.Internet Cadre Web Awarding (.Net Core) template, and name the project as APIConsume.

Call up to select the framework as .NET Cadre and version as ASP.Net Cadre v.0. I take shown this in the below image

.NET 5.0 version

Models

Create Models binder in your project root folder and add a class called Reservation.cs to it. The class code is shown below.

using System; using Organization.Collections.Generic; using Arrangement.Linq; using System.Threading.Tasks;  namespace APIConsume.Models {     public course Reservation     {         public int Id { get; set; }         public string Name { become; ready; }         public string StartLocation { get; fix; }         public string EndLocation { go; ready; }     } }          

This class contains 4 properties for dealing with a reservation object. In a moment I will starting time using it and you will understand it's working clearly.

Bootstrap Package

I volition demand Bootstrap package for giving the HTML of the View some proper layout. For this add this bundle inside the wwwroot ➤ lib binder. I have written a separate commodity o information technology so do check it – How to Install Bootstrap Bundle in ASP.NET Core Awarding in Visual Studio.

Layout

Create Views binder on the root of the awarding and create Shared binder inside the Views folder.

Adjacent inside the Shared folder create _Layout.cshtml file that will contain a common layout for all the Views. The _Layout.cshtml file's code is shown below.

<!DOCTYPE html>  <html> <head>     <meta name="viewport" content="width=device-width" />     <championship>@ViewBag.Title</title>     <link href="~/lib/twitter-bootstrap/css/bootstrap.css" rel="stylesheet" /> </head> <body>     <div form="container-fluid">         @RenderBody()     </div> </body> </html>          

View Imports

Side by side, create _ViewImports.cshtml file inside the Views folder and utilize it to setup the Born Tag Helpers and import the Model namespace.

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

Startup Class

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

using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting;  namespace APIConsume {     public class Startup     {         public void ConfigureServices(IServiceCollection services)         {             services.AddControllersWithViews();         }          public void Configure(IApplicationBuilder app, IWebHostEnvironment env)         {             if (env.IsDevelopment())             {                 app.UseDeveloperExceptionPage();             }             else             {                 app.UseExceptionHandler("/Domicile/Mistake");                 // The default HSTS value is 30 days. You may want to alter this for production scenarios, run into https://aka.ms/aspnetcore-hsts.                 app.UseHsts();             }              app.UseHttpsRedirection();             app.UseStaticFiles();             app.UseRouting();             app.UseAuthorization();              app.UseEndpoints(endpoints =>             {                 endpoints.MapControllerRoute(                     proper name: "default",                     pattern: "{controller=Home}/{action=Index}/{id?}");             });         }     } }          

Controller

Create Controllers folder on the root of your project and add a controller file chosen HomeController.cs to it. This controller will have activity methods to invoke methods of the Web API.

HttpClient to Phone call API

In social club to Consume the Web API in this projection, make sure your Web API project should be in running mode i.e. just printing F5 fundamental in Visual Studio to bring it to running mode. I made this Web API project in my previous tutorial and information technology's link is given on the top of this article.

To call Web API nosotros will exist using a very pop HttpClient() class. To Deserialize JSON to Reservation object I will use Newtonsoft.Json packet. I accept shown this package in the below screenshot.

Newtonsoft.Json package

The HttpClient has some very important method to call Web API. These should be noted.

Method Description
GetAsync Ship a GET asking to the specified Uri every bit an asynchronous operation.
PostAsync Ship a POST request to the specified Uri as an asynchronous operation.
PutAsync Ship a PUT asking to the specified Uri as an asynchronous operation.
SendAsync Send an HTTP asking every bit an asynchronous operation.
PatchAsync Sends a PATCH asking with a cancellation token as an asynchronous operation.
DeleteAsync Send a DELETE request to the specified Uri as an asynchronous operation.

Now let us deal with each of these methods i past 1.

Read Records from Web API

The Spider web API has a HttpGet method that returns all reservation records in JSON. This method'south code is.

          [HttpGet] public IEnumerable<Reservation> Go() => repository.Reservations;        

To read all these reservation records I take to make an HTTP GET Blazon of Request to this method of the Spider web API. So create a new controller within the Controllers folder and name it HomeController.cs. Supersede it's Index activity with the following version shown beneath.

using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; using APIConsume.Models; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json;  namespace APIConsume.Controllers {     public course HomeController : Controller     {         public async Job<IActionResult> Index()         {             List<Reservation> reservationList = new List<Reservation>();             using (var httpClient = new HttpClient())             {                 using (var response = await httpClient.GetAsync("https://localhost:44324/api/Reservation"))                 {                     string apiResponse = wait response.Content.ReadAsStringAsync();                     reservationList = JsonConvert.DeserializeObject<Listing<Reservation>>(apiResponse);                 }             }             render View(reservationList);         }     } }          

I used the HttpClient form of the System.Net.Http namespace to brand an API request. You will notice that the Index Activeness is an asynchronous type that returns a Task. This is because the HttpClient class makes merely asynchronous asking which can only happen from an asynchronous activeness method.

I fabricated the an HTTP Get asking to the API in the line – var response = wait httpClient.GetAsync("https://localhost:44324/api/Reservation"). Observe the URL of the API's activeness is supplied to the GetAsync() method.

The Web API Response i.e. the data returned by the API is fetched from the code – look response.Content.ReadAsStringAsync(), and stored in the variable chosen apiResponse.

Yous already know that the API response is a JSON blazon of all the Reservation objects. So I can easily Deserialize the JSON to a Listing type object by using the Newtonsoft.Json parcel. The Code that does this work is shown below.

          reservationList = JsonConvert.DeserializeObject<Listing<Reservation>>(apiResponse);        

Finally the List of Reservation objects which are stored in the variable chosen reservationList is returned to the View as the Model.

Now you need to create the Index View inside the Views ➤ Home folder and so every bit to testify all the reservations on an HTML table. The Index View code is given below:

@model IEnumerable<Reservation> @{ Layout = "_Layout"; ViewBag.Title = "All Reservations";}  <h2>All Reservations</h2> <a asp-activeness="AddReservation" form="btn btn-sm btn-primary">Add Reservation</a> <a asp-action="GetReservation" class="btn btn-sm btn-secondary">Become Reservation</a>  <tabular array class="tabular array table-sm table-striped table-bordered one thousand-2">     <thead>         <tr>             <th>ID</th>             <th>Proper name</thursday>             <th>Kickoff Location</th>             <thursday>Cease Location</thursday>             <th>Update</th>             <th>Delete</th>         </tr>     </thead>     <tbody>         @foreach (var r in Model)         {             <tr>                 <td>@r.Id</td>                 <td>@r.Proper noun</td>                 <td>@r.StartLocation</td>                 <td>@r.EndLocation</td>                 <td>                     <a asp-activity="UpdateReservation" asp-route-id="@r.Id">                         <img src="/icon/edit.png" />                     </a>                 </td>                 <td>                     <form asp-activity="DeleteReservation" method="mail service">                         <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 blazon as it's model. There is a foreach loop to populate a tabular array with all the reservations.

Now run your APIConsume projection as well make sure the APIControllers projection is running. You lot will notice a new browser window opens upwards and shows all the Reservations that are fetched from the Web API. The image beneath shows all the Reservations.

all reservations fetched from web api

Ignore the

Add Reservation

and

Get Reservation

links, and the

Update

and

Delete

columns. I will be adding their functionalities in a moment. The edit & delete icons will exist provided inside the

wwwroot/icon

binder of the project.

Reading a Reservation Record by it's Id by calling the Web API

If I transport an Id of a Reservation to the Web API then the API volition send me back the reservation details of that Id. The Spider web API, which I have already created on my previous tutorial, has a HttpGet method with an id parameter. It's work is to read a records whose id is provided to it. This method's code is shown below.

          [HttpGet("{id}")] public ActionResult<Reservation> Go(int id) {     if (id == 0)         return BadRequest("Value must exist passed in the asking body.");     return Ok(repository[id]); }        

Now I will call this method of the API from my customer projection. Practice you lot remember that in the Index View I have created a link to Get Reservation, at present I will add it's functionality. And so go to the Home Controller and add a new activeness called GetReservation to information technology. I accept highlighted it'south code, come across below.

using System.Collections.Generic; using System.Internet.Http; using Arrangement.Threading.Tasks; using APIConsume.Models; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json;  namespace APIConsume.Controllers {     public class HomeController : Controller     {         public async Task<IActionResult> Alphabetize()         {             List<Reservation> reservationList = new List<Reservation>();             using (var httpClient = new HttpClient())             {                 using (var response = await httpClient.GetAsync("https://localhost:44324/api/Reservation"))                 {                     cord apiResponse = await response.Content.ReadAsStringAsync();                     reservationList = JsonConvert.DeserializeObject<List<Reservation>>(apiResponse);                 }             }             return View(reservationList);         }          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("https://localhost:44324/api/Reservation/" + id))                 {                     if (response.StatusCode == System.Net.HttpStatusCode.OK)                     {                         string apiResponse = await response.Content.ReadAsStringAsync();                         reservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);                     }                     else                         ViewBag.StatusCode = response.StatusCode;                 }             }             return View(reservation);         }     } }          

I have added two GetReservation actions – HTTP GET & HTTP Post. The HTTP Get version simply returns the default view while the HTTP Post 1 has the chore to Telephone call the Spider web API and provide it with the reservation id. The API in turn volition return the reservation details of that id.

The API Telephone call 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 to the default view as Model.

Next, add the GetReservation.cshtml view file inside the Views ➤ Habitation folder. Information technology's full code is shown beneath.

@model Reservation @{ Layout = "_Layout"; ViewBag.Title = "Get Reservation past Id";}  <h2>Get Reservation by Id <a asp-activeness="Index" course="btn btn-sm btn-primary">Dorsum</a></h2> <h3>@ViewBag.StatusCode</h3> <form method="post">     <div form="course-grouping">         <characterization for="id">Id:</label>         <input class="class-control" name="id" />     </div>     <div class="text-middle panel-body">         <button type="submit" course="btn btn-sm btn-primary">Get Reservation</button>     </div> </form>  @if (Model != nil) {     <h2>Reservation</h2>     <table grade="table table-sm tabular array-striped table-bordered yard-2">         <thead>             <tr>                 <th>ID</th>                 <th>Name</th>                 <thursday>Showtime Location</th>                 <th>Cease Location</th>             </tr>         </thead>         <tbody>             <tr>                 <td>@Model.Id</td>                 <td>@Model.Proper name</td>                 <td>@Model.StartLocation</td>                 <td>@Model.EndLocation</td>             </tr>         </tbody>     </tabular array> }          

The view contains a form, in this form the Reservation Id is added, and on clicking the button the Spider web API request is fabricated.

The expression – @if (Model != null) checks if the model is not null. In that case the Model data, which is Reservation information fetched from the API, is shown.

Now run your project and on the main page click the Become Reservation link. Add the Id as three and click the button. You will see the tertiary Reservation's details shown on the view, meet the image below:

3rd reservation from api

Create a Reservation Record by Calling the Spider web API

The Web API has a [HttpPost] method that creates a new reservation. This method is shown beneath.

          [HttpPost] public Reservation Post([FromBody] Reservation res) => repository.AddReservation(new Reservation {     Name = res.Proper noun,     StartLocation = res.StartLocation,     EndLocation = res.EndLocation });        

To add together a new Reservation I take to make a HTTP Mail request to this method of the web API. I will make use of the PostAsync() method of the HttpClient class to brand a call to this method. So add a new action method called AddReservation to the Dwelling controller as highlighted by the beneath lawmaking.

using System.Collections.Generic; using System.Net.Http; using Organization.Threading.Tasks; using APIConsume.Models; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Organization.Text;  namespace APIConsume.Controllers {     public class HomeController : Controller     {         // other methods          public ViewResult AddReservation() => View();          [HttpPost]         public async Job<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("https://localhost:44324/api/Reservation", content))                 {                     string apiResponse = wait response.Content.ReadAsStringAsync();                     receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);                 }             }             render View(receivedReservation);         }     } }          

This Web API method needs the new reservation data in JSON format therefore I am serializing the reservation data into JSON and so converting it to a StringContent class blazon. Check the below code.

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

Next, this StringContent type object is added to the Web API request code past calculation it to the 2nd parameter of the PostAsync() method. Check cod below.

          using (var response = await httpClient.PostAsync("https://localhost:44324/api/Reservation", content)) { }        

The Spider web API method will add the new reservation to information technology's repository and sends dorsum the newly added reservation object as the API Response. This also contains the id of the created reservation.

The Response is Deserialized into the reservation type and in the cease is transferred to the View every bit a model.

At present create the view called 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> <course asp-action="AddReservation" method="post">     <div grade="form-group">         <label for="Proper name">Name:</label>         <input grade="form-control" proper noun="Proper name" />     </div>     <div form="course-group">         <label for="StartLocation">Start Location:</label>         <input class="form-control" proper noun="StartLocation" />     </div>     <div class="course-group">         <label for="EndLocation">Terminate Location:</characterization>         <input class="class-control" proper name="EndLocation" />     </div>     <div class="text-center panel-trunk">         <button blazon="submit" class="btn btn-sm btn-principal">Add together</button>     </div> </form>  @if (Model != null) {     <h2>Reservation</h2>     <table grade="table table-sm tabular array-striped tabular array-bordered m-ii">         <thead>             <tr>                 <thursday>ID</th>                 <thursday>Proper name</th>                 <thursday>Start Location</thursday>                 <th>Cease Location</th>             </tr>         </thead>         <tbody>             <tr>                 <td>@Model.Id</td>                 <td>@Model.Name</td>                 <td>@Model.StartLocation</td>                 <td>@Model.EndLocation</td>             </tr>         </tbody>     </tabular array> }          

The view has a HTML class for calculation a new reservation while it'due south model is of a type Reservation. In one case the API response is received the controller sends it to the view as a Model, the view then checks if the Model is non null from the code – @if (Model != zilch).

If the model contains the newly created reservation data then it is shown on the HTML table.

At present run your project and go to the add together reservation page whose URL in my case is https://localhost:44334/Domicile/AddReservation. Fill up the form and click the add together button. The reservation will be created and information technology's details will be shown on a table. Bank check below prototype.

creating a new reservation by calling the api

Update a Reservation Records through the Web API

The page that shows all the reservations has an Update Column (a pen icon). If you click on this icon (see the below image) then you tin can update the corresponding reservation record.

update icon in reservation table

Now I will create the Update Reservation functionality. Exercise you remember the Web API has a HttpPut method which has a task to update a reservation. Run across it's code below.

          [HttpPut] public Reservation Put([FromForm] Reservation res) => repository.UpdateReservation(res);        

I will at present call this method of the Spider web API in order to update whatever of the previously created reservation. For this add new actions called UpdateReservation to the

Home controller

whose codes are given below.

using System.Collections.Generic; using Organization.Internet.Http; using System.Threading.Tasks; using APIConsume.Models; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using System.Text;  namespace APIConsume.Controllers {     public class HomeController : Controller     {         // other methods          public async Chore<IActionResult> UpdateReservation(int id)         {             Reservation reservation = new Reservation();             using (var httpClient = new HttpClient())             {                 using (var response = look httpClient.GetAsync("https://localhost:44324/api/Reservation/" + id))                 {                     string apiResponse = await response.Content.ReadAsStringAsync();                     reservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);                 }             }             return View(reservation);         }          [HttpPost]         public async Job<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 together(new StringContent(reservation.Proper name), "Proper noun");                 content.Add(new StringContent(reservation.StartLocation), "StartLocation");                 content.Add together(new StringContent(reservation.EndLocation), "EndLocation");                  using (var response = await httpClient.PutAsync("https://localhost:44324/api/Reservation", content))                 {                     string apiResponse = wait response.Content.ReadAsStringAsync();                     ViewBag.Event = "Success";                     receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);                 }             }             return View(receivedReservation);         }     } }          

The HTTP GET version of the UpdateReservation action simply makes a Go blazon of request to the Web API. It provides the API with the Id of a reservation. The API volition send information technology dorsum the reservation tape whose Id was provided to it. The reservation record is and then shown on the default view.

The HTTP POST version of this activeness does the Update of the Reservation.

Since the PUT method of the API has [FromForm] attribute in it's argument therefore I am creating a class data by using the MultipartFormDataContent. This course data volition be sent to the API every bit:

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

Notice I am sending the id, name, kickoff location & end location of the reservation record to exist updated in the Form data.

Later on updating the tape the Web API will send back the response which is the updated reservation tape, and this is shown on the view.

Now add the view called UpdateReservation inside the Views ➤ Dwelling house folder with the following code:

@model Reservation @{ Layout = "_Layout"; ViewBag.Title = "Update a Reservation";}  <h2>Update a Reservation <a asp-action="Alphabetize" grade="btn btn-sm btn-secondary">Back</a></h2> <course method="mail service">     <div course="form-group">         <label asp-for="Id"></label>         <input course="grade-control" asp-for="Id" readonly />     </div>     <div form="form-group">         <label asp-for="Proper name"></characterization>         <input form="form-control" asp-for="Name" />     </div>     <div course="form-group">         <label asp-for="StartLocation"></label>         <input form="course-control" asp-for="StartLocation" />     </div>     <div class="form-grouping">         <label asp-for="EndLocation"></label>         <input form="form-control" asp-for="EndLocation" />     </div>     <div grade="text-center console-body">         <push button type="submit" class="btn btn-sm btn-chief">Update</push button>     </div> </course>  @if (ViewBag.Issue == "Success") {     <h2>Reservation</h2>     <table form="table table-sm table-striped table-bordered m-2">         <thead>             <tr>                 <th>ID</th>                 <thursday>Proper noun</th>                 <th>First Location</th>                 <thursday>End Location</th>             </tr>         </thead>         <tbody>             <tr>                 <td>@Model.Id</td>                 <td>@Model.Proper name</td>                 <td>@Model.StartLocation</td>                 <td>@Model.EndLocation</td>             </tr>         </tbody>     </table> }          

The view has a form where new values of the reservation are put, and on clicking the Update push button the reservation is updated.

The API response is shown inside an HTML table which is also provided on the view.

Now it'southward 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 prototype shows that I have updated the start location to New York and terminate location to Barcelona of the 2nd reservation record.

update record through api

Update a Reservation Record with "HTTP PATCH" through the Web API

The Web API has a HTTP PATCH method whose task is to update a reservation tape. This method is shown below.

          [HttpPatch("{id}")] public StatusCodeResult Patch(int id, [FromBody]JsonPatchDocument<Reservation> patch) {     Reservation res = Get(id).Value;     if (res != aught)     {         patch.ApplyTo(res);         return Ok();     }     render NotFound(); }        

To invoke this PATCH method of the Web API, I will have to use the HttpRequestMessage form to initialize 3 properties. These properties are:

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

The

PATCH

method has a wonderful advantage. I don't take to send all the Reservation fields to it, it only needs the fields that need to change along with their new values. This makes the PATCH asking light weight and more secure.

The Patch method will demand a JSON sent from the client. This JSON contains the operation to be performed forth with fields and their new values. See this JSON format given below.

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

I take used replace for the op argument, and this specifies that I will exist doing the update for the record. I accept also specified the Name and the StartLocation fields will be updated along with their new values.

Now it's time to Consume this method of the Web API from my client project. So get to the Home Controller and add the 2 actions called UpdateReservationPatch to it. See the below code.

using Organization.Collections.Generic; using Organisation.Net.Http; using Organization.Threading.Tasks; using APIConsume.Models; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Arrangement.Text; using System;  namespace APIConsume.Controllers {     public class HomeController : Controller     {         // other methods          public async Job<IActionResult> UpdateReservationPatch(int id)         {             Reservation reservation = new Reservation();             using (var httpClient = new HttpClient())             {                 using (var response = await httpClient.GetAsync("https://localhost:44324/api/Reservation/" + id))                 {                     string apiResponse = expect response.Content.ReadAsStringAsync();                     reservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);                 }             }             render View(reservation);         }          [HttpPost]         public async Job<IActionResult> UpdateReservationPatch(int id, Reservation reservation)         {             using (var httpClient = new HttpClient())             {                 var asking = new HttpRequestMessage                 {                     RequestUri = new Uri("https://localhost:44324/api/Reservation/" + id),                     Method = new HttpMethod("Patch"),                     Content = new StringContent("[{ \"op\": \"replace\", \"path\": \"Name\", \"value\": \"" + reservation.Name + "\"},{ \"op\": \"supervene upon\", \"path\": \"StartLocation\", \"value\": \"" + reservation.StartLocation + "\"}]", Encoding.UTF8, "awarding/json")                 };                  var response = look httpClient.SendAsync(request);             }             render RedirectToAction("Index");         }     } }          

The UpdateReservationPatch has 2 actions – HTTP GET & HTTP POST. The Go action will just fetch the reservation object who's Id it supplied to it. The POST activeness volition make the PATCH request.

Notation that to brand the HTTP PATCH request I will utilize the SendAsync() method of the HttpClient grade. The JSON, which is provided to the StringContent class, contains the new values of the proper name and start location fields and are added by using the reservation.Name and reservation.StartLocation. In the end the action redirects to the Index View.

Now, add the view chosen UpdateReservationPatch within the Views ➤ Habitation 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-activeness="Index" class="btn btn-sm btn-secondary">Back</a></h2> <course method="post">     <div class="form-group">         <characterization asp-for="Proper name"></label>         <input class="form-command" asp-for="Proper noun" />     </div>     <div class="course-grouping">         <characterization asp-for="StartLocation"></label>         <input class="class-control" asp-for="StartLocation" />     </div>     <div class="text-center console-torso">         <button type="submit" form="btn btn-sm btn-primary">Update</button>     </div> </course>          

The view contains a form where I am only binding the Proper name and the StartLocation fields and so that the user can update their values to a new one.

I as well need to create a link to the UpdateReservationPatch activity from the Index view. I tin do this thing by changing the asp-activity aspect given on the Index view from UpdateReservation to UpdateReservationPatch. I take shown this in the beneath code.

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

Now it's time to test the Patch functionality. So run your projection and click whatsoever of the update icon against any of the reservation. You lot will be taken to a new page where the Proper noun and StartLocation fields volition testify the values of the reservation which was clicked. At present change the Proper name and StartLocation field'southward values and click the Update button to update the records by PATCH request. Check the below image.

update reservation patch view

Delete a Reservation past calling the Spider web API

The Web API has a HttpDelete type method that volition delete whatever record whose id is provided to information technology. This method is shown below.

          [HttpDelete("{id}")] public void Delete(int id) => repository.DeleteReservation(id);        

From the client project I will call this method of the API and perform the delete operation. And then add a new action method called DeleteReservation to the Habitation Controller of the client project. This action volition delete a reservation record by calling the Web API's delete method. It's code is given below.

using Organisation.Collections.Generic; using Organisation.Net.Http; using System.Threading.Tasks; using APIConsume.Models; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using System.Text; using System;  namespace APIConsume.Controllers {     public class HomeController : Controller     {         // other action          [HttpPost]         public async Task<IActionResult> DeleteReservation(int ReservationId)         {             using (var httpClient = new HttpClient())             {                 using (var response = await httpClient.DeleteAsync("https://localhost:44324/api/Reservation/" + ReservationId))                 {                     cord apiResponse = expect response.Content.ReadAsStringAsync();                 }             }              return RedirectToAction("Index");         }     } }          

This activity has an argument called ReservationId which contains the id of the reservation to be deleted.

The reservation is deleted by making the HTTP DELETE request to the Spider web API'due south method. I used the DeleteAsync method to make this request.

Notice the Delete column on the Index View ( which is a cross icon). If you click on this icon then you lot can delete the corresponding reservation record through the API.

delete icon in reservation table

The Index View has a class which invokes the DeleteReservation action method. See below lawmaking.

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

Inside the form there is an epitome push button and a subconscious field which contains the reservation id for the detail record.

You tin delete a reservation past clicking on the cantankerous icon against it.

The below images shows the tertiary reservation deleted from the repository:

delete reservation with api

Call Web API with PowerShell

You tin Phone call Web API with PowerShell in club to exam them. PowerShell makes it like shooting fish in a barrel to create HTTP requests using command line. PowerShell commands can be executed using Visual Studio Bundle Manager Console, open it from Tools ➤ NuGet Parcel Manager ➤ Package Director Console.

In Package Manager Console window execute the commands listed beneath:

PowerShell: HTTP Become Request to Web API

The PowerShell command for calling HTTP GET method of Web API is:

          PM> Invoke-RestMethod https://localhost:44324/api/reservation -Method GET        

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

powershell http get request

The control that makes HTTP GET Request to fetch the 2nd reservation is:

          PM> Invoke-RestMethod https://localhost:44324/api/reservation/2 -Method GET        

It will bear witness the 2nd reservation. See the below image:

powershell http get request by reservation id

PowerShell: HTTP Mail service Asking to Web API

To call the HTTP Mail method of Web API with PowerShell run the following control:

PM> Invoke-RestMethod https://localhost:44324/api/Reservation -Method Mail -Body (@{Name="Jenny"; StartLocation="Moscow"; EndLocation="New Delhi"} | ConvertTo-Json) -ContentType "application/json"          

The control 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-Blazon header for the asking, which in my case is 'awarding/json'.

PowerShell: HTTP PUT Request to Web API

The command to make HTTP PUT request with PowerShello is like to the HTTP POST command and is given below:

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

Since I have to send the reservation object in Grade Information therefore I have removed the ConvertTo-Json statement from the command. Also, I have ready the –ContentType to awarding/ten-world wide web-grade-urlencoded.

Once the command executes the 5th reservation record is updated with values as Mary for name, Tokyo for commencement location and Abu Dhabi for end location.

The beneath image illustrates this:

powershell http put request

PowerShell: HTTP PATCH Request to Web API

Here I am making a HTTP PATCH asking with PowerShell to update a reservation record. And so in the JSON I will ship the op argument with supervene upon value.

The below PATCH command volition update the 2d reservation'southward proper name field to Bob and start location field to San Francisco.

          PM> Invoke-RestMethod https://localhost:44324/api/Reservation/2 -Method PATCH -Trunk (@{ op="replace"; path="Name"; value="Bob"},@{ op="supervene upon"; path="StartLocation";value="San Francisco"} | ConvertTo-Json) -ContentType "application/json"        

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

powershell http patch request

PowerShell: HTTP DELETE Request to Web API

To Powershell command to call DELETE type method of Web API is:

          PM> Invoke-RestMethod https://localhost:44324/api/Reservation/3 -Method DELETE        

The to a higher place control volition delete the 3rd reservation by invoking the Web API'southward Delete Action method.

Securing Web APIs by KEYS

You do non want to let Web API's admission to anybody. So you will need to secure Web APIs with Keys. The clients will have to transport the API Keys along with the asking, the keys are checked past the APIs and if they are correct then merely the response is sent to the clients.

The best manner to send the API Keys is through the Http Asking Header.

To sympathise this thing, I create a situation where only authorized clients tin add together a reservation by calling the Web API. I have to change the HTTP Post activeness of the Web API Controller to create a transmission check for the Keys which are provided in the header.

If the keys are right but then the Reservation is added, else unauthorized upshot 401 response is send dorsum.

So alter the HTTP Postal service action of the Spider web API every bit 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     })); }          

Discover I changed the return blazon to IActionResult since information technology volition exist returning both a HTTP Status Code and a reservation object.

Unauthorized Status code 401 is returned if Authenticate() method returns false, else Success 200 Status Code is returned forth with the newly created reservation object.

Also note that I take used the Ok() method to send both HTTP 200 Status Code with the reservation object.

You besides need to add an Authenticate() role to the API controller which checks for the keys placed on the header of the Http requests made by the clients.

bool Authenticate() {     var allowedKeys = new[] { "[e-mail protected]", "Cloak-and-dagger#12", "SecretABC" };     StringValues primal = Request.Headers["Key"];     int count = (from t in allowedKeys where t == key select t).Count();     render count == 0 ? false : true; }          

There are 3 valid keys provided in the allowedKeys variable. Then I check if the Key in the header matches from these three keys, merely and so true value is returned by this function.

Now go to the APIConsume project (i.eastward. the client project), and so inside the AddReservation action method of the HomeController, y'all add a key in the Header of the HTTP request with this code – httpClient.DefaultRequestHeaders.Add("Fundamental", "[email protected]").

Likewise add a try grab block to deserialize the response to a reservation object. If the deserialization fails then information technology is because the API Response does non contain the reservation object. This is a case when the key is invalid and 401 status code is returned by the API.

I take placed the ViewBag.Result variable, inside the catch block, to incorporate this 401 response sent by the API.

The updated AddReservation activity method's code is given beneath.

[HttpPost] public async Task<IActionResult> AddReservation(Reservation reservation) {     Reservation receivedReservation = new Reservation();     using (var httpClient = new HttpClient())     {         httpClient.DefaultRequestHeaders.Add("Primal", "[electronic mail protected]");         StringContent content = new StringContent(JsonConvert.SerializeObject(reservation), Encoding.UTF8, "application/json");          using (var response = await httpClient.PostAsync("https://localhost:44324/api/Reservation", content))         {             string apiResponse = await response.Content.ReadAsStringAsync();                          if (response.StatusCode == System.Net.HttpStatusCode.OK)                 receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);             else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)             {                 ViewBag.Result = apiResponse;                 return View();             }         }     }     return View(receivedReservation); }          

Now run your APIConsume projection and add a new reservation from the URL https://localhost:44334/Habitation/AddReservation. Y'all will be able to add the new reservation because the central which you provide is correct.

Now Change the key to a wrong one like – httpClient.DefaultRequestHeaders.Add together("Key", "wrongkey"). Then try in one case once again to add a new reservation. This time you will fail to do then and volition run across a JSON bulletin:

          {"type":"https://tools.ietf.org/html/rfc7235#section-3.1","championship":"Unauthorized","status":401,"traceId":"|cccb5daa-43da21f99ce83682.one.f7315d9e_"}        

This is shown past the image given beneath:

401 status message received for wrong key

This JSON contains the title & status nodes containing the texts – Unauthorized & 401. Yous tin only extract these texts by using Newtonsoft.Json and show them on the view.

Here I have shown only a simple way of securing Spider web APIs. In professional websites of big corporations the Web APIs are secured by JWT Token based hallmark. I accept besides written a tutorial on this topic – How to secure APIs with JWT in ASP.NET Core [with source codes]

File Upload Web API

You can also upload files to remote servers through Spider web API. This can be done by using the IFormFile form as the parameter of the Web API'southward action method. The IFormFile class represents the file sends through the HttpRequest.

Allow us create this file upload characteristic. Showtime add Images folder inside the wwwroot folder of the APIControllers project. In that folder files sent by the client volition be uploaded.

The below image illustrates the images folder location:

images folder location

For saving files I volition demand the data almost the web hosting surroundings. The best way is to use the ASP.Cyberspace Cadre Dependency Injection characteristic to inject IWebHostEnvironment of the Microsoft.AspNetCore.Hosting namespace into the controller's constructor. So update the Reservation Controller of the APIControllers project as shown beneath.

using System; using System.Collections.Generic; using APIControllers.Models; using Microsoft.AspNetCore.JsonPatch; using Microsoft.AspNetCore.Mvc; using System.Linq; using Microsoft.Extensions.Primitives; using Microsoft.AspNetCore.Hosting;  namespace APIControllers.Controllers {     [ApiController]     [Road("api/[controller]")]     public course ReservationController : ControllerBase     {         individual IRepository repository;                  private IWebHostEnvironment webHostEnvironment;          public ReservationController(IRepository repo, IWebHostEnvironment environment)         {             repository = repo;             webHostEnvironment = surround;         }                 // other methods     } }          

At present you are ready to utilise the webHostEnvironment variable which contains the hosting environs details.

Next, add a new action method chosen UploadFile to the Reservation Controller of the APIControllers project as shown below:

using System; using System.Collections.Generic; using APIControllers.Models; using Microsoft.AspNetCore.JsonPatch; using Microsoft.AspNetCore.Mvc; using System.Linq; using Microsoft.Extensions.Primitives; using Microsoft.AspNetCore.Hosting; using System.Threading.Tasks; using System.IO; using Microsoft.AspNetCore.Http;  namespace APIControllers.Controllers {     [ApiController]     [Route("api/[controller]")]     public class ReservationController : ControllerBase     {         private IRepository repository;                  private IWebHostEnvironment webHostEnvironment;          public ReservationController(IRepository repo, IWebHostEnvironment environment)         {             repository = repo;             webHostEnvironment = environment;         }                  [HttpPost("UploadFile")]         public async Task<string> UploadFile([FromForm] IFormFile file)         {             string path = Path.Combine(webHostEnvironment.WebRootPath, "Images/" + file.FileName);             using (var stream = new FileStream(path, FileMode.Create))             {                 await file.CopyToAsync(stream);             }             return "https://localhost:44324/Images/" + file.FileName;         }     } }          

This action contains the [HttpPost("UploadFile")] attribute that specifies this action method will be invoked from the URL – /api/Reservation/UploadFile.

The Customer volition be sending the file from HttpRequest and the file will exist saved to the wwwroot/Images folder of the Spider web API project.

The WebRootPath() method of the IWebHostEnvironment class gives the accented path of the application's wwwroot folder.

And then I can utilize the Path.Combine() method of the System.IO namespace to create an accented path where the file will be saved. I have also added the file name to this path by using the file.FileName property of the IFormFile form.

The FileStream course lawmaking 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 total path of the saved file to the client as a response.

Now going on the client side, which is the APIConsume project, where I will add a new activeness method that will upload the file by calling the Spider web API.

This activity method is given below:

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

This action method, whose name is AddFile, has a parameter of type IFormFile. This means I can get the file which is uploaded from the input control of file type, in the View through the ASP.NET Core Model Binding characteristic.

Next I am reading the file from the OpenReadStream() method, and adding it to the form information past using the MultipartFormDataContent class. The reason for adding the file to class data is because the Spider web API activity method has the [FromForm] aspect.

Finally, I am making the API call to the URL – https://localhost:44324/api/Reservation/UploadFile with the HTTP Post request and the Web API response is returned to the View as Model.

The API returns a string which contains the total location of the uploaded file. At the terminal I casted this cord to an object – (object)apiResponse and provided it to the default view.

Now create the View called AddFile inside the Views ➤ Home folder with the code given beneath:

@model string @{ Layout = "_Layout"; ViewBag.Title = "Add together File";}   <h2>Add File</h2> <a asp-action="Index" grade="btn btn-sm btn-primary">Back</a> <grade method="post" enctype="multipart/form-data">     <input type="file" name="file" />     <div form="text-center panel-body">         <push type="submit" course="btn btn-sm btn-primary">Add</button>     </div> </form>   @if (Model != null) {     <h2>Uploaded File</h2>     <img src="@Model" /> }          

The class should have the attribute – enctype="multipart/grade-data" whenever you are uploading files.

The view has a model of type cord then that I can show the API response inside an img tag.

At present let u.s. examination it by uploading an epitome file. So run the application and go to the URL – https://localhost:44334/Home/AddFile. Click the file control and select an image so click the Add push. Yous will see the image gets uploaded inside a matter of seconds and will exist displayed on the View.

The image below illustrates this:

file upload through web api

Y'all can now find this file uploaded in the Images folder of the API Controllers project:

file uploaded

Returning Data from Web API in XML instead of JSON – [Produces] aspect

I told earlier that ASP.NET Cadre returns data in JSON by default if the action method has the return type of anything other than a cord.

You may have noticed that if you run your APIControllers project and go to the URL – /api/Reservation, and so you will become a JSON data containing all the reservations.

Check the Response Headers in your Network section of Chrome browser's Developers Tools. Y'all volition find the Content-Type as application/json. This is shown in the beneath image:

API response in json

You tin change this and brand the Web API to return the information in XML rather than in JSON. For this you volition have to add the AddXmlDataContractSerializerFormatters() method in the ConfigureServices method of the Startup.cs.

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

Also add the aspect called [Produces("application/xml")] which forces the format used past the API response to XML.

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

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

Now re-run your application and go to the same URL over again. This fourth dimension you will run across the data in XML format and the Content-Type set equally awarding/xml. Run into the beneath image:

Web API response in xml

Spider web APIs accepting XML [Consumes("application/xml")]

The [Consumes] attribute specifies data types that an activeness/controller accepts. Some Web APIs accepts just XML information and then take [Consumes("awarding/xml")] aspect on them. Allow u.s. see how to deal with information technology.

Go to the APIControllers app and add a new action method chosen PostXml with the Eat aspect to accept but XML data. Run across it's code below.

[HttpPost("PostXml")] [Consumes("application/xml")] public Reservation PostXml([FromBody] Organisation.Xml.Linq.XElement res) {     return repository.AddReservation(new Reservation     {         Proper name = res.Chemical element("Name").Value,         StartLocation = res.Chemical element("StartLocation").Value,         EndLocation = res.Chemical element("EndLocation").Value     }); }          

Two things to note here.

  • 1. It has the eat attribute – [Consumes("application/xml")].
  • ii. Information technology'due south parameter is of type XElement.

The [Consume] attribute examines the Content-Type header in the HTTP Request made from the clients and decides whether the activity method tin process the asking or not.

Now to invoke this Web API'due south method from your client project you add an action method called AddReservationByXml having the code shown below.

public ViewResult AddReservationByXml() => View();  [HttpPost] public async Task<IActionResult> AddReservationByXml(Reservation reservation) {     Reservation receivedReservation = new Reservation();      using (var httpClient = new HttpClient())     {         StringContent content = new StringContent(ConvertObjectToXMLString(reservation), Encoding.UTF8, "awarding/xml");          using (var response = await httpClient.PostAsync("https://localhost:44324/api/Reservation/PostXml", content))         {             string apiResponse = look response.Content.ReadAsStringAsync();             receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);         }     }     return View(receivedReservation); }  string ConvertObjectToXMLString(object classObject) {     string xmlString = nada;     XmlSerializer xmlSerializer = new XmlSerializer(classObject.GetType());     using (MemoryStream memoryStream = new MemoryStream())     {         xmlSerializer.Serialize(memoryStream, classObject);         memoryStream.Position = 0;         xmlString = new StreamReader(memoryStream).ReadToEnd();     }     return xmlString; }          

Important things to note here are:

  • 1. You take to specify application/xml for the 3rd parameter (media type) of the StringContent class.
  • 2. The ConvertObjectToXMLString is a custom function to create XML from whatever form object.

Finally add the View called AddReservationByXml within the Views ➤ Abode folder (run across below).

@model Reservation @{ Layout = "_Layout"; ViewBag.Championship = "Add together a Reservation by XML";}  <h2>Add together a Reservation by XML <a asp-activity="Index" class="btn btn-sm btn-secondary">Back</a></h2> <form asp-activeness="AddReservationByXml" method="post">     <div class="form-grouping">         <characterization for="Name">Name:</label>         <input form="grade-control" name="Proper name" />     </div>     <div class="form-grouping">         <label for="StartLocation">Start Location:</label>         <input class="class-command" proper name="StartLocation" />     </div>     <div class="grade-group">         <label for="EndLocation">End Location:</label>         <input class="form-control" proper name="EndLocation" />     </div>     <div form="text-centre console-torso">         <push button blazon="submit" grade="btn btn-sm btn-primary">Add</push button>     </div> </grade>  <h3 form="alert">@ViewBag.Effect</h3>  @if (Model != null) {     <h2>Reservation</h2>     <table form="table table-sm table-striped tabular array-bordered g-2">         <thead>             <tr>                 <th>ID</thursday>                 <th>Name</th>                 <th>First Location</thursday>                 <th>End Location</thursday>             </tr>         </thead>         <tbody>             <tr>                 <td>@Model.Id</td>                 <td>@Model.Name</td>                 <td>@Model.StartLocation</td>                 <td>@Model.EndLocation</td>             </tr>         </tbody>     </table> }          
Important:

In one case yous publish your Web API you accept to make sure that you Enable Cantankerous-Origin Requests (CORS) otherwise the clients volition receive error chosen No 'Access-Control-Allow-Origin' header is present on the requested resource . Yous can check my tutorial How to Enable Cantankerous-Origin Requests (CORS) in ASP.Net Core. By the fashion, on the source codes, I take already enabled CORS (see Setup.cs file of APIControllers projection).

Web APIs "Format-specific" Methods

A single method of the Web API can produce both JSON & XML issue. For this you have to utilize the FormatFilter attribute.

Add together the beneath method to your Web API.

[HttpGet("ShowReservation.{format}"), FormatFilter] public IEnumerable<Reservation> ShowReservation() => repository.Reservations;          

See I have applied the format filter like – [HttpGet("ShowReservation.{format}"), FormatFilter]. And so this method can now send the reservation in both XML & JSON. This will reduce your code in a big fashion.

The URL to invoke the XML version:

https://localhost:44324/api/Reservation/ShowReservation.xml

The URL to invoke the JSON version:

https://localhost:44324/api/Reservation/ShowReservation.json

I have shown the working in the below video.

formatfilter attribute video

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

Download

Conclusion

In this tutorial I explained everything dealing with Web APIs in ASP.Cyberspace Cadre MVC. I promise you find it useful, please share this article that volition assist the website. Also check the next tutorial – How to Calll Web APIs from jQuery.

maxwelloune1991.blogspot.com

Source: https://www.yogihosting.com/aspnet-core-consume-api/

0 Response to "Asp.net Core 2.1 Web Api Upload File Httpclient"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel