Convenciones de aplicación y de ruta de Razor Pages en ASP.NET Core

Aquí encontrará información para saber cómo usar las convenciones de proveedor de modelos de aplicación y de ruta con objeto de controlar el enrutamiento, la detección y el procesamiento en aplicaciones de Razor Pages.

Para especificar una ruta de página, agregar segmentos de ruta o agregar parámetros a una ruta, use la directiva de página @page. Para obtener más información, consulte Rutas personalizadas.

Hay ciertas palabras reservadas que no se pueden usar como segmentos de ruta o nombres de parámetro. Para obtener más información, vea Enrutamiento: Nombres de enrutamientos reservados.

Vea o descargue el código de ejemplo (cómo descargarlo)

Escenario El ejemplo explica
Convenciones de modelo

Conventions.Add
Agregar un encabezado y una plantilla de ruta a las páginas de una aplicación.
Convenciones de acción de ruta de página Agregar una plantilla de ruta a las páginas de una carpeta y a una sola página.
Convenciones de acción del modelo de página Agregar un encabezado a las páginas de una carpeta, agregar un encabezado a una sola página y configurar una fábrica de filtros para agregar un encabezado a las páginas de la aplicación.

Las convenciones de Razor Pages se configuran mediante una sobrecarga de AddRazorPages que configura RazorPagesOptions. Más avanzado el tema veremos los siguientes ejemplos de convención:


var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages(options =>
    {
        options.Conventions.Add( ... );
        options.Conventions.AddFolderRouteModelConvention(
            "/OtherPages", model => { ... });
        options.Conventions.AddPageRouteModelConvention(
            "/About", model => { ... });
        options.Conventions.AddPageRoute(
            "/Contact", "TheContactPage/{text?}");
        options.Conventions.AddFolderApplicationModelConvention(
            "/OtherPages", model => { ... });
        options.Conventions.AddPageApplicationModelConvention(
            "/About", model => { ... });
        options.Conventions.ConfigureFilter(model => { ... });
        options.Conventions.ConfigureFilter( ... );
    });
}

Ordenación de la ruta

Las rutas especifican un Order para su procesamiento (una coincidencia de rutas).

Ordenación de la ruta Comportamiento
-1 La ruta se procesa antes de que se procesen otras rutas.
0 No se ha especificado ningún orden (valor predeterminado). Si no se asigna un valor Order (Order = null), el valor Order predeterminado de la ruta para su procesamiento es 0 (cero).
1, 2, … n Especifica el orden de procesamiento de la ruta.

El procesamiento de rutas se establece por convención:

  • Las rutas se procesan en orden secuencial (-1, 0, 1, 2,... n).
  • Cuando las rutas tienen el mismo orden (Order), primero se asigna la ruta más específica y, después, las rutas menos específicas.
  • Cuando varias rutas con el mismo orden (Order) y el mismo número de parámetros coinciden con una URL de solicitud, se procesan en el orden en que se han agregado a la clase PageConventionCollection.

Si es posible, evite depender de un orden de procesamiento de rutas establecido. Por lo general, el enrutamiento selecciona la ruta correcta con la coincidencia de dirección URL. Si tiene que establecer propiedades de orden (Order) de las rutas para enrutar las solicitudes correctamente, es probable que el esquema de enrutamiento de la aplicación resulte confuso para los clientes y cueste mantenerlo. Trate de simplificar el esquema de enrutamiento de la aplicación. La aplicación de ejemplo requiere un orden de procesamiento de rutas explícito para mostrar varios escenarios de enrutamiento con una sola aplicación. Sin embargo, intente evitar configurar un orden (Order) de enrutamiento en aplicaciones de producción.

El enrutamiento de Razor Pages y el del controlador MVC comparten una implementación. Puede encontrar más información sobre el orden de las rutas y MVC en el artículo Enrutamiento a acciones de controlador: Ordenación de rutas de atributo.

Convenciones de modelo

Agregue un delegado de IPageConvention con el fin de agregar convenciones de modelo que se apliquen a Razor Pages.

Adición de una convención de modelo de ruta a todas las páginas

Use Conventions para crear y agregar un elemento IPageRouteModelConvention a la colección de instancias IPageConvention que se van a aplicar durante la construcción del modelo de ruta de página.

En la aplicación de ejemplo contiene la clase {globalTemplate?} para agregar una plantilla de ruta GlobalTemplatePageRouteModelConvention a todas las páginas de la aplicación:

using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace SampleApp.Conventions;

public class GlobalTemplatePageRouteModelConvention : IPageRouteModelConvention
{
    public void Apply(PageRouteModel model)
    {
        var selectorCount = model.Selectors.Count;
        for (var i = 0; i < selectorCount; i++)
        {
            var selector = model.Selectors[i];
            model.Selectors.Add(new SelectorModel
            {
                AttributeRouteModel = new AttributeRouteModel
                {
                    Order = 1,
                    Template = AttributeRouteModel.CombineTemplates(
                        selector.AttributeRouteModel!.Template, 
                        "{globalTemplate?}"),
                }
            });
        }
    }
}

En el código anterior:

Las opciones de Razor Pages (por ejemplo, agregar Conventions) se agregan cuando Razor Pages se agrega a la colección de servicios. Para obtener un ejemplo, vea la aplicación de ejemplo.

using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.EntityFrameworkCore;
using SampleApp.Conventions;
using SampleApp.Data;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<AppDbContext>(options =>
                                   options.UseInMemoryDatabase("InMemoryDb"));

builder.Services.AddRazorPages(options =>
   {
       options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());

       options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
       {
           var selectorCount = model.Selectors.Count;
           for (var i = 0; i < selectorCount; i++)
           {
               var selector = model.Selectors[i];
               model.Selectors.Add(new SelectorModel
               {
                   AttributeRouteModel = new AttributeRouteModel
                   {
                       Order = 2,
                       Template = AttributeRouteModel.CombineTemplates(
                           selector.AttributeRouteModel!.Template,
                           "{otherPagesTemplate?}"),
                   }
               });
           }
       });

       options.Conventions.AddPageRouteModelConvention("/About", model =>
       {
           var selectorCount = model.Selectors.Count;
           for (var i = 0; i < selectorCount; i++)
           {
               var selector = model.Selectors[i];
               model.Selectors.Add(new SelectorModel
               {
                   AttributeRouteModel = new AttributeRouteModel
                   {
                       Order = 2,
                       Template = AttributeRouteModel.CombineTemplates(
                           selector.AttributeRouteModel!.Template,
                           "{aboutTemplate?}"),
                   }
               });
           }
       });

   });

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();

Considere la clase GlobalTemplatePageRouteModelConvention:

using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace SampleApp.Conventions;

public class GlobalTemplatePageRouteModelConvention : IPageRouteModelConvention
{
    public void Apply(PageRouteModel model)
    {
        var selectorCount = model.Selectors.Count;
        for (var i = 0; i < selectorCount; i++)
        {
            var selector = model.Selectors[i];
            model.Selectors.Add(new SelectorModel
            {
                AttributeRouteModel = new AttributeRouteModel
                {
                    Order = 1,
                    Template = AttributeRouteModel.CombineTemplates(
                        selector.AttributeRouteModel!.Template, 
                        "{globalTemplate?}"),
                }
            });
        }
    }
}

