La transformación de la ruta no funciona cuando se utiliza el soporte rizado

Tengo los siguientes códigos

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Conventions.Add(new RouteTokenTransformerConvention(new SlugifyParameterTransformer()));
    });
}

Donde SlugifyParameterTransformer implementos IOutboundParameterTransformer y transformar URL a URL amigable con SEO.

En mi HomeController, tengo estos

public IActionResult Index()
{
    return View();
}

[Route("{controller}/{action}")]   // Route transform ONLY work when using square bracket.
public IActionResult SomeTestPage()
{
    return View();
}

En mi Index.cshtml, tengo estos

@addTagHelper *,Microsoft.AspNetCore.Mvc.TagHelpers

Some Test Page

Al construir y ejecutar el sitio web, la URL a SomeTestPage es localhost\Home\SomeTestPage que no se transforma SlugifyParameterTransformer. Sin embargo, la URL se transforma correctamente localhost\home\some-test-page después de que sustituí el corchete de cursillo al soporte cuadrado RouteAttribute decoración SomeTestPage método de acción.

¿Cuál es la diferencia entre el soporte rizado y el soporte cuadrado al definir la plantilla de ruta con el enrutamiento de atributos?

Pregunta hecha hace 3 años, 4 meses, 28 días - Por scriptsculptor52b5


