asp.net实现非常实用的自定义页面基类(附源码)

时间:2022-09-14 12:09:42

本文实例讲述了asp.net实现非常实用的自定义页面基类。分享给大家供大家参考,具体如下:

看到前面几篇文章(如:《asp.net实现利用反射,泛型,静态方法快速获取表单值到Model的方法》)想到的。下面总结发布一个笔者在开发中常用的一个自定义BasePage类,废话不多说了,直接贴代码。

一、BasePage类

1、代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Reflection;
namespace DotNet.Common.WebForm
{
 using DotNet.Common.Model;
 using DotNet.Common.Util;
 public class BasePage : System.Web.UI.Page
 {
  public BasePage()
  {
  }
  protected override void OnInit(EventArgs e)
  {
   base.OnInit(e);
   //CancelFormControlEnterKey(this.Page.Form.Controls); //取消页面文本框的enter key
  }
  #region 取消页面文本控件的enter key功能
  /// <summary>
  /// 在这里我们给Form中的服务器控件添加客户端onkeydown脚步事件,防止服务器控件按下enter键直接回发
  /// </summary>
  /// <param name="controls"></param>
  public virtual void CancelFormControlEnterKey(ControlCollection controls)
  {
   //向页面注册脚本 用来取消input的enter key功能
   RegisterUndoEnterKeyScript();
   foreach (Control item in controls)
   {
    //服务器TextBox
    if (item.GetType() == typeof(System.Web.UI.WebControls.TextBox))
    {
     WebControl webControl = item as WebControl;
     webControl.Attributes.Add("onkeydown", "return forbidInputKeyDown(event)");
    }
    //html控件
    else if (item.GetType() == typeof(System.Web.UI.HtmlControls.HtmlInputText))
    {
     HtmlInputControl htmlControl = item as HtmlInputControl;
     htmlControl.Attributes.Add("onkeydown", "return forbidInputKeyDown(event)");
    }
    //用户控件
    else if (item is System.Web.UI.UserControl)
    {
     CancelFormControlEnterKey(item.Controls); //递归调用
    }
   }
  }
  /// <summary>
  /// 向页面注册forbidInputKeyDown脚本
  /// </summary>
  private void RegisterUndoEnterKeyScript()
  {
   string js = string.Empty;
   System.Text.StringBuilder sb = new System.Text.StringBuilder();
   sb.Append("function forbidInputKeyDown(ev) {");
   sb.Append(" if (typeof (ev) != \"undefined\") {");
   sb.Append(" if (ev.keyCode || ev.which) {");
   sb.Append(" if (ev.keyCode == 13 || ev.which == 13) { return false; }");
   sb.Append(" } } }");
   js = sb.ToString();
   if (!this.Page.ClientScript.IsClientScriptBlockRegistered("forbidInput2KeyDown"))
    this.Page.ClientScript.RegisterClientScriptBlock(typeof(Page), "forbidInput2KeyDown", js, true);
  }
  #endregion
  #region 利用反射取/赋页面控件的值
  /// <summary>
  /// 从页面中取控件值,并给对象赋值
  /// </summary>
  /// <param name="dataType">要被赋值的对象类型</param>
  /// <returns></returns>
  public virtual BaseObj GetFormData(Type dataType)
  {
   BaseObj data = (BaseObj)Activator.CreateInstance(dataType);//实例化一个类
   Type pgType = this.GetType(); //标识当前页面
   BindingFlags bf = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic;//反射标识
   PropertyInfo[] propInfos = data.GetType().GetProperties();//取出所有公共属性
   foreach (PropertyInfo item in propInfos)
   {
    FieldInfo fiPage = pgType.GetField(item.Name, bf);//从页面中取出满足某一个属性的字段
    if (fiPage != null) //页面的字段不为空,代表存在一个实例化的控件类
    {
     object value = null;
     Control pgControl = (Control)fiPage.GetValue(this); //根据属性,找到页面对应控件,这要求页面控件命名必须和对象的属性一一对应相同
     //下面取值
     Type controlType = pgControl.GetType();
     if (controlType == typeof(Label))
     {
      value = ((Label)pgControl).Text.Trim();
     }
     else if (controlType == typeof(TextBox))
     {
      value = ((TextBox)pgControl).Text.Trim();
     }
     else if (controlType == typeof(HtmlInputText))
     {
      value = ((HtmlInputText)pgControl).Value.Trim();
     }
     else if (controlType == typeof(HiddenField))
     {
      value = ((HiddenField)pgControl).Value.Trim();
     }
     else if (controlType == typeof(CheckBox))
     {
      value = (((CheckBox)pgControl).Checked);//复选框
     }
     else if (controlType == typeof(DropDownList))//下拉框
     {
      value = ((DropDownList)pgControl).SelectedValue;
     }
     else if (controlType == typeof(RadioButtonList))//单选框列表
     {
      value = ((RadioButtonList)pgControl).SelectedValue;
      if (value != null)
      {
       if (value.ToString().ToUpper() != "TRUE" && value.ToString().ToUpper() != "FALSE")
        value = value.ToString() == "1" ? true : false;
      }
     }
     else if (controlType == typeof(Image)) //图片
     {
      value = ((Image)pgControl).ImageUrl;
     }
     try
     {
      object realValue = null;
      if (item.PropertyType.Equals(typeof(Nullable<DateTime>))) //泛型可空类型
      {
       if (value != null)
       {
        if (string.IsNullOrEmpty(value.ToString()))
        {
         realValue = null;
        }
        else
        {
         realValue = DateTime.Parse(value.ToString());
        }
       }
      }
      else if (item.PropertyType.Equals(typeof(Nullable))) //可空类型
      {
       realValue = value;
      }
      else
      {
       try
       {
        realValue = Convert.ChangeType(value, item.PropertyType);
       }
       catch
       {
        realValue = null;
       }
      }
      item.SetValue(data, realValue, null);
     }
     catch (FormatException fex)
     {
      DotNet.Common.Util.Logger.WriteFileLog(fex.Message, HttpContext.Current.Request.PhysicalApplicationPath + "LogFile");
      throw fex;
     }
     catch (Exception ex)
     {
      DotNet.Common.Util.Logger.WriteFileLog(ex.Message, HttpContext.Current.Request.PhysicalApplicationPath + "LogFile");
      throw ex;
     }
    }
   }
   return data;
  }
  /// <summary>
  /// 通过对象的属性值,给页面控件赋值
  /// </summary>
  /// <param name="data"></param>
  public virtual void SetFormData(BaseObj data)
  {
   Type pgType = this.GetType();
   BindingFlags bf = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static;
   PropertyInfo[] propInfos = data.GetType().GetProperties();
   foreach (PropertyInfo item in propInfos)
   {
    FieldInfo myField = pgType.GetField(item.Name, bf);
    if (myField != null)
    {
     Control myControl = (Control)myField.GetValue(this); //根据属性名取到页面控件
     object value = item.GetValue(data, null); //取对象的属性值
     Type propType = item.PropertyType;
     if (value != null)
     {
      Type valueType = value.GetType();
      try
      {
       Type controlType = myControl.GetType();
       if (controlType == typeof(Label))
       {
        if (valueType == typeof(DateTime))
        {
         ((Label)myControl).Text = (Convert.ToDateTime(value)).ToShortDateString();
        }
        else
        {
         ((Label)myControl).Text = value.ToString();
        }
       }
       else if (controlType == typeof(TextBox))
       {
        if (valueType == typeof(DateTime))
        {
         ((TextBox)myControl).Text = (Convert.ToDateTime(value)).ToShortDateString();
        }
        else
        {
         ((TextBox)myControl).Text = value.ToString();
        }
       }
       else if (controlType == typeof(HtmlInputText))
       {
        if (valueType == typeof(DateTime))
        {
         ((HtmlInputText)myControl).Value = (Convert.ToDateTime(value)).ToShortDateString();
        }
        else
        {
         ((HtmlInputText)myControl).Value = value.ToString();
        }
       }
       else if (controlType == typeof(HiddenField))
       {
        ((HiddenField)myControl).Value = value.ToString();
       }
       else if (controlType == typeof(CheckBox))
       {
        if (valueType == typeof(Boolean)) //布尔型
        {
         if (value.ToString().ToUpper() == "TRUE")
          ((CheckBox)myControl).Checked = true;
         else
          ((CheckBox)myControl).Checked = false;
        }
        else if (valueType == typeof(Int32)) //整型 (正常情况下,1标识选择,0标识不选)
        {
         ((CheckBox)myControl).Checked = string.Compare(value.ToString(), "1") == 0;
        }
       }
       else if (controlType == typeof(DropDownList))
       {
        try
        {
         ((DropDownList)myControl).SelectedValue = value.ToString();
        }
        catch
        {
         ((DropDownList)myControl).SelectedIndex = -1;
        }
       }
       else if (controlType == typeof(RadioButton))
       {
        if (valueType == typeof(Boolean)) //布尔型
        {
         if (value.ToString().ToUpper() == "TRUE")
          ((RadioButton)myControl).Checked = true;
         else
          ((RadioButton)myControl).Checked = false;
        }
        else if (valueType == typeof(Int32)) //整型 (正常情况下,1标识选择,0标识不选)
        {
         ((RadioButton)myControl).Checked = string.Compare(value.ToString(), "1") == 0;
        }
       }
       else if (controlType == typeof(RadioButtonList))
       {
        try
        {
         if (valueType == typeof(Boolean)) //布尔型
         {
          if (value.ToString().ToUpper() == "TRUE")
           ((RadioButtonList)myControl).SelectedValue = "1";
          else
           ((RadioButtonList)myControl).SelectedValue = "0";
         }
         else
          ((RadioButtonList)myControl).SelectedValue = value.ToString();
        }
        catch
        {
         ((RadioButtonList)myControl).SelectedIndex = -1;
        }
       }
       else if (controlType == typeof(Image))
       {
        ((Image)myControl).ImageUrl = value.ToString();
       }
      }
      catch (FormatException fex)
      {
       DotNet.Common.Util.Logger.WriteFileLog(fex.Message, HttpContext.Current.Request.PhysicalApplicationPath + "LogFile");
      }
      catch (Exception ex)
      {
       DotNet.Common.Util.Logger.WriteFileLog(ex.Message, HttpContext.Current.Request.PhysicalApplicationPath + "LogFile");
      }
     }
    }
   }
  }
  #endregion
  #region 日志处理
  /// <summary>
  /// 出错处理:写日志,导航到公共出错页面
  /// </summary>
  /// <param name="e"></param>
  protected override void OnError(EventArgs e)
  {
   Exception ex = this.Server.GetLastError();
   string error = this.DealException(ex);
   DotNet.Common.Util.Logger.WriteFileLog(error, HttpContext.Current.Request.PhysicalApplicationPath + "LogFile");
   if (ex.InnerException != null)
   {
    error = this.DealException(ex);
    DotNet.Common.Util.Logger.WriteFileLog(error, HttpContext.Current.Request.PhysicalApplicationPath + "LogFile");
   }
   this.Server.ClearError();
   this.Response.Redirect("/Error.aspx");
  }
  /// <summary>
  /// 处理异常,用来将主要异常信息写入文本日志
  /// </summary>
  /// <param name="ex"></param>
  /// <returns></returns>
  private string DealException(Exception ex)
  {
   this.Application["StackTrace"] = ex.StackTrace;
   this.Application["MessageError"] = ex.Message;
   this.Application["SourceError"] = ex.Source;
   this.Application["TargetSite"] = ex.TargetSite.ToString();
   string error = string.Format("URl:{0}\n引发异常的方法:{1}\n错误信息:{2}\n错误堆栈:{3}\n",
    this.Request.RawUrl, ex.TargetSite, ex.Message, ex.StackTrace);
   return error;
  }
  #endregion
 }
}