La propiedad Order de AttributeRouteModel está establecida en 1. Esto garantiza el siguiente comportamiento de coincidencia de rutas en la aplicación de ejemplo:

  • Más adelante en este mismo tema se incluye una plantilla de ruta para TheContactPage/{text?}. La ruta de Contact Page tiene un orden predeterminado de null (Order = 0), por lo que coincide antes de la plantilla de ruta {globalTemplate?}, que tiene Order = 1.

  • La plantilla de ruta {aboutTemplate?} se muestra en el código anterior. La plantilla {aboutTemplate?} tiene un Order con un valor de 2. Cuando la página About se solicita en /About/RouteDataValue, "RouteDataValue" se carga en RouteData.Values["globalTemplate"] (Order = 1) y no RouteData.Values["aboutTemplate"] (Order = 2), debido a la configuración de la propiedad Order.

  • La plantilla de ruta {otherPagesTemplate?} se muestra en el código anterior. La plantilla {otherPagesTemplate?} tiene un Order con un valor de 2. Cuando se solicita cualquier página en la carpeta Pages/OtherPages con un parámetro de ruta:

  • Por ejemplo: /OtherPages/Page1/xyz

  • El valor "xyz" de los datos de ruta se carga en RouteData.Values["globalTemplate"] (Order = 1).

  • RouteData.Values["otherPagesTemplate"] con (Order = 2) no se carga debido a que la propiedad Order2 tiene un valor mayor.

Cuando sea posible, no establezca Order. Cuando Order no esté establecido, el valor predeterminado es Order = 0. Confíe en el enrutamiento para seleccionar la ruta correcta en lugar de la propiedad Order.

Solicite la página About del ejemplo en localhost:{port}/About/GlobalRouteValue y revise el resultado:

The About page is requested with a route segment of GlobalRouteValue. The rendered page shows that the route data value is captured in the OnGet method of the page.

La aplicación de ejemplo usa el paquete NuGet Rick.Docs.Samples.RouteInfo para mostrar información de enrutamiento en la salida del registro. Con localhost:{port}/About/GlobalRouteValue, el registrador muestra la solicitud, Order y la plantilla usada:

info: SampleApp.Pages.AboutModel[0]
       /About/GlobalRouteValue   Order = 1 Template = About/{globalTemplate?}

Adición de una convención de modelo de aplicación a todas las páginas

Use Conventions para crear y agregar un elemento IPageApplicationModelConvention a la colección de instancias IPageConvention que se van a aplicar durante la construcción del modelo de aplicación de página.

Para demostrar esta y otras convenciones más adelante en este tema, la aplicación de ejemplo incluye una clase AddHeaderAttribute. El constructor de esta clase acepta una cadena name y una matriz de cadenas values. Estos valores se usan en su método OnResultExecuting para establecer un encabezado de respuesta. La clase completa se muestra en la sección Convenciones de acción del modelo de página más adelante en este tema.

En la aplicación de ejemplo se usa la clase AddHeaderAttribute para agregar un encabezado (GlobalHeader) a todas las páginas de la aplicación:

public class GlobalHeaderPageApplicationModelConvention 
    : IPageApplicationModelConvention
{
    public void Apply(PageApplicationModel model)
    {
        model.Filters.Add(new AddHeaderAttribute(
            "GlobalHeader", new string[] { "Global Header Value" }));
    }
}

Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseInMemoryDatabase("InMemoryDb"));

builder.Services.AddRazorPages(options =>
   {
       options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());

       options.Conventions.Add(new GlobalHeaderPageApplicationModelConvention());

Solicite la página About del ejemplo en localhost:{port}/About y revise los encabezados para ver el resultado:

Response headers of the About page show that the GlobalHeader has been added.

Adición de una convención de modelo de controlador a todas las páginas

Use Conventions para crear y agregar un elemento IPageHandlerModelConvention a la colección de instancias IPageConvention que se van a aplicar durante la construcción del modelo de controlador de página.

public class GlobalPageHandlerModelConvention
    : IPageHandlerModelConvention
{
    public void Apply(PageHandlerModel model)
    {
        // Access the PageHandlerModel
    }
}

Convenciones de acción de ruta de página

El proveedor de modelos de ruta predeterminado que se deriva de IPageRouteModelProvider invoca convenciones diseñadas para proporcionar puntos de extensibilidad que permitan configurar rutas de página.

Convención de modelo de ruta de carpeta

Use AddFolderRouteModelConvention para crear y agregar un elemento IPageRouteModelConvention que invoca una acción en PageRouteModel para todas las páginas de la carpeta especificada.

En la aplicación de ejemplo se usa AddFolderRouteModelConvention para agregar una plantilla de ruta {otherPagesTemplate?} a las páginas de la carpeta OtherPages:

options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
{
    var selectorCount = model.Selectors.Count;
    for (var i = 0; i < selectorCount; i++)
    {
        var selector = model.Selectors[i];
        model.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel
            {
                Order = 2,
                Template = AttributeRouteModel.CombineTemplates(
                    selector.AttributeRouteModel!.Template,
                    "{otherPagesTemplate?}"),
            }
        });
    }
});

La propiedad Order de AttributeRouteModel está establecida en 2. Esto garantiza que la plantilla {globalTemplate?} (establecida en 1 anteriormente en este tema) tiene prioridad para colocarse en la primera posición de valor de datos de ruta cuando se proporcione un solo valor de ruta. Si se solicita una página de la carpeta Pages/OtherPages con un valor de parámetro de ruta (por ejemplo, /OtherPages/Page1/RouteDataValue), "RouteDataValue" se carga en RouteData.Values["globalTemplate"] (Order = 1) y no en RouteData.Values["otherPagesTemplate"] (Order = 2) debido a la configuración de la propiedad Order.

Siempre que sea posible, no especifique el valor de Order, lo que da como resultado Order = 0. Deje que el enrutamiento seleccione la ruta correcta.

Solicite la página Page1 del ejemplo en localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue y revise el resultado:

Page1 in the OtherPages folder is requested with a route segment of GlobalRouteValue and OtherPagesRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

Convención de modelo de ruta de página

Use AddPageRouteModelConvention para crear y agregar un elemento IPageRouteModelConvention que invoca una acción en PageRouteModel para la página con el nombre especificado.

En la aplicación de ejemplo se usa AddPageRouteModelConvention para agregar una plantilla de ruta {aboutTemplate?} a la página About:

options.Conventions.AddPageRouteModelConvention("/About", model =>
{
    var selectorCount = model.Selectors.Count;
    for (var i = 0; i < selectorCount; i++)
    {
        var selector = model.Selectors[i];
        model.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel
            {
                Order = 2,
                Template = AttributeRouteModel.CombineTemplates(
                    selector.AttributeRouteModel!.Template,
                    "{aboutTemplate?}"),
            }
        });
    }
});

La propiedad Order de AttributeRouteModel está establecida en 2. Esto garantiza que la plantilla {globalTemplate?} (establecida en 1 anteriormente en este tema) tiene prioridad para colocarse en la primera posición de valor de datos de ruta cuando se proporcione un solo valor de ruta. Si se solicita la página About con un valor de parámetro de ruta en /About/RouteDataValue, "RouteDataValue" se carga en RouteData.Values["globalTemplate"] (Order = 1) y no en RouteData.Values["aboutTemplate"] (Order = 2), debido a la configuración de la propiedad Order.

Siempre que sea posible, no especifique el valor de Order, lo que da como resultado Order = 0. Deje que el enrutamiento seleccione la ruta correcta.

Solicite la página About del ejemplo en localhost:{port}/About/GlobalRouteValue/AboutRouteValue y revise el resultado:

About page is requested with route segments for GlobalRouteValue and AboutRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

La salida del registrador muestra:

info: SampleApp.Pages.AboutModel[0]
       /About/GlobalRouteValue/AboutRouteValue   Order = 2 Template = About/{globalTemplate?}/{aboutTemplate?}

Uso de transformadores de parámetros para personalizar rutas de página

Consulte Transformadores de parámetros.

Configurar una ruta de página

Use AddPageRoute para configurar una ruta a una página en la ruta de acceso de página especificada. Los vínculos generados que apuntan a esa página usan la ruta especificada. AddPageRoute usa AddPageRouteModelConvention para establecer la ruta.

En la aplicación de ejemplo se crea una ruta a /TheContactPage para ContactRazor Page:

options.Conventions.AddPageRoute("/Contact", "TheContactPage/{text?}");

A la página Contact también se puede llegar en /Contact1 a través de su ruta predeterminada.

