【问题标题】:jquery datatables server side columnsjquery 数据表服务器端列
【发布时间】:2011-12-27 02:26:34
【问题描述】:

我正在使用带有服务器端 C#/asp.net mvc3 处理的 jquery 数据表。现在一切正常,但我有一个新任务要做:

出于安全原因,我想对某些用户隐藏一些列。如何在服务器端 c# 中创建列并传递给视图中的数据表?

【问题讨论】:

  • 简短的回答是将所有内容分配给一个大的 json 对象,然后在客户端解析它。理想情况下,该 json 应该具有至少列名和数据
  • 我试过了,但没有运气。你的意思是我必须在传递给查看的 c# 结果 JSON 中添加 columdef 或 acolum 属性?
  • 请展示您尝试过的内容以及当前的绑定方式。
  • js代码还是c#?当我在 js 中删除列属性时,我收到数据表警告,第 0 行的参数 9 为空

标签: c# jquery asp.net-mvc-3


【解决方案1】:

控制器可能看起来像:

public JsonResult NewsJSON(jQueryDataTableParamModel param)
    {
        var news = _newsRepository.GetNews();

        string col = param.sColumns.Split(',')[param.iSortCol_0];
        string orderby = col + " " + param.sSortDir_0;

        if (param.sSearch != null)
            news = news.Search(param.sSearch);

        var qry = new PaginatedList<News>(news.OrderBy(orderby), param.iDisplayStart, param.iDisplayLength);

        return Json(new
        {
            sEcho = param.sEcho,
            iTotalRecords = qry.TotalCount,
            iTotalDisplayRecords = qry.TotalCount,
            aaData = (
                from n in qry
                select new[]
                {
                    n.Headline, 
                    n.DateCreated.ToString() 
                }).ToArray()
        }, JsonRequestBehavior.AllowGet);
    }

jQueryDataTableParamModel.cs

public class jQueryDataTableParamModel
{
    /// <summary>
    /// Request sequence number sent by DataTable,
    /// same value must be returned in response
    /// </summary>       
    public string sEcho { get; set; }

    /// <summary>
    /// Text used for filtering
    /// </summary>
    public string sSearch { get; set; }

    /// <summary>
    /// Number of records that should be shown in table
    /// </summary>
    public int iDisplayLength { get; set; }

    /// <summary>
    /// First record that should be shown(used for paging)
    /// </summary>
    public int iDisplayStart { get; set; }

    /// <summary>
    /// Number of columns in table
    /// </summary>
    public int iColumns { get; set; }

    /// <summary>
    /// Number of columns that are used in sorting
    /// </summary>
    public int iSortingCols { get; set; }

    /// <summary>
    /// Comma separated list of column names
    /// </summary>
    public string sColumns { get; set; }

    /// <summary>
    /// Sort column
    /// </summary>
    public int iSortCol_0 { get; set; }

    /// <summary>
    /// Asc or Desc
    /// </summary>
    public string sSortDir_0 { get; set; }

}

并且在视图中:

<script type="text/javascript" charset="utf-8">

$(function () {

$('#news').dataTable({    
"bSort" : true,        
"bServerSide": true,    
"sAjaxSource": "/News/NewsJSON",    
"bProcessing": true,    
"sPaginationType": "full_numbers",    
"iDisplayLength": 25,    
"aLengthMenu": [[25, 50, 100, 150, 200], [25, 50, 100, 150, 200]],

"aaSorting": [[1,'asc']],    
"aoColumns": [    
{ "sName": "Headline" }    
,{ "sName": "DateCreated" }    
]    
});    
});    
</script>


<table id="news" class="default-table" cellpadding="0" cellspacing="0">
<thead>

        <tr>
            <th>
                Headline
            </th>
            <th style="width: 114px">
                Created
            </th>
        </tr>
    </thead>
</table>

或类似的 :) 不确定我的 js 是否正确,但是。

/拉瑟

更新:

有点乱,但类似:

public class DataTableOptions
{
    public string ID { get; set; }
    public string Url { get; set; }
    public string Cols { get; set; }
    public bool Sort { get; set; }
    public string ViewUrlLinkname { get; set; }
    public string EditUrlLinkname { get; set; }
    public string DeleteLinkname { get; set; }
    public string DeleteTitle { get; set; }
    public string DeleteYes { get; set; }
    public string DeleteNo { get; set; }
    public string DeleteMessage { get; set; }
}

public static class DataTableHelpers
{
    private static string aLengthMenu = "[[25, 50, 100, 150, 200], [25, 50, 100, 150, 200]]";

