2009-11-25 10 views
13

Nel mio file Site.Master, ho 3 semplici parametri ViewData (gli unici 3 nella mia intera soluzione). Questi valori di ViewData sono fondamentali per ogni singola pagina nella mia applicazione. Poiché questi valori sono utilizzati nel mio Site.Master, ho creato una classe SiteController astratta che sovrascrive il metodo OnActionExecuting per riempire questi valori per ogni metodo Action su ogni controller della mia soluzione.Come si passa ViewData a una vista HandleError?

[HandleError(ExceptionType=typeof(MyException), View="MyErrorView")] 
public abstract class SiteController : Controller 
{ 
    protected override void OnActionExecuting(...) 
    { 
    ViewData["Theme"] = "BlueTheme"; 
    ViewData["SiteName"] = "Company XYZ Web Portal"; 
    ViewData["HeaderMessage"] = "Some message...";   

    base.OnActionExecuting(filterContext); 

    } 
} 

Il problema che sto affrontando è che questi valori non vengono passati a MyErrorView (e in definitiva Site.master) quando il HandleErrorAttribute calci dall'attributo livello di classe SiteController. Ecco uno scenario semplice per mostrare il mio problema:

public class TestingController : SiteController 
{ 
    public ActionResult DoSomething() 
    { 
    throw new MyException("pwnd!"); 
    } 
} 

Ho provato riempiendo i parametri viewdata sovrascrivendo il metodo OnException() nel mio SiteController pure, ma senza alcun risultato. :(

Qual è il modo migliore per passare i parametri viewdata al mio Site.master in questo caso?

risposta

19

Questo perché HandleErrorAttribute cambia il Viewdata passato alla vista quando si verifica un errore. Si passa un'istanza di . classe HandleErrorInfo con le informazioni su eccezioni, controller e azione

che cosa si può fare è sostituire questo attributo con quello implementato in basso:

using System; 
using System.Web; 
using System.Web.Mvc; 

public class MyHandleErrorAttribute : HandleErrorAttribute { 

    public override void OnException(ExceptionContext filterContext) 
    { 
     if (filterContext == null) 
     { 
      throw new ArgumentNullException("filterContext"); 
     } 
     if (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled) 
     { 
      Exception innerException = filterContext.Exception; 
      if ((new HttpException(null, innerException).GetHttpCode() == 500) && this.ExceptionType.IsInstanceOfType(innerException)) 
      { 
       string controllerName = (string) filterContext.RouteData.Values["controller"]; 
       string actionName = (string) filterContext.RouteData.Values["action"]; 
       // Preserve old ViewData here 
       var viewData = new ViewDataDictionary<HandleErrorInfo>(filterContext.Controller.ViewData); 
       // Set the Exception information model here 
       viewData.Model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName); 
       filterContext.Result = new ViewResult { ViewName = this.View, MasterName = this.Master, ViewData = viewData, TempData = filterContext.Controller.TempData }; 
       filterContext.ExceptionHandled = true; 
       filterContext.HttpContext.Response.Clear(); 
       filterContext.HttpContext.Response.StatusCode = 500; 
       filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
      } 
     } 
    } 
} 
+0

Wow, questo è stato molto più complesso di quanto ho pensato che sarebbe stato. :) L'ho esaminato per capirlo e ha perfettamente senso per quello che stai facendo e perché lo stai facendo. Grazie per la tua risposta! – Luc

+1

questo non funziona ... – fearofawhackplanet

+0

"non funziona" non è particolarmente utile. Ho fatto per me e gli altri. Dovresti controllare la versione MVC che stai utilizzando poiché sono sicuro che molto è cambiato. –

3

Se avete solo bisogno di passare qualcosa attraverso ViewBag può essere don e in questo modo: (questo sembra essere in un BaseController tutti i miei controllori ereditano da)

protected override void OnException(ExceptionContext filterContext) 
    { 
     try 
     { 
      var v = filterContext.Result as ViewResult; 
      v.ViewBag.DataToPassToError = "Hello World!"; 
     } 
     catch { /* no-op */ } 

     base.OnException(filterContext); 
    } 

vedere qui: How can I use data placed into a ViewBag by a filter in my Error.cshtml view?

Problemi correlati