Over the weekend, I was doing some work on the internal CMS we use over at eagleenvision.net and I wanted to scrap my custom table implementation for a table system that would use JSON to return data rather than have the data be statically allocated on the page. Basically I wanted to have the ability to refresh, etc for editing purposes. My little table marker was too much code for something so simple.

I’m a HUGE fan of jQuery, especially of the recent changes in jQuery 1.4. We have already made a significant investment in jQuery code for our CMS and I didn’t want to simply add another library or framework into the mix… by that I mean I didn’t want to throw in the Ext framework, which specialized in UI controls rather than general purpose JavaScript.

I stumbled upon the jQuery DataTables plugin. It has a lot of great features… one of which is the ability to have server-side processing of your data. The examples on the site are written with PHP, as are the downloadable demos. I don’t use PHP, I use ASP.NET :). So I had to write my own library to process the incoming request. DataTables has a set of pre-defined request variables that are passed to the server for processing. A successful implementation will take all these variables into account and send the correct data back per these variables. (To see a complete list, check out the server-side usage page).

Our friend, IQueriable

If you’re a C# developer, there’s no way you don’t already know about LINQ… (double negatives… oops…. every C# knows about LINQ, or they’re not really current with technology… that’s better :) ). This includes VB people as well. IQueriable is the fundamental type of LINQ that drives the functionality of the various sequence operators. In my implementation of DataTables processing, I wanted to leverage LINQ so that you could throw this thing an IQueriable from Linq2Sql, Linq to NHibernate, Entity Framework, LightSpeed, in-memory list, or ANYTHING that has IQueriable functionality and it would just work.

How to output

The DataTables plugin accepts either JSON or XML… whichever jQuery will parse. My opinion is never use XML with JavaScript. It’s slower and there’s no point to using XML over JSON… especially in .NET where there are built-in JSON serializers. Having said that, you could certainly use XML… although I haven’t tested my code for this, I think (in theory) it will work the same. He’s the output type, which should be serialized into JSON or XML, which I will cover in a minute.

public class FormatedList
{
public int sEcho { get; set; }
public int iTotalRecords { get; set; }
public int iTotalDisplayRecords { get; set; }
public List<List<string>> aaData { get; set; }
public string sColumns { get; set; }
public void Import(string[] properties)
{
sColumns = string.Empty;
for (int i = 0; i < properties.Length; i++)
{
sColumns += properties[i];
if (i < properties.Length - 1)
sColumns += ",";
}
}
}

Basically the only interesting thing here is the output of the columns. I made a custom Import method that just takes a list of properties and forms the column string that DataTables will parse. Other than that the code here is just basic property holding.

ASP.NET MVC

Readers of my blog and twitter will know I am also a HUGE fan of ASP.NET MVC. I don’t think I’ll ever return to ASP.NET WebForms. But who knows. Anyways, here’s how you will output the thing in MVC

public ActionResult List()
{
IQueriable<User> users = Session.Linq<User>();
if (Request["sEcho"] != null)
{
var parser = new DataTableParser<User>(Request, users);
return Json(parser.Parse());
}
return Json(users);
}

You’ll notice that I referenced DataTableParser, which I will get to in a minute. This takes an HttpRequestBase (or an HttpRequest) and an IQueriable of whatever type. It will output a new FormattedList in the parse method, which you will return via JSON (which is serialized in the Json method for MVC).

ASP.NET Webservices

While I don’t claim to be an expert at ASP.NET Webservice, this I can handle :). He’s how would would do the same thing in ASP.NET Webservices.

using System.Web.Script.Serialization;
using System.Linq;
...
public class MyWebservice : System.Web.Services.WebService
{
public string MyMethod()
{
// change the following line per your data configuration
IQueriable<User> users = Session.Linq<User>(); response.ContentType = "application/json"; if(Request["sEcho"] != null)
{
var parser = new DataTableParser<User>(Request, users);
return new JavaScriptSerializer().Serialize(parser.Parse());
} return new JavaScriptSerializer().Serialize(users);
}
}

This is the same code… it just uses webservices and the JavaScriptSerializer (which MVC uses under the covers) to serialize the FormatedList object.

It should be noted that you should ALWAYS check if the request is a DataTables request (which is what that sEcho business is all about).

The Parser

Now is the time to show you my parser. I have taken out my code comments to keep this short on my blog… but you can download my code from here and the comments should explain what is going on.

