# Route Values and the Query String

Values reach an action from the route (/products/7) or the query string (?page=2). Choose which with the address's meaning, give optional values defaults, and use \[FromRoute\] and \[FromQuery\] to be explicit.

Journeyman · ASP.NET Core · C# · Updated November 3, 2026

## After this lesson you can

- Read values from the route and the query string, with defaults for optional ones
- Choose between a route value and a query string value for a piece of information

## Key takeaways

- A route value such as `{id:int}` fills the parameter with the same name and is required unless marked with `?`; other parameters come from the query string.
- Give a query string parameter a default, such as `int page = 1`, and it's optional.
- `[FromQuery(Name = "q")]` reads `?q=sauce` into a parameter with a clearer C# name; `[FromRoute]` and `[FromForm]` name the other sources.
- If leaving a value out makes no sense, it belongs in the route (`/products/7`); if it means "the default", it belongs in the query string (`?page=2`).

An action's parameters are filled from the request. Two parts of the address carry values:

```text
/products/7               the route:        id = 7
/products?page=2          the query string: page = 2
/products/search?q=tofu   the query string: q = tofu
```

## From the route

A value in the route template, such as `{id:int}`, fills the parameter with the same name:

```csharp
[HttpGet("{id:int}")]
public IActionResult Details(int id)
```

`/products/7` calls `Details(7)`. The route can't match without it, so a route value is **required** (unless it's marked optional with `?`).

## From the query string

Any other parameter is looked for in the **query string**, the part after `?`. Give it a **default value**, and it's optional:

```csharp
[HttpGet("")]
public IActionResult Index(int page = 1)
{
    int pageCount = (productDao.Count() + PageSize - 1) / PageSize;
    if (page < 1 || page > pageCount)
    {
        return NotFound();
    }

    ViewData["Page"] = page;
    ViewData["PageCount"] = pageCount;
    return View(productDao.GetPage(page, PageSize));
}
```

| Address | `page` |
|---|---|
| `/products` | 1, the default |
| `/products?page=2` | 2 |
| `/products?page=8` | 8, which is past the last of 7 pages, so Not Found |
| `/products?page=abc` | 1: `abc` isn't an `int`, so the default stays, and `ModelState` records the problem |

Tag helpers write query strings for you: `asp-action="Index" asp-route-page="2"` gives `href="/products?page=2"`, because `page` isn't part of the route.

## Saying where a value comes from

Usually the name is enough. When you want to be explicit, or the name in the address differs from the parameter's, use **`[FromRoute]`** and **`[FromQuery]`**:

```csharp
[HttpGet("search")]
public IActionResult Search([FromQuery(Name = "q")] string? text)
```

Now `/products/search?q=sauce` fills `text` with `sauce`. A short `q` is the usual name for a search box; the parameter keeps its clear C# name. And `?text=sauce` fills nothing: with `[FromQuery(Name = "q")]`, only `q` counts.

| Attribute | Takes the value from |
|---|---|
| `[FromRoute]` | The route template, such as `{id}` |
| `[FromQuery]` | The query string |
| `[FromForm]` | A posted form's fields |
| `(none)` | Wherever binding finds the name: form, route, then query string |

## Route or query string?

| Use the route for | Use the query string for |
|---|---|
| **Which thing** the page is about: `/products/7`, `/customers/ALFKI` | **How to show** it: `?page=2`, `?sort=price`, `?q=sauce` |
| Values the page can't do without | Optional values, with defaults |
| Addresses people bookmark and share as "the page for X" | Filters and settings that change the same page's view |

A rule of thumb: if leaving the value out makes no sense, it belongs in the route; if leaving it out means "the default", it belongs in the query string.

## Check yourself

2 questions to try on the lesson page.

## So what

The route says what the page is about; the query string says how to show it. Choose by meaning, give optional values defaults, and your addresses explain themselves.

## Key terms

- Route Parameter
- [Query String](https://www.ask-codey.com/glossary/query-string)
- \[FromQuery\]
- \[FromRoute\]

## Cheat sheets

- [Route Values and the Query String](https://www.ask-codey.com/cheat-sheets/routing-in-aspnet-core-route-values-and-the-query-string-cheat-sheet)

Source: https://www.ask-codey.com/lessons/routing-in-aspnet-core-route-values-and-the-query-string
