关于.net:ASP.NET的隐藏功能

Hidden Features of ASP.NET

This question exists because it has
historical significance, but it is not
considered a good, on-topic question
for this site, so please do not use it
as evidence that you can ask similar
questions here.

More info: https://stackoverflow.com/faq

在边缘场景中总是有一些有用的特性,但正因为如此,大多数人并不了解它们。我要的是课本上没有教过的功能。

你知道什么?


测试时,您可以将电子邮件发送到计算机上的文件夹,而不是SMTP服务器。将其放入web.config:

1
2
3
4
5
6
7
<system.net>
    <mailSettings>
        <smtp deliveryMethod="SpecifiedPickupDirectory">
            <specifiedPickupDirectory pickupDirectoryLocation="c:\Temp" />
        </smtp>
    </mailSettings>
</system.net>


如果放置名为app_offline.htm的文件在Web应用程序目录的根目录中,ASP.NET 2.0+将关闭应用程序并停止正常处理该应用程序的任何新传入请求,仅显示所有新请求的app_offline.htm文件的内容。

这是在将更改重新部署(或回滚)到生产服务器时显示"站点暂时不可用"通知的最快和最简单的方法。

另外,正如marxidad所指出的,确保文件中至少有512字节的内容,这样IE6就能正确地呈现它。


1
throw new HttpException(404,"Article not found");

这将被ASP.NET捕获,它将返回CustomErrors页。在最近的.NET每日小贴士文章中了解到这一点


这是最好的。将它添加到web.config中,可以更快地编译。这是通过该QFE发布的3.5SP1。

1
<compilation optimizeCompilations="true">

Quick summary: we are introducing a
new optimizeCompilations switch in
ASP.NET that can greatly improve the
compilation speed in some scenarios.
There are some catches, so read on for
more details. This switch is
currently available as a QFE for
3.5SP1, and will be part of VS 2010.

The ASP.NET compilation system takes a
very conservative approach which
causes it to wipe out any previous
work that it has done any time a ‘top
level’ file changes. ‘Top level’ files
include anything in bin and App_Code,
as well as global.asax. While this
works fine for small apps, it becomes
nearly unusable for very large apps.
E.g. a customer was running into a
case where it was taking 10 minutes to
refresh a page after making any change
to a ‘bin’ assembly.

To ease the pain, we added an
‘optimized’ compilation mode which
takes a much less conservative
approach to recompilation.

通过这里:


  • httpContext.current将始终为您提供对当前上下文的请求/响应等的访问,即使您没有访问页面属性的权限(例如,从松散耦合的助手类)。

  • 通过调用response.redirect(url,false),将用户重定向到另一个页面后,可以继续在同一页面上执行代码。

  • 如果您只需要一个已编译的页面(或任何IHttphandler),则不需要.aspx文件。只需设置path和http方法指向web.config文件中元素中的类。

  • 可以通过调用pageParser.getCompiledPageInstance(virtualPath、aspxFileName、context)以编程方式从.aspx文件中检索页面对象。


machine.config级别的零售模式:

1
2
3
4
5
<configuration>
  <system.web>
    <deployment retail="true"/>
  </system.web>
</configuration>

重写web.config设置以强制调试为false,打开自定义错误并禁用跟踪。在发布之前不要忘记更改属性-只需将它们全部配置为开发或测试环境,并更新生产零售设置。


为内容页中的母版页启用IntelliSense
我相信这是一个鲜为人知的黑客

大多数情况下,如果要使用findcontrol方法并从内容页强制转换母版页中的控件,则mastertype指令将在Visual Studio中启用IntelliSense。

只需再向页面添加一个指令

1
<%@ MasterType VirtualPath="~/Masters/MyMainMasterPage.master" %>

如果不想使用虚拟路径,而是使用类名,那么

1
<%@ MasterType TypeName="MyMainMasterPage" %>

在这里得到完整的文章


作为请求级缓存工具的httpContext.items


有两件事在我的脑海里很突出:

1)您可以从代码中打开和关闭跟踪:

1
2
3
4
5
6
7
#ifdef DEBUG
   if (Context.Request.QueryString["DoTrace"] =="true")
                {
                    Trace.IsEnabled = true;
                    Trace.Write("Application:TraceStarted");
                }
#endif

