Hidden Features of ASP.NET

Viewed 36165

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


There are always features that would be useful in fringe scenarios, but for that very reason most people don't know them. I am asking for features that are not typically taught by the text books.

What are the ones that you know?

53 Answers

While testing, you can have emails sent to a folder on your computer instead of an SMTP server. Put this in your web.config:

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

If you place a file named app_offline.htm in the root of a web application directory, ASP.NET 2.0+ will shut-down the application and stop normal processing any new incoming requests for that application, showing only the contents of the app_offline.htm file for all new requests.

This is the quickest and easiest way to display your "Site Temporarily Unavailable" notice while re-deploying (or rolling back) changes to a Production server.

Also, as pointed out by marxidad, make sure you have at least 512 bytes of content within the file so IE6 will render it correctly.

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

This will be caught by ASP.NET which will return the customErrors page. Learned about this one in a recent .NET Tip of the Day Post

Here's the best one. Add this to your web.config for MUCH faster compilation. This is post 3.5SP1 via this QFE.

<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.

Via here:

  • HttpContext.Current will always give you access to the current context's Request/Response/etc., even when you don't have access to the Page's properties (e.g., from a loosely-coupled helper class).

  • You can continue executing code on the same page after redirecting the user to another one by calling Response.Redirect(url, false )

  • You don't need .ASPX files if all you want is a compiled Page (or any IHttpHandler). Just set the path and HTTP methods to point to the class in the <httpHandlers> element in the web.config file.

  • A Page object can be retrieved from an .ASPX file programmatically by calling PageParser.GetCompiledPageInstance(virtualPath,aspxFileName,Context)

Retail mode at the machine.config level:

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

Overrides the web.config settings to enforce debug to false, turns custom errors on and disables tracing. No more forgetting to change attributes before publishing - just leave them all configured for development or test environments and update the production retail setting.

Enabling intellisense for MasterPages in the content pages
I am sure this is a very little known hack

Most of the time you have to use the findcontrol method and cast the controls in master page from the content pages when you want to use them, the MasterType directive will enable intellisense in visual studio once you to this

just add one more directive to the page

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

If you do not want to use the Virtual Path and use the class name instead then

<%@ MasterType TypeName="MyMainMasterPage" %>

Get the full article here

HttpContext.Items as a request-level caching tool

Two things stand out in my head:

1) You can turn Trace on and off from the code:

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

2) You can build multiple .aspx pages using only one shared "code-behind" file.

Build one class .cs file :

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

and then you can have any number of .aspx pages (after you delete .designer.cs and .cs code-behind that VS has generated) :

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

You can have controls in the ASPX that do not appear in Class1, and vice-versa, but you need to remeber to check your controls for nulls.

You can use:

 Request.Params[Control.UniqueId] 

To get the value of a control BEFORE viewstate is initialized (Control.Text etc will be empty at this point).

This is useful for code in Init.

WebMethods.

You can using ASP.NET AJAX callbacks to web methods placed in ASPX pages. You can decorate a static method with the [WebMethod()] and [ScriptMethod()] attributes. For example:

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

Now, in your ASPX page you can do this:

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

And call your server side method via JavaScript using:

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

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

One little known and rarely used feature of ASP.NET is:

Tag Mapping

It's rarely used because there's only a specific situation where you'd need it, but when you need it, it's so handy.

Some articles about this little know feature:

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

and from that last article:

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:

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

HttpModules. The architecture is crazy elegant. Maybe not a hidden feature, but cool none the less.

You can use ASP.NET Comments within an .aspx page to comment out full parts of a page including server controls. And the contents that is commented out will never be sent to the client.

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

The Code Expression Builder

Sample markup:

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

The real beauty of the code expression builder is that you can use databinding like expressions in non-databinding situations. You can also create other Expression Builders that perform other functions.

web.config:

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

The cs class that makes it all happen:

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

Usage of the ASHX file type:
If you want to just output some basic html or xml without going through the page event handlers then you can implement the HttpModule in a simple fashion

Name the page as SomeHandlerPage.ashx and just put the below code (just one line) in it

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

Then the code file

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

I worked on a asp.net application which went through a security audit by a leading security company and I learned this easy trick to preventing a lesser known but important security vulnerability.

The below explanation is from: http://www.guidanceshare.com/wiki/ASP.NET_2.0_Security_Guidelines_-_Parameter_Manipulation#Consider_Using_Page.ViewStateUserKey_to_Counter_One-Click_Attacks

Consider using Page.ViewStateUserKey to counter one-click attacks. If you authenticate your callers and use ViewState, set the Page.ViewStateUserKey property in the Page_Init event handler to prevent one-click attacks.

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

Set the property to a value you know is unique to each user, such as a session ID, user name, or user identifier.

