jqGrid and ASP.NET MVC – Batch updates

Recently I've been asked to prepare a batch update scenario for jqGrid. After playing around with few prototypes I decided use inline editing for that purpose.
First we need to put all displayed rows into editable state. The best way to do this is to call editRow for each row during gridComplete event:
<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.jqGrid.locale-en-3.8.2.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.jqGrid-3.8.2.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.json-2.2.min.js")" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#grid_id').jqGrid({
//Here you set up colModel, colNames and any other options
...
//This event fires after all the data is loaded into the grid
gridComplete: function() {
//Get ids for all current rows
var dataIds = $('#grid_id').jqGrid('getDataIDs');
for (var i = 0;i < dataIds.length; i++) {
//Put row in edit state
$("#grid_id").jqGrid('editRow', dataIds[i], false);
}
}
});
});
</script>
This way we can be sure, that every row loaded by jqGrid will end up in edit state. Now we need to add a button which will trigger the batch update. In the click event of that button we want to save every row to local data array. We can achieve that by using saveRow method, we just need to put 'clientArray' in third parameter. One important thing to remember here is that saveRow may throw an exception in case of validation errors - in such a case we will restore the original row and skip sending it to the server. Actual sending will be done by jQuery.ajax() method:
$('#button_id').click(function() {
var batch = new Array();
//Get ids for all current rows
var dataIds = $('#grid_id').jqGrid('getDataIDs');
for (var i = 0; i < dataIds.length; i++) {
try {
//Save row only to the grid
$('#grid_id').jqGrid('saveRow', dataIds[i], false, 'clientArray');
//Get row data
var data = $('#grid_id').jqGrid('getRowData', dataIds[i]);
//Data doesn't contains actual id
data.Id = dataIds[i];
//Add data to the batch
batch.push(data);
}
catch (ex) {
//If you are using editRules it might end up with exception
$('#grid_id').jqGrid('restoreRow', dataIds[i]);
}
}
//Send batch to the server
$.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
url: '@Url.Action("BatchUpdate", "Home")',
dataType: 'json',
data: $.toJSON(batch),
success: function(result) {
...
$('#grid_id').trigger('reloadGrid');
}
});
});
Now we have to receive the data on server side. Thanks to built in JSON model binding in ASP.NET MVC 3 we can do this with very simple action method:
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult BatchUpdate(List<ViewModel> viewModelsBatch)
{
//Update your data storage here
...
}
Feel free to use this solution if you need something like this.

Making WebPI work with proxy authentica​tion

Recently I had to use WebPI on a machine behind a proxy which required authentication. After some time with google all I have found was information, that WebPI doesn't support authenticated proxies. As I really needed the tool, I decided to try find some workaround.
First step was to get the offline installer for WebPI (it's available here). After installation, the first run attempt resulted in following error:
---------------------------
Microsoft Web Platform Installer
---------------------------
Url 'https://go.microsoft.com/fwlink/?LinkId=193533' returned HTTP status code: 407
---------------------------
OK
---------------------------
The 407 error code stands for proxy authentication failure. If you are lucky, all what you need to do is enabling default credentials for proxy authentication. This can be easily done by modifying WebPlatformInstaller.exe.config file:
<configuration>
...
<system.net>
<defaultProxy enabled="true" useDefaultCredentials="true" />
</system.net>
...
</configuration>
Things are getting a little bit more complicated, when you have to provide specific user and password combination for basic proxy authentication. The defaultProxy element can have a child element module, which can be used for adding a new proxy module to application. Such a proxy module is nothing more than a class which implements IWebProxy interface:
namespace WebPI.Net
{
public class AuthenticatedProxy : IWebProxy
{
public ICredentials Credentials
{
//Put your user name and password into credentials
get { return new NetworkCredential("user", "password"); }
set { }
}

public Uri GetProxy(Uri destination)
{
//Proxy URI will be taken from the current user's IE proxy settings
return WebRequest.GetSystemWebProxy().GetProxy(destination);
}

public bool IsBypassed(Uri host)
{
return false;
}
}
}
The GetSystemWebProxy method guarantees support for IE proxy settings (automatically detect proxy settings, automatic configuration script, manual proxy server settings and advanced manual proxy server settings). Now only a small change to WebPlatformInstaller.exe.config file is needed:
<configuration>
...
<system.net>
<defaultProxy enabled="true" useDefaultCredentials="false">
<module type="WebPI.Net.AuthenticatedProxy, WebPI.Net, Version=1.0.0.0, Culture=neutral, PublicKeyToken=79a8d77199cbf3bc" />
</defaultProxy>
</system.net>
...
</configuration>
That's it. This solution has been tested only on one machine but it has completely resolved the problem of proxy authentication for me, I hope it will do the same for some of you.