2)您只能使用一个共享的"代码隐藏"文件来构建多个.aspx页面。

生成一个类.cs文件:

1
2
3
4
5
6
7
8
9
10
11
public class Class1:System.Web.UI.Page
    {
        public TextBox tbLogin;

        protected void Page_Load(object sender, EventArgs e)
        {

          if (tbLogin!=null)
            tbLogin.Text ="Hello World";
        }
    }

然后您可以拥有任意数量的.aspx页面(在删除了vs生成的.designer.cs和.cs代码之后):

1
2
3
4
5
6
  <%@ Page Language="C#"  AutoEventWireup="true"  Inherits="Namespace.Class1" %>
     <form id="form1" runat="server">
     
     </asp: TextBox  >
     
     </form>

您可以在ASPX中拥有不在Class1中出现的控件,反之亦然,但您需要重新记忆以检查控件是否为空。


你可以使用:

1
 Request.Params[Control.UniqueId]

在初始化viewstate之前获取控件的值(此时control.text等将为空)。

这对于init中的代码很有用。


WebMethods。

可以使用ASP.NET AJAX回调放置在ASPX页中的Web方法。可以使用[WebMethod()]和[ScriptMethod()]属性来修饰静态方法。例如:

1
2
3
4
5
6
7
8
9
10
11
[System.Web.Services.WebMethod()]
[System.Web.Script.Services.ScriptMethod()]
public static List<string> GetFruitBeginingWith(string letter)
{
    List<string> products = new List<string>()
    {
       "Apple","Banana","Blackberry","Blueberries","Orange","Mango","Melon","Peach"
    };

    return products.Where(p => p.StartsWith(letter)).ToList();
}

现在,在您的ASPX页面中,您可以执行以下操作:

1
2
3
4
5
6
<form id="form1" runat="server">
   
       
        <input type="button" value="Get Fruit" onclick="GetFruit('B')" />
   
</form>

并通过javascript调用服务器端方法,使用:

1
2
3
4
5
6
7
8
9
10
    <script type="text/javascript">
    function GetFruit(l)
    {
        PageMethods.GetFruitBeginingWith(l, OnGetFruitComplete);
    }

    function OnGetFruitComplete(result)
    {
        alert("You got fruit:" + result);
    }

在启动长时间运行的任务之前,请检查客户端是否仍然连接:

1
2
3
4
if (this.Response.IsClientConnected)
{
  // long-running task
}

ASP.NET的一个鲜为人知且很少使用的功能是:

标签映射

它很少被使用,因为只有在特定的情况下你才需要它,但是当你需要它时,它是那么的方便。

关于这个鲜为人知的特性的一些文章:

ASP.NET中的标记映射在ASP.NET 2.0中使用标记映射

从上一篇文章:

Tag mapping allows you to swap
compatible controls at compile time on
every page in your web application. A
useful example is if you have a stock
ASP.NET control, such as a
DropDownList, and you want to replace
it with a customized control that is
derived from DropDownList. This could
be a control that has been customized
to provide more optimized caching of
lookup data. Instead of editing every
web form and replacing the built in
DropDownLists with your custom
version, you can have ASP.NET in
effect do it for you by modifying
web.config:

1
2
3
4
5
6
7
<pages>
 <tagMapping>
   <clear />
   <add tagType="System.Web.UI.WebControls.DropDownList"
        mappedTagType="SmartDropDown"/>
  </tagMapping>
</pages>


HTTPMODEL。这座建筑非常优雅。也许不是隐藏的功能,但仍然很酷。


代码表达式生成器

样本标记:

1
2
3
4
Text = '<%$ Code: GetText() %>'
Text = '<%$ Code: MyStaticClass.MyStaticProperty %>'
Text = '<%$ Code: DateTime.Now.ToShortDateString() %>'
MaxLenth = '<%$ Code: 30 + 40 %>'

代码表达式生成器的真正优点是可以在非数据绑定情况下使用类似数据绑定的表达式。还可以创建执行其他函数的其他表达式生成器。

Web.CONFIG:

1
2
3
<system.web>    
    <compilation debug="true">
        <expressionBuilders>

使一切发生的CS类:

