【问题标题】:Hidden Features of ASP.NET [closed]ASP.NET 的隐藏功能 [关闭]
【发布时间】:2010-09-08 11:15:46
【问题描述】:

这个问题存在是因为它有 历史意义,但不是 被认为是一个很好的主题问题 对于这个网站,所以请不要使用它 作为您可以提出类似问题的证据 问题在这里。

更多信息:https://stackoverflow.com/faq


总有一些功能在边缘场景中很有用,但正因为如此,大多数人并不了解它们。我要求的是教科书通常不会教授的功能。

你知道哪些?

【问题讨论】:

  • 好问题,我希望可以多次投票!
  • 同意。我喜欢这样的线程。该框架的深度如此之深,以至于您有时会对您从未知道的东西感到惊讶。
  • 我从这个帖子的回复中学到了很多很酷的新技巧 - 谢谢! :)
  • 不应该将这些东西命名为“...的鲜为人知的功能”而不是“... .
  • 请参阅meta.stackexchange.com/questions/56669/…meta.stackexchange.com/questions/57226/… 和相关的元帖子,以讨论适当性和关闭。

标签: asp.net .net


【解决方案1】:

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

<system.net>
    <mailSettings>
        <smtp deliveryMethod="SpecifiedPickupDirectory">
            <specifiedPickupDirectory pickupDirectoryLocation="c:\Temp\" />
        </smtp>
    </mailSettings>
</system.net>

【讨论】:

  • 真的吗?我正要安装一个假的 SMTP 服务器,比如 Dumbster。我隐藏了宝石。
  • 有谁知道您是否可以为目录位置指定 UNC 共享?
  • 更好的是,把它放在你的开发箱 machine.config 上,这样你就不必在你创建的每个应用程序上更改 web.config。
  • 你能设置它只在本地主机上这样做吗?这样就不用每次都改了?
  • 没有设置。您必须使用其他方法(Web 部署项目、构建任务等)管理配置差异
【解决方案2】:

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

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

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

【讨论】:

  • 不要忘记 IE 的“友好”消息的解决方法:tinyurl.com/app-offline-friendly
  • 哎哟!将此与 MOSS 2007 一起使用时要小心。它仅适用于自上次 IIS 重新启动以来已访问的页面。所以,如果你把这个页面添加到你的 wss 虚拟根目录,然后尝试打开一个以前没有访问过的页面,你会得到一个 404。
  • @Marc - 从 Scott Guthrie 那里得到这个提示,如果你觉得慷慨,如果你对 Gu 的文章发表评论,你将帮助许多 SharePoint 开发人员避免这种情况:weblogs.asp.net/scottgu/archive/2005/10/06/426755.aspx
  • 另外,这还将触发应用域的回收并在所有请求完成后关闭所有打开的数据库连接。
  • 这里有一个警告:IIS 返回 app_offline.htm 内容,HTTP 状态代码为 404。如果您处于离线模式,搜索引擎是否应该一直徘徊并尝试为您的网站编制索引,您可能不会欣赏结果。但它非常适合我的私人企业网络应用!
【解决方案3】:
throw new HttpException(404, "Article not found");

这将被 ASP.NET 捕获,并返回 customErrors 页面。在recent .NET Tip of the Day Post 中了解了这一点

【讨论】:

  • 一些开发人员可能会争辩说,最好在 HttpContext.Response 中手动包装,而不是抛出异常,这在 .NET 书籍中是相当昂贵的操作。
  • 这不是不好的形式吗?您正在显示 404 错误,而您想要显示错误/异常。
  • 我能想到的一种情况是,如果有人恶意弄乱参数并放入无效的内容,您可能需要通用 404 而不是特定错误。
  • 赞成纯粹是因为我现在知道 .NET 每日提示网站。
  • 只有在 httpModule 或 httpHandler 中抛出时才有效
【解决方案4】:

这是最好的。将此添加到您的 web.config 以加快编译速度。这是通过this QFE发布的 3.5SP1。

<compilation optimizeCompilations="true">

