Leer parámetros de la URL (query string) es una tarea fundamental en el desarrollo web con ASP.NET. Este artículo cubre todos los enfoques modernos y clásicos, desde Web Forms hasta ASP.NET Core y Minimal API.
¿Qué es una query string?
Una query string es la parte de una URL que viene después del signo ?. Contiene pares de clave-valor separados por &:
https://ejemplo.com/buscar?termino=asp.net&pagina=2&orden=fecha
En este ejemplo:
termino=asp.netpagina=2orden=fecha
ASP.NET Web Forms (clásico)
Request.QueryString
// URL: https://ejemplo.com/pagina.aspx?id=42&nombre=producto
// Obtener un solo parámetro
string id = Request.QueryString["id"]; // "42"
string nombre = Request.QueryString["nombre"]; // "producto"
// Verificar si existe antes de usar
if (!string.IsNullOrEmpty(Request.QueryString["id"]))
{
int productoId = int.Parse(Request.QueryString["id"]);
// Usar el ID...
}
Uso en Page_Load
protected void Page_Load(object sender, EventArgs e)
{
string categoria = Request.QueryString["cat"];
if (!string.IsNullOrEmpty(categoria))
{
lblCategoria.Text = Server.HtmlEncode(categoria);
CargarProductos(categoria);
}
}
Seguridad: Siempre usa
Server.HtmlEncode()al mostrar valores de query string en la página para prevenir ataques XSS (Cross-Site Scripting).
ASP.NET MVC
Enlace de modelo automático
En MVC, el framework vincula automáticamente los parámetros de la URL a los parámetros del método de acción:
// URL: /Productos/Buscar?termino=laptop&pagina=1
public ActionResult Buscar(string termino, int pagina = 1)
{
// 'termino' = "laptop", 'pagina' = 1
var resultados = _servicio.Buscar(termino, pagina);
return View(resultados);
}
Acceso directo a QueryString
public ActionResult Detalle()
{
string id = Request.QueryString["id"];
// O en MVC, preferiblemente:
string id2 = Request["id"];
return View();
}
ASP.NET Core
Atributo [FromQuery]
// URL: /api/productos?categoria=electronica&precioMin=100&precioMax=500
[HttpGet]
public IActionResult ListarProductos(
[FromQuery] string categoria,
[FromQuery] decimal? precioMin,
[FromQuery] decimal? precioMax)
{
// Los parámetros se enlazan automáticamente desde la query string
var productos = _repo.Filtrar(categoria, precioMin, precioMax);
return Ok(productos);
}
Enlace con objeto de consulta
Para múltiples parámetros, usa una clase:
public class FiltroProducto
{
public string Categoria { get; set; }
public decimal? PrecioMin { get; set; }
public decimal? PrecioMax { get; set; }
public int Pagina { get; set; } = 1;
public int TamañoPagina { get; set; } = 20;
}
[HttpGet]
public IActionResult Listar([FromQuery] FiltroProducto filtro)
{
// Todos los parámetros de la URL se mapean a las propiedades del objeto
var resultados = _repo.Filtrar(filtro);
return Ok(resultados);
}
Acceso directo a HttpContext
public IActionResult Index()
{
// Acceso directo sin enlace de modelo
string valor = HttpContext.Request.Query["parametro"];
// Verificar si existe
if (HttpContext.Request.Query.ContainsKey("modo"))
{
string modo = HttpContext.Request.Query["modo"];
}
return View();
}
Minimal API (ASP.NET Core 6+)
var app = WebApplication.CreateBuilder(args).Build();
// Los parámetros de la URL se enlazan automáticamente
app.MapGet("/buscar", (string termino, int pagina = 1) =>
{
return Results.Ok(new { Termino = termino, Pagina = pagina });
});
// Con [FromQuery] explícito
app.MapGet("/filtrar", ([FromQuery] string categoria, [FromQuery] int? limite) =>
{
return Results.Ok(new { Categoria = categoria, Limite = limite ?? 10 });
});
app.Run();
Patrón ReturnUrl (redirección post-login)
Un caso de uso muy común es la URL de retorno después del inicio de sesión:
// URL: /Cuenta/Login?ReturnUrl=%2Fpanel%2Fconfiguracion
[HttpPost]
public IActionResult Login(LoginViewModel modelo, string returnUrl = null)
{
if (ModelState.IsValid && AutenticarUsuario(modelo))
{
// IMPORTANTE: Validar que la URL sea local
if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Panel");
}
return View(modelo);
}
Prevención de redirecciones abiertas
Nunca hagas esto:
// PELIGROSO — vulnerable a redirección abierta
return Redirect(Request.QueryString["ReturnUrl"]);
Siempre valida antes de redirigir:
// SEGURO — valida que la URL sea local
string returnUrl = Request.Query["ReturnUrl"];
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
Un atacante podría usar ?ReturnUrl=https://sitio-malicioso.com para dirigir a los usuarios a un sitio de phishing.
Lectura con JavaScript
Para leer parámetros de la URL en el lado del cliente:
URLSearchParams (moderno)
// URL: https://ejemplo.com/pagina?termino=busqueda&lang=es
const params = new URLSearchParams(window.location.search);
// Obtener un parámetro
const termino = params.get('termino'); // "busqueda"
const lang = params.get('lang'); // "es"
// Verificar si existe
if (params.has('termino')) {
console.log('Buscando:', params.get('termino'));
}
// Iterar todos los parámetros
for (const [clave, valor] of params) {
console.log(`${clave} = ${valor}`);
}
Construir URLs con parámetros
const url = new URL('https://ejemplo.com/api/productos');
url.searchParams.set('categoria', 'electronica');
url.searchParams.set('pagina', '1');
console.log(url.toString());
// "https://ejemplo.com/api/productos?categoria=electronica&pagina=1"
Buenas prácticas
- Valida siempre los parámetros de entrada antes de usarlos
- Codifica la salida con
HtmlEncodeal mostrar valores en HTML - Usa tipos fuertemente tipados en lugar de strings cuando sea posible
- Proporciona valores predeterminados para parámetros opcionales
- Verifica nulos antes de conversiones de tipo
- Nunca confíes en valores de la URL para operaciones sensibles sin validación
Solución de problemas
El parámetro siempre es null
- Verifica que el nombre del parámetro coincide exactamente (distingue mayúsculas/minúsculas)
- Asegúrate de que el
?está presente en la URL - Confirma que no hay un error de codificación en caracteres especiales
Caracteres especiales no se leen correctamente
Usa Uri.UnescapeDataString() para decodificar:
string valor = Uri.UnescapeDataString(Request.Query["texto"]);