1
2
3
4
5
6
7
8
9
10
11
[ExpressionPrefix("Code")]
public class CodeExpressionBuilder : ExpressionBuilder
{
    public override CodeExpression GetCodeExpression(
        BoundPropertyEntry entry,
        object parsedData,
        ExpressionBuilderContext context)
    {            
        return new CodeSnippetExpression(entry.Expression);
    }
}


可以在.aspx页内使用ASP.NET注释来注释包括服务器控件在内的整个页面部分。注释掉的内容将永远不会发送到客户机。

1
2
3
4
5
<%--
   
       
   
--%>


ashx文件类型的用法:
如果您只想输出一些基本的HTML或XML,而不需要经过页面事件处理程序,那么可以简单地实现httpmodule。

将页面命名为somehandlerpage.ashx,并在其中输入以下代码(仅一行)

1
<%@ webhandler language="C#" class="MyNamespace.MyHandler" %>

然后是代码文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.IO;
using System.Web;

namespace MyNamespace
{
    public class MyHandler: IHttpHandler
    {
        public void ProcessRequest (HttpContext context)
        {  
            context.Response.ContentType ="text/xml";
            string myString = SomeLibrary.SomeClass.SomeMethod();
            context.Response.Write(myString);
        }

        public bool IsReusable
        {
            get { return true; }
        }
    }
}


基于目标浏览器等设置服务器控件属性。

1
2
3
4
5
<asp:Label runat="server" ID="labelText"
    ie:Text="This is IE text"
    mozilla:Text="This is Firefox text"
    Text="This is general text"
/>

那个有点让我吃惊。


system.web.virtualpathutility(系统.web.virtualpathutility)


我在一个ASP.NET应用程序上工作,该应用程序通过了一家领先的安全公司的安全审计,我学会了这个简单的技巧来防止一个不太知名但很重要的安全漏洞。

以下解释来自:http://www.guidanceshare.com/wiki/asp.net_2.0_安全指导原则_uuu参数_u操作考虑使用_page.viewstateUserkey_反击_一键单击攻击

考虑使用page.viewstateUserkey来反击一键攻击。如果您对调用者进行身份验证并使用viewstate,请在page_init事件处理程序中设置page.viewstateUserkey属性以防止一键攻击。

1
2
3
void Page_Init (object sender, EventArgs e) {
  ViewStateUserKey = Session.SessionID;
}

将属性设置为每个用户都知道的唯一值,例如会话ID、用户名或用户标识符。

当攻击者创建一个网页(.htm或.aspx),其中包含一个名为"viewstate"的隐藏表单字段,该字段已被viewstate数据填充时,就会发生一次单击攻击。可以从攻击者先前创建的页面(例如包含100个项目的购物车页面)生成viewstate。攻击者引诱一个毫无戒心的用户浏览页面,然后攻击者将页面发送到视图状态有效的服务器。服务器无法知道viewstate来自攻击者。viewstate验证和hmacs不应对这种攻击,因为viewstate是有效的,页面是在用户的安全上下文下执行的。

通过设置viewstateUserkey属性,当攻击者浏览到一个页面以创建viewstate时,该属性初始化为其名称。合法用户向服务器提交页面时,会使用攻击者的名称初始化页面。因此,VIEWSTATE HMAC检查失败,并生成异常。


已启用httpContext.current.isDebugging

这对于确定要输出哪些脚本(最小版本或完整版本)或在开发人员中可能需要但不是实时的任何其他脚本都非常有用。


面板中的DefaultButton属性。

它为特定面板设置默认按钮。


包含在ASP.NET 3.5 SP1中:

  • 现在,customErrors支持值为"responserewrite"的"redirectMode"属性。显示错误页而不更改URL。
  • 表单标记现在识别action属性。非常适合使用URL重写

使用configSource拆分配置文件。

例如,可以使用web.config文件中的configSource属性将配置元素推送到其他.config文件中。而不是:

1
2
        <!-- some more keys -->
    </appSettings>

…您可以将整个appsettings部分存储在另一个配置文件中。这是新的web.config

1
 

myAppSettings.config文件:

1
2
        <!-- some more keys -->
    </appSettings>

这对于将应用程序部署到客户而不希望它们干扰web.config文件本身并且只希望它们能够更改一些设置的情况非常有用。

参考:http://weblogs.asp.net/fmarguerie/archive/2007/04/26/using-configsource-to-split-configuration-files.aspx


