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.IEnumerable
1[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.AsyncTaskMethodBuilder
1 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:
- The attached JSON response is the
RootViewModel
type. You deserialize theresponse.Content
asRootViewModel
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;
}
- 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; }
...
}
- As in 1 we will return the
RootViewModel
value from the controller, modify the ViewModel asRootViewModel
. 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>
- Your controller action should return
Task<IActionResult>
and it is anasync
method.
public async Task<IActionResult> Index()
{
var all = await _client.GetAllProduct();
return View(all);
}