ASP.NET MVC Ajax Redirect (Legacy Pattern + 2026 Alternatives)

In ASP.NET MVC, returning RedirectResult from a controller action hit via AJAX gets swallowed — the browser sees a 302 and quietly follows it, never giving the original page a chance to actually navigate. The fix: return JSON with a redirect URL and handle it in the client-side callback. Legacy pattern, still valid on .NET Framework MVC 5 and .NET 8+ MVC apps.

I shipped this in 2009 for an ASP.NET MVC 2 project that did half of its form submissions through AJAX. The pattern has barely changed through .NET Framework 4.x, .NET Core 3.1, and .NET 8/9. It’s not a pretty pattern — modern .NET apps use Razor Pages or Blazor Server/WASM where this problem mostly doesn’t exist — but if you’re maintaining a legacy ASP.NET MVC codebase, this is still what you reach for.

What this pattern does

  • Returns a JSON response from an AJAX-invoked controller action that tells the browser where to navigate
  • Client-side JavaScript checks for the redirect marker and calls window.location.href
  • Avoids the silent-302 problem where AJAX handlers follow the redirect without the user ever seeing a page change
  • Works on ASP.NET MVC 5 (.NET Framework), ASP.NET Core MVC, and .NET 8/9 MVC
  • Includes a server-side helper extension so you write return this.AjaxRedirect("/home") instead of repeating the JSON shape

Install and use

Drop the controller extension into a ControllerExtensions.cs class. Call this.AjaxRedirect("/url") from any action invoked via AJAX. Wire up the client-side handler in your jQuery or fetch success callback.

// ControllerExtensions.cs
public static class ControllerExtensions
{
    public static JsonResult AjaxRedirect(this Controller c, string url)
    {
        return new JsonResult(new { redirect = url });
    }
}

// HomeController.cs
public class HomeController : Controller
{
    [HttpPost]
    public IActionResult SaveForm(FormModel model)
    {
        if (!ModelState.IsValid) return Json(new { success = false });

        // ... save logic ...

        return this.AjaxRedirect("/dashboard");
    }
}

// site.js
$.ajax({
    url: '/home/saveform',
    type: 'POST',
    data: formData,
    success: function (result) {
        if (result.redirect) {
            window.location.href = result.redirect;
            return;
        }
        // handle normal response
    }
});

Why the naive approach breaks

When a controller returns Redirect("/home"), ASP.NET sends HTTP 302 with a Location header. For a regular page navigation, the browser follows the 302 and the user sees the new page. For an AJAX request, the XMLHttpRequest follows the 302 automatically and hands the final response body back to your success callback — but the browser URL never changes. The user sees stale content and a silent no-op. The JSON-redirect pattern gives you an explicit control point where you decide to navigate, avoiding the silent follow.

Modern equivalents (2026)

  • Razor Pages — return new JsonResult(new { redirect = "/url" }) from a handler method, same client pattern
  • Blazor Server / WASM — call NavigationManager.NavigateTo("/url") directly in the handler, no client-side glue needed
  • ASP.NET Core + HTMX — return HX-Redirect header, HTMX handles the navigation without JavaScript
  • Next.js / Remix — built-in: redirect() helpers in server actions work correctly with both fetch and form submissions
  • For new .NET projects in 2026 — prefer Blazor + HTMX or Razor Pages + HTMX over MVC, the AJAX redirect pattern becomes obsolete

FAQs

Is ASP.NET MVC dead in 2026?

Not dead — Microsoft still ships it in every .NET release, and there are millions of lines of MVC code in production. But new .NET projects pick Blazor, Razor Pages, or Minimal APIs. MVC’s share of new greenfield .NET work is below 15% based on the 2025 Stack Overflow developer survey.

Why not just use Response.Redirect?

Response.Redirect and Redirect() both emit HTTP 302. Neither solves the AJAX silent-follow problem. The JSON-envelope pattern is the only way to give the client-side code an explicit decision point.

Does this work with .NET 8 Minimal APIs?

Yes. Return Results.Json(new { redirect = "/url" }) from a minimal API endpoint and use the same client handler. The pattern is framework-agnostic at the HTTP layer.

What about HTMX and its HX-Redirect header?

HTMX is the cleanest option. Return the HX-Redirect response header from any endpoint and HTMX navigates on the client automatically — no JavaScript, no JSON envelope. If you’re writing new AJAX-style code in 2026, HTMX deserves a serious look.

Can I use this pattern in Blazor?

Blazor doesn’t need it. Blazor Server renders on the server and Blazor WASM runs in the browser — both have direct access to NavigationManager.NavigateTo() from any handler. The AJAX-redirect pattern exists because MVC’s client and server are decoupled; Blazor couples them.

Leave a Comment