Scottgu在http://weblogs.asp.net/scottgu/archive/2006/04/03/441787.aspx上有很多技巧


page指令中的maintainScrollPositiononPostback属性。它用于在回发中保持ASPX页面的滚动位置。


httpContext.isCustomerRorEnabled是一个很酷的功能。我发现它不止一次有用。这是一篇短文。


默认情况下,自定义控件的标记之间的任何内容都将作为子控件添加。这可以在addParsedSubObject()重写中截获,用于筛选或附加分析(例如,LiteralControls中的文本内容):

1
2
3
4
5
    protected override void AddParsedSubObject(object obj)
     { var literal = obj as LiteralControl;
       if (literal != null) Controls.Add(parseControl(literal.Text));
       else base.AddParsedSubObject(obj);
     }

1
2
3
   <uc:MyControl runat='server'>
     ...this text is parsed as a LiteralControl...
  </uc:MyControl>

如果有ASP.NET生成RSS提要,它有时会在页面顶部添加一行额外的内容。这不会用普通的RSS验证器进行验证。您可以通过将page指令<@Page>放在页面底部来解决这个问题。


在ASP.NET v3.5添加路由之前,只需在页面管道的早期(如BeginRequest事件)中写入httpmodule并重写请求,就可以创建自己的友好URL。

像http://servername/page/param1/someparams1/param2/someparams2这样的URL将被映射到下面的另一个页面(通常使用正则表达式)。

1
HttpContext.RewritePath("PageHandler.aspx?Param1=SomeParms1&Param2=SomeParams2");

dotnetnuke有一个非常好的httpmodule,它为其友好的URL执行此操作。对于无法部署.NET 3.5版的计算机仍然有用。


我的团队经常把它当作黑客:

1
2
3
4
5
6
7
WebRequest myRequest = WebRequest.Create("http://www.google.com");
WebResponse myResponse = myRequest.GetResponse();
StreamReader sr = new StreamReader(myResponse.GetResponseStream());

// here's page's response loaded into a string for further use

String thisReturn = sr.ReadToEnd().Trim();

它以字符串形式加载网页的响应。您也可以发送post参数。

当我们需要廉价和快速的服务时,我们使用它来代替ascx/ajax/webservices。基本上,它是跨服务器访问Web可用内容的快速方法。事实上,我们昨天刚刚将其命名为"Redneck Web服务"。


您知道可以在IIS或Visual Studio之外运行ASP.NET吗?

整个运行时被打包并准备在任何想要尝试的进程中托管。使用ApplicationHostHttpRuntimeHttpApplication类,您也可以研磨这些.aspx页面并从中获得闪亮的HTML输出。

1
2
3
HostingClass host = ApplicationHost.CreateApplicationHost(typeof(HostingClass),
                                           "/virtualpath","physicalPath");
host.ProcessPage(urlToAspxFile);

还有你的主持课:

1
2
3
4
5
6
7
8
9
10
11
12
public class HostingClass : MarshalByRefObject
{
    public void ProcessPage(string url)
    {
        using (StreamWriter sw = new StreamWriter("C:\temp.html"))
        {
            SimpleWorkerRequest worker = new SimpleWorkerRequest(url, null, sw);
            HttpRuntime.ProcessRequest(worker);
        }
                    // Ta-dah!  C:\temp.html has some html for you.
    }
}

compilationmode="never"是在某些ASP.NET站点中至关重要的功能。

如果您有一个ASP.NET应用程序,在该应用程序中,经常通过CMS或其他发布系统生成和更新ASPX页,则必须使用compilationMode="never"。

如果不使用此设置,ASPX文件更改将触发重新编译,这将快速使AppDomain重新启动。这可以清除会话状态和httpruntime缓存,更不用说重新编译导致的延迟。

(为了防止重新编译,您可以增加NumRecompilesForAppRestart设置,但这并不理想,因为它会消耗更多的内存。)

该特性的一个警告是,ASPX页不能包含任何代码块。为了解决这个问题,可以将代码放在自定义控件和/或基类中。

在ASPX页面不经常更改的情况下,此功能通常是不相关的。


vs阻塞的有效语法:

1
2
3
<input type="checkbox" name="roles" value='<%# Eval("Name") %>'
  <%# ((bool) Eval("InRole")) ?"checked" :"" %>
  <%# ViewData.Model.IsInRole("Admin") ?"" :"disabled" %> />


