我们可以在ASP.NET中为pagemethod和webmethod使用相同的数据表吗?

我正在尝试创建一个新的网页,我需要显示近10个不同的网格视图和图表。

Gridview在pageload事件中绑定,并且通过调用WebMethod使用jquery-ajax方法(使用amcharts以及highcharts)显示图表。

最初我实现页面的方式是在执行gridview(用于显示网格视图数据)和webmethods(用于绘制图表)的同一组存储过程之后。为此页面执行两次相同的sps(一个用于网格,另一个用于图表) )。执行获取数据需要10个sps。

因此,为了提高页面性能,我创建了这样的静态数据表

static DataTable Report1; 

并且像这样捆绑了gridview。

 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()); } } 

在webmethod内部,我使用了相同的数据表来绘制图表

  [System.Web.Services.WebMethod] public static string GetDataReport1() { System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); List<Dictionary> rows = new List<Dictionary>(); Dictionary row; try { //processing for the data inside static datatable if (Report1.Rows.Count > 0) { foreach (DataRow dr in Report1.Rows) { row = new Dictionary(); 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); } 

有了这个我能够显示网格和图表。

现在请告诉我,这是处理web方法的正确方法吗? 我已经读过webmethod与页面没有任何关系。请告诉我这种方法的缺点。

如果这是错误的,请建议更好的方法来改善页面性能?

不,这不是正确的方法。 由于您已将DataTable声明为static (静态变量具有应用程序范围且无法实例化)

用户将获得相同的结果(上次更新的值)。

您可以在并发测试中实现这一点。

请检查以下场景:

考虑dtbl是在主页上初始化的静态dataTable ,并且您在索引页面上创建了另一个`datatable实例实例(两者都在页面加载中,如下所示)。

 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); } } } 

索引页面

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

现在在每个页面加载一个断点并运行应用程序,

  • separate tab打开两个页面。
  • 刷新主页并检查列是否显示
  • 现在转到下一个选项卡(索引)并刷新它(为dt创建一个新实例)。 现在,您将在家中获得新数据表,这将影响数据表。
  • 因此,如果同时执行这两个进程/页面,则两个页面都将获得最新值。 这就是为什么我说它会在并发测试中实现这一点。

在这种情况下,您可以使用会话。 请考虑以下代码:

 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"]; } } } 

首先,不要在Web应用程序中使用静态变量作为一般经验法则。 它们充当全局变量,并且不会针对每个请求进行实例化。

我也不建议你一直使用DataTables到你的UI层。 相反,使用强类型对象。

  1. 创建您尝试绑定的对象的模型。

例如,如果您有一个名为person的表,其中包含以下字段。

 Id | first_name | last_name | audit_ts 

您可以这样创建一个对象:

 public class Person { public int Id {get;set;} public string FirstName {get;set;} public string LastName {get;set;} } 
  1. 现在在一个单独的函数中,在某些类中,您可以从数据库中调用存储过程,然后将person表中的表行转换为Person对象列表。

  2. 现在,您可以做的不是在两次调用存储过程来获取相同的数据(仅降低应用程序的性能),而是在Page_Load事件中代替绑定代码中的网格视图。 只需在调用webmethod之后绑定HTML表格,我认为这是在您的代码隐藏中 。 您可以参考这篇文章,了解如何将HTML表与Ajax调用返回的JSON对象绑定。

  3. 这样,您将对服务器和数据库进行一次调用,以使用相同的数据来绑定表格和图表。

对于很少使用的缓存对象来说,这是一个很好的用例。许多用户理解ViewState和SessionState,但是Cache对象并没有被广泛使用,虽然这个概念非常相似,但它更灵活。

如果您的页面调用了10次存储过程两次 (一次用于网格,第二次用于图表),那么通过使用Cache对象消除额外调用,可以将性能提高大约100%

在一个单独的方法中调用存储过程,该方法填充数据表缓存对象,然后在整个应用程序中重用。

 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); } 

然后,当您在其他方法中时,可以使用Cache变量而不是再次调用存储过程。 例如:

 [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 } 

并为您的网格绑定:

 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()); } } 

现在,你将不得不做一些这里没有提到的事情。 您应该考虑何时希望缓存数据过期(给出的示例为10分钟)。 此外,您应该考虑是否要求它是绝对分钟数(绝对到期时间)或自上次访问后的分钟数(滑动到期时间)。 在你的情况下,可能绝对到期,但只有你知道。 然后,您将在设置变量内容时设置到期时间。

请参阅此处的缓存文档: https : //msdn.microsoft.com/en-us/library/6hbbsfk6.aspx

添加缓存数据: https : //msdn.microsoft.com/en-us/library/18c1wd61.aspx

检索缓存数据: https : //msdn.microsoft.com/en-us/library/xhy3h9f9.aspx

查看您给出的代码示例(以及您传递给GetReportGraph()的参数date_fromdate_to我假设

  1. 您有2个输入字段,其中用户指定日期范围,然后提交数据(导致回发),您将根据该字段过滤记录并显示在网格和图表中。

  2. 由于不同的用户将提供不同的日期范围,您不希望向所有用户显示相同的数据。

  3. 随着数据被过滤,它将不会有数千条记录。

我不确定您使用的网格视图的function。 它仅用于显示只读表格数据吗? 如果是,您可以考虑@Nabin Karki Thapa给出的方法。 如果没有,请检查以下替代方法:

获得数据表并将其绑定到网格视图后,立即将其序列化为JSON并将其注册为脚本块(定义JS变量并将序列化的JSON指定为其值)。

在客户端,绘制而不是调用webmethod来获取JSON对象时使用已注册的JS变量。 这样,您将完全避免调用Web方法(AJAX)和额外的存储过程调用。