public class DataTableParser<T>
{
private const string INDIVIDUAL_SEARCH_KEY_PREFIX = "sSearch_";
private const string INDIVIDUAL_SORT_KEY_PREFIX = "iSortCol_";
private const string INDIVIDUAL_SORT_DIRECTION_KEY_PREFIX = "sSortDir_";
private const string DISPLAY_START = "iDisplayStart";
private const string DISPLAY_LENGTH = "iDisplayLength";
private const string ECHO = "sEcho";
private const string ASCENDING_SORT = "asc";
private IQueryable<T> _queriable;
private readonly HttpRequestBase _httpRequest;
private readonly Type _type;
private readonly PropertyInfo[] _properties;
public DataTableParser(HttpRequestBase httpRequest, IQueryable<T> queriable)
{
_queriable = queriable;
_httpRequest = httpRequest;
_type = typeof(T);
_properties = _type.GetProperties();
}
public DataTableParser(HttpRequest httpRequest, IQueryable<T> queriable)
: this(new HttpRequestWrapper(httpRequest), queriable)
{ } public FormatedList Parse()
{
var list = new FormatedList();
list.Import(_properties.Select(x => x.Name).ToArray()); list.sEcho = int.Parse(_httpRequest[ECHO]); list.iTotalRecords = _queriable.Count(); ApplySort(); int skip = 0, take = 10;
int.TryParse(_httpRequest[DISPLAY_START], out skip);
int.TryParse(_httpRequest[DISPLAY_LENGTH], out take); list.aaData = _queriable.Where(ApplyGenericSearch)
.Where(IndividualPropertySearch)
.Skip(skip)
.Take(take)
.Select(SelectProperties)
.ToList(); list.iTotalDisplayRecords = list.aaData.Count;
return list;
}
private void ApplySort()
{
foreach (string key in _httpRequest.Params.AllKeys.Where(x => x.StartsWith(INDIVIDUAL_SORT_KEY_PREFIX)))
{
int sortcolumn = int.Parse(_httpRequest[key]);
if (sortcolumn < 0 || sortcolumn >= _properties.Length)
break; string sortdir = _httpRequest[INDIVIDUAL_SORT_DIRECTION_KEY_PREFIX + key.Replace(INDIVIDUAL_SORT_KEY_PREFIX, string.Empty)]; var paramExpr = Expression.Parameter(typeof(T), "val");
var propertyExpr = Expression.Lambda<Func<T, object>>(Expression.Property(paramExpr, _properties[sortcolumn]), paramExpr); if (string.IsNullOrEmpty(sortdir) || sortdir.Equals(ASCENDING_SORT, StringComparison.OrdinalIgnoreCase))
_queriable = _queriable.OrderBy(propertyExpr);
else
_queriable = _queriable.OrderByDescending(propertyExpr);
}
} private Expression<Func<T, List<string>>> SelectProperties
{
get
{
//
return value => _properties.Select
(
prop => (prop.GetValue(value, new object[0]) ?? string.Empty).ToString()
)
.ToList();
}
} private Expression<Func<T, bool>> IndividualPropertySearch
{
get
{
var paramExpr = Expression.Parameter(typeof(T), "val");
Expression whereExpr = Expression.Constant(true); // default is val => True
foreach (string key in _httpRequest.Params.AllKeys.Where(x => x.StartsWith(INDIVIDUAL_SEARCH_KEY_PREFIX)))
{
int property = -1;
if (!int.TryParse(_httpRequest[key].Replace(INDIVIDUAL_SEARCH_KEY_PREFIX, string.Empty), out property)
|| property >= _properties.Length || string.IsNullOrEmpty(_httpRequest[key]))
break; // ignore if the option is invalid
string query = _httpRequest[key].ToLower(); var toStringCall = Expression.Call(
Expression.Call(
Expression.Property(paramExpr, _properties[property]), "ToString", new Type[0]),
typeof(string).GetMethod("ToLower", new Type[0])); whereExpr = Expression.And(whereExpr,
Expression.Call(toStringCall,
typeof(string).GetMethod("Contains"),
Expression.Constant(query))); }
return Expression.Lambda<Func<T, bool>>(whereExpr, paramExpr);
}
} private Expression<Func<T, bool>> ApplyGenericSearch
{
get
{
string search = _httpRequest["sSearch"]; if (string.IsNullOrEmpty(search) || _properties.Length == 0)
return x => true; var searchExpression = Expression.Constant(search.ToLower());
var paramExpression = Expression.Parameter(typeof(T), "val"); var propertyQuery = (from property in _properties
let tostringcall = Expression.Call(
Expression.Call(
Expression.Property(paramExpression, property), "ToString", new Type[0]),
typeof(string).GetMethod("ToLower", new Type[0]))
select Expression.Call(tostringcall, typeof(string).GetMethod("Contains"), searchExpression)).ToArray(); Expression compoundExpression = propertyQuery[0]; for (int i = 1; i < propertyQuery.Length; i++)
compoundExpression = Expression.Or(compoundExpression, propertyQuery[i]); return Expression.Lambda<Func<T, bool>>(compoundExpression, paramExpression);
}
}
}

Caveat

Currently there’s a bug here, that I need to research :). If you have a boolean property and apply a sort on it, you’ll get an exception because I am trying to cast it as an object with the Expression.Lambda<Func<T, object>> call. I’ll look into this and update this blog post accordingly. If you can provide any help, that would be great :)

Conclusion

This is just a simple example of parsing a request and mutating IQueriable acordingly. I hope this helps someone out there who would like to use C# with the DataTables plugin. Again, you can download my code from here with full comments.

