How can I call a Web API method from an MVC controller action method?
This is what I am trying, this is my controller method:
public ActionResult ProductDetail(long id) { using (var client = new HttpClient()) { var productDetailUrl = Url.RouteUrl( "DefaultApi", new { httproute = "", controller = "ProductDetails", id = id }, Request.Url.Scheme ); var model = client .GetAsync(productDetailUrl) .Result .Content.ReadAsAsync<ProductItems>().Result; return View(model); } }
My Web API method:
private ProductEntities products = new ProductEntities(); public IEnumerable<ProductItems> GetProductDetail(int ID) { var produc = products.ExecuteStoreQuery<ProductItems>( "GetProductDetail @ProductID ", new SqlParameter("@ProductID", ID)); return produc; }
When I am doing this I am getting an error @ var model
in my MVC action method after returning the data, saying:
"
Newtonsoft.Json.JsonSerializationException
: Cannot deserialize JSON array "(i.e.[1,2,3]
) into type 'ProductDetails.Models.ProductItems
'. The deserialized type must be an array or implement a collection interface likeIEnumerable
,ICollection
orIList
. To force JSON arrays to deserialize add theJsonArrayAttribute
to the type. Line 1, position 1."
Can anyone help me do this, suggest another better method, or correct me if I am doing it wrong anywhere? I have to show the returned data in my view, the data should be returned to my controller.
As the exception states "Cannot deserialize JSON array ..." you have a problem on the receiver side e.g with the deserialization not in your web api method with the serialization.
And your problem is that you try to deserialize into the wrong type because your web api method looks like:
public IEnumerable<ProductItems> GetProductDetail(int ID)
So it returns IEnumerable<ProductItems>
(e.g. an array of ProductItems
) but in your controller action you try to deserialize the response into one ProductItems
with the call ReadAsAsync<ProductItems>()
So change your ReadAsAsync
to deserialize into an array ProductItems
and it should work:
var model = client .GetAsync(productDetailUrl) .Result .Content.ReadAsAsync<ProductItems[]>().Result;
When your ASP.NET web site is hosting together with Web API controller then you can call Web API as ordinary class method to avoid any delays related to HTTP request.
And problem is not in Web API call. Problem is in result deserialization, that comes from ExecuteStoreQuery, make sure you have serializable collection in it. To make sure, you can simply try to convert this method result to list before return and return from web api method serializable list, then localize problem.
UPD: So, root of problem is in what ExecuteStoreQuery method returns. It returns ObjectResult. It actually implements IEnumerable, but it's returned from EF and in some cases there are e.g. cyclic dependencies between objects, that Json deserialzers couldn't resolve.
To resolve problem simply convert explicitly ObjectResult to e.g. List:
public IEnumerable<ProductItems> GetProductDetail(int ID) { var products = products.ExecuteStoreQuery<ProductItems>( "GetProductDetail @ProductID ", new SqlParameter("@ProductID", ID)); return products.ToList<ProductItems>(); }
When problem is actually with cycle dependencies in collections of your objects that come from EF, you can switch it off in Json.NET
And also check your client side deserialization:
var model = client.GetAsync(productDetailUrl).Result .Content.ReadAsAsync<List<ProductItems>>().Result;
But when you are hosting your ASP.NET MVC site and ASP.NET Web API in one project, then you do not need all this stuff with HTTP request and serialization/deserialization, just call your method as ordinary class method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With