system.web.hostingenvironment.mappath(系统.web.hosting.hostingenvironment.mappath)


我想到了一个特点,有时候你需要把你的页面的一部分隐藏起来,不让乌鸦看到。您可以使用JavaScript或使用以下简单代码:

1
2
if (Request.Browser.Crawler){
        HideArticleComments();


与optimizations="true"解决方案类似,这里还有一个解决方案可以加快您在构建之间等待的时间(非常好,尤其是在处理大型项目时):创建基于RAM的驱动器(即使用ramdisk),并将默认的"临时ASP.NET文件"更改为此基于内存的驱动器。

关于如何做到这一点的详细信息,请访问我的博客:http://www.wagnerdanda.me/2009/11/speeding-up-build-times-in-asp-net-with-ramdisk/

基本上,您首先配置一个ramdisk(同样,在我的博客中有一个指向免费ramdisk的链接),然后根据以下内容更改web.config:

1
2
3
4
5
6
7
 <system.web>
 ....
     <compilation debug="true" tempDirectory="R:\ASP_NET_TempFiles">
     ....
     </compilation>
 ....
 </system.web>

它大大增加了我的开发时间,你只需要为你的电脑投资内存:)

编程愉快!

瓦格纳丹达


Request.IsLocal属性:

它指示当前请求是否来自本地计算机。

1
2
3
4
5
6
7
8
if( Request.IsLocal )
{
   LoadLocalAdminMailSettings();
}
else
{
   LoadServerAdminMailSettings();
}


当我将一个xmldocument()转储到一个标签中,并使用它的XSL转换显示时,我认为它很好。


默认情况下,任何Web窗体页都继承自System.Web.UI.Page类。如果您希望您的页面从一个从System.Web.UI.Page继承的自定义基类继承,该怎么办?

有一种方法可以约束任何要从自己的基类继承的页。只需在您的web.config上添加一个新行:

1
2
3
<system.web>
    <pages pageBaseType="MyBasePageClass" />
</system.web>

注意:只有当您的类是独立类时,这才有效。我的意思是一个没有代码的类,它看起来像<%@ Page Language="C#" AutoEventWireup="true" %>


EnsureChildControls方法:检查子控件是否已启动。如果未启动子控件,则调用CreateChildControls方法。


将app_code文件夹中的类附加到全局应用程序类文件。

ASP.NET 2.0-global.asax-代码隐藏文件。

这也适用于Visual Studio 2008。


很多人都提到了在重新编译时如何优化代码。最近我发现我可以在ASPX页面中完成大部分的开发(代码隐藏),并完全跳过构建步骤。只需保存文件并刷新页面即可。您只需将代码包装在以下标记中:

1
2
3
4
5
<script runat="server">

   Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
     Response.Write("Look Ma', I didn't even had to build!")
   End Sub

一旦你完成了,只需把所有的代码转移到后面,构建,测试所有的工作,瞧!

-D


可以使用其uniqueid属性查找任何控件:

1
Label label = (Label)Page.FindControl("UserControl1$Label1");


页对象上的ClientScript属性。


web.config中appsettings元素的"file"属性。

指定包含自定义应用程序配置设置的外部文件的相对路径。

如果在许多需要在不同环境(prod)中修改的应用程序设置中,您只有很少的设置,那么这是一个很好的选择。

由于对web.config文件的任何更改都会导致应用程序重新启动,因此使用单独的文件,用户可以修改appsettings部分中的值,而不会导致应用程序重新启动。单独文件的内容与web.config文件中的appsettings部分合并。


如果使用Web服务而不是WCF服务,则仍可以使用标准的.NET成员身份来强制身份验证和登录会话行为。在一组Web服务上,类似于在不需要特殊会话的情况下,如何通过成员身份验证来保护网站和/或SOAP头实现,只需调用System.Web.Security.FormsAuthentication.SetAuthcookie(用户名,假)[调用后membership.validateuser(用户名、密码)当然可以]在响应中创建cookie,就像用户通过Web表单登录一样。然后可以使用response.cookies[].value检索此身份验证cookie,并将其作为字符串返回给用户通过在应用程序中重新创建cookie,通过提取cookie方法从request.inputstream调用param,并在成员身份以这种方式验证请求之前重新创建auth cookie成员资格提供程序会被欺骗,并且会知道请求是经过身份验证的,并强制执行其所有规则。

