Kaan Yılmazer
Kaan Yılmazer

Reputation: 5

RestSharp - How to return data from API to View

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 class="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

Upvotes: 0

Views: 518

Answers (1)

Yong Shun
Yong Shun

Reputation: 51240

  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 class="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);
}

Upvotes: 1

Related Questions