    public static MvcHtmlString DataTable(this HtmlHelper helper, DataTableOptions options)
    {
        string[] arrcols = options.Cols.Split(',');
        int sortOffset = arrcols.Where(x => x == "Delete" || x == "View" || x == "Edit").Count();

        StringBuilder sb = new StringBuilder();

        sb.AppendLine("<script type=\"text/javascript\" charset=\"utf-8\">");
        sb.AppendLine("$(function () {");
        sb.AppendLine("$('#" + options.ID + "').dataTable({");
        sb.AppendLine("\"bSort\" : " + options.Sort.ToString().ToLower() + ",");
        sb.AppendLine("\"oLanguage\": { \"sUrl\": \"" + oLanguage + "\" },");
        sb.AppendLine("\"bServerSide\": true,");
        sb.AppendLine("\"sAjaxSource\": \"" + options.Url + "\",");
        sb.AppendLine("\"bProcessing\": true,");
        sb.AppendLine("\"sPaginationType\": \"full_numbers\",");
        sb.AppendLine("\"iDisplayLength\": 25,");
        sb.AppendLine("\"aLengthMenu\": " + aLengthMenu + ",");
        sb.AppendLine("\"aaSorting\": [[" + sortOffset.ToString() + ",'asc']],");
        sb.AppendLine("\"aoColumns\": [");


        for (int i = 0; i < arrcols.Length; i++)
        {
            if (i > 0)
                sb.Append(",");

            switch (arrcols[i])
            {
                case "Delete":
                    sb.AppendLine("{");
                    sb.AppendLine("\"sName\": \"" + arrcols[i] + "\",");
                    sb.AppendLine("\"bSearchable\": false,");
                    sb.AppendLine("\"bSortable\": false,");
                    sb.AppendLine("\"fnRender\": function (oObj) {");
                    sb.Append("return '");
                    sb.Append("<a class=\"deletelink\" href=\"' + oObj.aData["+ i.ToString() + "] + '\">" + options.DeleteLinkname + "</a> ");
                    sb.Append("';");
                    sb.AppendLine("}");
                    sb.AppendLine("}");

                    break;
                case "Edit":
                    sb.AppendLine("{");
                    sb.AppendLine("\"sName\": \"" + arrcols[i] + "\",");
                    sb.AppendLine("\"bSearchable\": false,");
                    sb.AppendLine("\"bSortable\": false,");
                    sb.AppendLine("\"fnRender\": function (oObj) {");
                    sb.Append("return '");
                    sb.Append("<a class=\"editlink\" href=\"' + oObj.aData["+ i.ToString() + "] +'\">" + options.EditUrlLinkname + "</a> ");
                    sb.Append("';");
                    sb.AppendLine("}");
                    sb.AppendLine("}");

                    break;
                case "View":
                    sb.AppendLine("{");
                    sb.AppendLine("\"sName\": \"" + arrcols[i] + "\",");
                    sb.AppendLine("\"bSearchable\": false,");
                    sb.AppendLine("\"bSortable\": false,");
                    sb.AppendLine("\"fnRender\": function (oObj) {");
                    sb.Append("return '");
                    sb.Append("<a class=\"viewlink\" href=\"' + oObj.aData["+ i.ToString() + "] + '\">" + options.ViewUrlLinkname + "</a> ");
                    sb.Append("';");
                    sb.AppendLine("}");
                    sb.AppendLine("}");

                    break;
                default:
                    sb.AppendLine("{ \"sName\": \"" + arrcols[i] + "\" }");
                    break;
            }

        }

        sb.AppendLine("]");
        sb.AppendLine("});");
        sb.AppendLine("});");
        sb.AppendLine("</script>");

        if (options.DeleteLinkname != null)
        {
            sb.Append(ConfirmHelpers.RenderConfirm(options.DeleteTitle, options.DeleteYes, options.DeleteNo, options.DeleteMessage));
        }

        return MvcHtmlString.Create(sb.ToString());
    }

并且在控制器中也传递链接:

    return Json(new
    {
        sEcho = param.sEcho,
        iTotalRecords = qry.TotalCount,
        iTotalDisplayRecords = qry.TotalCount,
        aaData = (
            from n in qry
            select new[]
            {
                Url.Action("Detail", new { newsID = n.NewsID, headline = n.Headline.ToURLParameter() }),
                Url.Action("Edit", new { newsID = n.NewsID, headline = n.Headline.ToURLParameter() }),
                Url.Action("Delete", new { newsID = n.NewsID }),
                n.Headline, 
                n.DateCreated.ToString() 
            }).ToArray()
    }, JsonRequestBehavior.AllowGet);

然后

