2010-02-27 10 views
1

J'ai défini l'itinéraire suivant pour un blog simple.Problème lors de l'utilisation d'Url.Action() lors de la création d'URL conviviales et "hackables"

routes.MapRoute(
    "Blog", 
    "blog/{year}/{month}/{day}", 
    new { controller = "Blog", action = "Index" }, 
    new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" } 
); 

L'URL doit être en mesure "hackable" pour accomplir ce qui suit:

J'ai créé un contrôleur qui gère assez bien cette action. Cependant, j'ai de la difficulté à créer des liens dans mes vues en utilisant Url.Action().

Par exemple, ce ...

var d = new DateTime(2010, 1, 25); 
Url.Action("Index", "Blog", new { year=d.Year, month=d.Month, day=d.Day}); 

... génère une URL comme ça ressemble à ceci:

http://abc.com/blog?year=2010&month=2&day=21

Je préférerais que pour générer un url qui ressemble aux urls de la liste ci-dessus.

http://abc.com/blog/2010/02/21

Est-il possible que je peux utiliser Url.Action() ou Html.ActionLink() pour générer urls dans le format que je désire?

Répondre

3

Le problème est que le mois que vous passez à Url.Action est un mois à un chiffre et ne correspond donc pas à la contrainte du mois sur la définition de l'itinéraire. Les contraintes sont généralement exécutées non seulement sur les URL entrantes, mais également lors de la génération d'URL. Le correctif consisterait à appeler manuellement .ToString() le mois et à le formater en un nombre à deux chiffres. Vous devrez également faire la même chose pour la journée. Pour l'année, ce n'est pas un problème car toutes les années de notre vie seront des numéros à quatre chiffres.

est ici exemple de code pour les numéros de format:

int month = 2; 
string formattedMonth = month.ToString("00", CultureInfo.InvariantCulture); 
// formattedMonth == "02" 

S'il vous plaît noter que lors du formatage du numéro manuellement que vous devez utiliser la culture Invariant afin que différentes langues et cultures n'affectera pas la façon dont il sera formaté.

Vous aurez également besoin de définir des valeurs par défaut pour le mois et le jour afin qu'ils ne sont pas nécessaires dans l'URL:

routes.MapRoute( 
    "Blog", 
    "blog/{year}/{month}/{day}", 
    new { controller = "Blog", action = "Index", month = "00", day = "00" }, 
    new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" } 
); 

Et dans votre chèque d'action du contrôleur si le mois ou le jour sont 0, dans lequel cas, vous devriez montrer un mois entier ou toute l'année.

+0

Vous l'avez cloué. Merci pour votre réponse. Il fonctionne comme un charme. – jessegavin

0

L'autre problème que je vois vous rencontrer est que vous aurez besoin de plusieurs autres entrées de route avec les valeurs par défaut appropriées pour gérer ces autres scénarios."" ne correspondra pas "blog/{year}/{month}/{day}". C'est une route très spécifique qui nécessite trois paramètres (avec des contraintes) pour correspondre. Pour accepter ces autres itinéraires que vous devrez créer d'autres entrées de route le long des lignes de:

routes.MapRoute(
    null, 
    "blog", 
    new { controller = "Blog", action = "Index", year = 0000, month = 00, day = 00 }, 
    new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" } 
); 

routes.MapRoute(
    null, 
    "blog/{year}", 
    new { controller = "Blog", action = "Index", month = 00, day = 00 }, 
    new { year = @"\d{4}" } 
); 

routes.MapRoute(
    null, 
    "blog/{year}/{month}", 
    new { controller = "Blog", action = "Index", day = 00 }, 
    new { year = @"\d{4}", month = @"\d{2}"} 
); 

Il y a quelques façons de gérer ce scénario, mais maintenant dans votre contrôleur de blog et votre action Index vous pouvez filtrer les résultats des posts par année, mois, jour.

Exemple rapide:

if(year == 0000 && month == 00 && day == 00) 
    var posts = postsRepository.GetAllPost(); 
else if(year != 0000 && month == 00 && day == 00) 
    var posts = postsRepository.GetPostsByYear(year); 

...

+1

Je suggère que plutôt que d'avoir trois routes distinctes pour utiliser uniquement les valeurs par défaut pour le mois et le jour. J'ai mis à jour ma réponse pour inclure ceci. – Eilon

+0

+1 pour la brièveté et l'awesomeness globale. Si je suis honnête après une utilisation assez lourde de MVC, je ne savais pas que c'était possible. Je pensais que si la route était acceptée, elle enverrait les valeurs par défaut, peu importe quoi, mais après un test rapide, votre solution sténographique fonctionne très bien. –

+0

Vous n'avez pas besoin de plusieurs routes pour accomplir ceci. L'itinéraire que je montre dans la description de ma question fonctionne à merveille. (Ma question était plus liée à la façon dont Url.Action() génère une URL pour correspondre à cette route.) – jessegavin

0

Vous ne devez pas écrire nouvelle méthode pour toutes les conditions. Je veux dire que tu peux le faire avec ça;

par ex. pour NHibernate.

public IList<Blog> GetBlogs(int? day, int? month, int? year) { 
    IQueryable<Blog> iQBlog = Session.Linq<Blog>(); 

    if (year.HasValue) { 
     iQBlog = iQBlog.Where(b => b.Year == year); 

     if (month.HasValue) { 
      iQBlog = iQBlog.Where(b => b.Month == month); 

      if (day.HasValue) { 
       iQBlog = iQBlog.Where(b => b.Day == day); 
      } 
     } 
    } 

    return iQBlog.ToList(); 
} 

ps. Il vérifie les paramètres étape par étape, année -> mois -> jour. Si l'utilisateur ne définit aucun paramètre dans la chaîne de requête, il renvoie tous les blogs.

+0

C'est en fait ce que je fais déjà. Ma question était plus liée au routage Url. – jessegavin

+0

Yup j'ai compris votre question, mais déjà répondu et il le fait avec de nouvelles méthodes. Je l'ai dit parce que ça va peut-être t'aider – cem