La ruta personalizada de la aplicación de ejemplo que lleva a la página Contact tiene cabida para un segmento de ruta text opcional ({text?}). La página también incluye este segmento opcional en su directiva @page por si el usuario que la visita tiene acceso a la página en su ruta /Contact:

@page "{text?}"
@model ContactModel
@{
    ViewData["Title"] = "Contact";
}

<h1>@ViewData["Title"]</h1>
<h2>@Model.Message</h2>

<address>
    One Microsoft Way<br>
    Redmond, WA 98052-6399<br>
    <abbr title="Phone">P:</abbr>
    425.555.0100
</address>

<address>
    <strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br>
    <strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>

<p>@Model.RouteDataTextTemplateValue</p>

Observe que la dirección URL generada para el vínculo Contact en la página presentada refleja la ruta actualizada:

Sample app Contact link in the navigation bar

Inspecting the Contact link in the rendered HTML indicates that the href is set to '/TheContactPage'

Visite la página Contact a través de su ruta normal, /Contact, o de la ruta personalizada, /TheContactPage. Si se proporciona un segmento de ruta text adicional, la página muestra el segmento codificado en HTML que se ha proporcionado:

Edge browser example of supplying an optional 'text' route segment of 'TextValue' in the URL. The rendered page shows the 'text' segment value.

Convenciones de acción del modelo de página

El proveedor de modelos de página predeterminado que implementa IPageApplicationModelProvider invoca convenciones que están diseñadas para proporcionar puntos de extensibilidad que permitan configurar modelos de página. Estas convenciones son útiles al crear y modificar escenarios de detección y procesamiento de páginas.

En los ejemplos de esta sección, la aplicación de ejemplo usa una clase AddHeaderAttribute (la cual es un atributo ResultFilterAttribute) que aplica un encabezado de respuesta:

public class AddHeaderAttribute : ResultFilterAttribute
{
    private readonly string _name;
    private readonly string[] _values;

    public AddHeaderAttribute(string name, string[] values)
    {
        _name = name;
        _values = values;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        context.HttpContext.Response.Headers.Add(_name, _values);
        base.OnResultExecuting(context);
    }
}

Si empleamos convenciones, el ejemplo indica cómo aplicar el atributo a todas las páginas de una carpeta y a una sola página.

Convención de modelo de aplicación de carpeta

Use AddFolderApplicationModelConvention para crear y agregar un elemento IPageApplicationModelConvention que invoca una acción en las instancias PageApplicationModel para todas las páginas de la carpeta especificada.

En el ejemplo se demuestra el uso de AddFolderApplicationModelConvention agregando un encabezado (OtherPagesHeader) a las páginas de la carpeta OtherPages de la aplicación:

options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});

Solicite la página Page1 del ejemplo en localhost:5000/OtherPages/Page1 y revise los encabezados para ver el resultado:

Response headers of the OtherPages/Page1 page show that the OtherPagesHeader has been added.

Convención de modelo de aplicación de página

Use AddPageApplicationModelConvention para crear y agregar un elemento IPageApplicationModelConvention que invoca una acción en PageApplicationModel para la página con el nombre especificado.

En el ejemplo se demuestra el uso de AddPageApplicationModelConvention agregando un encabezado (AboutHeader) a la página About:

options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "AboutHeader", new string[] { "About Header Value" }));
});

Solicite la página About del ejemplo en localhost:5000/About y revise los encabezados para ver el resultado:

Response headers of the About page show that the AboutHeader has been added.

Configurar un filtro

ConfigureFilter permite configurar el filtro que se quiere aplicar. Se puede implementar una clase de filtro, pero en la aplicación de ejemplo se muestra cómo implementar un filtro en una expresión lambda, cosa que sucede en segundo plano como una fábrica que devuelve un filtro:

options.Conventions.ConfigureFilter(model =>
{
    if (model.RelativePath.Contains("OtherPages/Page2"))
    {
        return new AddHeaderAttribute(
            "OtherPagesPage2Header",
            new string[] { "OtherPages/Page2 Header Value" });
    }
    return new EmptyFilter();
});

El modelo de páginas de aplicación se usa para comprobar la ruta de acceso relativa de los segmentos que conducen a la página Page2 en la carpeta OtherPages. Si la condición se supera, se agrega un encabezado. Si no, se aplica EmptyFilter.

EmptyFilter es un filtro de acciones. Razor Pages pasa por alto los filtros de acciones, por lo que EmptyFilter no funciona del modo previsto si la ruta de acceso no contiene OtherPages/Page2.

Solicite la página Page2 del ejemplo en localhost:5000/OtherPages/Page2 y revise los encabezados para ver el resultado:

The OtherPagesPage2Header is added to the response for Page2.

Configurar una fábrica de filtros

ConfigureFilter configura la fábrica especificada para aplicar filtros a todas las instancias de Razor Pages.

En la aplicación de ejemplo se proporciona un ejemplo del uso de una fábrica de filtros, para lo cual se agrega un encabezado (FilterFactoryHeader) con dos valores a las páginas de la aplicación:

options.Conventions.ConfigureFilter(new AddHeaderWithFactory());

AddHeaderWithFactory.cs:

public class AddHeaderWithFactory : IFilterFactory
{
    // Implement IFilterFactory
    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return new AddHeaderFilter();
    }

    private class AddHeaderFilter : IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(
                "FilterFactoryHeader", 
                new string[] 
                { 
                    "Filter Factory Header Value 1",
                    "Filter Factory Header Value 2"
                });
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
        }
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Solicite la página About del ejemplo en localhost:5000/About y revise los encabezados para ver el resultado:

Response headers of the About page show that two FilterFactoryHeader headers have been added.

Filtros de MVC y filtro de página (IPageFilter)

Razor Pages no tiene en cuenta los filtros de acciones de MVC, porque Razor Pages usa métodos de control. Otros tipos de filtros de MVC que tiene a su disposición son: filtros de autorización, de excepciones, de recursos y de resultados. Para más información, vea el tema Filters (Filtros).

El filtro de páginas (IPageFilter) se aplica a Razor Pages. Para obtener más información, vea Métodos de filtrado de Razor Pages.

Recursos adicionales

Aquí encontrará información para saber cómo usar las convenciones de proveedor de modelos de aplicación y de ruta con objeto de controlar el enrutamiento, la detección y el procesamiento en aplicaciones de Razor Pages.

Si necesita configurar rutas de una página personalizadas para páginas concretas, configure el enrutamiento a esas páginas con la convención AddPageRoute, descrita más adelante en este tema.

Para especificar una ruta de página, agregar segmentos de ruta o agregar parámetros a una ruta, use la directiva de página @page. Para obtener más información, consulte Rutas personalizadas.

Hay ciertas palabras reservadas que no se pueden usar como segmentos de ruta o nombres de parámetro. Para obtener más información, vea Enrutamiento: Nombres de enrutamientos reservados.

Vea o descargue el código de ejemplo (cómo descargarlo)

Escenario El ejemplo explica cómo...
Convenciones de modelo

Conventions.Add
  • IPageRouteModelConvention
  • IPageApplicationModelConvention
  • IPageHandlerModelConvention
Agregar un encabezado y una plantilla de ruta a las páginas de una aplicación.
Convenciones de acción de ruta de página
  • AddFolderRouteModelConvention
  • AddPageRouteModelConvention
  • AddPageRoute
Agregar una plantilla de ruta a las páginas de una carpeta y a una sola página.
Convenciones de acción del modelo de página
  • AddFolderApplicationModelConvention
  • AddPageApplicationModelConvention
  • ConfigureFilter (clase de filtro, expresión lambda o fábrica de filtros)
Agregar un encabezado a las páginas de una carpeta, agregar un encabezado a una sola página y configurar una fábrica de filtros para agregar un encabezado a las páginas de la aplicación.

