2013-04-15 20 views
59

Fondamentalmente ho un backend CMS che ho creato utilizzando ASP.NET MVC e ora sto passando al sito frontend e devo essere in grado di caricare pagine dal mio database cms, in base al percorso inserito.Rotte dinamiche dal database per ASP.NET MVC CMS

Quindi, se l'utente inserisce domain.com/students/information, MVC cerca nella tabella delle pagine per vedere se esiste una pagina che ha un permalink che corrisponde a studenti/informazioni, in tal caso reindirizzerà al controller di pagina e quindi caricare i dati della pagina dal database e restituirli alla vista per la visualizzazione.

Finora ho provato ad avere una cattura su tutto il percorso, ma funziona solo per due segmenti di URL, quindi/studenti/informazioni, ma non/studenti/informazioni/caduta. Non riesco a trovare nulla online su come realizzare questo, quindi, anche se vorrei chiedere qui, prima di trovare e aprire il codice ASP.NET MVC cms e sezionare il codice.

Ecco la configurazione del percorso che ho finora, ma sento che c'è un modo migliore per farlo.

public static void RegisterRoutes(RouteCollection routes) 
    { 
     routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

     // Default route to handle core pages 
     routes.MapRoute(null,"{controller}/{action}/{id}", 
         new { action = "Index", id = UrlParameter.Optional },     
         new { controller = "Index" } 
     ); 

     // CMS route to handle routing to the PageController to check the database for the route. 


     var db = new MvcCMS.Models.MvcCMSContext(); 
     //var page = db.CMSPages.Where(p => p.Permalink ==) 
     routes.MapRoute(
      null, 
      "{*.}", 
      new { controller = "Page", action = "Index" } 
     );   
    } 

Se qualcuno mi può puntare nella giusta direzione su come andrei sul caricamento di pagine CMS dal database, con un massimo di tre segmenti di URL, e ancora in grado di caricare le pagine di base, che hanno un controller e azione predefinita.

risposta

106

È possibile utilizzare un vincolo per decidere se sovrascrivere la logica di routing predefinita.

public class CmsUrlConstraint : IRouteConstraint 
{ 
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
     var db = new MvcCMS.Models.MvcCMSContext(); 
     if (values[parameterName] != null) 
     { 
      var permalink = values[parameterName].ToString(); 
      return db.CMSPages.Any(p => p.Permalink == permalink); 
     } 
     return false; 
    } 
} 

usarlo nella definizione di percorso come,

routes.MapRoute(
    name: "CmsRoute", 
    url: "{*permalink}", 
    defaults: new {controller = "Page", action = "Index"}, 
    constraints: new { permalink = new CmsUrlConstraint() } 
); 

routes.MapRoute(
    name: "Default", 
    url: "{controller}/{action}/{id}", 
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
); 

Ora, se si dispone di un'azione 'indice' in Controller 'Pagina' come,

public ActionResult Index(string permalink) 
{ 
    //load the content from db with permalink 
    //show the content with view 
} 
  1. tutti gli URL saranno catturato dalla prima rotta e verificato dal vincolo.
  2. se il permalink esiste in db l'url verrà gestito dall'azione Index in Page controller.
  3. in caso contrario il vincolo fallirà e l'url ricadrà sulla rotta predefinita (non so se hai altri controller nel progetto e come deciderà la logica 404).

EDIT

Per evitare nuovamente l'interrogazione del cms nell'azione Index in Page controllore, si può usare il dizionario HttpContext.Items, come

nel vincolo

var db = new MvcCMS.Models.MvcCMSContext(); 
if (values[parameterName] != null) 
{ 
    var permalink = values[parameterName].ToString(); 
    var page = db.CMSPages.Where(p => p.Permalink == permalink).FirstOrDefault(); 
    if(page != null) 
    { 
     HttpContext.Items["cmspage"] = page; 
     return true; 
    } 
    return false; 
} 
return false; 

quindi nell'azione,

public ActionResult Index(string permalink) 
{ 
    var page = HttpContext.Items["cmspage"] as CMSPage; 
    //show the content with view 
} 

spero che questo aiuti.

+0

Grazie mille, proverò e segnerò come risposta se funziona. :) –

+3

Impressionante ha funzionato benissimo, ho dovuto solo aggiungere un controllo if (values ​​[parameterName]! = Null), ma per il resto perfetto! Grazie :) –

+1

sei il benvenuto. felice che ha funzionato. :) – shakib

Problemi correlati