2、使用反射给控件赋值

根据id取一个员工(Employee),Employee类继承自BaseObj类,根据这个客户对象给页面控件赋值:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.Threading;
namespace WebTest
{
 using DotNet.Common.WebForm;
 using DotNet.Common.Model;
 using EntCor.Hrm.Model;
 public partial class _Default : BasePage
 {
  protected void Page_Load(object sender, EventArgs e)
  {
   if (!IsPostBack)
   {
    Employee employee = new Employee { ID = 1, UserName = "jeff wong", Address = "北京", IsLeave = false, RealName = "测试用户", State = "2" };
    this.SetFormData(employee); //给页面控件赋值
   }
  }
 }
}

3、使用反射给对象赋值

点击”测试”按钮,将页面控件(runat=server)的值赋给实体对象:

?
1
2
3
4
5
6
7
8
9
10
11
protected void btnSet_Click(object sender, EventArgs e)
{
 Employee employee = (Employee)this.GetFormData(typeof(Employee));
 StringBuilder sb = new StringBuilder();
 sb.Append("登录名:" + employee.UserName + "<br/>");
 sb.Append("真实姓名:" + employee.RealName + "<br/>");
 sb.Append("所在地:" + employee.Address + "<br/>");
 sb.Append("是否离职:" + employee.IsLeave + "<br/>");
 sb.Append("在职状态:" + employee.State + "<br/>");
 this.ltrContext.Text = sb.ToString();
}