快速总结:我们正在引入一个 新的 optimizeCompilations 切换 ASP.NET 可以大大提高 在某些情况下的编译速度。 有一些问题,请继续阅读 更多细节。这个开关是 目前可作为 QFE 用于 3.5SP1,并将成为 VS 2010 的一部分。

ASP.NET 编译系统需要一个 非常保守的方法 导致它消除任何以前的 它在任何时候都做过的工作 级别的文件更改。 “顶级”文件 在 bin 和 App_Code 中包含任何内容, 以及 global.asax。虽然这 适用于小型应用程序,它变成 对于非常大的应用程序几乎无法使用。 例如。一位顾客遇到了 需要 10 分钟才能完成的情况 进行任何更改后刷新页面 到“bin”程序集。

为了减轻痛苦,我们添加了一个 “优化”编译模式 不那么保守 重新编译的方法。

通过here

【讨论】:

  • 这是在 VS 2010 中“默认开启”还是我仍然应该尝试一下?
【解决方案5】:
  • HttpContext.Current 将始终让您访问当前上下文的请求/响应等,即使您无权访问页面的属性(例如,从松散的-耦合的辅助类)。

  • 调用Response.Redirect(url, false )Response.Redirect(url, false )

  • 如果您只需要一个已编译的 Page(或任何 IHttpHandler),则不需要 .ASPX 文件。只需将路径和 HTTP 方法设置为指向 web.config 文件中&lt;httpHandlers&gt; element 中的类即可。

  • 可以通过调用 PageParser.GetCompiledPageInstance(virtualPath,aspxFileName,Context) 以编程方式从 .ASPX 文件中检索 Page 对象

【讨论】:

  • 关于 Response.Redirect(url, false) - 这就是我很长一段时间以来所希望的。我不知道我是怎么错过的,但是比xxx
  • 有人能解释一下你会用这个做什么吗?我知道它有一些价值,但我不知道为什么......
  • 如果您想将用户重定向到不同的地址但仍有一些后端处理要做(例如,在继续生成报告的同时重定向到报告的生成状态页面的报告生成请求)在后台报告)
  • 有人能解释一下 PageParser.GetCompiledPageInstance(..) 的有用情况吗?文档说它是为了基础设施使用 - 它返回一个 IHttpHandler 类型,所以我看不出它是如何实际使用的。
  • @jdk:我过去在覆盖 *.aspx 请求的默认处理程序时使用过它,因此我可以使用动态内存中的 IHttpHandler 对象,但也可以将 GetCompiledPageInstance() 用于物理 *.aspx文件。
【解决方案6】:

machine.config 级别的零售模式:

<configuration>
  <system.web>
    <deployment retail="true"/>
  </system.web>
</configuration>

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

【讨论】:

  • 我有时会忘记在发布前将编译调试更改为 false,这会对性能产生负面影响。没问题了!
【解决方案7】:

在内容页面中启用 intellisense for MasterPages
我敢肯定这是一个鲜为人知的黑客攻击

大多数情况下,您必须使用 findcontrol 方法并从内容页面中将控件投射到母版页中,当您使用它们时,MasterType 指令将在 Visual Studio 中启用智能感知到这个

只需向页面添加一个指令

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

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

<%@ MasterType TypeName="MyMainMasterPage" %>

获取全文here

【讨论】:

  • 使用 FindControl 有时会很忙,感谢您提供的这个很棒的提示!
  • 使用它可能会导致意外行为。见stackoverflow.com/questions/1998931/…
  • 我个人认为功能应该不为人们所知,它将页面与母版页结合在一起。如果您最终使用母版页的属性/方法,然后更改母版页,您最终会遇到维护噩梦。
  • @Phil:有时需要它,并且对母版页进行静态类型访问比 FindControl 方法好得多。至少你得到编译器消息并且可以快速修复它。
【解决方案8】:

HttpContext.Items 作为请求级缓存工具

【讨论】:

  • 这也是我的观点,我在嵌套控件中使用它来传递/接收请求级别信息。我还在 MVC 中使用它来存储要附加的 js 文件列表,基于部分视图。
  • 我在使用 asp.net 路由将从 url 获取的参数传递到我的页面时使用它。 (不适用于 MVC)非常适合 url 重写并且非常灵活。
  • 嗯,只是想到了我可以在某个地方使用它而不是 Session - ta!