Published Tuesday, January 19, 2010 3:32 PM by zowens

转载:http://weblogs.asp.net/zowens/archive/2010/01/19/jquery-datatables-plugin-meets-c.aspx

http://www.fengfly.com/plus/view-196740-1.html

jQuery DataTables Plugin Meets C#的更多相关文章

  1. jQuery dataTables四种数据来源[转]

    2019独角兽企业重金招聘Python工程师标准>>> 四种数据来源 对于 dataTables 来说,支持四种表格数据来源. 最为基本的就是来源于网页,网页被浏览器解析为 DOM ...

  2. jQuery DataTables and ASP.NET MVC Integration

    part 1 : http://www.codeproject.com/Articles/155422/jQuery-DataTables-and-ASP-NET-MVC-Integration-Pa ...

  3. jQuery DataTables 插件使用笔记

    初始化 在页面中 <!DOCTYPE html> <html> <head> <link rel="stylesheet" type=&q ...

  4. [jQuery]jQuery DataTables插件自定义Ajax分页实现

    前言 昨天在博客园的博问上帮一位园友解决了一个问题,我觉得有必要记录一下,万一有人也遇上了呢. 问题描述 园友是做前端的,产品经理要求他使用jQuery DataTables插件显示一个列表,要实现分 ...

  5. jquery Datatables 行数据删除、行上升、行下降功能演示

    Datatables 是一款jquery表格插件.它是一个高度灵活的工具,可以将任何HTML表格添加高级的交互功能. 官方网站:http://www.datatables.net Datatables ...

  6. jQuery datatables

    jQuery datatables 属性,用例 参考:http://datatables.club/example/ http://blog.csdn.net/mickey_miki/article/ ...

  7. ASP.NET MVC+EF在服务端分页使用jqGrid以及jquery Datatables的注意事项

    引言: 本人想自己个博客网站出来,技术路线是用ASN.NET MVC5+EF6(Code First)+ZUI+各种Jquery插件,有了这个想法之后就开始选择UI,看了好多bootstrap的模板之 ...

  8. jQuery DataTables && Django serializer

    jQuery DataTables https://www.datatables.net 本文参考的官方示例 http://datatables.net/release-datatables/exam ...

  9. Jquery.Datatables 服务器处理(Server-side processing)

    看了看介绍 http://datatables.club/manual/server-side.html 没有经过处理的分页,先显示出来看看效果,就这样写(存储过程自己写) cshtml " ...

随机推荐

  1. HTML5 图片上传预览

    <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8& ...

  2. C#中参数传递【转】

    转自[Learning hard] 建议参考 『第十一回:参数之惑---传递的艺术(上)』 一.引言 对于一些初学者(包括工作几年的人在内)来说,有时候对于方法之间的参数传递的问题感觉比较困惑的,因为 ...

  3. Servlet & JSP - Listener

    Servlet API 中的 6 个事件类 1. ServletContextEvent:该类表示上下文事件,当应用上下文对象发生改变,例如创建或销毁上下文对象时,将触发上下文事件. 2. Servl ...

  4. Android 异常捕获

    在用户使用APP时,如果APP毫无征兆的突然退出程序,又没有任何提示信息.我想这是一种最差劲的用户体验了吧,如果是我估计干脆就直接卸载APP了.因此,作为Android开发者对于这种情况的发生一定要有 ...

  5. Sqlserver中关于锁

    大多数数据库需要同时处理多个查询,这些查询并不会像车等待红绿灯排队等待,而是会寻找最短的路径执行,因此需要一个红绿灯进行约束,这个红绿灯就是锁 理论上所有的事务之间应该是完全隔离的,但是事实上隔离的成 ...

  6. Contoso 大学 - 2 – 实现基本的增删改查

    原文 Contoso 大学 - 2 – 实现基本的增删改查 目录 Contoso 大学 - 使用 EF Code First 创建 MVC 应用 原文地址:http://www.asp.net/mvc ...

  7. Swing圆角边框的实现

    Swing圆角边框的实现方法: package com.justplay.basic; import java.awt.Color; import java.awt.Component; import ...

  8. (转)使用Aspose.Cell控件实现Excel高难度报表的生成(一)

    本文章主要介绍报表的生成,基于Aspose.Cell控件的报表生成.谈到报表,估计大家都有所领悟以及个人的理解,总的来说,一般的报表生成,基本上是基于以下几种方式:一种是基于微软Excel内置的引擎来 ...

  9. springMVC学习篇 - 搭建环境及关键点

    springMVC是spring家族中一个重要的组件,和struts一样作为一套前台框架被广泛的应用于各种项目. 之前在很多项目组都用到springMVC,只感觉很强大,但是对这套框架的知识了解比较少 ...

  10. [GeekBand] 面向对象的设计模式(C++)(1)

    一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心. 这样,你就能一次又一次 地使用该方案而不必做重复劳动. 0. 从面向对象谈起 底层思维与抽象思维: 底层思维要求程序员&q ...