Las convenciones de Razor Pages se configuran mediante una sobrecarga de AddRazorPages que configura RazorPagesOptions en Startup.ConfigureServices. Más avanzado el tema veremos los siguientes ejemplos de convención:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages(options =>
    {
        options.Conventions.Add( ... );
        options.Conventions.AddFolderRouteModelConvention(
            "/OtherPages", model => { ... });
        options.Conventions.AddPageRouteModelConvention(
            "/About", model => { ... });
        options.Conventions.AddPageRoute(
            "/Contact", "TheContactPage/{text?}");
        options.Conventions.AddFolderApplicationModelConvention(
            "/OtherPages", model => { ... });
        options.Conventions.AddPageApplicationModelConvention(
            "/About", model => { ... });
        options.Conventions.ConfigureFilter(model => { ... });
        options.Conventions.ConfigureFilter( ... );
    });
}

Ordenación de la ruta

Las rutas especifican un Order para su procesamiento (una coincidencia de rutas).

Ordenar Comportamiento
-1 La ruta se procesa antes de que se procesen otras rutas.
0 No se ha especificado ningún orden (valor predeterminado). Si no se asigna un valor Order (Order = null), el valor Order predeterminado de la ruta para su procesamiento es 0 (cero).
1, 2, … n Especifica el orden de procesamiento de la ruta.

El procesamiento de rutas se establece por convención:

  • Las rutas se procesan en orden secuencial (-1, 0, 1, 2,... n).
  • Cuando las rutas tienen el mismo orden (Order), primero se asigna la ruta más específica y, después, las rutas menos específicas.
  • Cuando varias rutas con el mismo orden (Order) y el mismo número de parámetros coinciden con una URL de solicitud, se procesan en el orden en que se han agregado a la clase PageConventionCollection.

Si es posible, evite depender de un orden de procesamiento de rutas establecido. Por lo general, el enrutamiento selecciona la ruta correcta con la coincidencia de dirección URL. Si tiene que establecer propiedades de orden (Order) de las rutas para enrutar las solicitudes correctamente, es probable que el esquema de enrutamiento de la aplicación resulte confuso para los clientes y cueste mantenerlo. Trate de simplificar el esquema de enrutamiento de la aplicación. La aplicación de ejemplo requiere un orden de procesamiento de rutas explícito para mostrar varios escenarios de enrutamiento con una sola aplicación. Sin embargo, intente evitar configurar un orden (Order) de enrutamiento en aplicaciones de producción.

El enrutamiento de Razor Pages y el del controlador MVC comparten una implementación. Puede encontrar más información sobre el orden de las rutas y MVC en el artículo Enrutamiento a acciones de controlador: Ordenación de rutas de atributo.

Convenciones de modelo

Agregue un delegado de IPageConvention con el fin de agregar convenciones de modelo que se apliquen a Razor Pages.

Adición de una convención de modelo de ruta a todas las páginas

Use Conventions para crear y agregar un elemento IPageRouteModelConvention a la colección de instancias IPageConvention que se van a aplicar durante la construcción del modelo de ruta de página.

En la aplicación de ejemplo se agrega una plantilla de ruta {globalTemplate?} a todas las páginas de la aplicación:

public class GlobalTemplatePageRouteModelConvention 
    : IPageRouteModelConvention
{
    public void Apply(PageRouteModel model)
    {
        var selectorCount = model.Selectors.Count;
        for (var i = 0; i < selectorCount; i++)
        {
            var selector = model.Selectors[i];
            model.Selectors.Add(new SelectorModel
            {
                AttributeRouteModel = new AttributeRouteModel
                {
                    Order = 1,
                    Template = AttributeRouteModel.CombineTemplates(
                        selector.AttributeRouteModel.Template, 
                        "{globalTemplate?}"),
                }
            });
        }
    }
}

La propiedad Order de AttributeRouteModel está establecida en 1. Esto garantiza el siguiente comportamiento de coincidencia de rutas en la aplicación de ejemplo:

  • Más adelante en este mismo tema se incluye una plantilla de ruta para TheContactPage/{text?}. La ruta de la página Contact tiene un orden predeterminado de null (Order = 0), por lo que coincide antes de la plantilla de ruta {globalTemplate?}.
  • Más adelante en este mismo tema se incluye una plantilla de ruta {aboutTemplate?}. La plantilla {aboutTemplate?} tiene un Order con un valor de 2. Cuando la página About se solicita en /About/RouteDataValue, "RouteDataValue" se carga en RouteData.Values["globalTemplate"] (Order = 1) y no RouteData.Values["aboutTemplate"] (Order = 2), debido a la configuración de la propiedad Order.
  • Más adelante en este mismo tema se incluye una plantilla de ruta {otherPagesTemplate?}. La plantilla {otherPagesTemplate?} tiene un Order con un valor de 2. Cuando se solicita una página de la carpeta Pages/OtherPages con un parámetro de ruta (por ejemplo, /OtherPages/Page1/RouteDataValue), "RouteDataValue" se carga en RouteData.Values["globalTemplate"] (Order = 1) y no en RouteData.Values["otherPagesTemplate"] (Order = 2) debido a la configuración de la propiedad Order.

Siempre que sea posible, no especifique el valor de Order, lo que da como resultado Order = 0. Deje que el enrutamiento seleccione la ruta correcta.

Las opciones de Razor Pages (por ejemplo, agregar Conventions) se agregan cuando Razor Pages se agrega a la colección de servicios en Startup.ConfigureServices. Para obtener un ejemplo, vea la aplicación de ejemplo.

options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());

Solicite la página About del ejemplo en localhost:5000/About/GlobalRouteValue y revise el resultado:

The About page is requested with a route segment of GlobalRouteValue. The rendered page shows that the route data value is captured in the OnGet method of the page.

Adición de una convención de modelo de aplicación a todas las páginas

Use Conventions para crear y agregar un elemento IPageApplicationModelConvention a la colección de instancias IPageConvention que se van a aplicar durante la construcción del modelo de aplicación de página.

Para demostrar esta y otras convenciones más adelante en este tema, la aplicación de ejemplo incluye una clase AddHeaderAttribute. El constructor de esta clase acepta una cadena name y una matriz de cadenas values. Estos valores se usan en su método OnResultExecuting para establecer un encabezado de respuesta. La clase completa se muestra en la sección Convenciones de acción del modelo de página más adelante en este tema.

En la aplicación de ejemplo se usa la clase AddHeaderAttribute para agregar un encabezado (GlobalHeader) a todas las páginas de la aplicación:

public class GlobalHeaderPageApplicationModelConvention 
    : IPageApplicationModelConvention
{
    public void Apply(PageApplicationModel model)
    {
        model.Filters.Add(new AddHeaderAttribute(
            "GlobalHeader", new string[] { "Global Header Value" }));
    }
}

Startup.cs:

options.Conventions.Add(new GlobalHeaderPageApplicationModelConvention());

Solicite la página About del ejemplo en localhost:5000/About y revise los encabezados para ver el resultado:

Response headers of the About page show that the GlobalHeader has been added.

Adición de una convención de modelo de controlador a todas las páginas

Use Conventions para crear y agregar un elemento IPageHandlerModelConvention a la colección de instancias IPageConvention que se van a aplicar durante la construcción del modelo de controlador de página.

public class GlobalPageHandlerModelConvention
    : IPageHandlerModelConvention
{
    public void Apply(PageHandlerModel model)
    {
        // Access the PageHandlerModel
    }
}

Startup.cs:

options.Conventions.Add(new GlobalPageHandlerModelConvention());

Convenciones de acción de ruta de página

El proveedor de modelos de ruta predeterminado que se deriva de IPageRouteModelProvider invoca convenciones diseñadas para proporcionar puntos de extensibilidad que permitan configurar rutas de página.

Convención de modelo de ruta de carpeta

Use AddFolderRouteModelConvention para crear y agregar un elemento IPageRouteModelConvention que invoca una acción en PageRouteModel para todas las páginas de la carpeta especificada.

En la aplicación de ejemplo se usa AddFolderRouteModelConvention para agregar una plantilla de ruta {otherPagesTemplate?} a las páginas de la carpeta OtherPages:

