Click here to Skip to main content
15,892,643 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
So I'm supposed to create a website with a bunch of sub-directories, one for each country (so 200+ of them). For example (the domain is made up):
www.dragon.com/china/
www.dragon.com/egypt/

Rather than actually create all those subdirectories and all the pages under them, I would like to redirect on the server side to a single page with a query string:
www.dragon.com/home.aspx?country=china
www.dragon.com/home.aspx?country=egypt

And I only want that URL to be used on the backend. I do not want the user to see the "home.aspx" page or the query string. The user should still see the original directory they typed in.

What would be an easy way of doing that? I'm on IIS6 (can't upgrade to IIS7 for a while). I read an article that uses a custom 404 page to do a server side transfer, but wouldn't that tell search engines that the page is invalid? If so, I'd like to find another way. Or maybe there is a way to tell the search engine "just kidding, it's not really a 404".
Posted
Comments
AspDotNetDev 8-Nov-10 14:14pm    
After some Google-fu, I may have found a solution, though I'll have to read a bit more about it before I'm sure: http://www.simple-talk.com/dotnet/asp.net/a-complete-url-rewriting-solution-for-asp.net-2.0/ .

The best way to do it is to use URL re-writer.


<rewrite url="^~/([-a-z0-9]+?)/{0,1}$" to ="~/home.aspx?country=$1/>

Of course you have to implement URL re-writer into your application.

Look into the following link:

http://urlrewriter.net[^]
 
Share this answer
 
Comments
AspDotNetDev 8-Nov-10 14:36pm    
Actually, we currently use http://www.urlrewriting.net/ (slightly different than the one you posted, but same idea). I was not able to get it to do server-side transfers rather than a redirect that the user sees. Though I suppose I could modify the source code to be able to do that (maybe). Thanks for the idea, I'll look into it.
Ed Guzman 8-Nov-10 15:59pm    
The one I referenced makes the transfer rather then redirect. You will never see the underlined URL. I could send you a dll and a sample of web.config. Let me know and good luck.
AspDotNetDev 8-Nov-10 16:56pm    
Thanks, but I actually figured out how to make www.urlrewriting.net do a transfer. Only problem is, it shows the original (underlying) URL on a postback (such as a button click). I think that problem is solved, but I'm reading about it now in that article I posted to above in the comment to my own question. Does the original URL show up when you postback when using www.urlrewriter.net?
Ed Guzman 8-Nov-10 17:17pm    
I wrote a piece of code to handle this. I will place it into the different answer.
See my last comment.

Here is how to handle post back situation.
I cut off some non important code, so the code might have errors.
It is easy to understand.
Together with the re-writer it will be working just fine.

C#
public class TextWriterRewriteFormAction : System.Web.UI.HtmlTextWriter
    {
        public TextWriterRewriteFormAction(TextWriter writer) : base(writer) { }
        public TextWriterRewriteFormAction(TextWriter writer, string tabString) : base(writer, tabString) { }
        public override void WriteAttribute(string name, string value, bool fEncode)
        {
            if (name == "action")
            {
                HttpContext Context = HttpContext.Current;
                if (Context.Items["ActionAlreadyWritten"] == null)
                {
                    value = Context.Request.RawUrl;
                    Context.Items["ActionAlreadyWritten"] = true;
                }
            }
            base.WriteAttribute(name, value, fEncode);
        }
    }



And use it in a BasePage (your pages must inherit from it)

public class BasePage: System.Web.UI.Page
{
    private bool _rendered;

    protected override void Render(HtmlTextWriter writer)
    {

        if (!_rendered)
        {
            _rendered = true;
            using (StringWriter sw = new StringWriter())
            {
                BaseObjects.TextWriterRewriteFormAction newWriter = new BaseObjects.TextWriterRewriteFormAction(sw);
                base.Render(newWriter);
                newWriter.Flush();
                renderedHtml = sw.ToString();
                newWriter.Close();
            }
        }
        else
        {
            base.Render(writer);
        }
        writer.Write(renderedHtml);
    }
}


Good luck.
 
Share this answer
 
