2009-07-15 22 views
31

Sto implorando la mia classe ApplicationContext che utilizza il modello singleton. Voglio memorizzare la mia istanza in HttpContext.Items, poiché è accessibile in tutte le parti della richiesta. Ho letto sull'utilizzo di HttpContext con ASP.NET MVC e uno dei principali problemi è che introduce la complessità del test. Ho provato a fare ricerche sulla testabilità di HttpContext.Items, ma tutto quello che posso trovare è roba su Session. Una delle uniche cose che ho trovato è un capitolo di esempio nel libro MVC Professional ASP.NET 3.5 su Wrox (pdf link here). A pagina 15 si legge questo:HttpContext.Items con ASP.NET MVC

Qualcosa Non è possibile utilizzare: HttpContext.Items
Sopra in questa sezione, siamo venuti pulito e ti ha detto che abbiamo mentito a voi: HttpContext non è condivisa tra ASP .NET MVC e moduli Web ASP.NET. Di conseguenza, non è possibile utilizzare la raccolta HttpContext.Items per archiviare e recuperare bit di dati.

Il motivo è che quando si reindirizza a un controller, HttpHandler diventa System.Web.Mvc.MvcHandler, che viene creato utilizzando HttpContextWrapper, che avrà la propria definizione di HttpContext.Current. Sfortunatamente, durante questa stretta di mano, cose come HttpContext.Items non vengono trasferite.

Ciò che si riduce a questo è che i tipi di HttpContext, nonostante lo sguardo e il suono molto lo stesso, non sono la stessa, e non è possibile passare i dati in questo modo.

Ora, ho provato testare questo fuori, e per quanto ne so, se si reindirizza a un altro controller utilizzando RedirectToAction, HttpContext.Items non rimangono. Sto usando il progetto MVC ASP.NET predefinito per testarlo. Quello che ho fatto è, aggiungere questo metodo per Global.asax.cs:

protected void Application_BeginRequest() 
{ 
    Context.Items["Test"] = "Hello World"; 
} 

E in HomeController.cs, ho cambiato il metodo Index a:

public ActionResult Index() 
{ 
    return RedirectToAction("About"); 
} 

e ha cambiato il proposito di metodo per:

public ActionResult About() 
{ 
    Response.Write(Convert.ToString(HttpContext.Items["Test"])); 
    return View(); 
} 

Quando eseguo l'applicazione, la pagina reindirizza correttamente/Home/Chi e Response.Writes la corretta stringa "Ciao mondo" impostato nelle global.asax.cs.

Quindi, mi sembra come se sto o non capire ciò che il libro è significato quando dicono "cose ​​come HttpContext.Items non vengono trasferiti" O lo fa trasferire questa roba ed è bene utilizzare HttpContext. Elementi.

Se si consiglia di evitare HttpContext.Items, esiste un altro modo alternativo per archiviare un oggetto su una richiesta in base alle richieste?

+0

Questo è piuttosto un risorsa utile per la creazione di un "contesto di applicazione" tipo di oggetto: http://jcapka.blogspot.co.uk/2013/11/creating-application-context-for-net.html – JDandChips

risposta

35

La tua domanda sta chiedendo alcune cose, ma penso che l'elemento n. 1 sia la risposta che stai cercando.

  1. E 'bene usare Context.Items per la cache su una base per ogni richiesta? Sì. Se in elaborazione, per richiesta, per macchina nella web farm sono i tuoi criteri allora Context.Items ti dà questo.

  2. È difficile testare con Context.Items? Per quanto riguarda la testabilità, nascondevo Context.Items dietro un'interfaccia di qualche tipo. In questo modo si ottengono le funzionalità di test delle unità senza dover fare riferimento direttamente allo Context.Items. Altrimenti, cosa è necessario testare su Context.Items? Che il framework memorizzerà e recupererà i valori? Mantieni il tuo codice all'oscuro di System.Web e sarai un campeggiatore felice.

  3. Il è il RedirectToAction? No. Il test non è valido. Sta impostando "Ciao, mondo" su ogni richiesta web e il tuo test copre due richieste web. Il primo è quando viene chiamata l'azione Index. Il secondo è quando viene chiamata l'azione RedirectToAction (è un HTTP 302). Per fallire, imposta un nuovo valore nell'azione Index e verifica se è mantenuto nell'azione About.

+0

Bingo! Hai ragione. Ovviamente non me ne sono reso conto, perché stavo impostando l'elemento di contesto in BeginRequest, che viene eseguito due volte, una volta quando viene chiamato Index e poi di nuovo dopo che Index reindirizza su About. Suppongo però che per il mio scenario (facendo un singleton quale istanza è memorizzata in Request.Items), starò bene con quel comportamento, in quanto l'oggetto verrà appena ricostruito quando reindirizzerò. Grazie ancora per la tua risposta! –

+0

Ryan - "facendo un singleton quale istanza è memorizzata in Request.Items," puoi per favore elaborare con codice di esempio come lo fai? – Picflight

+0

* "Nascondere Context.Item dietro un'interfaccia di qualche tipo" * oppure è possibile utilizzare [HttpContextBase] (https://msdn.microsoft.com/en-us/library/system.web.httpcontextbase (v = vs.110) .aspx) o [HttpContextWrapper] (https://msdn.microsoft.com/en-us/library/system.web.httpcontextwrapper (v = vs.110).aspx), entrambe le quali (essendo astratte) sono irrisolvibili. – Liam

3

usare il dizionario TempData, è soprattutto per la memorizzazione di oggetti tra le azioni reindirizza:

public ActionResult Index() 
{ 
    TempData.Add("Test", "Hello world"); 
    return RedirectToAction("About"); 
} 

public ActionResult About() 
{ 
    ViewData["Test"] = TempData["Test"]; 
    return View(); 
} 

quindi recuperare il valore nella vista:

<%=ViewData["Test"] %> 
+3

Grazie per la risposta, ma non voglio usare lo stato della sessione. Ciò è dovuto al fatto che la mia app potrebbe essere in esecuzione in una Web farm e le prestazioni dello stato della sessione non sono buone quando si esauriscono le procedure. (TempData memorizza i suoi valori in SessionState) –

1

Ho fatto un test e TempData fa, anzi , esplodere con lo stato della sessione disabilitato. Il mio unico consiglio sarebbe quello di non archiviare l'oggetto stesso nei dati temporanei ma memorizzare i semplici campi tipizzati come è stato suggerito. Dal momento che non stai serializzando gli alberi degli oggetti, non dovrebbe essere la conseguenza di un impatto estemporaneo sulle prestazioni.

+1

Beh, in realtà * è * un impatto sulle prestazioni. Se si esegue una web farm, è necessario condividere la sessione attraverso l'intera farm (perché su una richiesta si potrebbe colpire il server A, e quindi nella richiesta * next * si potrebbe essere indirizzati al server B). Ciò viene normalmente eseguito utilizzando il provider di sessione di SQL Server che è totalmente lento e scadente rispetto al processo. È così lento e schifoso che tutti dovrebbero evitarlo con un palo da 10 piedi. O più a lungo se hai qualcosa di utile;). –

+0

Inoltre, la memorizzazione dell'oggetto anche in TempData lo porterà attraverso le richieste. Non lo voglio Voglio memorizzarlo solo per la richiesta corrente. –

+0

FYI: È possibile disabilitare completamente TempData scrivendo un provider di dati temporali personalizzato che non fa nulla. Che il provider predefinito esploda quando lo stato della sessione è disabilitato è in realtà solo un bug in ASP.NET MVC 1.0 e lo abbiamo già risolto per la prossima versione di ASP.NET MVC! – Eilon