ASP.net RequiredFieldValidator not preventing postback - asp.net

I have a question about what could stop a RequiredFieldValidator from preventing a postback.
I began working on an older, but simple aspx form and my predecessor used manual, server-side form validation (checking to see if some form fields have a value and if not displaying an error message in a label). I thought I'd clean out some unneeded code and replace the manual checking with RequiredFieldValidator controls, but while they appear to be validating, they aren't preventing a postback. Ie., I get my error messages displayed but the postback still occurs.
The form is quite simple and there are no CausesValidation="false" attributes set. My controls look like:
<asp:TextBox ID="txtPhone" Runat="server" Columns="20" MaxLength="20" />
<asp:RequiredFieldValidator ID="rfvPhone" runat="server" Display="Dynamic"
ErrorMessage="* Required" ControlToValidate="txtPhone" />
I created a brand new webform in the same project with just a single textbox, validator and submit button and it acts the same way. Error message displays but postback still occurs.
Is there a global or project-wide setting that would cause this behaviour? Something in the web.config or global.asax?

Whew. Okay, I found the problem, basically by creating a brand new project and comparing its web.config line-by-line with my old project. Turns out the culprit is this:
<xhtmlConformance mode="Legacy"/>
If I remove the line, my validation works the way I expected it to. Googling that uncovered a bunch of blog posts about how VisualStudio adds that line to the web.config when upgrading web apps from .net 1.1 to .net 3.5.
The blog posts were mainly complaining about how that field interferes with .net's AJAX stuff, but I'm guessing it messes with the JavaScript emitted for the RequiredFieldValidator in a similar fashion.

Validation can occur on the client if available, or on the server. The job of the validator isn't to prevent a postback, it's to validate the input.
Make sure that you have javascript enabled, and try explicitly setting "EnableClientScript" to true.
In the code-behind, you should never trust that the validators are validating on the client, and always use "if Page.IsValid".

I had the same problem, but the answer turned out to be quite different. I was also upgrading to .NET validation from server-side hard coded validation.
The issue in my case turned out to be related to the ASP.NET rewriting engine used from the MSDN article URL Rewriting in ASP.NET. Using the default implementation of the "Actionless Form" was the culprit - apparently this one was written based off of an earlier version of .NET and the JavaScript on the form that prevented the postback was not being send to the output because it was missing code.
Anyway, in case anyone else is using this rewriting engine, the solution was to change the default implementation of ActionlessForm to the following:
Public Class Form
Inherits System.Web.UI.HtmlControls.HtmlForm
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
MyBase.Render(New ActionlessFormHtmlTextWriter(writer))
End Sub
End Class
Public Class ActionlessFormHtmlTextWriter
Inherits HtmlTextWriter
Sub New(ByVal writer As HtmlTextWriter)
MyBase.New(writer)
Me.InnerWriter = writer.InnerWriter
End Sub
Sub New(ByVal writer As System.IO.TextWriter)
MyBase.New(writer)
MyBase.InnerWriter = writer
End Sub
Public Overrides Sub WriteAttribute(ByVal name As String, ByVal value As String, ByVal fEncode As Boolean)
Dim Context As HttpContext = HttpContext.Current
'Skip the action attribute of the form control.
If Not (name = "action") OrElse Not Context.Items("ActionAlreadyWritten") Is Nothing Then
MyBase.WriteAttribute(name, value, fEncode)
Else
Context.Items("ActionAlreadyWritten") = True
End If
End Sub
End Class
What this does is simply supress the action attribute, but allow any other logic in the framework to run. This should future proof this in case Microsoft decides to change the form again.

If you press "Enter" inside a textbox to submit the form, I don't think the validators will prevent the postback.

Could you try an explicit EnableClientScript="True" parameter to the RequiredFieldValidator?

I have found that this can sometimes also be caused by the unobtrusive validation mode first introduced in .NET 4.5 (Microsoft docs here). Especially when bringing legacy projects forward to a newer framework version.
Adding the below value in the configuration section of the project's web.config file fixed the issue for me:
<appSettings>
<add key="ValidationSettings:UnobtrusiveValidationMode" value="None" />
</appSettings>

Related

Where is the code that runs when a button is clicked in ASP.NET

