2010-11-17 5 views
4

J'ai développé un CMS MVC pur pour m'amuser et j'ai été confronté à un bogue/une fonctionnalité gênant du routage ASP.NET.Extension du routage RouteCollection dans le routage ASP.NET

Chaque page dynamique gérée de mon CMS est associée à une route particulière extraite de la base de données. Ceux-ci sont chargés au démarrage de l'application. Lorsqu'un utilisateur ajoute une nouvelle page ou modifie l'URL d'une page existante, je dois être en mesure de modifier RouteTable pour insérer/modifier l'itinéraire en conséquence.

Le problème est que la nouvelle route n'a pas besoin d'être simplement ajoutée à la fin de RouteCollection, mais qu'elle doit être insérée dans une position particulière. Semble assez logique sauf que RouteCollection contient seulement une méthode Insert(int idx, RouteBase route) héritée de Collection<T> qui ne contient pas le nom de la route. Le nom de la route est important car je l'utilise partout pour générer des liens d'action.

En regardant le réflecteur Je ne vois pas de moyen facile d'étendre cette collection car le dictionnaire _namedMap est marqué comme privé. J'ai essayé de découper la collection au moment de l'insertion et de ré-ajouter chaque élément, mais comme il n'y a aucune méthode pour rechercher le nom d'une route dans RouteCollection, je ne peux pas les rajouter avec le nom qu'ils avaient auparavant. Si frustrant!!!

Pourquoi le nom de l'itinéraire n'est-il pas une propriété de l'objet route? Pourquoi si MS est sérieux au sujet de l'extension de MVC et du routage, est-ce que les classes cruciales sont difficiles à étendre?

Des suggestions sur la meilleure solution ici?

Edit:

Ok peut-être j'aurais beaucoup beaucoup plus claire ici. Je ne cherche pas une critique de mon design CMS. J'apprécie les commentaires mais ce n'est pas ce que je demande.

Question simplifiée. Comment puis-je insérer un itinéraire nommé dans la collection de routes au moment de l'exécution? La méthode d'insertion en cours sur la classe est insuffisante car elle n'inclut pas le nom.

Cheers,

Ian

+0

Pourquoi avez-vous exactement le mappage 1-à-1 des routes vers les pages gérées?Vous pourrez peut-être simplifier la structure de votre URL pour pouvoir continuer à réutiliser les mêmes itinéraires indépendamment de la page gérée. –

+0

@Berin: Ah, oui. Je n'avais pas pensé à ça. Une route par page est en effet un mauvais design. Devrait utiliser des valeurs de paramètre dans un itinéraire existant pour identifier les pages. –

+0

Je n'étais pas très clair, par exemple j'ai une page de détails de blog géré avec l'URL de post/{nom}/{id} et je n'ai pas à gérer l'analyse de l'url. J'ai une capture tout à la fin du bloc d'itinéraire géré qui gère les URLs simples simples, donc ce n'est pas tout à fait une route par page de son itinéraire par page dynamique + 1. Mon problème est toujours présent. – madcapnmckay

Répondre

0

Si vous regardez la méthode ClearItems(), cela devrait vous permettre de vider les routes. Si vous déplacez d'abord votre collection de routes dans une collection temporaire (et y insérez votre nouvelle route), exécutez ClearItems(), puis remplissez à nouveau en utilisant Add().

Il convient de mentionner que vous devez également utiliser les GetReadLock() et GetWriteLock() afin d'éviter les conflits potentiels dans votre application.

+0

Correct mais je perdrais l'information de nom de toutes les routes existantes en faisant cela. Comme le nom info est stocké dans un dictionnaire privé _namedMap, il ne fait pas partie de la route elle-même. Ce qui est requis est une méthode Insert (nom, RouteBase route). – madcapnmckay

+0

'RouteData.DataTokens' ne contient-il pas cette information que vous pouvez simplement extraire? Plus d'informations - http://stackoverflow.com/questions/363211 –

-2

Réponse courte: vous n'insérez pas les routes dynamiquement. Quand il est temps de les changer, ils doivent être reconstruits à partir de zéro. Il y a plusieurs raisons à cela, la plupart étant liées au fait que le système de routage n'est pas le goulot d'étranglement pour votre application. Essentiellement l'ensemble des routes est destiné être un petit ensemble statique de ressources qui mappent un grand nombre d'URL. Tout sur le système de routage a été conçu dans cet esprit.

