2010-10-05 10 views
8

Ho il seguente scenario: il mio sito Web visualizza articoli (immessi da un amministratore. Come un blog).Parametro controller ASP.NET MVC opzionale (i.e Index (int? Id))

Per visualizzare un articolo, l'utente fa riferimento a Home/Articoli/{ID articolo}.

Tuttavia, l'utente seleziona quale articolo visualizzare dalla vista Articles.aspx stessa, utilizzando un elenco jsTree.

Quindi, quello che devo fare è essere in grado di distinguere tra due casi: l'utente sta accedendo ad un articolo specifico, o sta semplicemente cercando di accedere alla pagina degli articoli "principale". Ho provato a impostare il parametro del controller "Articoli" come facoltativo (int? Id), ma poi ho problemi a "usare" il valore id all'interno del controller.

Qual è il modo ottimale per gestire questo scenario? Forse ho semplicemente bisogno di una logica migliore per verificare se un parametro id è stato fornito o meno nella "url"?

Sto cercando di evitare l'uso di due viste/controller, semplicemente per motivi di duplicazione del codice.

risposta

13

Utilizzare azioni separate, come:

public ActionResult Articles() ... 
public ActionResult Article(int id) ... 

alternativa spostarlo in un controller articoli (URL utilizzando il percorso di default saranno: Articles e Articles/Detail/{id}):

public class ArticlesController : Controller 
{ 
    public ActionResult Index() ... 
    public ActionResult Detail(int id) ... 
} 

Se ancora necessario utilizzare le cose come hai postato, provare uno di questi:

public ActionResult Articles(int id = 0) 
{ 
    if(id == 0) { 
     return View(GetArticlesSummaries()); 
    } 
    return View("Article", GetArticle(id)); 
} 
public ActionResult Articles(int? id) 
{ 
    if(id == null) { 
     return View(GetArticlesSummaries()); 
    } 
    return View("Article", GetArticle(id.Value)); 
} 
+0

"In alternativa spostalo in un controller Articoli (gli URL che utilizzano la route predefinita saranno: Articoli e articoli/Dettagli/{id}):" questo è probabilmente il modo migliore per farlo. Grazie! –

0

Fai il parametro richiesto quindi impostare un valore di default nel percorso che è un valore che non è un indice valido e indica per la vostra azione che dovrebbe rendere la principale pagina di .

1

questo per me suona come due pagine separate e dovrebbe essere trattato come tale. Hai la pagina di visualizzazione "Principale" e la pagina "Articoli".

Vorrei dividerlo in due azioni. Non dovrebbero essere affatto una vera e propria duplicazione, entrambi dovrebbero fare una chiamata per ottenere lo stesso ModelView e l'articolo otterrà semplicemente un'estensione!

5

definire un valore predefinito per l'ID che si conosce indicato nessun valore è stato fornito - di solito 0.

public ActionResult Articles([DefaultValue(0)]int Id) 
{ 
    if (Id == 0) 
    // show all 
    else 
    // show selected 
.. 
+0

grazie, questo è esattamente ciò di cui avevo bisogno. –

+1

L'utilizzo dell'attributo DefaultValue sembra un modo molto confuso per risolvere questo problema. – Ryan

+0

hmmmm ... forse userò 2 viste dopotutto. Ho bisogno che la pagina principale dell'articolo introduttivo sia più "interessante" HTML. –

7

Prima di tutto, sono d'accordo con @Steve :). Ma se si vuole veramente utilizzare

int? id 

si può solo controllare nel metodo di controllo se l'ID è impostato con un semplice

if(id == null) 

e in caso affermativo, caricare tutti gli articoli dal vostro DB (o qualcosa del genere allo stesso modo) e passarli alla vista (direttamente o utilizzando un modello di visualizzazione). Se l'ID è impostato, basta caricare l'articolo che ha quell'ID dal DB e inviarlo alla vista (eventualmente in un elenco anche se non usi i modelli di visualizzazione)?

Rispetto alla vista è sufficiente caricare tutti gli articoli nell'elenco con gli articoli forniti alla vista. Che contiene tutti o solo uno

codice fittizio completa

public ActionResult showArticles(int? id){ 
    List<Articles> aList; 
    if(id == null){ 
     aList = repository.GetAllArticles().ToList(); 
    }else{ 
     aList = new List<Articles>(); 
     aList.add(repository.GetArticleByID(id)); 
    } 

    return View(aList); 
} 

tua vista ha qualcosa come:

<% Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
Inherits="System.Web.Mvc.ViewPage<List<Articles>>"%> 

foreach(Articles a in Model) 
    //display article 

E si chiamano utilizzando una delle seguenti due opzioni:

html.ActionLink("one article","showArticles","Articles",new {id = aID},null} 

html.ActionLink("all articles","showArticles","Articles"} 
2

La soluzione più semplice è avere due diverse azioni e viste, ma nominare le azioni allo stesso modo.

public ViewResult Articles() 
{ 
    //get main page view model 
    return View("MainPage", model); 
} 

public ViewResult Articles(int id) 
{ 
    // get article view model 
    return View(model); 
} 
+1

Ok, ma quando provo a chiamare la pagina principale di articoli utilizzando: <% = Html.ActionLink ("Statuto", "Statuto", "Home")%> ottengo un errore: la richiesta corrente per l'azione 'Articoli' sul tipo di controller 'HomeController' è ambiguo tra i seguenti metodi di azione: System.Web.Mvc.ActionResult Articoli() sul tipo dr_teman_MVC.Controllers.HomeController Articoli System.Web.Mvc.ActionResult (Int32) su digita dr_teman_MVC.Controllers.HomeController –

+0

Il percorso (predefinito) specifica un ID predefinito? Suppongo che potrebbe essere un problema. Probabilmente nominerò un articolo di azione e l'altro articolo. – Ryan

0

Bene, questa è la soluzione combinata che sto usando:

Utilizzando stesso controller, con DefaultValue:

public ActionResult Articles([DefaultValue(0)]int id) 

Se DefaultValue è stato utilizzato, mi riferisco a "MainArticles" vista. Se è stato fornito un ID articolo, mi riferisco alla view "Articoli" con l'articolo appropriato passato all'interno di ViewModel.

In entrambi i casi, ViewModel viene popolato con i dati necessari per entrambe le visualizzazioni (elenco completo di articoli e categorie).

Grazie a tutti per il vostro aiuto!

0

Non so se si è tentato, ma invece se si sta digitando il valore direttamente nella URL, quindi, invece di passare in questo modo:

controller/action/idValue

Prova a passare in questo modo:

controller/action?id=value