I'm trying to learn basic aspects of ASP.NET by analyzing the default Web Site project with Visual Studio 2010.
In the Register.aspx page there are fields for user registration and this button:
<asp:Button ID="CreateUserButton" runat="server" CommandName="MoveNext"
Text="Create User" ValidationGroup="RegisterUserValidationGroup"/>
The button does register an user, but I can't find the piece of code that is run and even less how code was associated to that button. I've tried searching the solution for all the identifier keywords and found nothing relevant. Searching on the web mentions a Button.OnClick method that I also can't find.
Any info on the basic aspects of ASP.NET will help me; thanks in advance.
Edit: hierarchically, the button is inside:
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<asp:CreateUserWizard ID="RegisterUser" runat="server" EnableViewState="false" OnCreatedUser="RegisterUser_CreatedUser">
<WizardSteps>
<asp:CreateUserWizardStep ID="RegisterUserWizardStep" runat="server">
<ContentTemplate>
<div class="accountInfo">
<p class="submitButton">
There is a RegisterUser_CreatedUser method on the code behind and it does:
protected void RegisterUser_CreatedUser(object sender, EventArgs e)
{
FormsAuthentication.SetAuthCookie(RegisterUser.UserName, false /* createPersistentCookie */);
string continueUrl = RegisterUser.ContinueDestinationPageUrl;
if (String.IsNullOrEmpty(continueUrl))
{
continueUrl = "~/";
}
Response.Redirect(continueUrl);
}
I was expecting some kind of inserting of user data on a database. I wonder, is this all that the button does?
The button you are looking it should be in CreateUserWizardStep control. I don't know much about this control but probably control looks for a child button having CommandName = "MoveNext", then it hooks for its click event.
Try changing the CommandName to something else like "test", it should NOT hit the breakpoint on RegisterUser_CreatedUser event.
Also note that CreatedUser <- event is telling that user is created, now the rest of the code is just authenticating the same user. Behind that, the user is already been created and saved in database.
If you also look in the web.config you will find this ConnectionString
<connectionStrings>
<add name="ApplicationServices"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
</connectionStrings>
Since you are using the Visual Studio's Default Web Application project, these all things are already done by Visual Studio for you.
An aspx page will also have a "code behind" file with the same name but a different extension (the letters after the dot) which depends on the language it's written in. Visual basic files have a .vb extension while C# files have a .cs extension.
Try looking for Register.vb or Register.cs and see if that's more fruitful.
If you're using a development environment like Visual Studio, you'll probably find that in the Solution Explorer you can click to expand the aspx file and see its code behind file underneath. If you're not, you might want to pick up a copy of the free express edition:
http://www.visualstudio.com/en-US/products/visual-studio-express-vs
When you find the code-behind, look for method called "MoveNext" - that's the code that'll run when you click the button, as specified by the CommandName attribute of the asp: Tag.
You've complicated a couple of things and you are completely not at fault but partly the project templates which comes with VS 2010 IDE. Let me try to help you one by one:
Learning basics of ASP.Net : For this you should be using "ASP.NET Empty Web Application" project template present in Visual Studio 2010. You've started with "ASP.NET Web Application" project template which has complicated things for
you. To start afresh "ASP.NET Web Application" looks the obvious choice for anyone though but it comes with a precooked boiler-plate code meant for ASP.NET membership forms authentication and its associated controls which is the root cause of all your confusion. To get started with the basics take the "ASP.NET Empty Web Application" project template I've suggested above and then add a new "Web Form" and then add various basic server web controls like button or text box to get started with concepts like event handling and code behind stuff.
Your other problem -
"The button does register an user, but I can't find the piece of code
that is run and even less how code was associated to that button"
That is because the button that you are seeing on Register.aspx page is
NOT an individual server web control but it is part of a composite control asp:CreateUserWizard instead. All the events of various controls be it a button, label or text box which are part of the asp:CreateUserWizard composite control is handled by the parent composite control asp:CreateUserWizard. You will NOT find all that code in your code behind file as this is present in System.Web.dll which is referenced in your project.
Since all the control events present on the composite control are handled by a common function written inside the code of composite control it has to distinguish exactly which control was clicked by the user (to take an appropriate action) which caused the current page post back for which CommandName property comes into picture. There is a switch case statement inside that common function for parent composite control which uses the CommandName property.
So essentially what happened is when you tried to start understanding basics of ASP.Net server web controls and event handling you actually got into the path of understanding ASP.Net Membership & role web server controls & providers which might be comparatively tough to understand and grasp initially. Hope this helps you to get started and further your understanding on ASP.Net world.

Preventing the yellow screen of death

