Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I call a WebApi method from MVC Controller Action Method?

Tags:

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 like IEnumerable, ICollection or IList. To force JSON arrays to deserialize add the JsonArrayAttribute 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.

like image 532
SoftwareNerd Avatar asked Oct 05 '12 06:10

SoftwareNerd


2 Answers

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; 
like image 168
nemesv Avatar answered Sep 20 '22 05:09

nemesv


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.

like image 22
Regfor Avatar answered Sep 19 '22 05:09

Regfor