options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
{
    var selectorCount = model.Selectors.Count;
    for (var i = 0; i < selectorCount; i++)
    {
        var selector = model.Selectors[i];
        model.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel
            {
                Order = 2,
                Template = AttributeRouteModel.CombineTemplates(
                    selector.AttributeRouteModel.Template, 
                    "{otherPagesTemplate?}"),
            }
        });
    }
});

La propiedad Order de AttributeRouteModel está establecida en 2. Esto garantiza que la plantilla {globalTemplate?} (establecida en 1 anteriormente en este tema) tiene prioridad para colocarse en la primera posición de valor de datos de ruta cuando se proporcione un solo valor de ruta. Si se solicita una página de la carpeta Pages/OtherPages con un valor de parámetro de ruta (por ejemplo, /OtherPages/Page1/RouteDataValue), "RouteDataValue" se carga en RouteData.Values["globalTemplate"] (Order = 1) y no en RouteData.Values["otherPagesTemplate"] (Order = 2) debido a la configuración de la propiedad Order.

Siempre que sea posible, no especifique el valor de Order, lo que da como resultado Order = 0. Deje que el enrutamiento seleccione la ruta correcta.

Solicite la página Page1 del ejemplo en localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue y revise el resultado:

Page1 in the OtherPages folder is requested with a route segment of GlobalRouteValue and OtherPagesRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

Convención de modelo de ruta de página

Use AddPageRouteModelConvention para crear y agregar un elemento IPageRouteModelConvention que invoca una acción en PageRouteModel para la página con el nombre especificado.

En la aplicación de ejemplo se usa AddPageRouteModelConvention para agregar una plantilla de ruta {aboutTemplate?} a la página About:

options.Conventions.AddPageRouteModelConvention("/About", model =>
{
    var selectorCount = model.Selectors.Count;
    for (var i = 0; i < selectorCount; i++)
    {
        var selector = model.Selectors[i];
        model.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel
            {
                Order = 2,
                Template = AttributeRouteModel.CombineTemplates(
                    selector.AttributeRouteModel.Template, 
                    "{aboutTemplate?}"),
            }
        });
    }
});

La propiedad Order de AttributeRouteModel está establecida en 2. Esto garantiza que la plantilla {globalTemplate?} (establecida en 1 anteriormente en este tema) tiene prioridad para colocarse en la primera posición de valor de datos de ruta cuando se proporcione un solo valor de ruta. Si se solicita la página About con un valor de parámetro de ruta en /About/RouteDataValue, "RouteDataValue" se carga en RouteData.Values["globalTemplate"] (Order = 1) y no en RouteData.Values["aboutTemplate"] (Order = 2), debido a la configuración de la propiedad Order.

Siempre que sea posible, no especifique el valor de Order, lo que da como resultado Order = 0. Deje que el enrutamiento seleccione la ruta correcta.

Solicite la página About del ejemplo en localhost:5000/About/GlobalRouteValue/AboutRouteValue y revise el resultado:

About page is requested with route segments for GlobalRouteValue and AboutRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

Uso de transformadores de parámetros para personalizar rutas de página

Las rutas de página generadas por ASP.NET Core se pueden personalizar mediante el uso de un transformador de parámetros. Un transformador de parámetro implementa IOutboundParameterTransformer y transforma el valor de parámetros. Por ejemplo, un transformador de parámetros SlugifyParameterTransformer personalizado cambia el valor de ruta SubscriptionManagement a subscription-management.

La convención de modelo de ruta de página PageRouteTransformerConvention aplica un transformador de parámetros a los segmentos de nombre de archivo y carpeta de las rutas de página generadas automáticamente en una aplicación. Por ejemplo, para el archivo de Razor Pages en /Pages/SubscriptionManagement/ViewAll.cshtml, su ruta cambiaría de /SubscriptionManagement/ViewAll a /subscription-management/view-all.

PageRouteTransformerConvention solo transforma los segmentos de una ruta de página generados automáticamente que proceden de la carpeta y del archivo llamados Razor Pages. No transforma segmentos de ruta agregados con la directiva @page. Esta convención tampoco transforma las rutas agregadas por AddPageRoute.

La convención PageRouteTransformerConvention está registrada como una opción en Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages(options =>
    {
        options.Conventions.Add(
            new PageRouteTransformerConvention(
                new SlugifyParameterTransformer()));
    });
}
public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
    public string TransformOutbound(object value)
    {
        if (value == null) { return null; }

        return Regex.Replace(value.ToString(),
                             "([a-z])([A-Z])",
                             "$1-$2",
                             RegexOptions.CultureInvariant,
                             TimeSpan.FromMilliseconds(100)).ToLowerInvariant();
    }
}

Advertencia

Cuando se usa System.Text.RegularExpressions para procesar entradas que no son de confianza, pase un tiempo de expiración. Un usuario malintencionado puede proporcionar entradas a RegularExpressions y provocar un ataque por denegación de servicio. Las API del marco ASP.NET Core en las que se usa RegularExpressions pasan un tiempo de expiración.

Configurar una ruta de página

Use AddPageRoute para configurar una ruta a una página en la ruta de acceso de página especificada. Los vínculos generados que apuntan a esa página usan la ruta especificada. AddPageRoute usa AddPageRouteModelConvention para establecer la ruta.

En la aplicación de ejemplo se crea una ruta a /TheContactPage para Contact.cshtml:

options.Conventions.AddPageRoute("/Contact", "TheContactPage/{text?}");

A la página Contact también se puede llegar en /Contact a través de su ruta predeterminada.

La ruta personalizada de la aplicación de ejemplo que lleva a la página Contact tiene cabida para un segmento de ruta text opcional ({text?}). La página también incluye este segmento opcional en su directiva @page por si el usuario que la visita tiene acceso a la página en su ruta /Contact:

@page "{text?}"
@model ContactModel
@{
    ViewData["Title"] = "Contact";
}

<h1>@ViewData["Title"]</h1>
<h2>@Model.Message</h2>

<address>
    One Microsoft Way<br>
    Redmond, WA 98052-6399<br>
    <abbr title="Phone">P:</abbr>
    425.555.0100
</address>

<address>
    <strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br>
    <strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>

<p>@Model.RouteDataTextTemplateValue</p>

Observe que la dirección URL generada para el vínculo Contact en la página presentada refleja la ruta actualizada:

Sample app Contact link in the navigation bar

Inspecting the Contact link in the rendered HTML indicates that the href is set to '/TheContactPage'

Visite la página Contact a través de su ruta normal, /Contact, o de la ruta personalizada, /TheContactPage. Si se proporciona un segmento de ruta text adicional, la página muestra el segmento codificado en HTML que se ha proporcionado:

Edge browser example of supplying an optional 'text' route segment of 'TextValue' in the URL. The rendered page shows the 'text' segment value.

Convenciones de acción del modelo de página

El proveedor de modelos de página predeterminado que implementa IPageApplicationModelProvider invoca convenciones que están diseñadas para proporcionar puntos de extensibilidad que permitan configurar modelos de página. Estas convenciones son útiles al crear y modificar escenarios de detección y procesamiento de páginas.

En los ejemplos de esta sección, la aplicación de ejemplo usa una clase AddHeaderAttribute (la cual es un atributo ResultFilterAttribute) que aplica un encabezado de respuesta:

public class AddHeaderAttribute : ResultFilterAttribute
{
    private readonly string _name;
    private readonly string[] _values;

    public AddHeaderAttribute(string name, string[] values)
    {
        _name = name;
        _values = values;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        context.HttpContext.Response.Headers.Add(_name, _values);
        base.OnResultExecuting(context);
    }
}

Si empleamos convenciones, el ejemplo indica cómo aplicar el atributo a todas las páginas de una carpeta y a una sola página.

Convención de modelo de aplicación de carpeta

Use AddFolderApplicationModelConvention para crear y agregar un elemento IPageApplicationModelConvention que invoca una acción en las instancias PageApplicationModel para todas las páginas de la carpeta especificada.