总结:

(1)、对于页面中控件较多的情况,这个类里的反射取值和赋值的方法还是很有用的(比较恶心的是你要哼唧哼唧地对照实体类给页面控件命名。kao,实体类有代码生成器自动生成我就忍了,页面控件还要一一对应地命名,估计很多程序员在这方面没少花时间,还有就是不考虑反射对性能的影响)。不过从代码的简洁程度来看,这个确实显得out了;不过呢,笔者习惯了,命名多就多一些吧,在找到稳定可靠的解决方案之前,短时间看来是不会选择改进的了;
(2)、如果页面中有用户控件(UserControl),用户控件里的子控件直接在页面中就比较难取到了(你可能已经看出问题的端倪来了),解决的方法就是在用户控件里生成实体类(这个可以模仿BasePage写一个BaseControl类,让用户控件继承BaseControl,然后取值。本来想另开一篇介绍一下的,可是发现实现代码雷同,放弃);
(3)、取消页面文本框的enter key您可以参考《asp.net实现取消页面表单内文本输入框Enter响应的方法》;
(4)、异常处理见(二)。

二、异常处理

1、日志类(自己写的一个简单通用的文本日志处理类)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Web;
namespace DotNet.Common.WebForm
{
 /// <summary>
 /// 日志类(常用的都是log4net,这里简陋地实现一个写入文本日志类)
 /// </summary>
 public static class LogUtil
 {
  /// <summary>
  /// 写入异常日志
  /// </summary>
  /// <param name="ex"></param>
  public static void WriteFileLog(string exMsg)
  {
   string path = HttpContext.Current.Request.PhysicalApplicationPath + "LogFile";
   FileStream fs = null;
   StreamWriter m_streamWriter = null;
   try
   {
    if (!Directory.Exists(path))
    {
     Directory.CreateDirectory(path);
    }
    path = path + "\\" + DateTime.Now.ToString("yyyyMMdd") + ".txt";
    fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);
    m_streamWriter = new StreamWriter(fs);
    m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
    m_streamWriter.WriteLine(DateTime.Now.ToString() + "\n");
    m_streamWriter.WriteLine("-----------------------------------------------------------");
    m_streamWriter.WriteLine("-----------------------------------------------------------");
    m_streamWriter.WriteLine(exMsg);
    m_streamWriter.WriteLine("-----------------------------------------------------------");
    m_streamWriter.WriteLine("-----------------------------------------------------------");
    m_streamWriter.Flush();
   }
   finally
   {
    if (m_streamWriter != null)
    {
     m_streamWriter.Close();
    }
    if (fs != null)
    {
     fs.Close();
    }
   }
  }
 }
}

