Home > Software engineering >  RestSharp - How to return data from API to View
RestSharp - How to return data from API to View

Time:01-16

public class ProductViewModel
{
    public int id { get; set; }
    public string title { get; set; }
    public string description { get; set; }
    public int price { get; set; }
    public double discountPercentage { get; set; }
    public double rating { get; set; }
    public int stock { get; set; }
    public string brand { get; set; }
    public string category { get; set; }
    public string thumbnail { get; set; }
    public List<string> images { get; set; }
}

public class RootViewModel
{
    public ProductViewModel[] Products { get; set; }
    public int total { get; set; }
    public int skip { get; set; }
    public int limit { get; set; }
}
public class WebProductClient : IWebProductClient
{
    private readonly RestClient _client;
    private readonly string _url;

    public WebProductClient()
    {
        _url = "https://local/host:7123/";
        var options = new RestClientOptions(_url);
        _client = new RestClient(options);
    }

    public async Task<ProductViewModel> GetAllProduct()
    {
        var request = new RestRequest("Api/Products");
        var response = await _client.ExecuteGetAsync(request);
        var r = JsonConvert.DeserializeObject<ProductViewModel>(response.Content);
        return r;
    }
}

ProductsController:

public IActionResult Index()
{
    var all = _client.GetAllProduct();
            
    return View(all);
}

Index:

@model IEnumerable<DummyShop.Service.ViewModel.ProductViewModel>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table >
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.id)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.description)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.price)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.discountPercentage)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.rating)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.stock)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.brand)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.category)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.thumbnail)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.id)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.description)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.price)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.discountPercentage)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.rating)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.stock)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.brand)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.category)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.thumbnail)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
                @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
                @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
            </td>
        </tr>
}
    </tbody>
</table>

Returned data from my API:

{
  "products": [
    {
      "id": 1,
      "title": "iPhone 9",
      "description": "An apple mobile which is nothing like apple",
      "price": 549,
      "discountPercentage": 12.96,
      "rating": 4.69,
      "stock": 94,
      "brand": "Apple",
      "category": "smartphones",
      "thumbnail": "://i.dummyjson./data/products/1/thumbnail./jpg",
      "images": [
        "://i.dummyjson./data/products/1/1./",
        "://i.dummyjson./data/products/1/2./",
        "://i.dummyjson./data/products/1/3./",
        "://i.dummyjson./data/products/1/4./",
        "://i.dummyjson./data/products/1/thumbnail./"
      ]
    },
    {
      "id": 2,
      "title": "iPhone X",
      "description": "SIM-Free, Model A19211 6.5-inch Super Retina HD display with OLED technology A12 Bionic chip with ...",
      "price": 899,
      "discountPercentage": 17.94,
      "rating": 4.44,
      "stock": 34,
      "brand": "Apple",
      "category": "smartphones",
      "thumbnail": "://i.dummyjson/data/products/2/thumbnail.",
      "images": [
        "://i.dummyjson/data/products/2/1.",
        "://i.dummyjson/data/products/2/2.",
        "://i.dummyjson/data/products/2/3.",
        "://i.dummyjson/data/products/2/thumbnail."
      ]
    },
      ],
  "total": 100,
  "skip": 0,
  "limit": 30
}

The error I got:

System.Collections.Generic.IEnumerable1[DummyShop.Service.ViewModel.ProductViewModel].An unhandled exception occurred while processing the request. InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder1 AsyncStateMachineBox`1[DummyShop.Service.ViewModel.ProductViewModel,DummyShop.Service.ProductClientsWEB.WebProductClient d__5]', but this ViewDataDictionary instance requires a model item of type

CodePudding user response:

  1. The attached JSON response is the RootViewModel type. You deserialize the response.Content as RootViewModel type.
public async Task<RootViewModel> GetAllProduct()
{
    var request = new RestRequest("Api/Products");
    var response = await _client.ExecuteGetAsync(request);
    var r = JsonConvert.DeserializeObject<RootViewModel>(response.Content);

    return r;
}
  1. Consider using the JsonPropertyName attribute to match the property name in the JSON. Same goes for the other properties, you should name the properties as "Pascal Casing" instead of "camel Case".
public class RootViewModel
{
    [JsonPropertyName("products")]
    public ProductViewModel[] Products { get; set; }

    ...
}
  1. As in 1 we will return the RootViewModel value from the controller, modify the ViewModel as RootViewModel. And enumerate with @Model.Products for the <thead> and <tr> elements.
@model RootViewModel

<table >
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Products[0].id)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Products[0].title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Products[0].description)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Products[0].price)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Products[0].discountPercentage)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Products[0].rating)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Products[0].stock)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Products[0].brand)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Products[0].category)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Products[0].thumbnail)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>

      @foreach (var item in Model.Products) 
      {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.id)
            </td>
            
            <!-- Following td elements -->
        </tr>
      }
    </tbody>
</table>
  1. Your controller action should return Task<IActionResult> and it is an async method.
public async Task<IActionResult> Index()
{
    var all = await _client.GetAllProduct();
        
    return View(all);
}
  • Related