En el ejemplo se demuestra el uso de AddFolderApplicationModelConvention agregando un encabezado (OtherPagesHeader) a las páginas de la carpeta OtherPages de la aplicación:

options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});

Solicite la página Page1 del ejemplo en localhost:5000/OtherPages/Page1 y revise los encabezados para ver el resultado:

Response headers of the OtherPages/Page1 page show that the OtherPagesHeader has been added.

Convención de modelo de aplicación de página

Use AddPageApplicationModelConvention para crear y agregar un elemento IPageApplicationModelConvention que invoca una acción en PageApplicationModel para la página con el nombre especificado.

En el ejemplo se demuestra el uso de AddPageApplicationModelConvention agregando un encabezado (AboutHeader) a la página About:

options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "AboutHeader", new string[] { "About Header Value" }));
});

Solicite la página About del ejemplo en localhost:5000/About y revise los encabezados para ver el resultado:

Response headers of the About page show that the AboutHeader has been added.

Configurar un filtro

ConfigureFilter permite configurar el filtro que se quiere aplicar. Se puede implementar una clase de filtro, pero en la aplicación de ejemplo se muestra cómo implementar un filtro en una expresión lambda, cosa que sucede en segundo plano como una fábrica que devuelve un filtro:

options.Conventions.ConfigureFilter(model =>
{
    if (model.RelativePath.Contains("OtherPages/Page2"))
    {
        return new AddHeaderAttribute(
            "OtherPagesPage2Header", 
            new string[] { "OtherPages/Page2 Header Value" });
    }
    return new EmptyFilter();
});

El modelo de páginas de aplicación se usa para comprobar la ruta de acceso relativa de los segmentos que conducen a la página Page2 en la carpeta OtherPages. Si la condición se supera, se agrega un encabezado. Si no, se aplica EmptyFilter.

EmptyFilter es un filtro de acciones. Razor Pages pasa por alto los filtros de acciones, por lo que EmptyFilter no funciona del modo previsto si la ruta de acceso no contiene OtherPages/Page2.

Solicite la página Page2 del ejemplo en localhost:5000/OtherPages/Page2 y revise los encabezados para ver el resultado:

The OtherPagesPage2Header is added to the response for Page2.

Configurar una fábrica de filtros

ConfigureFilter configura la fábrica especificada para aplicar filtros a todas las instancias de Razor Pages.

En la aplicación de ejemplo se proporciona un ejemplo del uso de una fábrica de filtros, para lo cual se agrega un encabezado (FilterFactoryHeader) con dos valores a las páginas de la aplicación:

options.Conventions.ConfigureFilter(new AddHeaderWithFactory());

AddHeaderWithFactory.cs:

public class AddHeaderWithFactory : IFilterFactory
{
    // Implement IFilterFactory
    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return new AddHeaderFilter();
    }

    private class AddHeaderFilter : IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(
                "FilterFactoryHeader", 
                new string[] 
                { 
                    "Filter Factory Header Value 1",
                    "Filter Factory Header Value 2"
                });
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
        }
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Solicite la página About del ejemplo en localhost:5000/About y revise los encabezados para ver el resultado:

Response headers of the About page show that two FilterFactoryHeader headers have been added.

Filtros de MVC y filtro de página (IPageFilter)

Razor Pages no tiene en cuenta los filtros de acciones de MVC, porque Razor Pages usa métodos de control. Otros tipos de filtros de MVC que tiene a su disposición son: filtros de autorización, de excepciones, de recursos y de resultados. Para más información, vea el tema Filters (Filtros).

El filtro de páginas (IPageFilter) se aplica a Razor Pages. Para obtener más información, vea Métodos de filtrado de Razor Pages.

Recursos adicionales

Aquí encontrará información para saber cómo usar las convenciones de proveedor de modelos de aplicación y de ruta con objeto de controlar el enrutamiento, la detección y el procesamiento en aplicaciones de Razor Pages.

Si necesita configurar rutas de una página personalizadas para páginas concretas, configure el enrutamiento a esas páginas con la convención AddPageRoute, descrita más adelante en este tema.

Para especificar una ruta de página, agregar segmentos de ruta o agregar parámetros a una ruta, use la directiva de página @page. Para obtener más información, consulte Rutas personalizadas.

Hay ciertas palabras reservadas que no se pueden usar como segmentos de ruta o nombres de parámetro. Para obtener más información, vea Enrutamiento: Nombres de enrutamientos reservados.

Vea o descargue el código de ejemplo (cómo descargarlo)

Escenario El ejemplo explica cómo...
Convenciones de modelo

Conventions.Add
  • IPageRouteModelConvention
  • IPageApplicationModelConvention
  • IPageHandlerModelConvention
Agregar un encabezado y una plantilla de ruta a las páginas de una aplicación.
Convenciones de acción de ruta de página
  • AddFolderRouteModelConvention
  • AddPageRouteModelConvention
  • AddPageRoute
Agregar una plantilla de ruta a las páginas de una carpeta y a una sola página.
Convenciones de acción del modelo de página
  • AddFolderApplicationModelConvention
  • AddPageApplicationModelConvention
  • ConfigureFilter (clase de filtro, expresión lambda o fábrica de filtros)
Agregar un encabezado a las páginas de una carpeta, agregar un encabezado a una sola página y configurar una fábrica de filtros para agregar un encabezado a las páginas de la aplicación.

Las convenciones de Razor Pages se agregan y configuran a través del método de extensión AddRazorPagesOptions a AddMvc en la colección de servicios de la clase Startup. Más avanzado el tema veremos los siguientes ejemplos de convención:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddRazorPagesOptions(options =>
        {
            options.Conventions.Add( ... );
            options.Conventions.AddFolderRouteModelConvention(
                "/OtherPages", model => { ... });
            options.Conventions.AddPageRouteModelConvention(
                "/About", model => { ... });
            options.Conventions.AddPageRoute(
                "/Contact", "TheContactPage/{text?}");
            options.Conventions.AddFolderApplicationModelConvention(
                "/OtherPages", model => { ... });
            options.Conventions.AddPageApplicationModelConvention(
                "/About", model => { ... });
            options.Conventions.ConfigureFilter(model => { ... });
            options.Conventions.ConfigureFilter( ... );
        });
}

Ordenación de la ruta

Las rutas especifican un Order para su procesamiento (una coincidencia de rutas).

Ordenar Comportamiento
-1 La ruta se procesa antes de que se procesen otras rutas.
0 No se ha especificado ningún orden (valor predeterminado). Si no se asigna un valor Order (Order = null), el valor Order predeterminado de la ruta para su procesamiento es 0 (cero).
1, 2, … n Especifica el orden de procesamiento de la ruta.

El procesamiento de rutas se establece por convención:

  • Las rutas se procesan en orden secuencial (-1, 0, 1, 2,... n).
  • Cuando las rutas tienen el mismo orden (Order), primero se asigna la ruta más específica y, después, las rutas menos específicas.
  • Cuando varias rutas con el mismo orden (Order) y el mismo número de parámetros coinciden con una URL de solicitud, se procesan en el orden en que se han agregado a la clase PageConventionCollection.

Si es posible, evite depender de un orden de procesamiento de rutas establecido. Por lo general, el enrutamiento selecciona la ruta correcta con la coincidencia de dirección URL. Si tiene que establecer propiedades de orden (Order) de las rutas para enrutar las solicitudes correctamente, es probable que el esquema de enrutamiento de la aplicación resulte confuso para los clientes y cueste mantenerlo. Trate de simplificar el esquema de enrutamiento de la aplicación. La aplicación de ejemplo requiere un orden de procesamiento de rutas explícito para mostrar varios escenarios de enrutamiento con una sola aplicación. Sin embargo, intente evitar configurar un orden (Order) de enrutamiento en aplicaciones de producción.

El enrutamiento de Razor Pages y el del controlador MVC comparten una implementación. Puede encontrar más información sobre el orden de las rutas y MVC en el artículo Enrutamiento a acciones de controlador: Ordenación de rutas de atributo.

