Forse dovrei eseguire il back-up e ampliare l'ambito prima di immergermi nella domanda del titolo ...ASP.NET MVC: Come trovare i controller con gli attributi [Autorizza] utilizzando Reflection in C#? (o Come creare Dynamic Site.Master Menu?)
Attualmente sto scrivendo un'app Web in ASP.NET MVC 1.0 (anche se ho MVC 2.0 installato sul mio PC, quindi non sono esattamente limitato a 1.0) - Ho iniziato con il progetto MVC standard che ha il tuo "Welcome to ASP.NET MVC" di base e mostra sia il Scheda [Home] e scheda [Informazioni] nell'angolo in alto a destra. Abbastanza standard, giusto?
Ho aggiunto 4 nuove classi di controller, chiamiamole "Astronomo", "Biologo", "Chimico" e "Fisico". In allegato a ogni nuova classe di controller è presente l'attributo [Authorize].
Ad esempio, per i BiologistController.cs
[Authorize(Roles = "Biologist,Admin")]
public class BiologistController : Controller
{
public ActionResult Index() { return View(); }
}
Questi [Autorizza] Tag naturalmente limitare quale l'utente può accedere ai controller diversi a seconda dei ruoli, ma voglio costruire dinamicamente un menu nella parte superiore del mio sito web nella pagina Site.Master in base ai ruoli di cui l'utente fa parte. Così, per esempio, se "JoeUser" era un membro dei ruoli "Astronomo" e "Fisico", il menu di navigazione direbbe:
[Home] [Astronomo] [Fisico] [Chi]
E naturalmente, sarebbe non collegamenti elenco alla pagina indice "Biologo" o "Chemist".
O se "JohnAdmin" era un membro del ruolo "Amministratore", i collegamenti a tutti e 4 i controllori verrebbero visualizzati nella barra di navigazione.
Ok, si prolly ottiene l'idea ... Ora, per la vera domanda ...
Partendo the answer from this StackOverflow topic about Dynamic Menu building in ASP.NET, sto cercando di capire come avrei attuare pienamente questo. (Sono un principiante e ho bisogno di un po 'più di guida, quindi per favore nudi con me.)
La risposta propone Estendere la classe Controller (chiamiamola "ExtController") e poi avere ogni nuovo AnyController ereditato da ExtController.
La mia conclusione è che avrei bisogno di usare Reflection in questo Costruttore ExtController per determinare quali Classi e Metodi hanno attributi [Autorizza] ad essi associati per determinare i Ruoli. Quindi, usando un dizionario statico, memorizza i ruoli e i controllori/metodi nelle coppie chiave-valore.
immagino che qualcosa di simile:
public class ExtController : Controller
{
protected static Dictionary<Type,List<string>> ControllerRolesDictionary;
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
// build list of menu items based on user's permissions, and add it to ViewData
IEnumerable<MenuItem> menu = BuildMenu();
ViewData["Menu"] = menu;
}
private IEnumerable<MenuItem> BuildMenu()
{
// Code to build a menu
SomeRoleProvider rp = new SomeRoleProvider();
foreach (var role in rp.GetRolesForUser(HttpContext.User.Identity.Name))
{
}
}
public ExtController()
{
// Use this.GetType() to determine if this Controller is already in the Dictionary
if (!ControllerRolesDictionary.ContainsKey(this.GetType()))
{
// If not, use Reflection to add List of Roles to Dictionary
// associating with Controller
}
}
}
È questo fattibile? In tal caso, come faccio a eseguire Reflection nel costruttore ExtController per scoprire l'attributo [Autorizza] e i relativi ruoli (se presenti)
ANCHE! Sentiti libero di andare fuori campo su questa domanda e suggerire un modo alternativo per risolvere il problema "Sito dinamico. Menu principale basato sul ruolo". Sono il primo ad ammettere che questo potrebbe non essere l'approccio migliore.
EDIT
Dopo molto la lettura e la sperimentazione, mi si avvicinò con la mia soluzione. Vedi sotto per la mia risposta. Qualsiasi commento/critica costruttiva benvenuto!
Come nota, sarebbe probabilmente meglio creare un dizionario su ApplicationStart perché le classi non cambieranno fino a quando non si ridistribuisce. Quindi creare il menu non è sempre dinamico, ma una rapida ricerca in un dizionario. –