Comments
AspDotNetDev 8-Nov-10 18:30pm    
Wow, thanks for that. I'll try a few things and let you know what I decide on. This particular solution may be troublesome, as I'm using a CMS (Umbraco) that doesn't really allow for pages to be created... only masterpages (and all masterpages must descend from some built-in masterpage). Still, I can probably get something working. Right now I'm looking at a custom HTTP Module solution. And I imagine I can override that Render function in a masterpage. Thanks again.
Ed Guzman 8-Nov-10 19:49pm    
I am not sure about master page rendering. The master page is just a wrapper around a page, but it worth trying.
Let me know if you get it working. I agree that using a base page just for this purpose is a bit too much. Fortunately, I have a lot of different useful things in the base page. Let me know if how you handle this.
AspDotNetDev 8-Nov-10 23:26pm    
I came across this neat post by Scott Guthrie: http://weblogs.asp.net/scottgu/archive/2007/02/26/tip-trick-url-rewriting-with-asp-net.aspx . He explains how putting a ".browser" file in the "App_Browsers" does basically what you suggest here, but it avoids having to modify any of the pages. That may be exactly what I'm looking for. Once I'm done, I'll put my findings in an answer and put a comment here to let you know it's been posted. Thanks for all your help so far!
Ed Guzman 9-Nov-10 8:42am    
Very neat idea. I will try it too
AspDotNetDev 10-Nov-10 21:44pm    
I accepted your answer because it led me down the right path. However, I did some things differently than you described. See the answer I posted to see exactly what I did. Thanks again!
So here is what ended up working for me. We already have Umbraco installed, and as part of Umbraco comes http://www.urlrewriting.net/. That works fine with IIS6, but it didn't seem to handle postbacks well (the underlying URL would be revealed). So, I grabbed the Form.browser file described by this post and placed it in my App_Browsers folder. I also modified the web.config as that post states and I put the "FormRewriter.vb" file from that post in my App_Code directory. Since I am using UrlRewriting.net rather than UrlRewriter.net, I'm sure some of the web.config settings were not necessary (e.g., I setup the rewrite rules according to the methods required by UrlRewriting.net rather than UrlRewriter.net). Here is an example of a rule I used:
XML
<add name="MyTest" virtualUrl="^~/UserSeesThis/?$" destinationUrl="~/ThisIsABackendPage.aspx"
    ignoreCase="true" rewrite="Application" redirectMode="Temporary" />

This was the content of the Form.browser file:
XML
<browsers>
  <browser refID="Default">
    <controlAdapters>
      <adapter controlType="System.Web.UI.HtmlControls.HtmlForm" adapterType="FormRewriterControlAdapter" />
    </controlAdapters>
  </browser>
</browsers>

The FormRewriter.vb file contained this code:
VB.NET
Imports Microsoft.VisualBasic
Public Class FormRewriterControlAdapter
    Inherits System.Web.UI.Adapters.ControlAdapter
    Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
        MyBase.Render(New RewriteFormHtmlTextWriter(writer))
    End Sub
End Class
Public Class RewriteFormHtmlTextWriter
    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)
        ' If the attribute we are writing is the "action" attribute, and we are not on a sub-control, 
        ' then replace the value to write with the raw URL of the request - which ensures that we'll
        ' preserve the PathInfo value on postback scenarios
        If (name = "action") Then
            Dim Context As HttpContext
            Context = HttpContext.Current
            If Context.Items("ActionAlreadyWritten") Is Nothing Then
                ' Because we are using the UrlRewriting.net HttpModule, we will use the 
                ' Request.RawUrl property within ASP.NET to retrieve the origional URL
                ' before it was re-written.  You'll want to change the line of code below
                ' if you use a different URL rewriting implementation.
                value = Context.Request.RawUrl
                ' Indicate that we've already rewritten the <form>'s action attribute to prevent
                ' us from rewriting a sub-control under the <form> control
                Context.Items("ActionAlreadyWritten") = True
            End If
        End If
        MyBase.WriteAttribute(name, value, fEncode)
    End Sub
End Class

Here is the stuff that needed to be added to the web.config:
XML
<configuration>
  <configSections>
    <section name="rewriter" 
             requirePermission="false" 
             type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter" />
  </configSections>
  
  <system.web>
      
    <httpModules>
      <add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter" />
    </httpModules>
    
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule" />
    </modules>
    <validation validateIntegratedModeConfiguration="false" />
  </system.webServer>
  <!-- I actually left this out, as I wasn't using this rewriter. -->
  <rewriter>
    <rewrite url="~/products/(.+)" to="~/products.aspx?category=$1" />
  </rewriter>
  
</configuration>

Our server is running .Net 4, so that might be important too. This solution worked for extensionless URL's and for postbacks, so it satisfied all of my requirements.
 
Share this answer
 
v2
Comments
AspDotNetDev 10-Nov-10 21:45pm    
Oh, and I should mention that there might have been some IIS setup required for extensionless URL's, but I don't have access to the IIS setup on our server, so I have no idea what that setup (if any) might have been.
Ed Guzman 11-Nov-10 6:51am    
I looked through your code. The outcome is the same as mine, it handles post-backs through changing the "action" property of the form. I liked the way you handle: through form.browser rather than through basepage. I never used the form.browser before, need to try :-)
Good job.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900