2015-09-28 32 views
10

Tôi đang cố tạo một trang web mới nơi tôi cần hiển thị gần 10 lần xem lưới và biểu đồ khác nhau.Chúng ta có thể sử dụng cùng một datatable cho pagemethod và webmethod trong ASP.NET?

Gridviews được gắn vào sự kiện và biểu đồ tải trang được hiển thị bằng phương pháp jquery-ajax (sử dụng amcharts cũng như highcharts) bằng cách gọi WebMethod.

Ban đầu tôi đã triển khai trang theo cách sau khi thực hiện cùng một tập hợp các thủ tục được lưu trữ cho lưới xem (để hiển thị dữ liệu dạng xem lưới) và webmethods (đối với biểu đồ vẽ) .Sẽ cùng một lần được thực thi hai lần cho trang này (một cho lưới) và một cho biểu đồ) .Có 10 sps cần thiết để thực thi để tìm nạp dữ liệu.

Vì vậy, để cải thiện hiệu suất trang tôi đã tạo DataTable tĩnh như thế này

static DataTable Report1; 

và binded GridView như thế này.

private void gvbindReport1() 
    { 
     try 
     {    
      Report1 = new DataTable();//refreshed datatable 
      DataSet ReportDS1 = objmvbl.GetReportGraph(ClientID, date_From, date_To); 
      if (ReportDS1.Tables.Count > 0) 
      { 
       Report1 = ReportDS1.Tables[0];//bindinding data to static datatable 

      } 
      GdReport.DataSource = Report1; 
      GdReport.DataBind(); 
     } 
     catch (Exception ex) 
     { 
      Log.Errlog("Error Occured in gvbindReport1 : " + ex.Message.ToString()); 
     } 

    } 

và bên trong WebMethod tôi đã sử dụng DataTable cùng cho việc vẽ biểu đồ như thế này