    @Html.DataTable(Model.DataTableOptions)

    <table id="news" class="default-table" cellpadding="0" cellspacing="0">
<thead>
        <tr>
            <th style="width: 20px">
            </th>
            <th style="width: 50px">
            </th>
            <th style="width: 40px"></th>
            <th>
                Headline
            </th>....

对于删除我使用插件:http://tutorialzine.com/2010/12/better-confirm-box-jquery-css3/

public static string RenderConfirm(string title, string yes, string no, string deleteMessage)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("<script type=\"text/javascript\" charset=\"utf-8\">");
        sb.AppendLine("$(function () {");
        sb.AppendLine("$('.deletelink').live('click', function (e) {");
        sb.AppendLine("e.preventDefault();");
        sb.AppendLine("var elem = $(this);");
        sb.AppendLine("$.confirm({");
        sb.AppendLine("'title': '" + title + "',");
        //sb.AppendLine("'message': $(this).attr('data-delete-message'),");
        sb.AppendLine("'message': '" + deleteMessage + "',");
        sb.AppendLine("'buttons': {");
        sb.AppendLine("'" + yes + "': {");
        sb.AppendLine("'class': 'confirm-yes',");
        sb.AppendLine("'action': function () {");
        sb.AppendLine("$.post($(elem).attr('href'));");
        sb.AppendLine("}");
        sb.AppendLine("},");
        sb.AppendLine("'" + no + "': {");
        sb.AppendLine("'class': 'confirm-no',");
        sb.AppendLine("'action': function () { } // Nothing to do in this case. You can as well omit the action property.");
        sb.AppendLine("}");
        sb.AppendLine("}");
        sb.AppendLine("});");
        sb.AppendLine("});");
        sb.AppendLine("});");
        sb.AppendLine("</script>");

        return sb.ToString();
    }

【讨论】:

  • 很好。我有这个。我想要的只是在控制器中生成的 aoColumns 属性,所以我只发送用户可以看到的列的数据。例如,某些用户看不到 Headline 列和 Headline 列的数据,所以我不发送该数据,但由于 aoColumns 属性,jquery 需要两列(不仅仅是创建的列)
  • 您可以为此编写一个 html-helper,在其中将逗号分隔值(或类似值)传递给它并为您生成脚本。 @Html.DataTable(...)
  • 对不起,我不明白。你的意思是“aoColumns”:@Html.GetColumnsForUser(“UserRole”)?我不知道我是否清楚。我想隐藏一列。因此,如果一列包含编辑超链接并且用户不是管理员,那么我想为所有行隐藏此列。如果用户是管理员,那么我想在他创建行时隐藏编辑
  • 或者你建议我创建@Html.DataTable 并在帮助程序中编写生成javascript的脚本?然后我将如何注入 document.getready 函数?
  • 优秀。这绝对比我拥有的更安全。您能否在 ConfirmHelpers.RenderConfirm(options.DeleteTitle, options.DeleteYes, options.DeleteNo, options.DeleteMessage) 中发布您所拥有的内容,以便我可以清理它并创建一个解决方案以查看它是否有效?
【解决方案2】:

如果这是一个安全问题,我不会推送所有内容并在客户端解析它,因为这意味着根本没有安全性。您不呈现某些列的事实并不意味着未经授权的用户无法使用数据。它可以通过任何浏览器 (Firebug) 或代理的开发人员工具轻松访问。

您需要确保用户只会获得他们需要的数据。如果您的用户具有不同的权限/访问级别,则需要实施 RBAC - 基于角色的访问控制方法。然后,根据特定用户所属的角色,您为他提供他需要和他有权获得的数据。从这里您可以采取多种途径来实现您的目标。快速而肮脏的方法是创建一个动态 LINQ 查询以仅选择特定用户所需的列,并在 Role 变量上创建一个简单的 switch/case-like 结构来构造正确的查询。 更复杂的需要为每个角色创建列名集合,并为通用 LINQ 结果创建过滤逻辑。它将更加灵活,无需更改逻辑即可轻松添加/删除列。

这些是一些高级建议/想法,因为您没有提供任何代码或背景来说明应用程序是什么以及为什么它需要这样工作。但同样,如果您正在谈论隐藏数据的安全原因,请不要将其纯文本发送到客户端浏览器。最终有人会发现您正在发送完整的集合,而只是没有被渲染。使用 javascript 来确保安全从来都不是一个好主意,因为 ist 都在客户端并且可以在运行时进行修改。

【讨论】:

    猜你喜欢
    • 2014-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多