2009-10-14 6 views
5

Ho un controller che eredita da un controller di base e mi chiedo come posso utilizzare tutta la logica dal controller di base, ma restituire una visualizzazione diversa da quella utilizzata dal controller di base.Come posso ereditare un controller ASP.NET MVC e modificare solo la vista?

Il controller di base popola un oggetto modello e passa tale oggetto del modello alla sua vista, ma non sono sicuro di come accedere a tale oggetto modello nel controller figlio in modo che possa passarlo alla vista del controller figlio.

+1

Hai provato solo ad ereditare dal controller di base e preparare le viste? – LukLed

risposta

1

Sulla base del feedback fornito su questo thread, ho implementato una soluzione come quella proposta da Antony Koch.

Invece di utilizzare un metodo astratto, ho utilizzato un metodo GetIndex concreto e virtuale in modo che potessi inserire la logica per il controller di base.

public class SalesController : Controller 
{ 
    // Index view method and model 
    public virtual ActionResult GetIndex() 
    { 
     return View("Index", IndexModel); 
    } 
    protected TestModel IndexModel { get; set; } 

    public virtual ActionResult Index() 
    { 
     ViewData["test"] = "Set in base."; 

     IndexModel = new TestModel(); 
     IndexModel.Text = "123"; 

     return GetIndex(); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public virtual ActionResult Index(TestModel data, FormCollection form) 
    { 
     TryUpdateModel(data, form.ToValueProvider()); 
     IndexModel = data; 

     return GetIndex(); 
    } 
} 

// This class will need to be in a different namespace or named differently than the 
// parent controller 
public class SalesController : MyApp.Controllers.BaseControllers.SalesController 
{ 
    // Index view method and model 
    public override ActionResult GetIndex() 
    { 
     return View("ClientIndex", IndexModel); 
    } 