3 Respuestas:

  • ¿Cuál es la diferencia entre el soporte rizado y el soporte cuadrado al definir la plantilla de ruta con el enrutamiento de atributos?

    In oficial ejemplo código, podemos encontrar que generalmente utiliza [controller], [action], [area] con hojas cuadradas para el nombre del controlador, nombre de acción y nombre de área, y uso {id} etc para otros parámetros de ruta genéricos en rutas de atributos.

    Además, como se menciona en @serpent5 este asunto de github, un IOutboundParameterTransformer parece que el proceso sólo [ y ] cuando se utiliza con atributo routing.

    Código fuente de ReplaceTokens método que reemplaza las fichas en la plantilla con los valores proporcionados y transformador de token de ruta

    /// 
    /// Replaces the tokens in the template with the provided values and route token transformer.
    /// 
    /// The template.
    /// The token values to use.
    /// The route token transformer.
    /// A new string with the replaced values.
    public static string ReplaceTokens(string template, IDictionary values, IOutboundParameterTransformer routeTokenTransformer)
    {
        var builder = new StringBuilder();
        var state = TemplateParserState.Plaintext;
    
        int? tokenStart = null;
        var scope = 0;
    
        // We'll run the loop one extra time with 'null' to detect the end of the string.
        for (var i = 0; i <= template.Length; i++)
        {
            var c = i < template.Length ? (char?)template[i] : null;
            switch (state)
            {
                case TemplateParserState.Plaintext:
                    if (c == '[')
                    {
                        scope++;
                        state = TemplateParserState.SeenLeft;
                        break;
                    }
                    else if (c == ']')
                    {
                        state = TemplateParserState.SeenRight;
                        break;
                    }
                    else if (c == null)
                    {
                        // We're at the end of the string, nothing left to do.
                        break;
                    }
                    else
                    {
                        builder.Append(c);
                        break;
                    }
                case TemplateParserState.SeenLeft:
                    if (c == '[')
                    {
                        // This is an escaped left-bracket
                        builder.Append(c);
                        state = TemplateParserState.Plaintext;
                        break;
                    }
                    else if (c == ']')
                    {
                        // This is zero-width parameter - not allowed.
                        var message = Resources.FormatAttributeRoute_TokenReplacement_InvalidSyntax(
                            template,
                            Resources.AttributeRoute_TokenReplacement_EmptyTokenNotAllowed);
                        throw new InvalidOperationException(message);
                    }
                    else if (c == null)
                    {
                        // This is a left-bracket at the end of the string.
                        var message = Resources.FormatAttributeRoute_TokenReplacement_InvalidSyntax(
                            template,
                            Resources.AttributeRoute_TokenReplacement_UnclosedToken);
                        throw new InvalidOperationException(message);
                    }
                    else
                    {
                        tokenStart = i;
                        state = TemplateParserState.InsideToken;
                        break;
                    }
                case TemplateParserState.SeenRight:
                    if (c == ']')
                    {
                        // This is an escaped right-bracket
                        builder.Append(c);
                        state = TemplateParserState.Plaintext;
                        break;
                    }
                    else if (c == null)
                    {
                        // This is an imbalanced right-bracket at the end of the string.
                        var message = Resources.FormatAttributeRoute_TokenReplacement_InvalidSyntax(
                            template,
                            Resources.AttributeRoute_TokenReplacement_ImbalancedSquareBrackets);
                        throw new InvalidOperationException(message);
                    }
                    else
                    {
                        // This is an imbalanced right-bracket.
                        var message = Resources.FormatAttributeRoute_TokenReplacement_InvalidSyntax(
                            template,
                            Resources.AttributeRoute_TokenReplacement_ImbalancedSquareBrackets);
                        throw new InvalidOperationException(message);
                    }
                case TemplateParserState.InsideToken:
                    if (c == '[')
                    {
                        state = TemplateParserState.InsideToken | TemplateParserState.SeenLeft;
                        break;
                    }
                    else if (c == ']')
                    {
                        --scope;
                        state = TemplateParserState.InsideToken | TemplateParserState.SeenRight;
                        break;
                    }
                    else if (c == null)
                    {
                        // This is an unclosed replacement token
                        var message = Resources.FormatAttributeRoute_TokenReplacement_InvalidSyntax(
                            template,
                            Resources.AttributeRoute_TokenReplacement_UnclosedToken);
                        throw new InvalidOperationException(message);
                    }
                    else
                    {
                        // This is a just part of the parameter
                        break;
                    }
                case TemplateParserState.InsideToken | TemplateParserState.SeenLeft:
                    if (c == '[')
                    {
                        // This is an escaped left-bracket
                        state = TemplateParserState.InsideToken;
                        break;
                    }
                    else
                    {
                        // Unescaped left-bracket is not allowed inside a token.
                        var message = Resources.FormatAttributeRoute_TokenReplacement_InvalidSyntax(
                            template,
                            Resources.AttributeRoute_TokenReplacement_UnescapedBraceInToken);
                        throw new InvalidOperationException(message);
                    }
                case TemplateParserState.InsideToken | TemplateParserState.SeenRight:
                    if (c == ']' && scope == 0)
                    {
                        // This is an escaped right-bracket
                        state = TemplateParserState.InsideToken;
                        break;
                    }
                    else
                    {
                        // This is the end of a replacement token.
                        var token = template
                            .Substring(tokenStart.Value, i - tokenStart.Value - 1)
                            .Replace("[[", "[")
                            .Replace("]]", "]");
    
                        if (!values.TryGetValue(token, out var value))
                        {
                            // Value not found
                            var message = Resources.FormatAttributeRoute_TokenReplacement_ReplacementValueNotFound(
                                template,
                                token,
                                string.Join(", ", values.Keys.OrderBy(k => k, StringComparer.OrdinalIgnoreCase)));
                            throw new InvalidOperationException(message);
                        }
    
                        if (routeTokenTransformer != null)
                        {
                            value = routeTokenTransformer.TransformOutbound(value);
                        }
    
                        builder.Append(value);
    
                        if (c == '[')
                        {
                            state = TemplateParserState.SeenLeft;
                        }
                        else if (c == ']')
                        {
                            state = TemplateParserState.SeenRight;
                        }
                        else if (c == null)
                        {
                            state = TemplateParserState.Plaintext;
                        }
                        else
                        {
                            builder.Append(c);
                            state = TemplateParserState.Plaintext;
                        }
    
                        scope = 0;
                        tokenStart = null;
                        break;
                    }
            }
        }
    
        return builder.ToString();
    }
    

    Respondida el Dec 18, 2020 a las 00:39 - por cyberscribe

    Votos positivos: 0 | Votos negativos: 0

  • La diferencia principal entre el soporte rizado {} y el soporte cuadrado [] al definir la plantilla de ruta con el enrutamiento de atributos en ASP.NET Core es cómo se interpretan y utilizan en el enrutamiento.

    • Soporte rizado `{}`: Cuando utilizas el soporte rizado en la plantilla de ruta, ASP.NET Core considera esos segmentos como variables en la ruta. Esto significa que cualquier valor proporcionado en esa posición dentro de la URL se tomará como un parámetro dinámico en la acción del controlador. Por ejemplo, en tu caso, al definir `[Route("{controller}/{action}")]`, estás especificando que el primer segmento de la ruta será el nombre del controlador y el segundo el nombre de la acción.
    • Soporte cuadrado `[]`: Por otro lado, al utilizar el soporte cuadrado en la plantilla de ruta, los segmentos dentro de los corchetes son considerados como una constante en la ruta. Estos segmentos deben coincidir exactamente con la URL solicitada para que la ruta sea reconocida y la acción del controlador asociada se ejecute. Por ejemplo, `[Route("[controller]/[action]")]` requerirá que la URL coincida exactamente con `/Home/SomeTestPage` para que la acción se ejecute.

    En tu caso, al utilizar [Route("{controller}/{action}")], la transformación de la ruta no funcionó porque los valores en esos segmentos son variables y no constantes. Por lo tanto, la URL localhost\Home\SomeTestPage coincidía con la ruta, pero no se aplicaba la transformación deseada.

    Para que la transformación de la URL funcione correctamente con el SlugifyParameterTransformer, debes asegurarte de que estás utilizando los corchetes [Route("[controller]/[action]")] en lugar de los corchetes rizados {}, de esta manera se considerarán segmentos constantes y se aplicará la transformación adecuadamente.

    Respondida el Dec 19, 2020 a las 00:41 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • La diferencia principal entre el uso de llaves ({}) y corchetes ([]) en la definición de plantillas de ruta con el enrutamiento de atributos en ASP.NET Core es la forma en que se vinculan los parámetros de ruta a los parámetros del método de acción.

    Soporte rizado ({}): Enrutamiento de convenciones

    Las llaves indican parámetros de ruta que se vincularán a los parámetros del método de acción mediante convenciones de enrutamiento. Las convenciones predeterminadas de ASP.NET Core mapean los parámetros de ruta a los parámetros del método de acción con el mismo nombre. El uso de transformadores de parámetros, como SlugifyParameterTransformer, no afecta a las rutas definidas con llaves.

    Soporte cuadrado ([]): Enrutamiento de atributos

    Los corchetes indican parámetros de ruta que se vincularán explícitamente a los parámetros del método de acción mediante atributos de enrutamiento. Los atributos de enrutamiento te permiten especificar el nombre y las restricciones del parámetro de ruta. Los transformadores de parámetros se aplican a los parámetros de ruta definidos con corchetes.

    En tu ejemplo, el uso de llaves en [Route("{controller}/{action}")] indica que los parámetros de ruta controller y action se vincularán a los parámetros del método de acción mediante convenciones. Como el método de acción SomeTestPage no tiene ningún parámetro, el enrutamiento de convenciones no vincula ningún parámetro de ruta al método.

    Al cambiar a corchetes en [Route("[controller]/[action]")], estás definiendo explícitamente un parámetro de ruta action que se vincula al parámetro action del método de acción. Esto permite que el transformador de parámetros SlugifyParameterTransformer se aplique al parámetro de ruta y transforme la URL a una URL amigable con SEO.

    En resumen, las llaves se utilizan para el enrutamiento de convenciones, donde los parámetros de ruta se vinculan mediante convenciones predeterminadas. Los corchetes se utilizan para el enrutamiento de atributos, donde los parámetros de ruta se vinculan explícitamente mediante atributos y pueden verse afectados por los transformadores de parámetros.

    Respondida el Dec 19, 2020 a las 00:48 - por Gemini

    Votos positivos: 0 | Votos negativos: 0