Reading parameters from the URL query string is one of the most common tasks in web development. This guide covers how to do it across different versions of ASP.NET, with a focus on the common login redirect scenario where you need to read the ReturnUrl parameter.

The Problem

When ASP.NET’s authentication system redirects an unauthenticated user to the login page, it automatically appends the original URL as a query string parameter:

https://yoursite.com/Login.aspx?ReturnUrl=/Dashboard

After successful authentication, you need to read that ReturnUrl parameter and redirect the user back to where they were going.

ASP.NET Web Forms (Classic)

Reading a Query String Parameter

// URL: /Login.aspx?ReturnUrl=/Dashboard
string returnUrl = Request.QueryString["ReturnUrl"];

if (!string.IsNullOrEmpty(returnUrl))
{
    Response.Redirect(returnUrl);
}
else
{
    Response.Redirect("~/Default.aspx");
}

Reading Multiple Parameters

// URL: /Search.aspx?q=mysql+tables&page=2&sort=date
string query = Request.QueryString["q"];        // "mysql tables"
string page = Request.QueryString["page"];      // "2"
string sort = Request.QueryString["sort"];      // "date"

Safely Parsing Numeric Parameters

// Always use TryParse for numeric values
int page = 1; // default
if (int.TryParse(Request.QueryString["page"], out int parsedPage))
{
    page = parsedPage;
}

Full Login Page Example

protected void LoginButton_Click(object sender, EventArgs e)
{
    if (Membership.ValidateUser(UsernameTextBox.Text, PasswordTextBox.Text))
    {
        FormsAuthentication.SetAuthCookie(UsernameTextBox.Text, RememberMeCheckBox.Checked);
        
        string returnUrl = Request.QueryString["ReturnUrl"];
        
        if (!string.IsNullOrEmpty(returnUrl) && IsLocalUrl(returnUrl))
        {
            Response.Redirect(returnUrl);
        }
        else
        {
            Response.Redirect("~/Default.aspx");
        }
    }
    else
    {
        ErrorLabel.Text = "Invalid username or password.";
    }
}

// Security: Prevent open redirect attacks
private bool IsLocalUrl(string url)
{
    return !string.IsNullOrEmpty(url) 
        && (url.StartsWith("/") && !url.StartsWith("//") && !url.StartsWith("/\\"));
}

ASP.NET MVC

Reading from the Controller

public ActionResult Login(string returnUrl)
{
    // ASP.NET MVC automatically binds query string parameters to action parameters
    ViewBag.ReturnUrl = returnUrl;
    return View();
}

[HttpPost]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        // ... validate credentials ...
        
        if (Url.IsLocalUrl(returnUrl))
        {
            return Redirect(returnUrl);
        }
        return RedirectToAction("Index", "Home");
    }
    return View(model);
}

Reading Any Query String Parameter

public ActionResult Search()
{
    string query = Request.QueryString["q"];
    int page = int.TryParse(Request.QueryString["page"], out int p) ? p : 1;
    
    // Or using the ValueProvider (preferred in MVC):
    string sort = RouteData.Values["sort"]?.ToString() 
                  ?? Request.QueryString["sort"] 
                  ?? "relevance";
    
    return View();
}

ASP.NET Core (Modern)

Model Binding (Preferred)

ASP.NET Core automatically binds query string parameters to action method parameters:

// URL: /api/products?category=electronics&page=2&pageSize=20

[HttpGet]
public IActionResult GetProducts(
    [FromQuery] string category,
    [FromQuery] int page = 1,
    [FromQuery] int pageSize = 10)
{
    // Parameters are automatically bound and typed
    var products = _service.GetProducts(category, page, pageSize);
    return Ok(products);
}

Using HttpContext Directly

[HttpGet]
public IActionResult Search()
{
    // Read individual parameter
    string query = HttpContext.Request.Query["q"];
    
    // Check if parameter exists
    if (HttpContext.Request.Query.ContainsKey("sort"))
    {
        string sort = HttpContext.Request.Query["sort"];
    }
    
    // Get all query string parameters
    foreach (var param in HttpContext.Request.Query)
    {
        Console.WriteLine($"{param.Key} = {param.Value}");
    }
    
    return View();
}

Minimal API (ASP.NET Core 6+)

var app = WebApplication.Create(args);

app.MapGet("/search", (string q, int page = 1) =>
{
    return Results.Ok(new { Query = q, Page = page });
});

app.Run();

Login Redirect in ASP.NET Core

[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
    if (ModelState.IsValid)
    {
        var result = await _signInManager.PasswordSignInAsync(
            model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
        
        if (result.Succeeded)
        {
            if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
            {
                return LocalRedirect(returnUrl);
            }
            return RedirectToAction("Index", "Home");
        }
    }
    return View(model);
}

Security: Always use Url.IsLocalUrl() or LocalRedirect() to validate return URLs. Without validation, attackers can craft URLs that redirect users to malicious sites (open redirect attack).

JavaScript (Client-Side)

For completeness, here is how to read query string parameters in JavaScript:

// URL: /page?name=John&age=30

// Modern approach (URLSearchParams)
const params = new URLSearchParams(window.location.search);
const name = params.get('name');  // "John"
const age = params.get('age');    // "30"

// Check if parameter exists
if (params.has('sort')) {
    const sort = params.get('sort');
}

Quick Reference

FrameworkMethod
Web FormsRequest.QueryString["param"]
MVCAction parameter binding or Request.QueryString["param"]
ASP.NET Core[FromQuery] attribute or HttpContext.Request.Query["param"]
Minimal APIMethod parameter binding
JavaScriptnew URLSearchParams(window.location.search).get("param")

Summary

Reading URL query string parameters in ASP.NET is straightforward: use Request.QueryString["name"] in Web Forms, parameter binding in MVC, and [FromQuery] in ASP.NET Core. For the common login redirect pattern, always validate the ReturnUrl with Url.IsLocalUrl() to prevent open redirect attacks.