Convenciones de modelo

Agregue un delegado de IPageConvention con el fin de agregar convenciones de modelo que se apliquen a Razor Pages.

Adición de una convención de modelo de ruta a todas las páginas

Use Conventions para crear y agregar un elemento IPageRouteModelConvention a la colección de instancias IPageConvention que se van a aplicar durante la construcción del modelo de ruta de página.

En la aplicación de ejemplo se agrega una plantilla de ruta {globalTemplate?} a todas las páginas de la aplicación:

public class GlobalTemplatePageRouteModelConvention 
    : IPageRouteModelConvention
{
    public void Apply(PageRouteModel model)
    {
        var selectorCount = model.Selectors.Count;
        for (var i = 0; i < selectorCount; i++)
        {
            var selector = model.Selectors[i];
            model.Selectors.Add(new SelectorModel
            {
                AttributeRouteModel = new AttributeRouteModel
                {
                    Order = 1,
                    Template = AttributeRouteModel.CombineTemplates(
                        selector.AttributeRouteModel.Template, 
                        "{globalTemplate?}"),
                }
            });
        }
    }
}

La propiedad Order de AttributeRouteModel está establecida en 1. Esto garantiza el siguiente comportamiento de coincidencia de rutas en la aplicación de ejemplo:

  • Más adelante en este mismo tema se incluye una plantilla de ruta para TheContactPage/{text?}. La ruta de la página Contact tiene un orden predeterminado de null (Order = 0), por lo que coincide antes de la plantilla de ruta {globalTemplate?}.
  • Más adelante en este mismo tema se incluye una plantilla de ruta {aboutTemplate?}. La plantilla {aboutTemplate?} tiene un Order con un valor de 2. Cuando la página About se solicita en /About/RouteDataValue, "RouteDataValue" se carga en RouteData.Values["globalTemplate"] (Order = 1) y no RouteData.Values["aboutTemplate"] (Order = 2), debido a la configuración de la propiedad Order.
  • Más adelante en este mismo tema se incluye una plantilla de ruta {otherPagesTemplate?}. La plantilla {otherPagesTemplate?} tiene un Order con un valor de 2. Cuando se solicita una página de la carpeta Pages/OtherPages con un parámetro de ruta (por ejemplo, /OtherPages/Page1/RouteDataValue), "RouteDataValue" se carga en RouteData.Values["globalTemplate"] (Order = 1) y no en RouteData.Values["otherPagesTemplate"] (Order = 2) debido a la configuración de la propiedad Order.

Siempre que sea posible, no especifique el valor de Order, lo que da como resultado Order = 0. Deje que el enrutamiento seleccione la ruta correcta.

Las opciones de Razor Pages (por ejemplo, agregar Conventions) se agregan cuando se incluye MVC en la colección de servicios de Startup.ConfigureServices. Para obtener un ejemplo, vea la aplicación de ejemplo.

options.Conventions.Add(new GlobalTemplatePageRouteModelConvention());

Solicite la página About del ejemplo en localhost:5000/About/GlobalRouteValue y revise el resultado:

The About page is requested with a route segment of GlobalRouteValue. The rendered page shows that the route data value is captured in the OnGet method of the page.

Adición de una convención de modelo de aplicación a todas las páginas

Use Conventions para crear y agregar un elemento IPageApplicationModelConvention a la colección de instancias IPageConvention que se van a aplicar durante la construcción del modelo de aplicación de página.

Para demostrar esta y otras convenciones más adelante en este tema, la aplicación de ejemplo incluye una clase AddHeaderAttribute. El constructor de esta clase acepta una cadena name y una matriz de cadenas values. Estos valores se usan en su método OnResultExecuting para establecer un encabezado de respuesta. La clase completa se muestra en la sección Convenciones de acción del modelo de página más adelante en este tema.

En la aplicación de ejemplo se usa la clase AddHeaderAttribute para agregar un encabezado (GlobalHeader) a todas las páginas de la aplicación:

public class GlobalHeaderPageApplicationModelConvention 
    : IPageApplicationModelConvention
{
    public void Apply(PageApplicationModel model)
    {
        model.Filters.Add(new AddHeaderAttribute(
            "GlobalHeader", new string[] { "Global Header Value" }));
    }
}

Startup.cs:

options.Conventions.Add(new GlobalHeaderPageApplicationModelConvention());

Solicite la página About del ejemplo en localhost:5000/About y revise los encabezados para ver el resultado:

Response headers of the About page show that the GlobalHeader has been added.

Adición de una convención de modelo de controlador a todas las páginas

Use Conventions para crear y agregar un elemento IPageHandlerModelConvention a la colección de instancias IPageConvention que se van a aplicar durante la construcción del modelo de controlador de página.

public class GlobalPageHandlerModelConvention
    : IPageHandlerModelConvention
{
    public void Apply(PageHandlerModel model)
    {
        // Access the PageHandlerModel
    }
}

Startup.cs:

options.Conventions.Add(new GlobalPageHandlerModelConvention());

Convenciones de acción de ruta de página

El proveedor de modelos de ruta predeterminado que se deriva de IPageRouteModelProvider invoca convenciones diseñadas para proporcionar puntos de extensibilidad que permitan configurar rutas de página.

Convención de modelo de ruta de carpeta

Use AddFolderRouteModelConvention para crear y agregar un elemento IPageRouteModelConvention que invoca una acción en PageRouteModel para todas las páginas de la carpeta especificada.

En la aplicación de ejemplo se usa AddFolderRouteModelConvention para agregar una plantilla de ruta {otherPagesTemplate?} a las páginas de la carpeta OtherPages:

options.Conventions.AddFolderRouteModelConvention("/OtherPages", model =>
{
    var selectorCount = model.Selectors.Count;
    for (var i = 0; i < selectorCount; i++)
    {
        var selector = model.Selectors[i];
        model.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel
            {
                Order = 2,
                Template = AttributeRouteModel.CombineTemplates(
                    selector.AttributeRouteModel.Template, 
                    "{otherPagesTemplate?}"),
            }
        });
    }
});

La propiedad Order de AttributeRouteModel está establecida en 2. Esto garantiza que la plantilla {globalTemplate?} (establecida en 1 anteriormente en este tema) tiene prioridad para colocarse en la primera posición de valor de datos de ruta cuando se proporcione un solo valor de ruta. Si se solicita una página de la carpeta Pages/OtherPages con un valor de parámetro de ruta (por ejemplo, /OtherPages/Page1/RouteDataValue), "RouteDataValue" se carga en RouteData.Values["globalTemplate"] (Order = 1) y no en RouteData.Values["otherPagesTemplate"] (Order = 2) debido a la configuración de la propiedad Order.

Siempre que sea posible, no especifique el valor de Order, lo que da como resultado Order = 0. Deje que el enrutamiento seleccione la ruta correcta.

Solicite la página Page1 del ejemplo en localhost:5000/OtherPages/Page1/GlobalRouteValue/OtherPagesRouteValue y revise el resultado:

Page1 in the OtherPages folder is requested with a route segment of GlobalRouteValue and OtherPagesRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

Convención de modelo de ruta de página

Use AddPageRouteModelConvention para crear y agregar un elemento IPageRouteModelConvention que invoca una acción en PageRouteModel para la página con el nombre especificado.

En la aplicación de ejemplo se usa AddPageRouteModelConvention para agregar una plantilla de ruta {aboutTemplate?} a la página About:

options.Conventions.AddPageRouteModelConvention("/About", model =>
{
    var selectorCount = model.Selectors.Count;
    for (var i = 0; i < selectorCount; i++)
    {
        var selector = model.Selectors[i];
        model.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel
            {
                Order = 2,
                Template = AttributeRouteModel.CombineTemplates(
                    selector.AttributeRouteModel.Template, 
                    "{aboutTemplate?}"),
            }
        });
    }
});

