`
chuanlhc
  • 浏览: 69641 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

ASP.NET Page那点事

 
阅读更多

Page,我想每个ASP.NET开发人员对它应该都是比较熟悉的。

这次的博客我就打算专门谈谈它。不过呢,我不打算说 在Page中使用控件的一些话题,也不会说Page的生命周期的相关话题,因为我认为这些话题被人谈论的次数实在是太多了,尤其是市面上的ASP.NET的书籍,都会比较喜欢这些话题。

我不喜欢重复,因此今天我只想谈些人家不谈的那点事,但我认为它们仍然很重要。

一些重要的Page指令

虽然Page公开了很多属性,让我们可以在运行时调整它的状态与行为,但是,还有些重要的参数却是以“指令”方式提供的,需要在设计时就指定。

下面是我整理的一些我认为 比较重要并且经常需要使用的指令:

web.config的全局设置

前面我介绍了一些常用的Page指令,考虑到方便性,ASP.NET还允许我们在web.config中为一些常用的指令配置默认值。下面我就一些常用的场景来说明这些全局配置的方便性。

1. 通常,我在创建一个网站项目时,肯定会决定不使用ViewState和Session的。那么如果为每个页面设置EnableViewState,EnableSessionState指令属性,那就显得太麻烦了,而且还容易遗漏。此时,我们可以直接在web.config中为这些参数指定一个全局的默认值:

  1. <pages enableViewState="false" enableSessionState="false"></pages> 
  2.  

补充说明一下:全局禁用Session的彻底方法是把Session对应的HttpModule从httpModules列表中移除。

web.config允许我们设置Page默认参数的具体配置节如下:

  1. <pages       
  2.    buffer="[True|False]" 
  3.    enableEventValidation="[True|False]" 
  4.    enableSessionState="[True|False|ReadOnly]" 
  5.    enableViewState="[True|False]" 
  6.    enableViewStateMac="[True|False]" 
  7.    smartNavigation="[True|False]" 
  8.    autoEventWireup="[True|False]" 
  9.    pageBaseType="typename, assembly" 
  10.    userControlBaseType="typename" 
  11.    validateRequest="[True|False]" 
  12.    masterPageFile="file path"   
  13.    theme="string" 
  14.    styleSheetTheme="string" 
  15.    maxPageStateFieldLength="number"   
  16.    compilationMode="[Always|Auto|Never]"   
  17.    pageParserFilterType="string"   
  18.    viewStateEncryptionMode="[Always|Auto|Never]"   
  19.    maintainScrollPositionOnPostBack="[True|False]"   
  20.    asyncTimeout="number" 
  21. > 
  22.    <controls>...</controls> 
  23.    <namespaces>...</namespaces> 
  24.    <tagMapping>...</tagMapping> 
  25. </pages> 

2. 为了代码重用,设计用户控件也是很常用的方法。

我们可以使用 @ Register指令 在页面注册需要使用的UserControl或者WebControl。然而,有些控件比较通用,许多页面都会使用它,那么就不要再使用 @ Register指令了,可以在web.config中统一注册。例如:

  1. <pages> 
  2.     <controls> 
  3.         <add tagPrefix="fish" tagName="MainMenu" src="~/Controls/MainMenu.ascx" /> 
  4.         <add tagPrefix="fish" tagName="PageHeader" src="~/Controls/PageHeader.ascx" /> 
  5.     </controls> 
  6. </pages> 

有了这个定义后,我就可以在任何页面中直接使用:

  1. <fish:PageHeader runat="server" ID="PageHeader1" /> 

3. 对于喜欢使用页面内联代码的人来说,可能经常需要使用自己定义的类型。如果这些类型定义在某个命名空间中,那么就需要在内联代码中采用完整命名空间的写法。虽然这样做没有什么问题,但就是麻烦,于是,我们可以在页面中使用 @ Import指令 来导入我们需要使用的命名空间,但是这个指令每次只能导入一个命名空间,而且每个页面还得重复导入,显然不够方便。

为了方便使用一些常用的命名空间,我们可以在web.config中统一指定,例如:

  1. <pages> 
  2.     <namespaces> 
  3.         <add namespace="MyMVC" /> 
  4.         <add namespace="WebSiteCommonLib" /> 
  5.         <add namespace="WebSiteModel" /> 
  6.     </namespaces> 
  7. </pages> 

这样设置后,所有页面就可以直接使用这些命名空间下的类型了。

不知道有些人想过:为什么在页面中使用某些微软提供的类型就不需要导入命名空间?

答案是:其实ASP.NET已经将一些微软认为常用的命名空间在web.config中配置好了:

  1. <pages> 
  2.     <namespaces> 
  3.         <add namespace="System"/> 
  4.         <add namespace="System.Collections"/> 
  5.         <add namespace="System.Collections.Specialized"/> 
  6.         <add namespace="System.Configuration"/> 
  7.         <add namespace="System.Text"/> 
  8.         <add namespace="System.Text.RegularExpressions"/> 
  9.         <add namespace="System.Web"/> 
  10.         <add namespace="System.Web.Caching"/> 
  11.         <add namespace="System.Web.SessionState"/> 
  12.         <add namespace="System.Web.Security"/> 
  13.         <add namespace="System.Web.Profile"/> 
  14.         <add namespace="System.Web.UI"/> 
  15.         <add namespace="System.Web.UI.WebControls"/> 
  16.         <add namespace="System.Web.UI.WebControls.WebParts"/> 
  17.         <add namespace="System.Web.UI.HtmlControls"/> 
  18.     </namespaces> 
  19. </pages> 

4. 现在,有越来越多的人为了方便而使用扩展方法。使用扩展方法的好处是:可以让我们不去关心这些扩展方法定义在那个类中,只要在支持扩展方法的对象上调用就可以了,就像下面的代码这样:

  1. 当前用户已登录,登录名:<%= Context.User.Identity.Name.HtmlEncode() %> 

然而,在页面中使用扩展方法时,也必须先导入扩展方法的定义类的命名空间。

因此,为了方便,我们可以在web.config中为我们定义的扩展方法导入相应的命名空间:

  1. <pages> 
  2.     <namespaces> 
  3.         <add namespace="FishDemoCodeLib" /> 
  4.     </namespaces> 
  5. </pages> 

换个方式使用 Page

在传统的WEB开发模式下,我们通常会设计一些页面(Page)响应来自用户浏览器的请求,在这种模式下,Page会将最后生成的整页HTML代码直接发送给用户浏览器。然而,在某些时候,我们只需要生成一个HTML片段:

1. 在AJAX请求中,客户端为了局部刷新,只要求服务端返回一个HTML片段。

2. BigPipe方式下,为了能分块输出,每次也只需要输出一个HTML片段。

如果只是为了得到一段简单的HTML代码,可能有些人会选择采用代码来拼接,但是如果那段HTML还有些复杂呢?显然拼接方法肯定是不行的。

对于第一个问题,可能有人说:我可以创建一个页面,只放部分代码到页面上。的确,这种方法可以勉强解决第一个问题,但是,很有可能那部分代码在整页输出时也会用到,怎么办?

做成UserControl,然后放在一个单独的页面中!其实这种做法很无奈,因为那个容器页面的意义不大(仅仅是个容器),最后搞得项目中一大堆页面文件!事实上,这种方法仅适用于使用简单服务端控件的场合,如果想使用一些高级的服务端控件,它根本就不行。

为了能实现前面说到的二个需求,我们就不能再按照传统的方式来使用Page了。因为我们希望能得到(返回)一段HTML。

有二种方法可以让我们继续使用页面模板代码的方式生成HTML代码:

1. Server.Execute()方法。

2. Page.RenderControl()方法。

下面这段代码来源于 MyMVC框架,这个方法可以根据指定的用户控件以及控件显示所需的数据得到控件的输出结果(一段HTML代码)。

  1. /// <summary> 
  2. /// 用指定的用户控件以及视图数据呈现结果,最后返回生成的HTML代码。  
  3. /// 用户控件应从MyUserControlView<T>继承  
  4. /// </summary> 
  5. /// <param name="ucVirtualPath">用户控件的虚拟路径</param> 
  6. /// <param name="model">视图数据</param> 
  7. /// <returns>生成的HTML代码</returns> 
  8. public static string Render(string ucVirtualPath, object model)  
  9. {  
  10.     if( string.IsNullOrEmpty(ucVirtualPath) )  
  11.         throw new ArgumentNullException("ucVirtualPath");  
  12.       
  13.     Page page = new Page();  
  14.     Control ctl = page.LoadControl(ucVirtualPath);  
  15.     if( ctl == null )  
  16.         throw new InvalidOperationException(  
  17.             string.Format("指定的用户控件 {0} 没有找到。", ucVirtualPath));  
  18.  
  19.     if( model != null ) {  
  20.         MyBaseUserControl myctl = ctl as MyBaseUserControl;  
  21.         if( myctl != null )  
  22.             myctl.SetModel(model);  
  23.     }  
  24.  
  25.     // 将用户控件放在Page容器中。  
  26.     page.Controls.Add(ctl);  
  27.  
  28.     StringWriter output = new StringWriter();  
  29.     HtmlTextWriter write = new HtmlTextWriter(output, string.Empty);  
  30.     page.RenderControl(write);  
  31.  
  32.     // 用下面的方法也可以的。  
  33.     //HttpContext.Current.Server.Execute(page, output, false);  
  34.  
  35.     return output.ToString();  
  36. }  

整段代码分为以下几个步骤(我已用空行分隔开了):

1. 检查参数。

2. 创建页面容器并加载用户控件。

3. 设置页面(视图)所需的显示数据。

4. 将用户控件添加到Page的Controls集合中。

5. 调用RenderControl或者Execute让Page输出HTML代码。

6. 返回结果。

这段代码很简单,唯独值得介绍的就是第5步,调用它们就可以得到控件输出的HTML代码。

RenderControl或者Execute的差别在于:

RenderControl不支持服务器控件,原因在于它利用了页面的一种独特编译方式,我已在以前的博客中分析过了。

Execute可以支持服务器控件,因为它会执行一次完整的页面生命周期。

注意:上面这段代码就算使用Execute,也只能支持部分简单的服务器控件,因为一些复杂的服务器控件需要在HtmlForm中才能运行。因此,如果需要支持所有的服务器控件,那么还必须创建HtmlForm对象,并调整包含关系,还有就是还需要去掉产生的多余HTML代码。

如果你需要生成整个页面生成的HTML代码,可以参考 MyMVC框架,那里有实现这个功能的完整代码。

重新认识Eval()方法

我想很多人都写过类似下面的代码:

  1. <asp:Repeater ID="repeater1" runat="server"> 
  2.     <HeaderTemplate><ul></HeaderTemplate> 
  3.     <FooterTemplate></ul></FooterTemplate> 
  4.     <ItemTemplate> 
  5.         <li><%# Eval("OrderID")%><%# Eval("OrderDate")%><%# Eval("SumMoney")%> 
  6.         </li> 
  7.     </ItemTemplate> 
  8. </asp:Repeater> 

在这里我要说的是 Eval() 的调用,还不是Repeater控件。

Eval()不仅仅可以读取一个绑定数据项的属性,还可以去读取DataTable中的一个数据列。而且还能完成更复杂的绑定计算:

  1. <li><%# Eval("OrderID")%><%# Eval("OrderDate")%><%# Eval("SumMoney")%> 
  2.     ,订单中的第一个商品:<%# Eval("Detail[0].ProductName") %> 
  3. </li> 

当然了,对于页面上的数据绑定,用Eval()的确不是性能最好的方法,建议还是使用强类型转换的方法。

有时候,尤其是在写反射应用时,时常会有从字符串解析并实现求值计算的需求。那么,前面这个示例中,Eval()的功能是不是值得挖掘呢?我认为答案是肯定的。

通过分析ASP.NET的绑定代码,我发现Eval在内部会调用DataBinder.Eval这个静态方法,这个方法的签名如下:

  1. //     在运行时计算数据绑定表达式。  
  2. //  
  3. // 参数:  
  4. //   container:  
  5. //     表达式根据其进行计算的对象引用。此标识符必须是以页的指定语言表示的有效对象标识符。  
  6. //  
  7. //   expression:  
  8. //     从 container 到要放置在绑定控件属性中的公共属性值的导航路径。  
  9. //     此路径必须是以点分隔的属性或字段名称字符串,如 C# 中的 "Tables[0].DefaultView.[0].Price"  
  10. //     或 Visual Basic 中的 "Tables(0).DefaultView.(0).Price"。  
  11. //  
  12. // 返回结果:  
  13. //     System.Object,它是数据绑定表达式的计算结果。  
  14. public static object Eval(object container, string expression);  

通过这个签名的注释,我们可以很容易地看出它的用法。

下面我来举个例子把它应用在非绑定的应用中:

我有一个类:

  1. public class TestEvalClass  
  2. {  
  3.     public List<Order> Orders { get; set; }  
  4.  
  5.     // Order以及OrderDetail的定义就省略了,我想大家能想像得出来。  
  6. }  

那么下面的代码是可以运行的:

  1. static void Main()  
  2. {  
  3.     TestEvalClass testObject = GetTestEvalClassInstance();  
  4.  
  5.     string productName = (string)System.Web.UI.DataBinder.Eval(testObject, "Orders[0].Detail[0].ProductName");  
  6.     Console.WriteLine(productName);  
  7. }  

对于这个示例,我想输出什么结果,并不重要。

我只想说:如果让你去解析那个表达式,会不会比较麻烦,现在有现成的,用起来是不是很方便?

不用基类也能扩展

在一个ASP.NET网站中,如果想为所有的页面添加某个功能,我们通常会想到使用基类的方式去实现。这的确是一种很有效的方法,但不并唯一的方法,还有一种方法也能容易实现这个需求,那就是使用PageAdapter的方式。

在我写博客的过程中,我写了很多示例页面,页面中包含一些提交按钮是少不了的事情,然而,为了能让示例代码看起来比较原始(简单),我尽量不使用服务器控件,因此就要面临提交按钮的事件处理问题。在博客【细说 ASP.NET Cache 及其高级用法】的示例代码中,我开始采用PageAdapter这种方法,它可以让代码很简单,而且以后也方便以后重用(只需要复制几个文件即可)。

或许有些人认为:扩展所有页面的功能,还是使用基类比较好。

对于这个观点,我完全不反对。

但是,PageAdapter的好处在于它的可插拔性(类似HttpModule的优点)。不过,我当时设计这种扩展方式只是想再换个方法尝试一下而已。

其实微软设计PageAdapter的本意是为了处理各种浏览器的兼容问题,但是我把这个功能用到扩展Page的功能上去了。 HttpModule可以进入到ASP.NET请求管线的任何阶段,但它就是进入不了页面的生命周期中,有了这个方法,我们就可以采用HttpModule这种【外挂】式的方法进入到页面生命周期中,我认为是很有意义的。

方法多了,我想不是件坏事。每种方法都有适合它们的应用场合,了解更多的方法,以后就能做出更优秀的设计。

这次想到这个话题是因为前面的博客【细说ASP.NET Forms 身份认证】中的示例代码。有些人看到那些代码,发现代码的运行方式比较特别,所以,今天我就打算着重介绍这种方法。

我们再来回顾一下以前博客中的示例代码,首先从页面代码开始:

  1. <fieldset><legend>普通登录</legend><form action="<%= Request.RawUrl %>" method="post"> 
  2.     登录名:<input type="text" name="loginName" style="width: 200px" value="Fish" /> 
  3.     <input type="submit" name="NormalLogin" value="登录" /> 
  4. </form></fieldset> 
  5.    
  6. <fieldset><legend>包含【用户信息】的自定义登录</legend>    <form action="<%= Request.RawUrl %>" method="post"> 
  7.     <table border="0"> 
  8.     <tr><td>登录名:</td> 
  9.         <td><input type="text" name="loginName" style="width: 200px" value="Fish" /></td></tr> 
  10.     <tr><td>UserId:</td> 
  11.         <td><input type="text" name="UserId" style="width: 200px" value="78" /></td></tr> 
  12.     <tr><td>GroupId:</td> 
  13.         <td><input type="text" name="GroupId" style="width: 200px" /> 
  14.         1表示管理员用户  
  15.         </td></tr> 
  16.     <tr><td>用户全名:</td> 
  17.         <td><input type="text" name="UserName" style="width: 200px" value="Fish Li" /></td></tr> 
  18.     </table>      
  19.     <input type="submit" name="CustomizeLogin" value="登录" /> 
  20. </form></fieldset> 

在这段页面代码中,我定义了二个表单,它们包含各自的提交按钮(其实这也只是部分代码)。

再来看后台处理代码是如何响应提交请求的:

  1. public partial class _Default : System.Web.UI.Page   
  2. {  
  3.     [SubmitMethod(AutoRedirect = true)]  
  4.     public void NormalLogin()  
  5.     {  
  6.         // 省略登录处理代码。  
  7.         // 如果需要知道这段代码可以浏览下面的网址:  
  8.         // http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html   
  9.     }  
  10.  
  11.     [SubmitMethod(AutoRedirect = true)]  
  12.     public void CustomizeLogin()  
  13.     {  
  14.         // 省略登录处理代码。  
  15.         // 如果需要知道这段代码可以浏览下面的网址:  
  16.         // http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html   
  17.     }  

注意观察,这二个C#方法的名称与页面二个submit按钮的name属性相同,因此可以猜测到这二个C#方法可以处理那二个submit按钮的提交请求。那么这二段代码是如何运行起来的呢?有些人或许看到了[SubmitMethod]的使用,认为与它们有关。其实这种说法并不正确,我也可以完全不使用它们。请记住:Attribute永远只是一个标记,它不可能让代码自动运行起来。

前面的代码能运行起来,与App_Browsers目录下的Page.browser文件有关,此文件的代码如下:

  1. <browsers> 
  2.     <browser refID="Default"> 
  3.         <controlAdapters> 
  4.             <adapter controlType="System.Web.UI.Page" 
  5.                      adapterType="FishDemoCodeLib.MyPageAdapter, FishDemoCodeLib" /> 
  6.         </controlAdapters> 
  7.     </browser> 
  8. </browsers> 

这里定义了一个MyPageAdapter,它用于Page控件的请求过程。 refID="Default" 表示是对ASP.NET定义的Default.browser文件补充一些配置,它将能匹配来自所有浏览器的请求。

我再来看一下MyPageAdapter的代码:

  1. [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]  
  2. public class SubmitMethodAttribute : Attribute  
  3. {  
  4.     public bool AutoRedirect { get; set; }  
  5. }  
  6.  
  7. internal sealed class MethodInvokeInfo  
  8. {  
  9.     public MethodInfo MethodInfo;  
  10.     public SubmitMethodAttribute MethodAttribute;  
  11. }  
  12.  
  13. public class MyPageAdapter : System.Web.UI.Adapters.PageAdapter  
  14. {  
  15.     private static readonly Hashtable s_table = Hashtable.Synchronized(new Hashtable());  
  16.  
  17.     private static MethodInvokeInfo[] GetMethodInfo(Type type)  
  18.     {  
  19.         MethodInvokeInfo[] array = s_table[type.AssemblyQualifiedName] as MethodInvokeInfo[];  
  20.         if( array == null ) {  
  21.             array = (from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Public)  
  22.                      let a = m.GetCustomAttributes(  
  23.                             typeof(SubmitMethodAttribute), false) as SubmitMethodAttribute[]  
  24.                      where a.Length > 0  
  25.                      select new MethodInvokeInfo {   
  26.                             MethodInfo = mMethodAttribute = a[0] }).ToArray();  
  27.  
  28.             s_table[type.ToString()] = array;  
  29.         }  
  30.         return array;  
  31.     }  
  32.  
  33.  
  34.     protected override void OnLoad(EventArgs e)  
  35.     {  
  36.         base.OnLoad(e);  
  37.  
  38.         if( Page.Request.Form.AllKeys.Length == 0 )  
  39.             return;    // 没有提交表单  
  40.  
  41.         MethodInvokeInfo[] array = GetMethodInfo(Page.GetType().BaseType);  
  42.         if( array.Length == 0 )  
  43.             return;  
  44.  
  45.         foreach( MethodInvokeInfo m in array ) {  
  46.             if( string.IsNullOrEmpty(Page.Request.Form[m.MethodInfo.Name]) == false ) {  
  47.                 m.MethodInfo.Invoke(Page, null);  
  48.  
  49.                 if( m.MethodAttribute.AutoRedirect   
  50.                                 && Page.Response.IsRequestBeingRedirected == false )  
  51.                     Page.Response.Redirect(Page.Request.RawUrl);  
  52.  
  53.                 return;  
  54.             }  
  55.         }  
  56.     }  
  57. }  

这段代码并不长,核心代码更是比较少。

代码中,最重要的一块是MyPageAdapter的实现,它继承了System.Web.UI.Adapters.PageAdapter,并重写了OnLoad方法(相当是在重写Page的OnLoad方法),也正是由于这个重写,代码才有机会在页面的生命周期中被执行,这一点是HttpModule做不到的。

在OnLoad方法中做了以下事情:

1. 检查是不是发生了表单提交的操作。

2. 获取当前页面类型的所有[SubmitMethod]修饰过的方法。

3. 检查提交的表单数据中,是否存在与name对应的C#方法名。

4. 如果找到一个匹配的方法名,则调用。

5. 如果在[SubmitMethod]中设置了AutoRedirect=true,则引发重定向。

注意:如果不调用base.OnLoad(e); 那么页面的Load事件根本不会发生。也就是说:PageAdapter.OnLoad的调用时间要早于Page.Onload方法。

由于这段代码仅供我写示例代码时使用,因此并没有检查要调用的方法的参数是否满足条件,也没有优化刻意去优化它的性能。在我的设计中,被调用的方法应该是无参的,因此是容易判断的,而且可以使用一个固定签名的委托去优化它的,这些细节留着以后再去完善它吧!

 

原文链接:http://www.cnblogs.com/fish-li/archive/2012/06/10/2544087.html

分享到:
评论

相关推荐

    ASP.NET PAGE对象使用

    ASP.NET PAGE对象使用了解ASP.NET 页的结构 掌握Page对象的各种事件和属性 理解_ViewState 对象 理解代码隐藏的概念

    asp.net夜话

    五、 ASP.NET 夜话之 5 : Page 类和回调技术 六、 ASP.NET 夜话之 6 : ASP.NET 基本控件 七、 ASP.NET 夜话之 7 : ADO.NET 介绍 八、 ASP.NET 夜话之 8 :数据绑定控件 九、 ASP.NET 夜话之 9 :验证控件 十、 ...

    在线编辑office的神器PageOffice For ASP.NET

    PageOffice for ASP.NET是一款非常优秀的专业的集成微软OFFICE功能的ASP.NET控件平台,能够帮助Web开发人员轻松实现在网页中嵌入运行微软Office的特殊功能。PageOffice把微软复杂的Office编程接口(COM API) 有效地...

    ASP.NET数据库网站设计教程(C#版)[孙士保][电子教案]

    ASP.NET数据库网站设计教程(C#版)[孙士保][电子教案] 第1章 ASP.NET基础 本章内容:C/S和B/S架构...本章内容:ASP.NET Web窗体模型,ASP.NET网站的组成文件,Page对象。 本章重点:ASP.NET Web窗体模型,Page对象。

    asp.net MasterPage模板页技术详解

    asp.net masterpage 模板页

    十天学会ASP.net--我认为ASP.NET比ASP难很多,希望大家做好准备

    这样ASP.NET就有四种组合:VB+ACCESS,VB+SQL,C#+ACCESS,C#+SQL,本教程会使用C#+ACCESS,兼顾四种来写,让大家对ASP.NET有一个全面的认识。虽然说学习ASP.NET不需要任何ASP基础,但是我觉得如果大家ASP不会,还是...

    Asp.net 2.0高级编程(pdf)

    43 3.2.1内置编码 44 3.2.2新的后台编码模型 46 3.3ASP.NET2.0的Page指令 48 3.3.1@Page 49 3.3.2@Master 51 3.3.3@Control 52 3.3.4@Import 53 3.3.5@Implements 54 3.3.6@Register 55...

    asp.net单系统的单点登录

    asp.net单系统的单点登录 通过一个CommonPage类统一控制一个账号只能在一个地方登录。

    Pro ASP.NET MVC 5 epub

    The ASP.NET MVC 5 Framework is the latest evolution of Microsoft’s ASP.NET web platform. It provides a high-productivity programming model that promotes cleaner code architecture, test-driven ...

    ASP.NET完全入门PDF

    第一篇 概论 第一章 微软.NET战略和ASP.NET简介i. 微软.NET的历史 ii. ASP.NET历史iii. 众说纷纭.NET iv. ASP.NET综述 v. 小结第二章 我的第一个ASP.NET程序 i. 配置开发环境ii. 运行配套光盘iii. 第一个例子iv. ...

    ASP.NET 2.0开发技术大全

    全书共分37章,包括认识ASP.NET 2.0、ASP.NET 2.0网页语法、字符串与日期处理、Page对象、Response和Request对象、Application和Session对象、Server对象、Cookie对象、Cache对象、Global.asax全局程序集文件、标准...

    Learning ASP.NET Core MVC Programming

    Get to know the concepts of ASP.NET MVC and build a new static web page using HTML, CSS, and jQuery Set up a development environment and run a sample application using the template Create a Controller...

    Professional ASP.NET 3.5 SP1 Edition: In C# and VB(part1)

    How to create templated ASP.NET pages using the master page feature * How to work with data from enterprise databases including SQL Server® * Ways to debug, package, and deploy ASP.NET ...

    [源代码] 《ASP.NET夜话》 随书源代码

    《ASP.NET夜话》 周金桥 著 随书源代码 ☆ 章节清单:☆ 第02章 — ASP.NET基础 第03章 — 表单和控件 第05章 — Page类和回调技术 第06章 — ASP.NET基本控件 第07章 — ADO.NET介绍 第08章 — 数据绑定控件 第09...

    [Navigation] Navigation for ASP.NET Web Forms

    Navigation for ASP.NET Web Forms manages movement and data passing between ASPX pages in a unit-testable manner. There is no client-side logic, so it works in all browsers, and no server-side cache, ...

    Migrate an ASP.NET 1.1 Web Page Using the CodeBehind Attribute to ASP.NET 2.0

    How to- Migrate an ASP.NET 1.1 Web Page Using the CodeBehind Attribute to ASP.NET 2.0

    ASP.NET AJAX

    导读:在ASP.NET AJAX中,由于一个ASPX页面上只能有一个ScriptManager控件,所以在有母版页的情况下,如果需要在Master-Page和Content-Page中需要引入不同的脚本时,这就需要在Content-page中使用...

    Asp.net单点登录解决方案源码

    单点登录源码下了就知道!单点登录源码下了就知道!单点登录源码下了就知道!在IIS中配置站点 配置4个站点指向相应的目录,并分别指定4个站点的主机头: http://www.passport.com/ http://www.a.com/ ...

    Beginning ASP.NET 2.0 in C# 2005:From Novice to Professional

    This book provides thorough coverage of ASP.NET, guiding you from beginning to advanced techniques, such as querying databases from within a web page and performance-tuning your site. You'll find tips...

    Test-Drive ASP.NET MVC

    From building your first page, to data access, to integrating with web services such as Blogger.com, Test-Drive ASP.NET MVC guides you step by step. You’ll come away with a complete understanding of...

Global site tag (gtag.js) - Google Analytics