Asp.Net MVC Core realizzare un menu dinamico a tendina tramite C#

Articolo che illustra una tecnica per la creazione di un menu dinamici con tanto di gestione dei profili utenti.

il
Sviluppatore Microsoft .Net, Collaboratore di IProgrammatori

 

In questo articolo vedremo come creare un menu dinamico che permette di visualizzare un menu a tendina, con le voci a scomparsa che richiama le singole pagine "view" il tutto come nella figura precedente.
Il menu che contiene diverse proprietà, permette anche di eseguire codice Javascript, oppure richiamare delle finestre modale.
Naturalmente nell’esempio proposto vedremo come richiamare le varie pagina Asp.Net MVC tramite il nome del controller e della Action.
Inoltre in base al tipo di profilo con il quale si effettuerà l’accesso possiamo visualizzare alcune voci ed altre no, permettendo in questo modo di dare l’accesso solo ad alcuni profilo.
L’articolo vuole fornire al lettore le basi per realizzare un semplice menu che può essere esteso con le più comuni funzionalità da utilizzare in ambiente Asp.Net MVC Core.

Stesura del progetto


Si crea un nuovo progetto di tipo Asp.Net Core e nella finestra successiva selezionare tra i modelli preposti quello relativo ad Asp.Net MVC.
Dopo aver creato il progetto, nella finestra "Esplora soluzioni" facciamo click sulla cartella “Model” con il quale andremo a creare una classe per il menu.
Facciamo tasto destro sulla cartella e nel menu che viene visualizzato selezioniamo la voce “Aggiungi” e nel sottomenu la voce denominata “Classe” nella finestra che viene aperta impostiamo come nome “MenuModel” .

In questo file saranno presenti tre classi, una classe nel quale avremmo i sottomenu, che sono le voci che fanno parte di una voce di menu principale. Una classe del menu che rappresenta la voce che viene sempre visualizzata, ed infine la classe che contiene tutte e due le classi citate.
La classe “Sottomenu” contiene alcune proprietà importanti, come IdMenu che è il campo univoco della voce di tipo intero, un campo per l’ordinamento, una proprietà riguardante il testo da visualizzare, una proprietà se fa parte di un'altra voce, il nome del controller, il nome della Action, una lista contenente i profili autorizzati a visualizzare la voce e due proprietà di tipo testo, con il quale possiamo impostare le informazioni per eseguire una finestra modale oppure del codice Javascript.
Qui di seguito si riportano le suddette operazioni.

C#
public class SottoMenu
{
public Int16 IdMenu { get; set; }
public Int16 OrdineMenu { get; set; }
public string MenuTesto { get; set; }
public Int16 ParentMenu { get; set; }
public string ControllerName { get; set; }
public string ActionName { get; set; }
public List<string> ProfiliAutorizzati { get; set; }
public string Modale { get; set; }
public string CodiceJavascript { get; set; }
}

Sempre nello stesso file dobbiamo scrivere una classe il quale contiene le voci di menu principali con le voci del sottomenu che fanno riferimento alla precedente classe,.
Qui di seguito la classe.


C#
public class MenuItem
{
public Int16 IdMenu { get; set; }
public Int16 OrdineMenu { get; set; }
public string MenuTesto { get; set; }
public Int16 ParentMenu { get; set; }
public string ControllerName { get; set; }
public string ActionName { get; set; }
public List<SottoMenu> MenuSub { get; set; }
public string Modale { get; set; }
public List<string> ProfiliAutorizzati { get; set; }
public string CodiceJavascript { get; set; }
}

Infine la classe che sarà utilizzate nei vari controller, e che sarà inizializzata in ogni pagina.

C#
public class MenuModel
{
public List<MenuItem> MenuItems { get; set; }
//Costruttore
public MenuModel()
{
MenuItems = new List<MenuItem>();
}
}

Qui di seguito il codice completo di tutto file completo di questa classe.


C#
namespace ArtMenuCoreMVC.Models
{
public class MenuModel
{
public List<MenuItem> MenuItems { get; set; }
//Costruttore
public MenuModel()
{
MenuItems = new List<MenuItem>();
}
}
public class MenuItem
{
public Int16 IdMenu { get; set; }
public Int16 OrdineMenu { get; set; }
public string MenuTesto { get; set; }
public Int16 ParentMenu { get; set; }
public string ControllerName { get; set; }
public string ActionName { get; set; }
public List<SottoMenu> MenuSub { get; set; }
public string Modale { get; set; }
public List<string> ProfiliAutorizzati { get; set; }
public string CodiceJavascript { get; set; }
}
public class SottoMenu
{
public Int16 IdMenu { get; set; }
public Int16 OrdineMenu { get; set; }
public string MenuTesto { get; set; }
public Int16 ParentMenu { get; set; }
public string ControllerName { get; set; }
public string ActionName { get; set; }
public List<string> ProfiliAutorizzati { get; set; }
public string Modale { get; set; }
public string CodiceJavascript { get; set; }
}
}