I'm having a problem with asp.net request validation. I have a basic page with a search field and a button. If the user inputs some illegal characters in the search field and clicks the button then of course I can validate his input in JS and everything's OK. However I have also a lot of LinkButtons not associated with the search functionality that do postbacks and when it happens I get the YSOD.
I know you can turn this feature off by adding ValidateRequest="false" in page directives or web.config, however I'd like to know if there is better and more elegant solution than simply disabling request validation completely.
Thanks.
you can use anti XSS Library to avoid cross scripting attack. check for this link AntiXSS asp.net .
and you can turn of the Yellowscreen of Death. by changing the CustomError mode to Remoteonly. so that remote user wont see the YSOD. only local server will see the YSOD
in web.config add line like this.
<configuration>
<system.web>
<customErrors defaultRedirect="yourErrorPage.html"
mode="RemoteOnly">
</customErrors>
</system.web>
</configuration>
Sounds to me like you need to put validation groups against your form elements (could be I'm misunderstanding the question).
(This would be easier if you'd have posted some code)
<asp:Panel runat="server" DefaultButton="btnSearch">
<asp:TextBox runat="server" ID="txtSearch" />
<asp:RequiredFieldValidator runat="server" ControlToValidate="txtSearch" ValidationGroup="vgSearch" ErrorMessage="Search is required!" />
<asp:Button runat="server" ID="btnSearch" ValidationGroup="vgSearch" Text="Search" />
</asp:Panel>
<asp:LinkButton runat="server" ID="btnLogin" Text="Login" ValidationGroup="vgLogin" />
<asp:LinkButton runat="server" ID="btnCakes" Text="Cakes!" ValidationGroup="vgCakes" />
Anyway, the idea is that your search form and associated validators have one validation group, and your other buttons have other validation groups, then the validator won't fire when you click another button.
I'm not actually sure if you NEED the validation groups against individual link buttons, I don't think you do, but I'm putting 'em in there to demonstrate my point.
If I've completely missed the boat, let me know :)
EDIT:
I should mention that I've just thrown the above code together, can't guarantee it's all formatted correctly, etc, etc.
Oddly enough, the day after I attempted to answer this, a co-worked asked me to help with the same problem, so here's what I'm up to so far...
(Bare in mind that while I've been developing in .Net for a number of years, I've never had need to delve that deeply into the page life cycle, ViewState or any of the hideously complicated bits that keep better dev's up at night)
Initially, I thought that overriding the PostBack event in JavaScript would allow me to edit the form post and remove the offending characters, so I tried it with a simple alert, but the potentially dangerous Request.Form was still appearing, so whatever's causing it is happening before the PostBack event is being fired.
So, after investigating the page life cycle, overriding every method I could and doing a whole lot of debugging, I found that the error is being throw in the DeterminePostBackMode method.
Now, by my understanding, this method looks at the form post and converts it to a NameValueCollection, so I built my own NameValueCollection, stripping out the "<" character (I only tested with that character to start with).
Protected Overrides Function DeterminePostBackMode() As System.Collections.Specialized.NameValueCollection
Dim stream As New System.IO.StreamReader(Request.InputStream)
Dim nvCollection As New System.Collections.Specialized.NameValueCollection()
Dim _split() As String = stream.ReadToEnd().Split("&")
If _split.Length > 1 Then
For i As Integer = 0 To _split.Length - 1
Dim kv() As String = _split(i).Split("=")
Dim _key As String = HttpUtility.UrlDecode(kv(0))
Dim _value As String = HttpUtility.UrlDecode(kv(1))
If _value.Contains("<") Then _value = ""
nvCollection.Add(_key, _value)
Next
End If
'For Each s As String In nvCollection
' Response.Write(String.Format("<p>{0}={1}</p>", s, nvCollection(s)))
'Next
Return nvCollection
End Function
And that worked brilliantly, the offending value was being stripped out and the NameValueCollection was being returned without causing an error...
Except I was still seeing the error message.
At the moment, I've tracked it to the PreInit page event, and I'm trying to figure a way around it, I'll update this as I make progress.
UPDATE:
I'm now fairly sure that the issue ISN'T with the values being stored in the ViewState. After reading this excellent article on ViewState, I tried setting the value of a TextBox to "<script" declaratively, which means it shouldn't be stored in the ViewState, which means that the error isn't caused by processing being carried out on the ViewState.
I think.

ASP.net doesn't populate action="" of the server form when released

I have an ASP.net webforms site, with a server form in the masterpage, as all pages require it.
When debugging the action parameter is populated at runtime along with the id, but when deployed on my server with IIS7 it doesn't appear... but still works. It's not causing the site issues, but its making my W3C HTML5 validation fail, as it needs to be populated.
Debug source:
<form method="post" action="index.aspx" id="aspnetForm">
Live source:
<form method="post" action="" id="aspnetForm">
Form declaration in masterpage:
<form runat="server">
.. some divs
</form>
I know the form tag doesnt have ID/action defined etc, because ASP configures the default at runtime and thats fine, although for some reason it messes up on my server. I've tried using the action="<% Path etc %>", to get the path name but it doesn't work.
What am I doing wrong? Am I missing something, or is it just bad practise to use a form in a masterpage?
Thanks.
Update
Ok, to solve the issue pointed out in the answer I just set the Form.Action on the Masterpage Page_Load, finally got that W3C green light!
Note: I'm using Intelligencia Rewriter, but you can pull the URL using Request.Url
public partial class myMasterPage : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
Form.Action = Intelligencia.UrlRewriter.RewriterHttpModule.RawUrl;
}
}
asp.net 4.0? If so, here's your answer: http://www.asp.net/whitepapers/aspnet4/breaking-changes#0.1__Toc256770154; It's not an easy read, and I'm not familiar myself, so you should probably read it and see how that affects your site.
I just saw your post having had exactly the same experience. In my opinion this is unintuitive by-design behaviour that will bring confusion to the majority of newer ASP.NET developers trying to grasp compliant HTML5.
Anyway after some tampering the problem can be fixed very easily using the following approach. There is no need to tamper with the web.config - thankfully!
In the Master page, add this snippet (or in the default page where this problem arises, if you're not using a master page)
Protected Sub Page_PreRender(sender As Object, e As EventArgs) Handles Me.PreRender
If Not Page.IsPostBack Then
If Page.Form.Action = String.Empty Then
Page.Form.Action = Request.Url.AbsoluteUri
End If
End If
End Sub

Handles clause requires a WithEvents variable defined in the containing type or one of its base types

I get the error
Handles clause requires a WithEvents variable defined in the containing type or one of its base types.
in the following code..
Public Sub selCurrentManuf_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles selCurrentManuf.SelectedIndexChanged
End Sub
The drop list to go with it is the following...
<asp:DropDownList
OnSelectedIndexChanged="selCurrentManuf_SelectedIndexChanged"
selectedvalue='<%#Container.DataItem("c1_manufidcurrent")%>'
ID="selCurrentManuf"
Runat="Server"
DataTextField="c4_Desc"
DataValueField="c4_manufid"
DataSource="<%# GetCurrentManuf() %>"
autopostback="true"
></asp:DropDownList>
I've gotten this error when for some I've renamed a field. For some reason sometimes the designer messes up and doesn't rename it in the form.aspx.designer.vb file, if you look in there and fix the name it can fix this issue if that has happened to you.
So double check that the field name is the same in your even handler, the aspx file and the designer.aspx files.
I had encountered this issue when upgrading a legacy page. The problem is in the Inherits attribute #Page directive has the wrong namespace.
Correct the namespace for Inherits attribute
Remove the namespace in the designer file or match with it in the designer code
I had this happen on the OnClick event for a button. I originally the button inside a panel inside of an ItemTemplate for a gridview column. I only needed the panel to popup on some other buttons OnClick event so I didn't really need it repeated through out the grid. It was hidden anyhow. I moved the panel outside the gridview all together and the error went away.
When converting a legacy Web Sites Project to a Web Application Project type, when following these directions, after converting the application, it created a bunch of .aspx.designer.vb files for me but didn't include them in the project. So I clicked on the project root in solution explorer, pressed the * key to expand everything, then multiselected all of the designer.vb files and right-clicked then said 'include in project'. Then it was able to see the types and the compiler lived happily ever after.
THE END
I had this happen when I created a command button. When I let VB.net create the event I was immediately greeted with that error.
What I did to fix it was deleted the object in the designer (a command button in my case), the code tied to it, saving my .sln & recreating the object. Problem solved.
I had this error on a handler function for an ASP button on vb.net. Solved by adding
runat="server"
to the enclosing form tag
<form name="formUpdate" method="post" id="frmUpdate" runat="server">
<asp:Button ID="btnUpdate" runat="server" Text="Update" />
</form>
I encountered this error in a solution while testing something. It is related to Designer.vb related to the form. Make sure that it was updated.
Error may like this in winform vb.net
solution:
Change this :
Public button3 As Button
TO:
Public WithEvents button3 As Button
Actually there is some fault in the designer. Closing and Re-Opening the solution fixes it
I got this error randomly 268 times in a solution that I hadn't changed. I closed and reopened the file and it seemed to fix it...

Hidden Features of ASP.NET [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
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?
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>
Check to see if the client is still connected, before starting a long-running task:
if (this.Response.IsClientConnected)
{
// long-running task
}
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; }
}
}
}
Setting Server Control Properties Based on Target Browser and more.
<asp:Label runat="server" ID="labelText"
ie:Text="This is IE text"
mozilla:Text="This is Firefox text"
Text="This is general text"
/>
That one kinda took me by surprise.
System.Web.VirtualPathUtility
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.
HttpContext.Current.IsDebuggingEnabled
This is great for determining which scripts to output (min or full versions) or anything else you might want in dev, but not live.
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
DefaultButton property in Panels.
It sets default button for a particular panel.
ScottGu has a bunch of tricks at http://weblogs.asp.net/scottgu/archive/2006/04/03/441787.aspx
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
MaintainScrollPositionOnPostback attribute in Page directive. It is used to maintain scroll position of aspx page across postbacks.
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.

Resources