HTML5 offline ASP.NET MVC4 application allows to enter order quantities and submit order for customer.
Product list rendered in browser contains about 4000 products. Only few products are ordered for particular order.
Using code below request times out. Browser posts all products. Request takes too much time and is probably terminated by httpruntime ExecutionTimeout
Server error log shows that all posted data is received. It looks like MVC model binder requires too much time to create product list from posted data.
How to fix this ? How to post only ordered items whose quantities are entered or other idea ? I can switch to ajax, jquery and MVC4 Web API if this is reasonable.
Controller:
public class OfflineOrderController : ControllerBase
{
[HttpGet]
public ActionResult Order(string customerId)
{
return View(new MobileOrderOrderViewModel(customerId));
}
[HttpPost]
public ActionResult Order(string customerId, [Bind(Prefix = "Products")] IEnumerable<OrderedItems> Result)
{
... save order to database
return new ContentResult() { Content = "Order received" };
}
public AppCacheResult Manifest()
{
return new AppCacheResult(new[] {
Url.Content("~/Image/Icon/favicon")
});
}
}
View:
<!DOCTYPE html>
<html manifest="~/MobileOrder/Manifest">
<body>
@using (Html.BeginForm())
{
<table>
@for (int i = 0; i < Model.Products.Count; i++)
{
<tr>
<td>@Model.Products[i].Id</td>
<td>
@Html.HiddenFor(m => Model.Products[i].Id)
@Html.TextBoxFor(m => Model.Products[i].Quantity,
new { type = "number", min = 0 })
</td>
</tr>
}
</table>
<input type="submit" value="Send order">
@Html.HiddenFor(m => Model.CustomerId)
}
</body>
</html>
ViewModel:
public class MobileOrderOrderViewModel : ViewModelBase
{
public string CustomerId { get; set; }
public List<OrderedItems> Products { get; set; }
public MobileOrderOrderViewModel( string customer ) {
CustomerId = customer;
... populate Products property from database
}
}
Model:
public class OrderedItems
{
public string Id;
public decimal Quantity;
}
Update2
Using code from Imrans answer I created API controller to receive ordered products:
public class OrderController :ApiController
{
public HttpResponseMessage Post(string customerid, [FromBody]List<OrderedItems> products) {
....
}
}
Debugger shows that products are posted but products parameter is empty list. How to pass selected product list to Web API ?
Code used for posting is:
<script>
$(function () {
"use strict";
var BASE_URL = '@Url.Content("~/")';
$("form").submit(function (ev) {
var elementsToSend = [];
ev.preventDefault();
var quantityElements = $("input.quantity").filter(function (index, element) {
if ($(this).val() != 0) {
return true;
}
else {
return false;
}
});
$.each(quantityElements, function (index, element) {
var productIndex = $(element).prevAll()[1];
var productIdElement = $(element).prevAll()[0];
elementsToSend.push(productIndex);
elementsToSend.push(productIdElement);
elementsToSend.push(element);
});
var dataToPost = $(elementsToSend).serializeArray();
$.post(BASE_URL + "api/Order?" + $.param({
customerid: $("#CustomerId").val()
}), dataToPost);
return false;
});
})
</script>
You can try AJAX to reduce the load:
Bear in mind, this only hijacks the default HTML form behavior. It can be superseded by turning off JavaScript.
EDIT: Make sure you are using the Controller / C# naming conventions. Else, binding may not work.
There are fancier ways to do list comprehensions using
filter
but what you have makes sense to me.Finally, in your
Order
POST action, it is a good idea to return aJsonResult
.Ok, here is what I think your view should look like
And here is the controller method:
Hope this helps.