68 votes

URLs avec une barre oblique dans le paramètre?

Question :

Je crée un logiciel wiki, essentiellement un clone de wikipedia/mediawiki, mais en ASP.NET MVC (le MVC est essentiel, donc ne me recommandez pas ScrewTurn).

Maintenant, j'ai une question :

J'utilise ce mapping de route, pour mapper une URL comme :
http://fr.wikipedia.org/wiki/ASP.NET

        routes.MapRoute(
            "Wiki", // Nom de la route
            //"{controller}/{action}/{id}", // URL avec des paramètres
            "wiki/{id}", // URL avec des paramètres
            new { controller = "Wiki", action = "dbLookup", id = UrlParameter.Optional } // Valeurs par défaut des paramètres
        );

Maintenant il m'est juste venu à l'esprit qu'il pourrait y avoir des titres comme 'AS/400' :
http://fr.wikipedia.org/wiki/AS/400

Accessoirement, il y en a aussi un (titre 'Slash') :
http://fr.wikipedia.org/wiki//

Et celui-ci :
http://fr.wikipedia.org/wiki//dev/null

En général, Wikipedia semble avoir une liste de titres intéressants comme celui-ci : http://fr.wikipedia.org/wiki/Wikipedia:Articles_with_slashes_in_title

Comment puis-je faire en sorte que les routes comme celle-ci soient correctement mappées ?

Modifier :
Quelque chose comme :
Si l'URL commence par /Wiki/, et si elle ne commence pas par /wiki/Edit/ (mais pas /Wiki/Edit) alors passer tout le reste de l'URL en tant qu'Id.

Modifier :
Hmm, juste un autre problème : Comment puis-je mapper celui-ci :
http://fr.wikipedia.org/wiki/C&A

Wikipedia peut...

Modifier :
Selon Wikipedia, en raison de conflits avec la syntaxe du wikitexte, seuls les caractères suivants ne peuvent jamais être utilisés dans les titres de page (ni pris en charge par DISPLAYTITLE) :

# < > [ ] | { }

http://fr.wikipedia.org/wiki/Wikipedia:Naming_conventions_(technical_restrictions)#Forbidden_characters

Modifier :
Pour autoriser * et &, ajoutez

dans la section du fichier web.config

(Trouvé ici : http://www.christophercrooker.com/use-any-characters-you-want-in-your-urls-with-aspnet-4-and-iis)

0 votes

Pouvez-vous changer votre caractère de paramètre de routage en quelque chose de "plus habituel", comme un point d'interrogation ou une virgule... quelque chose qui n'est PAS valide dans un titre?

1 votes

ASP.NET MVC routage n'est pas votre seul problème. Essayez des sujets comme "LPT", "SQL*plus", "US$", "C#" etc. Beaucoup d'entre eux seront attrapés par IIS. Vous feriez mieux de penser à échapper à certains d'entre eux.

104voto

Darin Dimitrov Points 528142

Vous pouvez utiliser une route catchall pour capturer tout ce qui suit la partie wiki de l'URL dans le jeton id :

routes.MapRoute(
    "Wiki",
    "wiki/{*id}",
     new { controller = "Wiki", action = "DbLookup", id = UrlParameter.Optional }
);

Maintenant, si vous avez la requête suivante : /wiki/AS/400, elle sera associée à l'action suivante sur le contrôleur Wiki :

public ActionResult DbLookup(string id)
{
    // id sera égal à AS/400 ici
    ...
}

En ce qui concerne /wiki//, je crois que vous obtiendrez une erreur 400 Bad Request du serveur web avant que cette requête n'atteigne le pipeline ASP.NET. Vous pouvez consulter le blog post suivant.

0 votes

Agréable, ça fonctionne, mais que se passe-t-il lorsque je veux exempter /wiki/Edit/ArticleTitle de cette règle ? (mais cela ne devrait pas exempter /wiki/Edit)

3 votes

@Quandary, je ne pense pas que vous puissiez vous exempter avec une règle catchall. Vous pourriez essayer de définir une autre route avant celle que j'ai montrée qui ressemble à ceci wiki/Edit/{*id}.

0 votes

@Darin : OK, fonctionne parfaitement. En mode Édition, cela nécessite de capturer l'identifiant is null ou vide et de rediriger vers l'action dbLookup avec l'identifiant en tant qu'Édition.

31voto

Usman Points 3640

Dans Attribute Routing dans mvc j'avais le même problème en ayant / dans la chaîne abc/cde dans HttpGet

        [Route("verifytoken/{*token}")]
        [AllowAnonymous]
        [HttpGet]
        public ActionResult VerifyToken(string token)
        {
          //logique ici
        }

donc vous devez placer * car après cela il sera considéré comme un paramètre

2 votes

Génial. c'est la meilleure et la plus facile solution :)

2 votes

Cela semble fonctionner pour une barre oblique, mais pas deux d'affilée. Des idées à ce sujet?

2 votes

@Usman Que se passe-t-il si vous avez une autre route qui est [Route("verifytoken/{token}/something")] ? Le caractère générique ne risquerait-il pas d'entrer en conflit avec cette route s'il y a des barres obliques ? Existe-t-il une autre manière de faire cela pour ce cas d'utilisation ?

5voto

Adam Points 66

@Darin: Eh bien, c'est évident, la question est : Pourquoi ? le contrôleur + action + id sont donnés, c'est comme s'il envoyait tout ça à nouveau au routage... – Quandary 13 juin 2011 à 17h38

Quandary - vous avez peut-être déjà compris cela puisque votre question date de plus d'un an, mais lorsque vous appelez RedirectToAction, vous envoyez en fait une réponse HTTP 302 au navigateur, ce qui amène le navigateur à faire une requête GET vers l'action spécifiée. D'où la boucle infinie que vous voyez.

voir : Méthode Controller.RedirectToAction

0 votes

Server.Transfer résoudre cela: stackoverflow.com/questions/799511/…

-3voto

bobparker58 Points 1

Toujours comme option, écrivez dans le fichier Global.asax :

 var uri = Context.Request.Url.ToString();
        if (UriHasRedundantSlashes(uri))
        {
            var correctUri = RemoveRedundantSlashes(uri);
            Response.RedirectPermanent(correctUri);
        }
    }

    private string RemoveRedundantSlashes(string uri)
    {
        const string http = "http://";
        const string https = "https://";
        string prefix = string.Empty;

        if (uri.Contains(http))
        {
            uri = uri.Replace(http, string.Empty);
            prefix = http;
        }
        else if (uri.Contains(https))
        {
            uri = uri.Replace(https, string.Empty);
            prefix = https;
        }

        while (uri.Contains("//"))
        {
            uri = uri.Replace("//", "/");
        }

        if (!string.IsNullOrEmpty(prefix))
        {
            return prefix + uri;
        }
        return uri;
    }

    private bool UriHasRedundantSlashes(string uri)
    {
        const string http = "http://";
        const string https = "https://";

        if (uri.Contains(http))
        {
            uri = uri.Replace(http, string.Empty);
        }
        else if (uri.Contains(https))
        {
            uri = uri.Replace(https, string.Empty);
        }
        return uri.Contains("//");
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X