2、Error.aspx

这个比较无语。通常用来提供一个有好的出错页面。对于开发人员,建议显示完整的异常信息。

下面贴一个对开发人员有帮助的页面:

(1)、设计页面

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Error.aspx.cs" Inherits="Error" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<head runat="server">
 <title>出错啦</title>
</head>
<body>
 <form id="form1" runat="server">
 <div>
  <table width='100%' align='center' style='font-size: 10pt; font-family: Trebuchet MS, Arial'>
   <tr align='center'>
    <td align="center" colspan="2">
     <b>Error on page</b>
    </td>
   </tr>
   <tr>
    <td align='right' width="200">
     <b>stackTrace :</b>
    </td>
    <td align='left'>
     <asp:Label ID="lblStackTrace" runat="server"></asp:Label>
    </td>
   </tr>
   <tr>
    <td align='right'>
     <b>Error message :</b>
    </td>
    <td align='left'>
     <asp:Label ID="lblMessageError" runat="server"></asp:Label>
    </td>
   </tr>
   <tr>
    <td align='right'>
     <b>Source :</b>
    </td>
    <td align='left'>
     <asp:Label ID="lblSourceError" runat="server"></asp:Label>
    </td>
   </tr>
   <tr>
    <td align='right'>
     <b>TargetSite :</b>
    </td>
    <td align='left'>
     <asp:Label ID="lblTagetSiteError" runat="server"></asp:Label>
    </td>
   </tr>
  </table>
 </div>
 </form>
</body>
</html>

(2)、实现代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class ErrorPage : System.Web.UI.Page
{
 protected void Page_Load(object sender, EventArgs e)
 {
  this.lblStackTrace.Text = this.Application["StackTrace"] as string;
  this.lblMessageError.Text = this.Application["MessageError"] as string;
  this.lblSourceError.Text = this.Application["SourceError"] as string;
  this.lblTagetSiteError.Text = this.Application["TargetSite"] as string;
 }
}

完整实例代码代码点击此处本站下载

希望本文所述对大家asp.net程序设计有所帮助。