0

My requirement is to redirect user to new url from old url . My entity is as follows:

public class HttpRedirect
{
    [Key]
    public int Id { get; set; }

    [Required(ErrorMessage = "Old url is required.")]
    [MaxLength(1000)]
    //[Url]
    [Display(Name = "Old Url")]
    public string OldUrl { get; set; }


    [Required(ErrorMessage = "New url is required.")]
    [MaxLength(1000)]
    //[Url]
    [Display (Name = "New Url")]
    public string NewUrl { get; set; }

}

Url is commented so that I can work in localhost.

So when Old url is requested I want the request is transferred to new url To achieve this in global.asax file in Application_BeginRequest event I have following code

protected void Application_BeginRequest(object sender, EventArgs e)
{
  //You don't want to redirect on posts, or images/css/js
  bool isGet = HttpContext.Current.Request.RequestType.ToLowerInvariant().Contains("get");
  if (isGet && HttpContext.Current.Request.Url.AbsolutePath.Contains(".") == false)
  {
    string lowercaseURL = (Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority + HttpContext.Current.Request.Url.AbsolutePath);
    string newUrl = new HttpRedirectRepository().RedirectUrl(lowercaseURL);
    if(newUrl != null)
       {
         lowercaseURL = newUrl;
       }
     lowercaseURL = lowercaseURL.ToLower().Trim() + HttpContext.Current.Request.Url.Query;
     Response.Clear();
     Response.Status = "301 Moved Permanently";
     Response.AddHeader("Location", lowercaseURL);
     Response.End();
   }
}

I have implemented the above code to accomplish 2 task. 1. Change url to lower case 2. If new url is available for requested url redirect to that url.

With my above implementation I have strong feeling that its working but causing infinite loop by redirecting to a lowercaseURL

So how can I prevent multiple redirection. For e.g. I request http://localhost:80/mypage and I have set its new url to http://localhost:80/home then when mypage is requested it should redirect to home making url in lowercase and redirect should occur only one time.

note

  1. I need to redirect within my own domain only.
  2. User will enter full url address for both old and new url.

UPDATE

With some hint from @RobertHarvey I have modified my code as follows which is working for me

protected void Application_BeginRequest(object sender, EventArgs e)
{
  //You don't want to redirect on posts, or images/css/js
  bool isGet = HttpContext.Current.Request.RequestType.ToLowerInvariant().Contains("get");
  if (isGet && HttpContext.Current.Request.Url.AbsolutePath.Contains(".") == false)
  {
    bool redirect = false;
    string requestUrl = (Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority + HttpContext.Current.Request.Url.AbsolutePath);
    //You don't want to change casing on query strings
    string newUrl = new HttpRedirectRepository().RedirectUrl(requestUrl);
    if (newUrl != null)
    {
      requestUrl = newUrl;
      redirect = true;
     }
     if (Regex.IsMatch(requestUrl, @"[A-Z]"))
     {
       requestUrl = requestUrl.ToLower().Trim() + HttpContext.Current.Request.Url.Query;
       redirect = true;
      }
      if (redirect)
      {
        Response.Clear();
        Response.Status = "301 Moved Permanently";
        Response.AddHeader("Location", requestUrl);
        Response.End();
       }
    }
} 

Though still I believe updated implementation has some limitation. I would appreciate any further code enhancement and case coverage.

Bhuban Shrestha
  • 1,304
  • 11
  • 27
  • Infinite loop means, your Home controller getting called repeatedly? – Siva Gopal Jul 05 '17 at 18:00
  • @SivaGopal yes as beginrequest is executed for redirected url too and that url also response by adding response header Location which cause another redirect and this process keeps going and going. I get similar situation like writing Response.Redirect("~/Home.aspx") in Home.aspx page load event. – Bhuban Shrestha Jul 05 '17 at 18:02
  • 1
    Can you simply add an `if` condition that prevents the second redirect? – Robert Harvey Jul 05 '17 at 18:03
  • Can you show some sample code of what you are you doing in Home.aspx? – Siva Gopal Jul 05 '17 at 18:06
  • @RobertHarvey I tried to do so by writing url in session but session object is not available while begin request is being handled. so i think i need to introduce some variable within begin request. – Bhuban Shrestha Jul 05 '17 at 18:07
  • @SivaGopal I have no code for that but giving you reference about similar problem we used to face in web form. I am getting similar problem in mvc 5. – Bhuban Shrestha Jul 05 '17 at 18:09
  • Just wondering, why reinvent the wheel? How about using URL Rewrite or some other redirection component? – JuanR Jul 05 '17 at 18:11
  • Include a `?redirect=0` parameter on your new target URL, and check for that. – Robert Harvey Jul 05 '17 at 18:14
  • @Juan does URL Rewrite component give me feature what I want. As far as I know URL Rewrite if for make url user friendly. My requirement is to redirect. URL Rewrite like thing has already been handled by routing. I need one step ahead of routing .ie. dynamic routing. – Bhuban Shrestha Jul 05 '17 at 18:14
  • @BhubanShrestha: That is exactly what URL Rewrite does. A rewrite IS a redirect. You can create a custom provider that loads the redirects your users define from a database or something of the sort and let it do the work for you. You get additional functionality (like rules and pattern matching) out of the box too. – JuanR Jul 05 '17 at 18:22
  • @Juan I haven't gone through URL Rewrite component in depth. I have though seen how that thing is implemented from configuration file. i will do some research on that component. But still I believe writing few lines of code is better than loading fully featured component. anyways thanks for info and I will be looking at resources for that component if that can be more benefit. – Bhuban Shrestha Jul 05 '17 at 18:28
  • @BhubanShrestha: As you have already seen, there is a bit more to redirecting than meets the eye. I have been down this road before, that is why I am suggesting you use an existing component. Good luck! – JuanR Jul 05 '17 at 18:31

1 Answers1

0

Your two "notes" are contradictory. If you only want to allow redirection within your domain, then recording a full URL, including a domain, is entirely unnecessary, and only serves to complicate things. Make the old/new URLs just absolute paths. This also solves your problem with working in development vs. production, since you don't need to worry about the data having the right domain for the right environment.

Note: your infinite redirect is a bug in your code here. You should be redirecting to newUrl, not lowercaseUrl. In the case where newUrl is null, there is no redirect, so you should simply not redirect at all in that case.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • How does this solve his infinite redirection problem? – Robert Harvey Jul 05 '17 at 18:04
  • @Chris Pratt It would be easier for user to add full url than adding content other than protocol and domain name. Though we can get absolute url from full ur. With absolute url how things will be done ? – Bhuban Shrestha Jul 05 '17 at 18:04
  • Redirection doesn't require a full URL. Just redirect to the path, and the current domain and protocol will be assumed. – Chris Pratt Jul 05 '17 at 18:05