MVC+EF中返回JSON的性能和安全問題


目錄

  1. 前言
  2. 問題
  3. 解決辦法1
  4. 解決辦法2
  5. 解決辦法3

前言

最近在用EasyUI搭建框架,上周寫的一篇文章沒想到有這么多人看,呵呵,

看到好多人要我網站的地圖插件,http://www.5imvc.com/,本來是想寫的,結果本周都在忙框架的事情,明天有時間寫寫吧

http://www.cnblogs.com/linfei721/archive/2013/06/02/3114174.html 地圖的代碼)

回到正題,在搭建框架的時候,無意發現自己的一個壞習慣,返回Json數據時會導致安全問題和性能的損耗,不知道其他人會不會有這習慣,寫出來大家討論下

 

問題

 我在用LINQ返回數據習慣不寫Selet(s=>字段),直接返回全部數據,代碼:

var json = db.ReportInfo.Take(100);
return Json(json);

這樣的代碼看起來沒什么問題,但是仔細想想卻發現了問題,先看看json返回的數據

CostPrice 字段為成本價,這字段一般情況下是不讓所有人看的,如果是用戶表,這樣也會把密碼泄露出來,不管加密還是沒加密,這樣都不好

解決辦法1:拉姆達表達式

其實這就像我們在寫SQL一樣,select * from,都知道這個 * 會很影響性能,在MVC中這樣會讓很多敏感字段暴露出來,代碼改成:

var json = db.ReportInfo.Take(100).Select(s => new
            {
                AreaName = s.AreaName,
                FCustIDName = s.FCustIDName,
                FName = s.FName,
                FProductName = s.FProductName,
                HType = s.HType,
                銷量 = s.銷量,
                計划銷售量 = s.計划銷售量,
                RDate = s.RDate
            });

return Json(json);

然后在來看看兩種寫法的性能差異

沒寫select

改寫后

因為我這是測試數據,字段較少,速度這塊不是很明顯,但是大家可以看看文件大小,如果一個庫中字段很多,但是你頁面只需要其中幾個,這樣浪費了很多無用數據

解決辦法2:System.Linq.Dynamic

好吧,問題到這里應該完了,但是上面的代碼太麻煩,每次都寫 AreaName = s.AreaName .......這樣的代碼,

在網上找了下,終於發現了一個好東西 System.Linq.Dynamic,看名字大家應該知道了,就是動態Linq,這東西Nuget里有,直接去下載

安裝完后導入命名空間

using System.Linq.Dynamic;

改成代碼:

var json = db.ReportInfo.Take(100).Select("new (AreaName,FCustIDName,FName,FProductName,HType,銷量,計划銷售量,RDate)");
return Json(json);

解決辦法3:System.Linq.Dynamic + 自定義插件

 

其實在后台限制字段是最安全的,下面介紹個字段過多,解決性能但不安全的方法

在回到界面起,這是EasyUI中datagrid的寫法

<table id="list_data" cellspacing="0" cellpadding="0">
    <thead>
        <tr>
            <th field="AreaName" sortable="true">省區</th>
            <th field="FName" sortable="true">商業公司</th>
            <th field="FProductName" sortable="true">產品名稱</th>
            <th field="HType" sortable="true">類型</th>
            <th field="銷量" sortable="true">數量</th>
            <th field="計划銷售量" sortable="true">計划</th>
            <th field="RDate" sortable="true">銷售日期</th>
        </tr>
    </thead>
</table>

其實可以把這里需要的字段傳給后台,這樣我們后台就什么代碼就不用寫了,前台配置什么就返回什么json,自定義一個jQuery的插件,代碼如下:

$.fn.extend({
        //獲取界面字段
        fieldSelect: function (attr) {
            var str = Array();
            if (attr != undefined) {
                //循環增加屬性值
                $(this).each(function (index, e) {
                    var value = $(this).attr(attr);
                    //防止重復
                    if (jQuery.inArray(value, str) == -1)
                        str.push(value);
                });
                str = str.join(",");
            }
            return str;
        }
    });

這插件的作用就是把th中field屬性拼接成字符串,使用方法

var f = $("#list_data tr:eq(0)>th").fieldSelect("field");
//返回結果是AreaName,FCustIDName,FName,FProductName,HType,銷量,計划銷售量,RDate

$.post("url",{fieldSelect : f},function(data){
.....
});

后台代碼:

var json = db.ReportInfo.Take(100).Select(string.Format("new ({0})", Server.UrlDecode(Request.Form["fieldSelect"]))); 
return Json(json);

好了,這樣就是前台配置什么后台就返回什么json的數據,但是注意這里的參數別人是可以偽造的,所以並不安全,但是可以達到縮小傳送數據的目的

 結束

我也是隨便想想,不知道大家有什么想法或我哪里想的不對的歡迎討論

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM