web-dev-qa-db-fra.com

Vide href après la mise à niveau vers asp.net core 2.2

Nous avons créé un site Web ASP.NET Core 2.1 où des URL telles que www.example.org/uk et www.example.org/de travaux déterminent les fichiers et le contenu resx à afficher. Après la mise à niveau vers ASP.NET Core 2.2, les pages se chargent, mais tous les liens générés produisent des href vides/vides.

Par exemple, un lien ceci:

<a asp-controller="Home" asp-action="Contact">@Res.ContactUs</a>

en 2.2 produira un href vide comme ceci:

<a href="">Contact us</a>

Mais en 2.1 nous obtenons le bon href:

<a href="/uk/contact">Contact us</a>

Nous utilisons un Constraint Map pour gérer la fonctionnalité de langue basée sur les URL - en voici le code:

Startup.cs

// configure route options {lang}, e.g. /uk, /de, /es etc
services.Configure<RouteOptions>(options =>
{
    options.LowercaseUrls = true;
    options.AppendTrailingSlash = false;
    options.ConstraintMap.Add("lang", typeof(LanguageRouteConstraint));
 });

 ...

app.UseMvc(routes =>
{
    routes.MapRoute(
       name: "LocalizedDefault",
       template: "{lang:lang}/{controller=Home}/{action=Index}/{id?}");
}

LanguageRouteConstraint.cs

public class LanguageRouteConstraint : IRouteConstraint
{
    private readonly AppLanguages _languageSettings;

    public LanguageRouteConstraint(IHostingEnvironment hostingEnvironment)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(hostingEnvironment.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

        IConfigurationRoot configuration = builder.Build();

        _languageSettings = new AppLanguages();
        configuration.GetSection("AppLanguages").Bind(_languageSettings);
    }

    public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (!values.ContainsKey("lang"))
        {
            return false;
        }

        var lang = values["lang"].ToString();
        foreach (Language lang_in_app in _languageSettings.Dict.Values)
        {
            if (lang == lang_in_app.Icc)
            {
                return true;
            }
        }
        return false;
    }
}

J'ai réduit le problème mais je ne trouve pas le moyen de le résoudre; Essentiellement en 2.2. certains paramètres ne sont pas définis dans la méthode IRouteConstraint Match ci-dessus, par exemple. 

httpContext = null
route = {Microsoft.AspNetCore.Routing.NullRouter)

En 2.1 

 httpContext = {Microsoft.AspNetCore.Http.DefaultHttpContext}
 route = {{lang:lang}/{controller=Home}/{action=Index}/{id?}}

La seule différence que j'ai faite entre 2.1 et 2.2 est que j'ai changé 

var builder = new ConfigurationBuilder()
   .SetBasePath(Directory.GetCurrentDirectory())
   .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

à ce qui suit (à cause de https://github.com/aspnet/AspNetCore/issues/4206 )

 var builder = new ConfigurationBuilder()
    .SetBasePath(hostingEnvironment.ContentRootPath) // using IHostingEnvironment 
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

Des idées?

Mise à jour Selon https://docs.Microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-2.2#parameter-transformer-reference ASP.NET Core 2.2 utilise EndpointRouting alors que 2.1 utilise la logique de base IRouter. Cela explique mon problème. Maintenant, ma question serait alors quel code va ressembler pour 2.2 à utiliser le nouveau EndpointRouting?

4
Sha
// Use the routing logic of ASP.NET Core 2.1 or earlier:
services.AddMvc(options => options.EnableEndpointRouting = false)
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
1
Diyar

Différences par rapport aux versions précédentes de routage explique ce qui se passe ici (c'est moi qui souligne):

La génération de lien algorithme d'invalidation de la valeur ambiante se comporte différemment lorsqu'elle est utilisée avec le routage de point final.

Invalidation de la valeur ambiante} est l'algorithme qui détermine les valeurs de route à partir de la demande en cours d'exécution (les valeurs ambiantes) pouvant être utilisées dans les opérations de génération de lien. Le routage conventionnel invalide toujours les valeurs de route supplémentaires lors de la liaison à une action différente. Le routage d'attribut n'avait pas ce comportement avant la publication d'ASP.NET Core 2.2. Dans les versions antérieures d'ASP.NET Core, les liens vers une autre action utilisant les mêmes noms de paramètre de route entraînaient des erreurs de génération de lien. Dans ASP.NET Core 2.2 ou version ultérieure, les deux formes de routage invalident les valeurs lors de la liaison à une autre action.

...

Les valeurs Ambient ne sont pas réutilisées lorsque la destination liée est une action ou une page différente.

Dans votre exemple, lang est un valeur ambiante et n'est donc pas réutilisé lors du passage de Home/Index à Home/About (action différente). Sans valeur spécifiée pour lang, il n'y a pas d'action correspondante et un href vide est donc généré. Ceci est également décrit dans la documentation comme une différence d'acheminement des points de terminaison:

Cependant, le routage des noeuds finaux génère une chaîne vide si l'action n'existe pas. Conceptuellement, le routage des noeuds finaux ne suppose pas que le noeud final existe si l'action n'existe pas.

Si vous souhaitez continuer à utiliser le routage des noeuds finaux, il semble que vous deviez transmettre la valeur lang de votre contrôleur à votre vue, puis la définir explicitement. Voici un exemple:

public class HomeController : Controller
{
    public IActionResult Index(string lang)
    {
        ViewData["lang"] = lang; // Using ViewData just for demonstration purposes.
        return View();
    }
}
<a asp-controller="Home" asp-action="Contact"
    asp-route-lang="@ViewData["lang"]">@Res.ContactUs</a>

Vous pouvez rendre ceci un peu moins répétitif avec par exemple un filtre d'action, mais les concepts sont toujours les mêmes. Je ne vois pas comment il existe un autre moyen de gérer cela (par exemple, être capable de marquer une valeur spécifique comme étant ambiante), mais peut-être que quelqu'un d'autre pourra en parler.

1
Kirk Larkin