![]() |
Web Development »
ASP.NET »
General
Intermediate
A Smart Form Control for ASP.NET URL RewritingBy David T NelsonA smart form control that fixes many of the problem that are caused by extensionless url rewriting in ASP.NET |
C# 2.0, Windows, .NET 2.0, .NET 3.0, ASP.NET, WebForms, VS2005, Dev
|
||||||||
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
One of the websites I work on uses URL rewriting, i.e. when you type in an address www.somesite.com/Products/WidgetA/ you are really browsing to an ASP.NET page somewhere else in the website say www.somesite.com/ProductDisplay.aspx?page=Products/WidgetA/.
For a full explanation of URL rewriting along with a very usable rewriting engine
go to 15seconds.com and read Rewrite.NET
-- A URL Rewriting Engine for .NET by Robert Chartier.
One problem with this, and believe me there are many problems with URL rewriting, is that it breaks the form tag. The action of the form tag will be the real address of the .aspx page and not the nice friendly address you wanted. To work around this problem MSDN suggests that you create an "Action-less form" meaning you create a custom Form tag that simply doesn't write the action attribute on the form tag.
namespace ActionlessForm {
public class Form : System.Web.UI.HtmlControls.HtmlForm
{
protected override void RenderAttributes(HtmlTextWriter writer)
{
writer.WriteAttribute("name", this.Name);
base.Attributes.Remove("name");
writer.WriteAttribute("method", this.Method);
base.Attributes.Remove("method");
this.Attributes.Render(writer);
base.Attributes.Remove("action");
if (base.ID != null)
writer.WriteAttribute("id", base.ClientID);
}
}
}
From "http://msdn2.microsoft.com/en-us/library/ms972974.aspx">URL Rewriting in ASP.NET by Scott Mitchell
The big problem with the above code is that it completely breaks the form tag for any server control that hooks into the postback cycle, validators for instance. If you look at the source code for RenderAttributes method the HtmlForm class in the .net Framework using the excellent Lutz Reflector you will see that there is a whole lot going on in the .net Framework's HtmlForm class that Scott's version does not duplicate. Besides that what if the HtmlForm tag was changed in a future version of the .net Framework?
If we examine exactly how the action attribute gets written we see that, because the GetActionAttribute is private, there is no way to directly change the action attribute value before it gets to the HtmlTextWriter.
Also some of the logic in the RenderAttributes method simply can't be reproduced using a derived class because many of the necessary methods and attributes are private.
writer.WriteAttribute("action", this.GetActionAttribute(), true);
So we need to take a different approach to take control over if / how the Form tag action attribute gets written.
public class SelectiveHtmlTextWriter : HtmlTextWriter
{
...
public override void WriteAttribute(string name, string value, bool fEncode)
{
base.WriteAttribute(name, "/newpagename/goes/here/", fEncode);
}
}
public class SmartForm : HtmlForm
{
...
protected override void RenderAttributes(HtmlTextWriter writer)
{
SelectiveHtmlTextWriter customWriter = new SelectiveHtmlTextWriter(writer);
base.RenderAttributes(customWriter);
}
}
A new SelectiveHtmlTextWriter object is created and passed into HtmlForm class RenderAttribute method in place of the normal the HtmlTextWriter.
This works because of polymorphism. All the HtmlForm class is cares about is that it gets a reference to an HtmlTextWriter. However when it calls the RenderAttribute my override gets called instead.
This works great but I have never been fond of hard-coded values so in order to make this more extensible I added an event to the new SelectiveHtmlTextWriter called WritingAttribute which the SmartForm class subscribes to. This allows any attribute, but specifically the action, to be modified before its value is written. In this case I am substituting the Request.RawUrl value which holds the actual URL that the request came from.
public class SmartForm : HtmlForm
{
public SmartForm()
: base()
{
}
protected override void RenderAttributes(HtmlTextWriter writer)
{
SelectiveHtmlTextWriter customWriter = new SelectiveHtmlTextWriter(writer);
customWriter.WritingAttribute += new SubstituteValueEventHandler(customWriter_WritingAttribute);
base.RenderAttributes(customWriter);
}
void customWriter_WritingAttribute(object sender, SubstituteValueEventArgs e)
{
if (e.Name == "action")
{
e.NewValue = Context.Request.RawUrl;
}
}
}
In conclusion if I had a choice I would not use URL rewriting at all I would find some other way to make the client happy. But the SmartForm that we outlined here will ease the pain quite a bit. One last caveat, using the SmartForm breaks the Visual Studio designer. I have been unsuccessful at creating a custom designer for this. If anybody comes up with a designer for this email me and I'll add it to the article with the appropriate credits.
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 20 Jul 2007 Editor: |
Copyright 2007 by David T Nelson Everything else Copyright © CodeProject, 1999-2009 Web20 | Advertise on the Code Project |