Ceci est un départ pour de nombreux développeurs, en particulier provenant de frameworks basés sur des fichiers (comme les projets WebForms sans routines). Cela vous force à réfléchir un peu différemment aux URL.


de routage d'URL a été récemment rendu populaire par Ruby on Rails, ce qui a eu l'idée d'un document sur Representational State Transfer (REST): http://en.wikipedia.org/wiki/Representational_State_Transfer. Le concept existait avant Rails, mais c'est un concept qui a été transféré à ASP.NET MVC.

Le principe derrière les routes RESTful est qu'elles ont une structure commune, avec seulement certaines parties qui changent.Dans votre application, ce serait le nom de la page gérée. Par défaut, ASP.NET correspond à votre itinéraire comme ceci:

/{controller}/{action}/{id} 

Cela signifie que la partie de l'URL qui correspond où le « {contrôleur} » mot sera stocké dans le paramètre « contrôleur ». Pareil avec {action} et {id} aussi. Ce que cela signifie est que vous pouvez avoir une logique commune pour les pages gérées comme celui-ci:

/Page/Details/I eat spinach 

qui obtient mappée comme suit:

  • controller = « Page » (cartes à la classe PageController dans votre répertoire des contrôleurs)
  • action = "Détails" (cartes à la méthode des détails sur la classe PageController)
  • id = "Je mange des épinards" (passés en paramètre sur l'action Détails.

Votre code de contrôleur aurait une méthode comme ceci:

public ActionResult Details(string id) 
{ 
    return View(db.FindPage(id)); 
} 

Avec ces bases sur le chemin, nous ne sommes pas limités à cette structure. Tant que nous avons un moyen de fournir un mappage au bon contrôleur, la bonne action, et que nous pouvons rechercher la page gérée par identifiant, nous pouvons créer l'URL que nous voulons. Disons que nous voulions que le nom de la page arrive en premier, et que l'action arrive en deuxième position, et nous ne voulions pas du tout nous soucier du contrôleur. Nous créerions une route qui ressemble à ceci:

routes.MapRoute(
    "ManagedPages", // Route Name 
    "{id}/{action}", // URL structure 
    // Default route parameters 
    new { controller = "ManagedPage", action = "Details", id = "Home" } 
); 

Les paramètres fournissent des valeurs par défaut si elles ne sont pas masquées dans l'URL. Cela signifie qu'une URL vide correspondra toujours à ManagedPageController.Details("Home"). Si vous vouliez éditer la page, l'URL pourrait ressembler à "I eat spinach/Edit".

Il existe certaines mises en garde concernant le paramètre "id", qui se rapportent à des caractères interdits dont le MVC essaie de vous sauver. Si vous forcez les noms de pages à ne jamais inclure ces caractères interdits, vous aurez beaucoup moins de problèmes.

+0

Erm. Merci pour l'effort mais je suis bien conscient du fonctionnement du routage. Ma question est simplement comment insérer une route dynamiquement dans RouteCollection dans le routage ASP.NET. – madcapnmckay

+0

Ma réponse est que je crois que vous le rendez plus compliqué que nécessaire. –

0

Regardez l'interface IRouteConstraint. Fondamentalement, vous ajoutez un attraper tous les itinéraires ajouter la fin de la collection au démarrage de l'application, ce qui prend un objet de contrainte en paramètre. Ici vous rechercher dans votre CMS si l'URL entrant correspond à une page valide, puis retourne vrai ou faux, qui instruira le cadre de routage si la route doit être envisagée pour la requête entrante ou non

public interface IRouteConstraint 
{ 
    bool Match(HttpContextBase httpContext, 
    Route route, 
    string parameterName, 
    RouteValueDictionary values, 
    RouteDirection routeDirection); 
} 

http://msdn.microsoft.com/en-us/library/system.web.routing.irouteconstraint.aspx

Définit le contrat qu'une classe doit implémenter pour vérifier si une valeur de paramètre d'URL est valide pour une contrainte.