1

I'm currently working on a 1 page website, and I'm having the following issue.

This website has 5 sections and we would like to create links for each of the sections in the page without using #/hash linking. We went about this by using the PJAX plug-in. So for example if the user clicks on About link, it will use PJAX-plugin to change the URL and add to the push-state... that works great. However when we go directly to the URL for example /About we want to be able to "catch" this request and route the page request back onto the homepage (and use jquery to scroll to the About div). As the actual /About page has no content and is just used as a dummy-page for the PJAX calls.

Thanks.

Ian Daz
  • 143
  • 1
  • 11
  • You can define a catch-all route, see the following topic: http://stackoverflow.com/questions/19941/how-do-i-redirect-a-user-to-a-custom-404-page-in-asp-net-mvc-instead-of-throwing – SebastianStehle Jun 02 '14 at 21:51

1 Answers1

1

When a PJAX request is sent, it is always supposed to include this header in the HTTP Request:

X-PJAX: true

You can redirect the different requests by adding a custom ActionMethodSelectorAttribute that checks if the X-PJAX header is present.

Add this custom Attribute class to your solution:

public class AcceptHeaderAttribute : ActionMethodSelectorAttribute
{
    public string HeaderName { get; set; }

    public string HeaderValue { get; set; }

    public AcceptHeaderAttribute(string headerName, string headerValue = null)
    {
        if (String.IsNullOrWhiteSpace(headerName))
            throw new ArgumentNullException("headerName");

        HeaderName = headerName;
        HeaderValue = headerValue;
    }

    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        if (controllerContext == null)
            throw new ArgumentNullException("controllerContext");

        var incomingHeader = controllerContext.HttpContext.Request.Headers[HeaderName];

        var headerExists = String.IsNullOrWhiteSpace(incomingHeader);

        // NOTE: can optionally change this to Contains, or add a parameter for that.
        var valueCorrect = String.Equals(incomingHeader, HeaderValue, StringComparison.OrdinalIgnoreCase);

        return (String.IsNullOrWhiteSpace(HeaderValue)
            ? headerExists
            : valueCorrect);
    }
}

You can then set different Action for PJAX requests versus direct user requests:

[AcceptHeader("X-PJAX", "true")]
public ActionResult About(string myInput)
{
    ViewBag.Test = "This is a PJAX request";

    return View();
}

public ActionResult About()
{
    ViewBag.Test = "This is a normal request";

    return View();

    // or redirect them to root page
    return RedirectToAction("Index");
}

If you only care to check that the Header exists in the HTTP Request, and don't care that the value is correct, you can simplify the usage to just:

[AcceptHeader("X-PJAX")]
arserbin3
  • 6,010
  • 8
  • 36
  • 52
  • Hey thanks for your help. Quick question, Will the Redirect (in the second ActionResult, clear the URL and set it back to the root?) if so is there a way to keep the URL "/About" to show as a URL?) – Ian Daz Jun 02 '14 at 22:18
  • @IanDaz Yes the `RedirectToAction()` returns a 302, which will change the URL. You could instead choose to do `return Index(myInput);` and keep the same URL, but then the Index method may need to explicitly define its view as `return View("Index");` unless you want it to use the `About.cshtml` view. Hope that makes sense. – arserbin3 Jun 03 '14 at 12:54