How to receive the view model in a GET request Webapi?

Asked

Viewed 352 times

2

Okay, I have a problem with my API here, and I’d like to ask for your help. I have here a form in Knockout JS, I serialize a constructor that in turn returns me a querystring so

API? Page=1&Minprice=185&Maxprice=694

My problem is that the API does not understand what this is and gives me back this

{"message":"An error has occurred.","exceptionMessage":"Multiple actions were found that match the request: \r\nGet on type SiteMvc.Controllers.ProductAPIController\r\nGet on type SiteMvc.Controllers.ProductAPIController","exceptionType":"System.InvalidOperationException","stackTrace":"   em System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n   em System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n   em System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"}

Listvm

public class ListVM 
{

    public decimal? MinPrice { get; set; }

    public decimal? MaxPrice { get; set; }

    public int? CategoryID { get; set; }

    public int ProductType { get; set; }

}

API Controller

   public HttpResponseMessage Get(int page, [FromUri]ListVM vm)
            {

                CompanyManager m = new CompanyManager();
                HttpResponseMessage r = CheckEntryJson(m);
                if (r != null)
                    return r;

                ProductsBL bl = new ProductsBL(m.CompanyID);

                var query = bl.GetProducts();

                if (vm.MinPrice.HasValue)
                    query = query.Where(x => x.ProductStore.Price >= vm.MinPrice);
                if (vm.MaxPrice.HasValue)
                    query = query.Where(x => x.ProductStore.Price <= vm.MaxPrice);

                if (vm.CategoryID.HasValue)
                    query = query.Where(x => x.CategoryID == vm.CategoryID);




                Func<ProductType, string> getProductTypeName = x => x.ToName();

                var result = query.Select(x => new ProductAPIModel
                {

                    Name = x.Name,
                    TotalPrice = x.ProductStore == null ? 0 : x.ProductStore.TotalPrice,
                    ID = x.ProductID,
                    ProductType = getProductTypeName(x.ProductType),
                    Reference = x.Reference,
                    Description = x.Description

                });
     if (result == null) return Request.CreateResponse(HttpStatusCode.NotFound);

                var json = new
                {
                    Items = result.Skip(pageSize * (page - 1)).Take(pageSize).ToList(),
                    TotalItems = result.Count()
                };

                return Request.CreateResponse(HttpStatusCode.OK, json);
            }


        }

My goal is to make the API understand that these are model fields without having to put the fields all at hand as parameters and/or touch the Routes

Thanks in advance !

2 answers

2


For those who have doubts, to solve this problem, I decided to abandon the Restful of the API and specify actions within them, I use gets, however in the specific Razor on Url.Route to action and so mvc can already decipher the query string and compare it with the model

Routes

      config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{company}/{controller}/{action}/{id}",
        defaults: new { action = "Default", id = RouteParameter.Optional },
        constraints: new { company = @"\d+" } //Obriga a que o company seja um valor númerico
        );

1

If you are using API 2+, Voce should use annotations in your actions. It is more elegant and simpler to configure.

[RoutePrefix("/api/product")]
public class ProductApiController : ApiController
{
    [HttpGet] // Sempre é bom ser explícito
    [Route("{page}")]
    public HttpResponseMessage Get([FromUri] int page, [FromUri] ListVM vm) {...}
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.