2009-10-14 29 views
5

Tengo un controlador que hereda de un controlador base, y me pregunto cómo puedo utilizar toda la lógica desde el controlador base, pero devolver una vista diferente a la que usa el controlador base.¿Cómo puedo heredar un controlador ASP.NET MVC y cambiar solo la vista?

El controlador base rellena un objeto modelo y pasa ese objeto modelo a su vista, pero no estoy seguro de cómo puedo acceder al objeto modelo en el controlador secundario para poder pasarlo a la vista del controlador secundario.

+1

¿Intentó simplemente heredar del controlador base y preparar las vistas? – LukLed

Respuesta

1

Basado en los comentarios dados en este hilo, he implementado una solución como la propuesta por Antony Koch.

En lugar de usar un método abstracto, utilicé un método GetIndex concreto y virtual para poder poner lógica en él para el controlador 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

Estoy enfrentando el mismo tipo de problema, ¿alguien me puede ayudar? [Mi pregunta] (http://stackoverflow.com/questions/12720611/cant-add-controller-which-uses-class-which-is-herited-from-other-class) – user1668543

3

muestra de mi aplicación:

Clase 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()); 
    } 

Hereditaria:

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

    //NO CODE INSIDE 
} 

SeverityController.Index() lleva a Vistas/Severidad/Index.aspx . Solo tenía que preparar la vista. La gravedad es una de las dictionadas en mi aplicación de seguimiento de errores. Cada diccionario tiene una lógica similar, por lo que podría compartir algún código.

0

Terminé simplemente poniendo un parámetro adicional en la base Controller - viewName.

Parece que funciona bien.

¿Echas en falta algún inconveniente importante?

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

Una preocupación que tengo es que un usuario puede enviar los parámetros a un ActionResult en un controlador a través de http. Se corre el riesgo de que un usuario pueda llamar al índice en un controlador que no anula "Índice" y que pueda pasar un viewName con resultados inesperados. Poco probable pero aún posible. –

+1

No me gusta la solución. No es necesario especificar el nombre de la vista. Imagine que tiene un BaseController y dos heredadores: ChildOneController y ChildTwoController. Si llama a ~/ChildOne/Index, toma la vista de ~/ChildOne/Index/Index.aspx. Si llama/ChildTwo/Index, toma la vista de ~/ChildTwo/Index/Index.aspx. El nombre de la vista es el mismo, pero se toma desde un lugar diferente. – LukLed

+0

Estoy enfrentando el mismo tipo de problema, ¿alguien me puede ayudar? [Mi pregunta] (http://stackoverflow.com/questions/12720611/cant-add-controller-which-uses-class-which-is-herited-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"); 
} 

}

sólo tiene que utilizar la abstracción para llamar los bits que necesita de las subclases.

+0

Hice algo similar. Ver mi nueva respuesta. Esperaba evitar tener que crear métodos secundarios para cada acción del controlador, pero supongo que es la mejor manera. –

7

Un par de puntos. Puede escribir su valor de retorno como ViewResult si sabe que eso es todo lo que va a devolver. Entonces puede interrogar ese valor desde la implementación anulada. Más importante aún, de acuerdo con la fuente MVC v1, al llamar a View (objeto) simplemente establece ViewData.Model en el controlador, luego construye 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 
    }; 
} 

Así que todo lo que necesita hacer es llamar al método de base y la vista Llamada (cadena).

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"); 
    } 
} 

Por supuesto que desperdicia ciclos de CPU construyendo el ViewResult que ignora.Así que en lugar usted puede hacer esto:

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

Si el controlador base vuelve ActionResult, vas a tener que echarlo a ViewResult antes de cambiar la ViewName.

Cuestiones relacionadas