La propiedad Order de AttributeRouteModel está establecida en 2. Esto garantiza que la plantilla {globalTemplate?} (establecida en 1 anteriormente en este tema) tiene prioridad para colocarse en la primera posición de valor de datos de ruta cuando se proporcione un solo valor de ruta. Si se solicita la página About con un valor de parámetro de ruta en /About/RouteDataValue, "RouteDataValue" se carga en RouteData.Values["globalTemplate"] (Order = 1) y no en RouteData.Values["aboutTemplate"] (Order = 2), debido a la configuración de la propiedad Order.

Siempre que sea posible, no especifique el valor de Order, lo que da como resultado Order = 0. Deje que el enrutamiento seleccione la ruta correcta.

Solicite la página About del ejemplo en localhost:5000/About/GlobalRouteValue/AboutRouteValue y revise el resultado:

About page is requested with route segments for GlobalRouteValue and AboutRouteValue. The rendered page shows that the route data values are captured in the OnGet method of the page.

Configurar una ruta de página

Use AddPageRoute para configurar una ruta a una página en la ruta de acceso de página especificada. Los vínculos generados que apuntan a esa página usan la ruta especificada. AddPageRoute usa AddPageRouteModelConvention para establecer la ruta.

En la aplicación de ejemplo se crea una ruta a /TheContactPage para Contact.cshtml:

options.Conventions.AddPageRoute("/Contact", "TheContactPage/{text?}");

A la página Contact también se puede llegar en /Contact a través de su ruta predeterminada.

La ruta personalizada de la aplicación de ejemplo que lleva a la página Contact tiene cabida para un segmento de ruta text opcional ({text?}). La página también incluye este segmento opcional en su directiva @page por si el usuario que la visita tiene acceso a la página en su ruta /Contact:

@page "{text?}"
@model ContactModel
@{
    ViewData["Title"] = "Contact";
}

<h1>@ViewData["Title"]</h1>
<h2>@Model.Message</h2>

<address>
    One Microsoft Way<br>
    Redmond, WA 98052-6399<br>
    <abbr title="Phone">P:</abbr>
    425.555.0100
</address>

<address>
    <strong>Support:</strong> <a href="mailto:Support@example.com">Support@example.com</a><br>
    <strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>

<p>@Model.RouteDataTextTemplateValue</p>

Observe que la dirección URL generada para el vínculo Contact en la página presentada refleja la ruta actualizada:

Sample app Contact link in the navigation bar

Inspecting the Contact link in the rendered HTML indicates that the href is set to '/TheContactPage'

Visite la página Contact a través de su ruta normal, /Contact, o de la ruta personalizada, /TheContactPage. Si se proporciona un segmento de ruta text adicional, la página muestra el segmento codificado en HTML que se ha proporcionado:

Edge browser example of supplying an optional 'text' route segment of 'TextValue' in the URL. The rendered page shows the 'text' segment value.

Convenciones de acción del modelo de página

El proveedor de modelos de página predeterminado que implementa IPageApplicationModelProvider invoca convenciones que están diseñadas para proporcionar puntos de extensibilidad que permitan configurar modelos de página. Estas convenciones son útiles al crear y modificar escenarios de detección y procesamiento de páginas.

En los ejemplos de esta sección, la aplicación de ejemplo usa una clase AddHeaderAttribute (la cual es un atributo ResultFilterAttribute) que aplica un encabezado de respuesta:

public class AddHeaderAttribute : ResultFilterAttribute
{
    private readonly string _name;
    private readonly string[] _values;

    public AddHeaderAttribute(string name, string[] values)
    {
        _name = name;
        _values = values;
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        context.HttpContext.Response.Headers.Add(_name, _values);
        base.OnResultExecuting(context);
    }
}

Si empleamos convenciones, el ejemplo indica cómo aplicar el atributo a todas las páginas de una carpeta y a una sola página.

Convención de modelo de aplicación de carpeta

Use AddFolderApplicationModelConvention para crear y agregar un elemento IPageApplicationModelConvention que invoca una acción en las instancias PageApplicationModel para todas las páginas de la carpeta especificada.

En el ejemplo se demuestra el uso de AddFolderApplicationModelConvention agregando un encabezado (OtherPagesHeader) a las páginas de la carpeta OtherPages de la aplicación:

options.Conventions.AddFolderApplicationModelConvention("/OtherPages", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "OtherPagesHeader", new string[] { "OtherPages Header Value" }));
});

Solicite la página Page1 del ejemplo en localhost:5000/OtherPages/Page1 y revise los encabezados para ver el resultado:

Response headers of the OtherPages/Page1 page show that the OtherPagesHeader has been added.

Convención de modelo de aplicación de página

Use AddPageApplicationModelConvention para crear y agregar un elemento IPageApplicationModelConvention que invoca una acción en PageApplicationModel para la página con el nombre especificado.

En el ejemplo se demuestra el uso de AddPageApplicationModelConvention agregando un encabezado (AboutHeader) a la página About:

options.Conventions.AddPageApplicationModelConvention("/About", model =>
{
    model.Filters.Add(new AddHeaderAttribute(
        "AboutHeader", new string[] { "About Header Value" }));
});

Solicite la página About del ejemplo en localhost:5000/About y revise los encabezados para ver el resultado:

Response headers of the About page show that the AboutHeader has been added.

Configurar un filtro

ConfigureFilter permite configurar el filtro que se quiere aplicar. Se puede implementar una clase de filtro, pero en la aplicación de ejemplo se muestra cómo implementar un filtro en una expresión lambda, cosa que sucede en segundo plano como una fábrica que devuelve un filtro:

options.Conventions.ConfigureFilter(model =>
{
    if (model.RelativePath.Contains("OtherPages/Page2"))
    {
        return new AddHeaderAttribute(
            "OtherPagesPage2Header", 
            new string[] { "OtherPages/Page2 Header Value" });
    }
    return new EmptyFilter();
});

El modelo de páginas de aplicación se usa para comprobar la ruta de acceso relativa de los segmentos que conducen a la página Page2 en la carpeta OtherPages. Si la condición se supera, se agrega un encabezado. Si no, se aplica EmptyFilter.

EmptyFilter es un filtro de acciones. Razor Pages pasa por alto los filtros de acciones, por lo que EmptyFilter no funciona del modo previsto si la ruta de acceso no contiene OtherPages/Page2.

Solicite la página Page2 del ejemplo en localhost:5000/OtherPages/Page2 y revise los encabezados para ver el resultado:

The OtherPagesPage2Header is added to the response for Page2.

Configurar una fábrica de filtros

ConfigureFilter configura la fábrica especificada para aplicar filtros a todas las instancias de Razor Pages.

En la aplicación de ejemplo se proporciona un ejemplo del uso de una fábrica de filtros, para lo cual se agrega un encabezado (FilterFactoryHeader) con dos valores a las páginas de la aplicación:

options.Conventions.ConfigureFilter(new AddHeaderWithFactory());

AddHeaderWithFactory.cs:

public class AddHeaderWithFactory : IFilterFactory
{
    // Implement IFilterFactory
    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return new AddHeaderFilter();
    }

    private class AddHeaderFilter : IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add(
                "FilterFactoryHeader", 
                new string[] 
                { 
                    "Filter Factory Header Value 1",
                    "Filter Factory Header Value 2"
                });
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
        }
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Solicite la página About del ejemplo en localhost:5000/About y revise los encabezados para ver el resultado:

Response headers of the About page show that two FilterFactoryHeader headers have been added.

Filtros de MVC y filtro de página (IPageFilter)

Razor Pages no tiene en cuenta los filtros de acciones de MVC, porque Razor Pages usa métodos de control. Otros tipos de filtros de MVC que tiene a su disposición son: filtros de autorización, de excepciones, de recursos y de resultados. Para más información, vea el tema Filters (Filtros).

El filtro de páginas (IPageFilter) se aplica a Razor Pages. Para obtener más información, vea Métodos de filtrado de Razor Pages.

Recursos adicionales