29 messaggi dal 12 settembre 2010
Buongiorno a tutti,
sono alle prime armi per lo sviluppo di applicazioni con ASP.NET Core e per fare pratica avevo pensato come primo progetto di provare a realizzare un CMS.
Vorrei fare in modo che dal back-end si possa configurare per ogni contenuto (alias pagina del sito sul front-end) anche il layout (file razor .cshtml) di riferimento da associare...ora però in un progetto ASP.NET Core MVC non so come tradurre questo comportamento o meglio qual'è il percorso da seguire...spero di avere indicazioni da persone più esperte di me!!!

Grazie a tutti in anticipo!!!
10.907 messaggi dal 09 febbraio 2002
Contributi
Ciao,
anche in ASP.NET Core, una view può decidere lei stessa quale layout usare. E' sufficiente mettere questo codice in cima alla view.
@{
  Layout = "~/Views/Shared/Layouts/NomeLayout.cshtml";
}

Ovviamente, nel tuo caso non dovrai cablare il percorso al file .cshtml nel codice ma ti dovrà essere fornito dall'action del controller. La view può essere fortemente tipizzata su un tipo di oggetto a tua scelta, quindi ad esempio:
@model MioNamespace.Models.ContentPageViewModel;
@{
  Layout = Model.LayoutPath;
}

Dove la classe ContentPageViewModel sarà fatta come segue:
public class ContentPageViewModel
{
  public string LayoutPath { get; set; }
  //Qui altre proprietà per la view, es Title, Text, ecc...
}


Dentro la proprietà LayoutPath inserirai il percorso del layout che la view dovrà usare. Il percorso può arrivare da database. Ad esempio, ecco cosa fa l'action che restituisce la view:
public ActionResult Content()
{
  var pageInfo = GetPageInfoFromDatabase();
  var viewModel = new ContentPageViewModel();
  viewModel.LayoutPath = pageInfo.LayoutPath;
  //Qui valorizza altre proprietà del viewmodel

  //E poi restituisci la view passandole il viewmodel appena creato
  return View(viewModel);
}


ciao,
Moreno
Modificato da BrightSoul il 15 settembre 2018 17.20 -

Enjoy learning and just keep making
29 messaggi dal 12 settembre 2010
Ciao Moreno,
intanto grazie per avermi risposto.

A questo punto sulla base delle preziose indicazioni che mi hai dato ti chiedo:
1) se applicassi una logica di questo tipo su un progetto strutturato secondo il paradigma MVC, come faccio a fare in modo che ad ogni url corrisponda univocamente un contenuto presente all’interno del DB?

Quello che io vorrei realizzare, logicamente parlando, è questo:
- per ogni percorso (url) del sito richiamare univocamente un contenuto presente all’int del DB che a sua volta avrebbe un riferimento al layout che deve essere caricato.

Grazie,
Alessio.
10.907 messaggi dal 09 febbraio 2002
Contributi
Ciao Alessio, prego!
il primo passo consiste nel predisporre un Controller allo scopo. Ad esempio, chiamalo PageController.
public class PageController : Controller {
  public ActionResult Content(int id) {
    //Ottengo le informazioni per la pagina che ha l'id indicato
    var pageInfo = GetPageInfoFromDatabase(id);
    var viewModel = new ContentPageViewModel();
    viewModel.LayoutPath = pageInfo.LayoutPath;
    viewModel.Title = pageInfo.Title;
    viewModel.Text = pageInfo.Text;
    //E poi restituisci la view passandole il viewmodel appena creato
    return View(viewModel);
  }
}


Lato View avrai una cosa del genere:
@model MioNamespace.Models.ContentPageViewModel;
@{
  Layout = Model.LayoutPath;
}
<h1>@Model.Title</h1>
<p>@Model.Text</p>


In questo modo, ogni qualvolta visiti l'url /Page/Content/1, l'action estrarrà dal database i contenuti della pagina con id=1.
Allo stesso modo quando visiti /Page/Content/2 verrà visualizzato il contenuto della pagina 2 (con il relativo layout) e così via.

A questo punto, il passo successivo potrebbe essere quello di rendere un po' più leggibile l'url e passare da /Page/Content/1 a /contact-us oppure /privacy. Insomma, usare quel che si chiama uno "slug", cioè una stringa che rappresenta univocamente una pagina come farebbe un id.
In realtà anche con questo sistema non è che il controller cambi molto. Anzi, resta quasi identico. Devi solo sostituire il parametro "id" con "slug".
public class PageController : Controller {
  public ActionResult Content(string slug) {
    //Ottengo le informazioni per la pagina che ha lo slug indicato
    var pageInfo = GetPageInfoFromDatabase(slug);
    var viewModel = new ContentPageViewModel();
    viewModel.LayoutPath = pageInfo.LayoutPath;
    viewModel.Title = pageInfo.Title;
    viewModel.Text = pageInfo.Text;
    //E poi restituisci la view passandole il viewmodel appena creato
    return View(viewModel);
  }
}


Quel che cambia, invece è la regola di routing. Bisogna fare in modo che se lo slug "contact-us" o "privacy" esiste nel database, la richiesta verrà gestita dall'action Content del PageController. Se invece non esiste, allora tutto torna a funzionare come al solito.

Dal metodo Configure della classe Startup aggiungi un'altra route prima di quella di default (perciò più prioritaria).
app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "contentPages",
                    template: "{*slug}",
                    defaults: new { controller = "Page", action = "Content" },
                    constraints: new { slug = new SlugRouteConstraint()}
                );
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });

Come vedi ho aggiunto un constraint alla nuova route "contentPages" che serve a verificare se lo slug esiste nel database. Se esiste, allora la route sarà presa in considerazione dal motore di routing di MVC e la richiesta verrà gestita dall'action Content del PageController. Se non esiste, allora verrà presa in considerazione la seconda route, quella di default.

Il constraint è implementato in questo modo. E' una bozza, quindi dovrai adattarlo alle tue esigenze. Tieni una cache in modo da non fargli effettuare una richiesta al database solo per verificare lo slug.
Lo scopo è far restituire true al metodo Match se lo slug esiste. Altrimenti false.
    public class SlugRouteConstraint : IRouteConstraint
    {
        public SlugRouteConstraint()
        {
        }

        public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
        {
            var slug = values["slug"] as string;
            if (string.IsNullOrEmpty(slug))
            {
                return false;
            }

            return SlugExistsInDatabase(slug);
        }

        private bool SlugExistsInDatabase(string slug)
        {
            //TODO: cambia questa logica. Accedi al db solo se gli slug esistenti non sono ancora stati caricati in cache
            if (slug == "contact-us" || slug == "privacy")
            {
                return true;
            }
            return false;
        }
    }


ciao,
Moreno
Modificato da BrightSoul il 15 settembre 2018 21.49 -

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.