A one-click attack occurs when an attacker creates a Web page (.htm or .aspx) that contains a hidden form field named __VIEWSTATE that is already filled with ViewState data. The ViewState can be generated from a page that the attacker had previously created, such as a shopping cart page with 100 items. The attacker lures an unsuspecting user into browsing to the page, and then the attacker causes the page to be sent to the server where the ViewState is valid. The server has no way of knowing that the ViewState originated from the attacker. ViewState validation and HMACs do not counter this attack because the ViewState is valid and the page is executed under the security context of the user.

By setting the ViewStateUserKey property, when the attacker browses to a page to create the ViewState, the property is initialized to his or her name. When the legitimate user submits the page to the server, it is initialized with the attacker's name. As a result, the ViewState HMAC check fails and an exception is generated.

Included in ASP.NET 3.5 SP1:

  • customErrors now supports "redirectMode" attribute with a value of "ResponseRewrite". Shows error page without changing URL.
  • The form tag now recognizes the action attribute. Great for when you're using URL rewriting

Using configSource to split configuration files.

You can use the configSource attribute in a web.config file to push configuration elements to other .config files, for example, instead of:

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

...you can have the entire appSettings section stored in another configuration file. Here's the new web.config :

    <appSettings configSource="myAppSettings.config" />

The myAppSettings.config file :

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

This is quite useful for scenarios where you deploy an application to a customer and you don't want them interfering with the web.config file itself and just want them to be able to change just a few settings.

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

HttpContext.IsCustomErrorEnabled is a cool feature.I've found it useful more than once. Here is a short post about it.

By default, any content between tags for a custom control is added as a child control. This can be intercepted in an AddParsedSubObject() override for filtering or additional parsing (e.g., of text content in 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>

If you have ASP.NET generating an RSS feed, it will sometimes put an extra line at the top of the page. This won't validate with common RSS validators. You can work around it by putting the page directive <@Page> at the bottom of the page.

Before ASP.NET v3.5 added routes you could create your own friendly URLs simply by writing an HTTPModule to and rewrite the request early in the page pipeline (like the BeginRequest event).

Urls like http://servername/page/Param1/SomeParams1/Param2/SomeParams2 would get mapped to another page like below (often using regular expressions).

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

DotNetNuke has a really good HttpModule that does this for their friendly urls. Is still useful for machines where you can't deploy .NET v3.5.

My team uses this a lot as a hack:

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

It loads a webpage's response as a string. You can send in post parameters too.

We use it in the place of ASCX/AJAX/WebServices when we need something cheap and fast. Basically, its a quick way to access web-available content across servers. In fact, we just dubbed it the "Redneck Web Service" yesterday.

Did you know it's possible to run ASP.Net outside of IIS or Visual Studio?

The whole runtime is packaged up and ready to be hosted in any process that wants to give it a try. Using ApplicationHost, HttpRuntime and HttpApplication classes, you too can grind up those .aspx pages and get shiny HTML output from them.

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

And your hosting class:

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" is a feature which can be crucial in certain ASP.NET sites.

If you have an ASP.NET application where ASPX pages are frequently generated and updated via a CMS or other publishing system, it is important to use CompilationMode="Never".

Without this setting, the ASPX file changes will trigger recompilations which will quickly make your appdomain restart. This can wipe out session state and httpruntime cache, not to mention lag caused by recompilation.

(To prevent recompilation you could increase the numRecompilesBeforeAppRestart setting, but that is not ideal as it consumes more memory.)

One caveat to this feature is that the ASPX pages cannot contain any code blocks. To get around this, one may place code in custom controls and/or base classes.

This feature is mostly irrelevant in cases where ASPX pages don't change often.

Valid syntax that VS chokes on:

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

one feature came to my mind, sometimes you will need to hide some part of your page from the crowlers. you can do it with javascript or using this simple code:

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

I thought it was neat when I dumped a xmlDocument() into a label and it displayed using it's xsl transforms.

EnsureChildControls Method : It checks the child controls if they're initiated. If the child controls are not initiated it calls CreateChildControls method.

You can find any control by using its UniqueID property:

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

'file' attribute on appsettings element in web.config.

Specifies a relative path to an external file that contains custom application configuration settings.

If you have few app settings out of many that need to modified on different environments (prod), this is excellent choice.

Because any changes to the Web.config file cause the application to restart, using a separate file allows users to modify values that are in the appSettings section without causing the application to restart. The contents of the separate file are merged with the appSettings section in the Web.config file.

Application variables can be used with web application for communicating across the whole application. It is initialized in Global.asax file and used over the pages in that web application by all the user independent of the session they create.

This seems like a huge, vague question... But I will throw in Reflection, as it has allowed me to do some incredibly powerful things like pluggable DALs and such.

Related