Ora dobbiamo creare una funzione che permette il  caricamento delle varie voci di menu.
Questa funzione che si trova nella cartella dei controller, permette di valorizzare le varie voci di menu e di ordinarli oltre che impostare la visibilità in base al profilo.
Facciamo click con il tasto destro sulla cartella “Controller” e nel menu che viene visualizzato aggiungiamo una nuova classe, come abbiamo fatto in precedenza.
La classe sarà denominata “Funzioni” ed al suo interno ci sarà un metodo denominato “GetMenu” il quale passiamo un parametro di tipo “string” per indicare il profilo che deve vedere le voci.
Qui di seguito le dichiarazione delle suddette operazioni.

C#
public class Funzioni
{
public MenuModel GetMenu(string Profilo)
{
MenuModel returnMenu = new MenuModel();
try
{
//Menu Home
MenuItem menuHome = new MenuItem() { IdMenu = 0, OrdineMenu = 0, MenuTesto = "Home", ParentMenu = 0, ActionName = "Index", ControllerName = "Home", ProfiliAutorizzati = new List<string>() { "Amministratore", "Visualizzatore", "Avanzato", "UtenteEnte" }, Modale = "", CodiceJavascript = "onclick=HomePage();" };
//Menu Categoria Anagrafica
MenuItem menuAnagrafica = new MenuItem() { IdMenu = 1, OrdineMenu = 1, MenuTesto = "Anagrafica", ParentMenu = 0, ActionName = "Index", ControllerName = "Home", ProfiliAutorizzati = new List<string>() { "Amministratore", "Avanzato", "Modificatore", "UtenteEnte" }   };
//SottoMenu Anagrafica
SottoMenu SottmenuClienti = new SottoMenu() { IdMenu = 2, OrdineMenu = 1, MenuTesto = "Clienti", ParentMenu = 1, ActionName = "Index", ControllerName = "Clienti", ProfiliAutorizzati = new List<string>() { "Amministratore", "Avanzato", "Modificatore", "UtenteEnte" }, Modale = "", CodiceJavascript = "onclick=alert('Prova');" };
SottoMenu SottmenuFornitori = new SottoMenu() { IdMenu = 3, OrdineMenu = 2, MenuTesto = "Fornitori", ParentMenu = 1, ActionName = "Index", ControllerName = "Fornitori", ProfiliAutorizzati = new List<string>() { "Amministratore", "Avanzato", "Modificatore", "UtenteEnte" }, Modale = "", CodiceJavascript = "" };
SottoMenu SottmenuEnti = new SottoMenu() { IdMenu = 4, OrdineMenu = 3, MenuTesto = "Enti", ParentMenu = 1, ActionName = "Index", ControllerName = "Enti", ProfiliAutorizzati = new List<string>() { "Amministratore", "Avanzato", "Modificatore", "UtenteEnte" }, Modale = "", CodiceJavascript = "" };
menuAnagrafica.MenuSub = new List<SottoMenu>();
menuAnagrafica.MenuSub.Add(SottmenuClienti);
menuAnagrafica.MenuSub.Add(SottmenuFornitori);
menuAnagrafica.MenuSub.Add(SottmenuEnti);
//Menu Contabilità
MenuItem menuContabilita = new MenuItem() { IdMenu = 2, OrdineMenu = 2, MenuTesto = "Contabilita", ParentMenu = 0, ActionName = "Index", ControllerName = "Home", ProfiliAutorizzati = new List<string>() { "Amministratore", "Avanzato"  }  };
//SottoMenu Contabilità
SottoMenu SottmenuCassa = new SottoMenu() { IdMenu = 2, OrdineMenu = 1, MenuTesto = "Clienti", ParentMenu = 1, ActionName = "Index", ControllerName = "Clienti", ProfiliAutorizzati = new List<string>() { "Amministratore", "Avanzato" }, Modale = "", CodiceJavascript = "onclick=alert('Prova');" };
menuContabilita.MenuSub = new List<SottoMenu>();
menuContabilita.MenuSub.Add(SottmenuCassa);
//Aggiungo le varie sottovoci di menu
returnMenu.MenuItems.Add(menuHome);
returnMenu.MenuItems.Add(menuAnagrafica);
returnMenu.MenuItems.Add(menuContabilita);
//Ordino i menu in modo che poi vengono visualizzati correttamente
returnMenu.MenuItems = returnMenu.MenuItems.OrderBy(campo => campo.IdMenu).ThenByDescending(campo => campo.ParentMenu).ToList();
//Gestione delle pagine al quale si è abilitati.
returnMenu.MenuItems = returnMenu.MenuItems.OrderBy(campo => campo.IdMenu).ThenByDescending(campo => campo.ParentMenu).Where(profilo => profilo.ProfiliAutorizzati.Contains(Profilo)).ToList();
return returnMenu;
}
catch (Exception ex)
{
throw ex;
}
}

Naturalmente si prevede che per ogni voce del sottomenu è presente un Controller ed il relativo Action, in tal caso creare uno con la denominazione impostata nella proprietà “ActionName” e “ControllerName”.
Ora in ogni controller nell’evento di apertura, che di solito è “Index” inizializziamo il menu e passiamo come parametro il profilo desiderato. Possiamo anche fare delle prove con vari profili per verificare la visibilità delle voci.

Qui di seguito il frammento di codice delle suddette operazioni nell'evento Index del controller HomeController.

C#
public IActionResult Index()
{
Funzioni menu = new Funzioni();
ViewBag.Menu = menu.GetMenu("Amministratore");
return View();
}

Ora dobbiamo fare la modifica alla pagina “_Layout” che è quella che viene visualizzata in ogni “view” in particolare il caricamento del menu che viene restituito dal “ViewBag”.
Dopo il tag “<div class="container">” inseriamo il codice di menu come riportato qui di seguito.

_Layout.cshtml

@{
ArtMenuCoreMVC.Models.MenuModel MenuDaCaricare = new ArtMenuCoreMVC.Models.MenuModel();
MenuDaCaricare = ViewBag.Menu;
if (MenuDaCaricare != null)
{
<div class="col-md-3">
<ul class="nav-stacked">
@foreach (var VoceMenu in MenuDaCaricare.MenuItems)
{
if (VoceMenu.MenuSub == null)
{
<li> <a href="#" @VoceMenu.Modale @VoceMenu.CodiceJavascript> @VoceMenu.MenuTesto</a></li>
}
else
{
<li>
<a href="#" data-toggle="collapse" data-target="#sub1"> @VoceMenu.MenuTesto</a>
<ul class="collapse" id="sub1">
@foreach (var SottoMenuTrovato in VoceMenu.MenuSub)
{
<li class="col-md-12">
<p class="linkMenu"> - <a asp-area="" asp-controller="@SottoMenuTrovato.ControllerName" asp-action="@SottoMenuTrovato.ActionName">@SottoMenuTrovato.MenuTesto</a></p>
</li>
}
</ul>
</li>
}
}
</ul>
</div>
}
}


Qui di seguito si riporta il codice html completo della pagina _Layout

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - ArtMenuCoreMVC</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">ArtMenuCoreMVC</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
@{
ArtMenuCoreMVC.Models.MenuModel MenuDaCaricare = new ArtMenuCoreMVC.Models.MenuModel();
MenuDaCaricare = ViewBag.Menu;
if (MenuDaCaricare != null)
{
<div class="col-md-3">
<ul class="nav-stacked">
@foreach (var VoceMenu in MenuDaCaricare.MenuItems)
{
if (VoceMenu.MenuSub == null)
{
<li> <a href="#" @VoceMenu.Modale @VoceMenu.CodiceJavascript>  @VoceMenu.MenuTesto</a></li>
}
else
{
<li>
<a href="#" data-toggle="collapse" data-target="#sub1">  @VoceMenu.MenuTesto</a>
<ul class="collapse" id="sub1">
@foreach (var SottoMenuTrovato in VoceMenu.MenuSub)
{
<li class="col-md-12">
<p class="linkMenu"> - <a  asp-area="" asp-controller="@SottoMenuTrovato.ControllerName" asp-action="@SottoMenuTrovato.ActionName">@SottoMenuTrovato.MenuTesto</a></p>
</li>
}
</ul>
</li>
}
}
</ul>
</div>
}
}
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>

<footer class="border-top footer text-muted">
<div class="container">
&copy; 2020 - ArtMenuCoreMVC - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>


Terminata questa modifica non ci resta che eseguire il nostro progetto e fare le prove sulle singole voci.
Naturalmente possiamo impostare anche un profilo con il quale non sono visibili determinate voci.


Conclusioni


Questo articolo ha fornito al lettore una tecnica per dotare le proprie applicazioni Asp.Net Core MVC di un menu laterale a comparsa con il quale rendere la navigazione della propria applicazioni più amichevole.
Naturalmente la flessibilità di questo menu permette anche di gestirlo con una base dati e renderlo ancora più personalizzato in ambito di utenti.
Asp.Net Core MVC è una tecnologia, con il quale si possono creare applicazioni web di tipo MVC per vari sistemi operativi, oltre al sistema operativo Windows.
Nell’articolo si è utilizzato la versione del Framework Core 3.1 con l’ambiente di sviluppo Microsoft Visual Studio Community 2019.