    public override ActionResult Index() 
    { 
     return base.Index(); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public override ActionResult Index(TestModel data, FormCollection form) 
    { 
     return base.Index(data, form); 
    } 
} 
+0

Sto affrontando lo stesso tipo di problema, Qualcuno può aiutarmi? [La mia domanda] (http://stackoverflow.com/questions/12720611/cant-add-controller-which-uses-class-which-is-inherited-from-other-class) – user1668543

3

d'esempio della mia app:

Classe base:

public abstract class BaseTableController<T,TU> : BaseController where TU : IGenericService<T>,IModelWrapperService 
{ 
    protected readonly TU _service; 

    public BaseTableController(TU service) 
    { 
     _service = service; 
     _service.ModelWrapper = new ControllerModelStateWrapper(ModelState); 
    } 


    public ActionResult Index() 
    { 
     return View(_service.List()); 
    } 

Ereditato:

public class SeverityController : BaseTableController<Severity, ISeverityService> 
{ 
    public SeverityController(ISeverityService service) 
     : base(service) 
    { 
    } 

    //NO CODE INSIDE 
} 

SeverityController.Index() porta alla Visualizzazioni/Gravità/Index.aspx . Dovevo solo preparare la vista. Severity è uno dei dizionari nella mia applicazione di tracciamento dei bug. Ogni dizionario ha una logica simile, quindi potrei condividere del codice.

0

Ho finito per mettere un parametro in più sul controller di base - viewName.

Sembra funzionare bene.

Mi mancano alcuni aspetti negativi importanti?

public class SalesController : Controller 
{ 
    public virtual ActionResult Index(string viewName) 
    { 
     ViewData["test"] = "Set in base."; 

     TestModel model = new TestModel(); 
     model.Text = "123"; 

     return String.IsNullOrEmpty(viewName) ? View(model) : View(viewName, model); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public virtual ActionResult Index(TestModel data, FormCollection form, string viewName) 
    { 
     TryUpdateModel(data, form.ToValueProvider()); 
     return String.IsNullOrEmpty(viewName) ? View(data) : View(viewName, data); 
    } 
} 

public class SalesController : MyApp.Controllers.BaseControllers.SalesController 
{ 
    public override ActionResult Index(string viewName) 
    { 
     return base.Index("ClientIndex"); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public override ActionResult Index(TestModel data, FormCollection form, string viewName) 
    { 
     return base.Index(data, form, "ClientIndex"); 
    } 
} 
+1

Un problema che ho è che un utente può inviare i parametri a un ActionResult in un controller tramite http. Si corre il rischio che un utente sia in grado di chiamare l'indice su un controller che non sovrascrive "Index" in grado di passare un viewName con risultati imprevisti. Improbabile ma ancora possibile. –

+1

Non mi piace la soluzione. Non è necessario specificare il nome della vista. Immagina di avere un BaseController e due ereditari: ChildOneController e ChildTwoController. Se chiami ~/ChildOne/Index, prende visione da ~/ChildOne/Index/Index.aspx. Se chiami/ChildTwo/Index, prende visione da ~/ChildTwo/Index/Index.aspx. Il nome della vista è lo stesso, ma è preso da un posto diverso. – LukLed

+0

Sto affrontando lo stesso tipo di problema, Qualcuno può aiutarmi? [La mia domanda] (http://stackoverflow.com/questions/12720611/cant-add-controller-which-uses-class-which-is- inherited-from-other-class) – user1668543

0
public class BaseController : Controller { 
protected BaseController() {} 

public ActionResult Index() 
{ 
    return GetIndex(); 
} 

public abstract ActionResult GetIndex(); } 

public class MyController : BaseController { 
public MyController() {} 

public override GetIndex() 
{ 
    return RedirectToAction("Cakes","Pies"); 
} 

}

Basta usare l'astrazione di chiamare i bit necessari dalle sottoclassi.

+0

Ho fatto qualcosa di simile. Vedi la mia nuova risposta. Speravo di evitare di dover creare metodi secondari per ogni azione del controller, ma immagino sia il modo migliore. –

7

Un paio di punti. Puoi digitare il tuo valore di ritorno come ViewResult se sai che è tutto ciò che intendi restituire. Quindi puoi interrogare quel valore dall'implementazione sostituita. Ancora più importante, secondo il sorgente MVC v1, chiamare View (oggetto) semplicemente imposta ViewData.Model sul controller, quindi costruisce un ViewResult.

Controller.cs: 440

protected internal ViewResult View(object model) { 
    return View(null /* viewName */, null /* masterName */, model); 
} 

Controller.cs: 456

protected internal virtual ViewResult View(string viewName, string masterName, object model) { 
    if (model != null) { 
     ViewData.Model = model; 
    } 

    return new ViewResult { 
     ViewName = viewName, 
     MasterName = masterName, 
     ViewData = ViewData, 
     TempData = TempData 
    }; 
} 

Quindi, tutto quello che dovete fare è chiamare il metodo di base e chiamare View (stringa).

namespace BaseControllers 
{ 
    public class CoolController 
    { 
     public virtual ViewResult Get() 
     { 
      var awesomeModel = new object(); 
      return View(awesomeModel); 
     } 
    } 
} 

public class CoolController : BaseControllers.CoolController 
{ 
    public override ViewResult Get() 
    { 
     var ignoredResult = base.Get(); 
     // ViewData.Model now refers to awesomeModel 
     return View("NotGet"); 
    } 
} 

Ovviamente si sprecano cicli di CPU che costruiscono ViewResult che si ignora.Così, invece si può fare questo:

public class CoolController : BaseControllers.CoolController 
{ 
    public override ViewResult Get() 
    { 
     var baseResult = base.Get(); 
     baseResult.ViewName = "NotGet"; 
     return baseResult; 
    } 
} 

Se il controller di base ritorna ActionResult, dovrete gettarlo ai ViewResult prima di cambiare la ViewName.

Problemi correlati