jqGrid ajax Operations in ASP.NMET MVC

I am using jqGrid in my current project, and I already blogged prior on how impressed I am with the functionality available in this control.  I am using it in ASP.NET MVC application, but it can be used in any web app.  One of the key features is that it supports ajax based asynchronous server operations.

Upon my research I stumbled onto this article that greatly simplifies the code required to process search requests in ASP.NET MVS that are generated by the grid

http://www.codeproject.com/KB/aspnet/AspNetMVCandJqGrid.aspx

I had to make a small addition to it though.  The code works great in multi-search scenarios, but if you turn off multisearch option in search options, than you will get an error.  I also remove empty try/catch blocks which I personally find to be a bad practice.  Here is the updated code I used for Filter class:

using System.Runtime.Serialization;
using
System.Runtime.Serialization.Json;
using
System.Text;
 
[
DataContract
]
public class Filter

{
    [
DataMember]
   
public string groupOp { get; set
; }
    [
DataMember
]
   
public Rule[] rules { get; set
; }
 
   
public static Filter
Create(
       
string
jsonData, 
       
string
searchField, 
       
string
searchString, 
       
string
searchOper)
    {
       
Filter returnValue = null
;
       
if (!string
.IsNullOrEmpty(jsonData))
        {
           
var serializer = new DataContractJsonSerializer(typeof(Filter
));
           
using (var ms = new System.IO.MemoryStream(Encoding
.Default.GetBytes(jsonData)))
            {
                returnValue = serializer.ReadObject(ms)
as Filter
;
            }
 
        }
       
else

        {
            returnValue =
                   
new Filter()
                    {
                        groupOp =
"AND"
,
                        rules =
new[] { new Rule
() 
                        { data = searchString, field = searchField, op = searchOper } }
                    };
        }
       
return
returnValue;
    }
}

 

I added else statement that checks the json data variable, which will be null in cases of single field search.  The code will fall into same patch though, which is convenient because you process data code can stay the same whether or not you are using single or multi-search. 

Of course, I had to update the model binder to match:

using System.Web.Mvc;
 

public class GridModelBinder : IModelBinder

{
   
public object BindModel(
       
ControllerContext
controllerContext,
       
ModelBindingContext
bindingContext)
    {
       
var
request = controllerContext.HttpContext.Request;
       
return new GridSettings

        {
            IsSearch =
bool.Parse(request["_search"] ?? "false"),
            PageIndex =
int.Parse(request["page"] ?? "1"
),
            PageSize =
int.Parse(request["rows"] ?? "10"
),
            SortColumn = request[
"sidx"] ?? ""
,
            SortOrder = request[
"sord"] ?? "asc"
,
            Where =
Filter
.Create(
                request[
"filters"
],
                request[
"searchField"
],
                request[
"searchString"
],
                request[
"searchOper"
])
        };
    }
}

 

I want to thank Ilya Builuk for sharing his code.  I hope you will find my enhancements useful.  Another side thought.  There is a string based IQueryable extensions library that you can use to construct queries against this interface based on syntax such as “Where SomeColumn =- 2”.  Not that I am a giant fan of leaking my data access code into controllers or anything.  You can read more about dynamic linq on Scott Guthrie’s blog here

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Thanks.

2 Comments

  1. Hi,

    Great article! Helped me a lot and directed in right direction. However I am struggling in figuring it out as How can I implement the same in multi tier application with repository pattern.

    I do not want to implement following repetitive code in each controller action.

    var query = _repository.Computers();

    //filtring
    if (grid.IsSearch)
    {
    //And
    if (grid.Where.groupOp == “AND”)
    foreach (var rule in grid.Where.rules)
    query = query.Where(
    rule.field, rule.data,
    (WhereOperation)StringEnum.Parse(typeof(WhereOperation), rule.op));
    else
    {
    //Or
    var temp = (new List()).AsQueryable();
    foreach (var rule in grid.Where.rules)
    {
    var t = query.Where(
    rule.field, rule.data,
    (WhereOperation)StringEnum.Parse(typeof(WhereOperation), rule.op));
    temp = temp.Concat(t);
    }
    //remove repeating records
    query = temp.Distinct();
    }
    }

    //sorting
    query = query.OrderBy(grid.SortColumn,
    grid.SortOrder);

    //count
    var count = query.Count();

    //paging
    var data = query.Skip((grid.PageIndex – 1) * grid.PageSize).Take(grid.PageSize).ToArray();

    Rather want a repository method to handle this code. Also I want to implement pagination.
    Any suggestions and help on this is highly appreciable.

    Thanks.

  2. You should probably create a base repository and put that the code there. Assuming you use EF you could have something like

    public PagedData GetPagedData(IDictionary filters, string sortColumns, string sortDirection, int pageNumber, int pageSize)
    {
    var query = context.Set
    ().OrderBy(sortColumn, sortOrder).Skip().Take()….

    }

    then you have a class for result

    public class PagedData
    {
    public Ienumerable
    Data{get; internal set;};
    public int Total{}
    public int Rows{}
    }

    etc…

    Hope this is what you are looking for.

    Sergey Barskiy

Leave a Reply

Your email address will not be published. Required fields are marked *