【解决方案9】:

有两件事在我脑海中突出:

1) 您可以通过代码打开和关闭 Trace:

#ifdef DEBUG 
   if (Context.Request.QueryString["DoTrace"] == "true")
                {
                    Trace.IsEnabled = true;
                    Trace.Write("Application:TraceStarted");
                }
#endif

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

构建一个类 .cs 文件:

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 代码隐藏之后):

  <%@ Page Language="C#"  AutoEventWireup="true"  Inherits="Namespace.Class1" %>
     <form id="form1" runat="server">
     <div>
     <asp:TextBox  ID="tbLogin" runat="server"></asp: TextBox  >
     </div>
     </form>

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

【讨论】:

  • 我会投票赞成,但票数已用完。我将尝试并记得回来投票。我不知道我们可以为多个页面使用相同的代码隐藏文件。不确定,这将如何工作。
  • 是否有其他人认为允许您从 url 激活跟踪存在安全风险? (#1)我不会否决这个问题,但了解那里的风险很重要。
  • 当然,您真的应该将该代码放在#ifdef DEBUG #endif 块中
  • 伟大的 cmets,指出安全方面。
  • 为什么从 url 激活跟踪存在安全风险?它如何被用来伤害我?
【解决方案10】:

你可以使用:

 Request.Params[Control.UniqueId] 

在初始化视图状态之前获取控件的值(此时,Control.Text 等将为空)。

这对 Init 中的代码很有用。

【讨论】:

  • Viewstate 初始化不处理 Request.Params。在调用实现 IPostBackDataHandler 的控件的方法 LoadPostData 之前使用它。
【解决方案11】:

网络方法。

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

[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 页面中执行以下操作:

<form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true" />
        <input type="button" value="Get Fruit" onclick="GetFruit('B')" />
    </div>
</form>

并通过 JavaScript 调用您的服务器端方法:

    <script type="text/javascript">
    function GetFruit(l)
    {
        PageMethods.GetFruitBeginingWith(l, OnGetFruitComplete);
    }

    function OnGetFruitComplete(result)
    {
        alert("You got fruit: " + result);
    }
</script>

【讨论】:

    【解决方案12】:

    在开始长时间运行的任务之前检查客户端是否仍然连接:

    if (this.Response.IsClientConnected)
    {
      // long-running task
    }
    

    【讨论】:

      【解决方案13】:

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

      Tag Mapping

      它很少使用,因为只有在特定情况下您才需要它,但当您需要它时,它非常很方便。

      一些关于这个鲜为人知的功能的文章:

      Tag Mapping in ASP.NET
      Using Tag Mapping in ASP.NET 2.0

      最后一篇文章:

      标签映射允许您交换 编译时的兼容控件 Web 应用程序中的每个页面。一种 有用的例子是如果你有股票 ASP.NET 控件,例如 DropDownList,你想替换 它带有一个自定义控件,即 派生自下拉列表。这可以 是一个已定制的控件 提供更优化的缓存 查找数据。而不是编辑每个 网页表单并替换内置 DropDownLists 与您的自定义 版本,你可以在 ASP.NET 效果通过修改为你做 网络配置:

      <pages>
       <tagMapping>
         <clear />
         <add tagType="System.Web.UI.WebControls.DropDownList"
              mappedTagType="SmartDropDown"/>
        </tagMapping>
      </pages>
      

      【讨论】:

      • 这会让您团队中的其他开发人员感到非常困惑
      • @Aykut - 确实可以,这就是为什么我说它的用处相当狭窄,但是,当需要时它非常很方便。另外,我会确保标签映射的任何使用都被非常清楚地记录下来,以避免任何混淆和歧义。
      【解决方案14】:

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

      【讨论】:

      • HttpModules 是先进的东西,但我不会称它为稀有或很少使用(或称我为幼稚)。但是,是的,我喜欢这种架构。
      • +1 因为很多经验丰富的开发人员可能知道 HttpModules 但并不完全了解它们与请求的关系。 (与 HttpHandlers 相同)
      【解决方案15】:

      您可以在 .aspx 页面中使用 ASP.NET 注释来注释掉页面的全部部分,包括服务器控件。并且被注释掉的内容永远不会发送给客户端。

      <%--
          <div>
              <asp:Button runat="server" id="btnOne"/>
          </div>
      --%>
      

      【讨论】:

      • 还有人真的不知道有cmets?
      • 我喜欢你在
      【解决方案16】:

      代码表达式构建器

      示例标记:

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

      代码表达式构建器的真正美妙之处在于,您可以在非数据绑定情况下使用类似表达式的数据绑定。您还可以创建执行其他功能的其他表达式生成器。

      web.config:

      <system.web>    
          <compilation debug="true">
              <expressionBuilders>
                  <add expressionPrefix="Code" type="CodeExpressionBuilder" />
      

      让这一切发生的cs类:

      [ExpressionPrefix("Code")]
      public class CodeExpressionBuilder : ExpressionBuilder
      {
          public override CodeExpression GetCodeExpression(
              BoundPropertyEntry entry,
              object parsedData,
              ExpressionBuilderContext context)
          {            
              return new CodeSnippetExpression(entry.Expression);
          }
      } 
      

      【讨论】:

      • 标题中的“和其他人”是什么意思?
      • 好吧,我想我从来没有接触过其他人。
      • +1,非常酷的功能...这实际上与 WPF 的标记扩展非常相似
      • 这和使用&lt;%= /*code*/ %&gt;不一样吗?
      【解决方案17】:

      ASHX 文件类型的用法:
      如果您只想输出一些基本的 html 或 xml 而不通过页面事件处理程序,那么您可以以简单的方式实现 HttpModule

      将页面命名为 SomeHandlerPage.ashx 并将以下代码(仅一行)放入其中

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

      然后是代码文件

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

      【讨论】:

      • 值得注意的是,如果需要,应该添加IRequiresSessionState或IReadOnlySessionState,否则不会出现。
      • 另外值得注意的是,您可以在 web.config 中指定处理程序的设置,因此您不需要放置物理 ashx 文件。或者,您可以在全局 asax 的应用程序启动中以编程方式注册处理程序。
      【解决方案18】:

      Setting Server Control Properties Based on Target Browsermore

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

      这让我有点意外。

      【讨论】:

      • +1。您可以在线发布一个简短的代码示例吗?我认为它会引起更多的关注和支持。我想让这个上升。
      【解决方案19】:
      【解决方案20】:

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

      以下解释来自: http://www.guidanceshare.com/wiki/ASP.NET_2.0_Security_Guidelines_-_Parameter_Manipulation#Consider_Using_Page.ViewStateUserKey_to_Counter_One-Click_Attacks

      考虑使用 Page.ViewStateUserKey 来应对一键式攻击。如果您对调用者进行身份验证并使用 ViewState,请在 Page_Init 事件处理程序中设置 Page.ViewStateUserKey 属性以防止一键式攻击。

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

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

      当攻击者创建的网页(.htm 或 .aspx)包含一个名为 __VIEWSTATE 且已填充 ViewState 数据的隐藏表单字段时,就会发生一键式攻击。 ViewState 可以从攻击者之前创建的页面生成,例如包含 100 件商品的购物车页面。攻击者引诱毫无戒心的用户浏览页面,然后攻击者将页面发送到 ViewState 有效的服务器。服务器无法知道 ViewState 来自攻击者。 ViewState 验证和 HMAC 不应对这种攻击,因为 ViewState 是有效的,并且页面是在用户的安全上下文下执行的。

      通过设置 ViewStateUserKey 属性,当攻击者浏览到一个页面创建 ViewState 时,该属性被初始化为他或她的名字。当合法用户向服务器提交页面时,它会被初始化为攻击者的名字。因此,ViewState HMAC 检查失败并生成异常。

      【讨论】:

      • 也记得离开base.OnInit(e);让 Page_Init() 函数完成其工作。
      • 我认为如果真实用户不接受 cookie,或者 sessionid 超时,这个技巧可能会失败。
      • 如果页面使用AutoEventWireup="true",则不需要base.OnInit(e);
      • 德鲁伊:他没有覆盖 OnInit(在这种情况下,base.OnInit(e) 是必要的)。
      • 只有在会话实际开始后才能使用 ViewStateUserKey 的会话 ID。这也意味着这些页面可以在会话过期后超时。如果担心这些问题,您可能会考虑使用更持久的东西,例如用户的 IP 地址。
      【解决方案21】:

      HttpContext.Current.IsDebuggingEnabled

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

      【讨论】:

      • 我同意 Jan 的观点,但有时让应用知道其执行状态 Debug/Release 可能会很有趣。
      【解决方案22】:

      包含在 ASP.NET 3.5 SP1 中:

      • customErrors 现在支持值为“ResponseRewrite”的“redirectMode”属性。在不更改 URL 的情况下显示错误页面。
      • form 标签现在可以识别 action 属性。非常适合使用 URL 重写时

      【讨论】:

        【解决方案23】:

        DefaultButton 面板中的属性。

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

        【讨论】:

        • 注意,不适用于所有类型的按钮,例如链接按钮!
        【解决方案24】:

        【讨论】:

          【解决方案25】:

          使用 configSource 拆分配置文件。

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

              <appSettings>
                  <add key="webServiceURL" value="https://some/ws.url" />
                  <!-- some more keys -->
              </appSettings>
          

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

              <appSettings configSource="myAppSettings.config" />
          

          myAppSettings.config 文件:

              <appSettings>        
                  <add key="webServiceURL" value="https://some/ws.url" />
                  <!-- some more keys -->
              </appSettings>
          

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

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

          【讨论】:

          • 这也适用于任何类型的 .net 项目,例如桌面应用程序。配置
          【解决方案26】:

          MaintainScrollPositionOnPostback Page 指令中的属性。它用于在回发中保持 aspx 页面的滚动位置。

          【讨论】:

          • 评论将有助于改进答案。
          【解决方案27】:

          HttpContext.IsCustomErrorEnabled 是一个很酷的功能。我不止一次发现它很有用。这是关于它的short post

          【讨论】:

            【解决方案28】:

            默认情况下,自定义控件的标签之间的任何内容都作为子控件添加。这可以在 AddParsedSubObject() 覆盖中被拦截,以进行过滤或其他解析(例如,LiteralControls 中的文本内容):

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

            ...

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

            【讨论】:

              【解决方案29】:

              如果您让 ASP.NET 生成 RSS 提要,它有时会在页面顶部添加一行。这不会使用常见的 RSS 验证器进行验证。您可以通过将页面指令&lt;@Page&gt; 放在页面底部来解决它。

              【讨论】:

              • 使用 .ASHX 处理程序生成 RSS 提要不是更好吗?
              • 我猜这取决于项目的复杂性。不是每个人都有能力或技能来创建和编译处理程序。在页面 asp.net 中为此工作得相当好
              • 您可以使用类似 的东西来生成 RSS 项目并执行其他技巧(例如使用 LogInView 删除一些项目),这比从 ASHX IMO 编写字符串要好得多跨度>
              • LinqToXml + ASHX 是要走的路!
              • 这不仅仅用于生成 RSS 提要。 IIRC,HTML5 必须在顶部的第一行有 标签才能正确验证。
              【解决方案30】:

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

              http://servername/page/Param1/SomeParams1/Param2/SomeParams2 之类的网址会映射到如下所示的另一个页面(通常使用正则表达式)。

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

              DotNetNuke 有一个非常好的 HttpModule 可以为他们友好的 url 做到这一点。对于无法部署 .NET v3.5 的机器仍然有用。

              【讨论】:

              • 这需要将所有 IIS 请求映射到 ASP.NET
              • 或者只是 404 错误处理程序。
              猜你喜欢
              • 2011-06-25
              • 2011-02-03
              • 2010-09-08
              • 2010-10-25
              • 2010-12-11
              • 1970-01-01
              • 2012-08-24
              • 2011-11-07
              • 2014-08-13
              相关资源
              最近更新 更多