web-dev-qa-db-fra.com

Itinéraires dynamiques à partir de la base de données pour ASP.NET MVC CMS

Fondamentalement, j'ai un backend CMS que j'ai construit à l'aide d'ASP.NET MVC et maintenant je passe au site frontend et j'ai besoin de pouvoir charger des pages de ma base de données cms, en fonction de l'itinéraire entré.

Donc, si l'utilisateur entre domain.com/students/information, MVC regarderait dans le tableau des pages pour voir s'il existe une page qui a un permalien qui correspond aux étudiants/informations, si c'est le cas, il redirigerait vers le contrôleur de page, puis chargerait la page les données de la base de données et les renvoyer à la vue pour affichage.

Jusqu'à présent, j'ai essayé d'avoir une route catch all, mais cela ne fonctionne que pour deux segments URL, donc/étudiants/informations, mais pas/étudiants/informations/automne. Je ne trouve rien en ligne sur la façon d'accomplir cela, donc je pensais que je demanderais ici, avant de trouver et d'ouvrir les cms ASP.NET MVC et de disséquer le code.

Voici la configuration d'itinéraire que j'ai jusqu'à présent, mais je pense qu'il existe une meilleure façon de procéder.

 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" }
        );          
    }

Si quelqu'un peut m'orienter dans la bonne direction sur la façon dont je procéderais pour charger des pages CMS à partir de la base de données, avec jusqu'à trois segments d'URL, et être toujours en mesure de charger des pages principales, qui ont un contrôleur et une action prédéfinis.

66
Carl Weis

Vous pouvez utiliser une contrainte pour décider de remplacer la logique de routage par défaut.

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;
    }
}

l'utiliser dans la définition d'itinéraire comme,

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 }
);

Maintenant, si vous avez une action "Index" dans le contrôleur "Page" comme,

public ActionResult Index(string permalink)
{
    //load the content from db with permalink
    //show the content with view
}
  1. toutes les URL seront capturées par la première route et vérifiées par la contrainte.
  2. si le lien permanent existe dans db, l'url sera gérée par l'action Index dans le contrôleur de page.
  3. sinon, la contrainte échouera et l'URL reviendra à la route par défaut (je ne sais pas si vous avez d'autres contrôleurs dans le projet et comment vous déciderez de votre logique 404).

MODIFIER

Pour éviter de réinterroger la page cms dans l'action Index dans le contrôleur Page, on peut utiliser le HttpContext.Items dictionnaire, comme

dans la contrainte

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;

puis dans l'action,

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

j'espère que cela t'aides.

120
shakib

J'utilise une approche plus simple qui ne nécessite aucune gestion de routeur personnalisée. Créez simplement un contrôleur unique/global qui gère quelques paramètres facultatifs, puis traitez ces paramètres comme vous le souhaitez:

//Route all traffic through this controller with the base URL being the domain 
[Route("")]
[ApiController]
public class ValuesController : ControllerBase
{
    //GET api/values
    [HttpGet("{a1?}/{a2?}/{a3?}/{a4?}/{a5?}")]
    public ActionResult<IEnumerable<string>> Get(string a1 = "", string a2 = "", string a3 = "", string a4 = "", string a5 = "")
    {
        //Custom logic processing each of the route values
        return new string[] { a1, a2, a3, a4, a5 };
    }
}

Exemple de sortie sur domain.com/test1/test2/test3

["test1","test2","test3","",""]
0
Kon Rad