[System.Web.Services.WebMethod] 
    public static string GetDataReport1() 
    { 
     System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); 
     List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>(); 
     Dictionary<string, object> row; 
     try 
     { 
      //processing for the data inside static datatable 
      if (Report1.Rows.Count > 0) 
      { 
       foreach (DataRow dr in Report1.Rows) 
       { 
        row = new Dictionary<string, object>(); 
        foreach (DataColumn col in Report1.Columns) 
        { 
         row.Add(col.ColumnName, dr[col]); 
        } 
        rows.Add(row); 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      Log.Errlog("Error Occured in GetDataReport WebMethod of Report Page : " + ex.Message.ToString()); 
     } 

     return serializer.Serialize(rows); 

    } 

với điều này tôi có thể hiển thị cả lưới và biểu đồ.

Bây giờ, hãy cho tôi biết, đây có phải là cách tiếp cận chính xác để xử lý webmethod không? tôi đã đọc rằng webmethod không có liên quan đến trang và all.Please Hãy cho tôi biết những hạn chế của phương pháp này.

Nếu điều này sai, Vui lòng đề xuất cách tốt hơn để cải thiện hiệu suất trang?

+1

Có một điều là bạn không nên tự gọi 'JavaScriptSerializer'. Nếu bạn chỉ trả về 'List >' trực tiếp, ASP.NET sẽ xử lý serializing đó. Nó làm điều đó bất kể kiểu trả về của bạn, vì vậy mã hiện tại của bạn đang chạy 'JavaScriptSerializer' hai lần trên kết quả (và bạn phải phân tích cú pháp nó hai lần ở phía máy khách). Thông tin thêm: http://encosia.com/asp-net-web-services-mistake-manual-json-serialization/ –

+0

@ Dave Ward: cảm ơn vì đã chỉ ra điều này. Bạn có thể cho biết cách đồng bộ hóa dữ liệu giữa trang và webmethod? – Athul

+0

Bạn có thể sử dụng DataTables và sử dụng các lớp được nhập tĩnh và Danh sách chung thay thế không? – sm14

Trả lời

6

Không, đây không phải là phương pháp chính xác. Vì bạn đã khai báo DataTablestatic (biến tĩnh có phạm vi ứng dụng và không thể khởi tạo được) tất cả

người dùng sẽ nhận được cùng một kết quả (giá trị cập nhật cuối cùng).

Bạn có thể nhận ra điều này trong thử nghiệm concurrency.

Vui lòng kiểm tra các tình huống sau:

Cân nhắc dtbl là tĩnh dataTable đó được khởi tạo trên trang chủ, và bạn tạo một ví dụ Ví dụ của `DataTable trên trang index (cả hai đều trong tải trang như đưa ra dưới đây).

Home

public static DataTable dtbl; 
protected void Page_Load(object sender, EventArgs e) 
{ 
    if (!Page.IsPostBack) 
    { 
     dtbl = new DataTable(); 
     dtbl.Columns.Add("id"); 
     dtbl.Columns.Add("name"); 
     for (int i = 0; i < 10; i++) 
     { 
      DataRow dr = dtbl.NewRow(); 
      dr["id"] = i.ToString(); 
      dr["name"] = i + 1; 
      dtbl.Rows.Add(dr); 
     } 
    } 
} 

trang Index

protected void Page_Load(object sender, EventArgs e) 
{ 
    if (!Page.IsPostBack) 
    { 
     home.dtbl = new DataTable(); 
    } 
} 

Bây giờ đặt một breakpoint trong mỗi tải trang và chạy ứng dụng,

  • mở cả các trang trong separate tab .
  • Làm mới trang chủ và kiểm tra xem các cột có đang hiển thị
  • Bây giờ chuyển đến tab tiếp theo (chỉ mục) và làm mới nó (ví dụ mới được tạo cho dt). Nó sẽ ảnh hưởng đến datatable bây giờ bạn sẽ nhận được datatable mới trong nhà cũng có.
  • Vì vậy, nếu hai quy trình/trang này được thực thi đồng thời, giá trị mới nhất sẽ nhận được cho cả hai trang. Đó là lý do tại sao tôi nói rằng nó sẽ nhận ra điều này trong thử nghiệm đồng thời.

Bạn có thể sử dụng phiên trong trường hợp này. Xét đoạn mã sau:

Home

protected void Page_Load(object sender, EventArgs e) 
{ 
    if (!Page.IsPostBack) 
    { 
     dtbl = new DataTable(); 
     dtbl.Columns.Add("id"); 
     dtbl.Columns.Add("name"); 
     for (int i = 0; i < 10; i++) 
     { 
      DataRow dr = dtbl.NewRow(); 
      dr["id"] = i.ToString(); 
      dr["name"] = i + 1; 
      dtbl.Rows.Add(dr); 
     } 
     if (((DataTable)Session["MyDatatable"]).Columns.Count < 0) 
     { 
      Session["MyDatatable"] = dtbl; 
     } 
     else 
     { 
      dtbl = (DataTable)Session["MyDatatable"]; 
     } 
    } 
} 
+0

sau đó làm thế nào tôi có thể cải thiện hiệu suất? Bất kỳ cách nào khác? – Athul

+0

không có dữ liệu riêng biệt được tạo cho người dùng cá nhân, Tất cả đều chia sẻ như vậy để nhận được giá trị cập nhật cuối cùng cho tất cả. –

+0

Report1 = new DataTable(); điều này sẽ không hoạt động đúng không? giả sử user1 truy cập lưới trang và đồ thị được hiển thị. Sau đó user2 truy cập lưới và đồ thị mới sẽ hiển thị đúng không? – Athul

5

Trước hết, không sử dụng, như một quy luật chung của ngón tay cái, các biến tĩnh trong một ứng dụng web. Các hành động này là các biến toàn cục và không được khởi tạo với từng yêu cầu.

Tôi cũng sẽ không đề xuất bạn sử dụng DataTables tất cả các cách lên đến lớp giao diện người dùng của bạn. Thay vào đó, hãy làm việc với các đối tượng được gõ mạnh.

  1. Tạo mô hình đối tượng bạn đang cố gắng ràng buộc.

Ví dụ: nếu bạn có bảng gọi là người có các trường sau đây.

Id | first_name | last_name | audit_ts 

Bạn có thể tạo một đối tượng như vậy:

public class Person 
{ 
    public int Id {get;set;} 
    public string FirstName {get;set;} 
    public string LastName {get;set;} 
} 
  1. Bây giờ trong một chức năng riêng biệt, trong một số lớp học mà bạn có thể gọi thủ tục lưu trữ của bạn từ cơ sở dữ liệu và sau đó đưa các hàng trong bảng của bạn vào bảng Person vào danh sách Person Object.

  2. Bây giờ, thay vì gọi thủ tục lưu trữ của bạn hai lần để nhận dữ liệu giống nhau, điều này chỉ làm giảm hiệu suất của ứng dụng của bạn, thay vì ràng buộc khung nhìn lưới trong mã của bạn ở sau sự kiện Page_Load. Đơn giản chỉ cần ràng buộc bảng HTML sau khi bạn thực hiện cuộc gọi đến webmethod của bạn mà tôi tin là trong code-behind của bạn. Bạn có thể tham khảo this post về cách liên kết bảng HTML của bạn với đối tượng JSON được trả về bởi cuộc gọi Ajax của bạn.

  3. Bằng cách này, bạn đang thực hiện một cuộc gọi đến máy chủ và đến cơ sở dữ liệu để sử dụng cùng một dữ liệu để ràng buộc bảng của bạn cũng như biểu đồ của bạn.

2

Đây là một trường hợp sử dụng tốt cho các bé sử dụng cache Object Nhiều người dùng hiểu ViewState và sessionState, tuy nhiên đối tượng Cache không được sử dụng rộng rãi, và mặc dù khái niệm này là rất giống nhau, đó là nhiều hơn nữa Linh hoạt.

Nếu trang của bạn đang kêu gọi 10 thủ tục được lưu trữ hai lần (một lần cho lưới của bạn và một lần nữa cho biểu đồ của bạn) sau đó cho phép cải thiện hiệu suất bằng khoảng 100% bằng cách loại bỏ các cuộc gọi thêm với Cache Object

Có một cuộc gọi đến các thủ tục được lưu trữ trong một phương thức riêng biệt để điền vào đối tượng bộ nhớ cache của bảng dữ liệu của bạn, sau đó được sử dụng lại trong suốt ứng dụng của bạn.

private void loadReport1IntoCache() 
{ 
    //...load your data from DB into the Report1 variable here 


    //this line is new, and it saves your data into a global Cache variable 
    //with an absolute expiration of 10 minutes 
    Cache.Insert("Report1", Report1, null, 
    DateTime.Now.AddMinutes(10d), 
    System.Web.Caching.Cache.NoSlidingExpiration); 


} 

Sau đó, khi bạn ở trong các phương pháp khác, bạn có thể sử dụng biến Cache thay vì gọi lại các thủ tục đã lưu. Ví dụ:

[System.Web.Services.WebMethod] 
public static string GetDataReport1() 
{ 
    //first load the application variable before performing your other work 
    DataTable myCachedReport1Data = (DataTable)Cache["Report1"]; 
    //did the Cache expire? 
    if (myCachedReport1Data == null) 
    { 
    //if so refresh it 
    loadReport1IntoCache(); 
    //and then assign the variable the contents of the refresh and proceed 
    myCachedReport1Data = (DataTable)Cache["Report1"]; 
    } 

    //other work here, utilizing the myCachedReport1Data variable 
} 

và cho mạng lưới của bạn ràng buộc:

private void gvbindReport1() 
{ 
    try 
    {    
     DataTable myCachedReport1Data = (DataTable)Cache["Report1"]; 
     //did the Cache expire? 
     if (myCachedReport1Data == null) 
     { 
      //if so refresh it 
      loadReport1IntoCache(); 
      //and then assign the variable the contents of the refresh 
      myCachedReport1Data = (DataTable)Cache["Report1"]; 
     } 

     GdReport.DataSource = myCachedReport1Data ; 
     GdReport.DataBind(); 
    } 
    catch (Exception ex) 
    { 
     Log.Errlog("Error Occured in gvbindReport1 : " + ex.Message.ToString()); 
    } 

} 

Bây giờ, bạn sẽ phải làm một vài điều không được đề cập ở đây. Bạn nên cân nhắc khi nào bạn muốn dữ liệu Cache hết hạn (ví dụ được đưa ra là 10 phút). Ngoài ra, bạn nên xem xét nếu bạn muốn nó là một số tuyệt đối của phút (tuyệt đối hết hạn) hoặc một số phút kể từ lần truy cập cuối cùng (trượt hết hạn). Trong trường hợp của bạn, có thể hết hạn tuyệt đối, nhưng chỉ bạn mới biết điều đó. Sau đó, bạn sẽ đặt hết hạn khi bạn đang thiết lập nội dung biến.

Xem tài liệu bộ nhớ cache ở đây: https://msdn.microsoft.com/en-us/library/6hbbsfk6.aspx

Thêm dữ liệu bộ nhớ cache: https://msdn.microsoft.com/en-us/library/18c1wd61.aspx

Lấy dữ liệu bộ nhớ cache: https://msdn.microsoft.com/en-us/library/xhy3h9f9.aspx

2

Nhìn vào mẫu mã mà bạn đã đưa ra (và các thông số date_fromdate_to mà bạn đang chuyển đến GetReportGraph()) Tôi giả sử:

  1. bạn có 2 trường nhập nơi người dùng xác định phạm vi ngày và sau đó gửi dữ liệu (gây postback), dựa vào đó bạn lọc các bản ghi và hiển thị trong lưới cũng như biểu đồ.

  2. vì người dùng khác nhau sẽ cung cấp các phạm vi ngày khác nhau, bạn không muốn hiển thị cùng một dữ liệu cho tất cả người dùng.

  3. khi dữ liệu được lọc, nó sẽ không có hàng nghìn bản ghi.

Tôi không chắc chắn chức năng của chế độ xem lưới bạn đang sử dụng. Nó chỉ được sử dụng để hiển thị dữ liệu bảng chỉ đọc? Nếu có, bạn có thể xem xét cách tiếp cận được đưa ra bởi @Nabin Karki Thapa. Nếu bạn không kiểm tra phương pháp thay thế dưới đây:

Sau khi bạn đã có bảng dữ liệu và đặt nó vào chế độ xem lưới, hãy nối tiếp nó thành JSON và đăng ký nó như một khối tập lệnh (xác định biến JS và gán JSON tuần tự hóa giá trị).

Ở phía máy khách, trong khi vẽ biểu đồ, thay vì gọi phương thức webmethod, để lấy đối tượng JSON sử dụng biến JS mà bạn đã đăng ký. Bằng cách này, bạn sẽ tránh được cuộc gọi đến phương thức web (AJAX) và gọi thủ tục lưu trữ bổ sung hoàn toàn.

Các vấn đề liên quan