将此cookie返回给用户的Web方法签名示例如下:字符串登录(用户名、密码)

随后的Web方法调用示例如下:需要从request.inputstreamis中提取authcookie(从登录方法获得的值)参数的字符串dosomething(string authcookie、string methodparam1、int methodparam2等)

这还模拟登录会话,并在Web方法中调用FormsAuthentication.Signout,如此注销(Authcookie)将使用户需要重新登录。


应用程序变量可以与Web应用程序一起用于整个应用程序之间的通信。它在global.asax文件中初始化,并由独立于所创建会话的所有用户在该Web应用程序的页面上使用。


可以将ASPX页打包到库(.dll)中,并将其与ASP.NET引擎一起使用。

您需要实现自己的virtualpathprovider,它将通过特定于relfection的dll加载,或者您可以在路径名中包含dll名称。这取决于你。

当覆盖virtualfile.open方法时会发生这种魔力,在该方法中,您将ASPX文件作为来自程序集类:assembly.getManifestResourceStream的资源返回。ASP.NET引擎将处理该资源,因为它是通过virtualpathprovider提供服务的。

这允许插入页面,或者像我一样,使用它包含一个带有控件的httphandler。


模板化用户控件。一旦你知道它们是如何工作的,你就会看到各种各样的可能性。下面是最简单的实现:

模板控件.ascx

这里最棒的是使用简单而熟悉的用户控制构建块,并且能够使用HTML和一些占位符来布局UI的不同部分。

1
<%@ Control Language="C#" CodeFile="TemplatedControl.ascx.cs" Inherits="TemplatedControl" %>

模板控件.ascx.cs

这里的"秘密"是使用ITemplate类型的公共属性,并了解[ParseChildren][PersistenceMode]属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System.Web.UI;

[ParseChildren(true)]
public partial class TemplatedControl : System.Web.UI.UserControl
{
    [PersistenceMode(PersistenceMode.InnerProperty)]
    public ITemplate Header { get; set; }

    [PersistenceMode(PersistenceMode.InnerProperty)]
    public ITemplate Body { get; set; }

    void Page_Init()
    {
        if (Header != null)
            Header.InstantiateIn(HeaderPlaceHolder);

        if (Body != null)
            Body.InstantiateIn(BodyPlaceHolder);
    }
}

阿斯克斯

1
2
3
4
5
6
7
8
9
10
11
<%@ Register TagPrefix="uc" TagName="TemplatedControl" Src="TemplatedControl.ascx" %>

<uc:TemplatedControl runat="server">
    <Header>Lorem ipsum</Header>
    <Body>
        // You can add literal text, HTML and server controls to the templates
        <p>
Hello !
</p>
    </Body>
</uc:TemplatedControl>

您甚至可以获得内部模板属性的IntelliSense。因此,如果您在一个团队中工作,您可以快速创建可重用的UI,以实现与您的团队已经从内置的ASP.NET服务器控件中享受到的相同的可组合性。

msdn示例(与开头链接相同)添加了一些额外的控件和命名容器,但只有在您希望支持"转发器类型"控件时才需要这样做。


我在vb、vbscript和vb.net的多个版本中使用的方法之一是将记录集值转换为字符串,以消除对空或空的多重测试。即Trim(rsData("FieldName").Value &"")。如果是整数值,则为:CLng("0" & Trim(rsData("FieldName").Value &""))


在网站发布并部署到生产服务器之后,如果需要在服务器端按钮上做一些更改,请单击事件。我们可以使用ASPX页面本身的new关键字来覆盖现有的click事件。

例子

代码隐藏方法

1
2
3
4
 Protected void button_click(sender object, e System.EventArgs)
  {
     Response.Write("Look Ma', I Am code behind code!")  
  }

重写的方法:

1
2
3
4
5
6
7
<script runat="server">  
   Protected void new button_click(sender object, e System.EventArgs)
  {
     Response.Write("Look Ma', I am overrided method!")  
  }

</script

这样,我们就可以轻松地修复生产服务器错误,而无需重新部署。


这似乎是一个巨大的,模糊的问题…但是我会加入反射,因为它允许我做一些非常强大的事情,比如可插拔的DAL等等。