Esercitazione: Usare la resilienza della connessione e l'intercettazione dei comandi con Entity Framework in un'app MVC ASP.NET
Finora l'applicazione è stata eseguita localmente in IIS Express nel computer di sviluppo. Per rendere disponibile un'applicazione reale per altre persone da usare tramite Internet, è necessario distribuirla in un provider di hosting Web e distribuire il database in un server di database.
In questa esercitazione si apprenderà come usare la resilienza della connessione e l'intercettazione dei comandi. Sono due funzionalità importanti di Entity Framework 6 particolarmente importanti quando si esegue la distribuzione nell'ambiente cloud: resilienza della connessione (tentativi automatici per gli errori temporanei) e intercettazione dei comandi (intercettare tutte le query SQL inviate al database per registrarle o modificarle).
Questa esercitazione sulla resilienza della connessione e l'intercettazione dei comandi è facoltativa. Se si ignora questa esercitazione, è necessario apportare alcune piccole modifiche nelle esercitazioni successive.
In questa esercitazione:
- Abilitare la resilienza della connessione
- Abilitare l'intercettazione dei comandi
- Testare la nuova configurazione
Prerequisiti
Abilitare la resilienza della connessione
Quando si distribuisce l'applicazione in Windows Azure, si distribuirà il database in Windows Azure SQL Database, un servizio di database cloud. Gli errori di connessione temporanei sono in genere più frequenti quando ci si connette a un servizio di database cloud rispetto a quando il server Web e il server di database vengono connessi direttamente nello stesso data center. Anche se un server Web cloud e un servizio di database cloud sono ospitati nello stesso data center, esistono più connessioni di rete tra di esse che possono avere problemi, ad esempio i servizi di bilanciamento del carico.
Inoltre, un servizio cloud viene in genere condiviso da altri utenti, il che significa che la velocità di risposta può essere influenzata da essi. L'accesso al database potrebbe essere soggetto a limitazioni. La limitazione indica che il servizio di database genera eccezioni quando si tenta di accedervi più frequentemente rispetto a quanto consentito nel contratto di servizio.
Molti o la maggior parte dei problemi di connessione quando si accede a un servizio cloud sono temporanei, ovvero si risolvono in un breve periodo di tempo. Pertanto, quando si tenta un'operazione di database e si ottiene un tipo di errore in genere temporaneo, è possibile ritentare l'operazione dopo un breve attesa e l'operazione potrebbe avere esito positivo. È possibile offrire agli utenti un'esperienza molto migliore se si gestiscono gli errori temporanei riprovando automaticamente, rendendo la maggior parte invisibili al cliente. La funzionalità di resilienza della connessione in Entity Framework 6 automatizza il processo di ripetizione dei tentativi di query SQL non riuscite.
La funzionalità di resilienza della connessione deve essere configurata in modo appropriato per un determinato servizio di database:
- Deve sapere quali eccezioni sono probabilmente temporanee. Si desidera ripetere gli errori causati da una perdita temporanea nella connettività di rete, non da errori causati da bug del programma, ad esempio.
- Deve attendere un intervallo di tempo appropriato tra tentativi di un'operazione non riuscita. È possibile attendere più tempo tra tentativi per un processo batch rispetto a una pagina Web online in cui un utente è in attesa di una risposta.
- È necessario riprovare un numero appropriato di volte prima di rinunciare. È possibile riprovare più volte in un processo batch che si farebbe in un'applicazione online.
È possibile configurare queste impostazioni manualmente per qualsiasi ambiente di database supportato da un provider Entity Framework, ma i valori predefiniti che in genere funzionano correttamente per un'applicazione online che usa Windows Azure SQL Database sono già state configurate automaticamente e queste sono le impostazioni che verranno implementate per l'applicazione Contoso University.
Tutto ciò che è necessario fare per abilitare la resilienza della connessione è creare una classe nell'assembly che deriva dalla classe DbConfiguration e in tale classe impostare la strategia di esecuzione database SQL, che in EF è un altro termine per i criteri di ripetizione dei tentativi.
Nella cartella DAL aggiungere un file di classe denominato SchoolConfiguration.cs.
Sostituire il codice del modello con il codice seguente:
using System.Data.Entity; using System.Data.Entity.SqlServer; namespace ContosoUniversity.DAL { public class SchoolConfiguration : DbConfiguration { public SchoolConfiguration() { SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy()); } } }
Entity Framework esegue automaticamente il codice trovato in una classe che deriva da
DbConfiguration
. È possibile usare laDbConfiguration
classe per eseguire attività di configurazione nel codice che altrimenti si farebbe nel file Web.config . Per altre informazioni, vedere EntityFramework Code-Based Configuration.In StudentController.cs aggiungere un'istruzione
using
perSystem.Data.Entity.Infrastructure
.using System.Data.Entity.Infrastructure;
Modificare tutti i
catch
blocchi che intercettanoDataException
le eccezioni in modo che intercettanoRetryLimitExceededException
invece le eccezioni. Ad esempio:catch (RetryLimitExceededException /* dex */) { //Log the error (uncomment dex variable name and add a line here to write a log. ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator."); }
Si stava usando
DataException
per provare a identificare gli errori che potrebbero essere temporanei per fornire un messaggio descrittivo "riprova". Ma ora che è stato attivato un criterio di ripetizione dei tentativi, gli unici errori probabilmente saranno già stati provati e non sono riusciti più volte e l'eccezione effettiva restituita verrà sottoposta a wrapping nell'eccezioneRetryLimitExceededException
.
Per altre informazioni, vedere Entity Framework Connection Resiliency/Retry Logic.For more information, see Entity Framework Connection Resiliency/Retry Logic.
Abilitare l'intercettazione dei comandi
Dopo aver attivato un criterio di ripetizione dei tentativi, come si esegue il test per verificare che funzioni come previsto? Non è così facile forzare un errore temporaneo, soprattutto quando si esegue localmente e sarebbe particolarmente difficile integrare gli errori temporanei effettivi in uno unit test automatizzato. Per testare la funzionalità di resilienza della connessione, è necessario un modo per intercettare le query inviate da Entity Framework a SQL Server e sostituire la risposta SQL Server con un tipo di eccezione in genere temporaneo.
È anche possibile usare l'intercettazione di query per implementare una procedura consigliata per le applicazioni cloud: registrare la latenza e l'esito positivo o negativo di tutte le chiamate a servizi esterni , ad esempio i servizi di database. EF6 offre un'API di registrazione dedicata che consente di semplificare la registrazione, ma in questa sezione dell'esercitazione si apprenderà come usare direttamente la funzionalità di intercettazione di Entity Framework, sia per la registrazione che per la simulazione di errori temporanei.
Creare un'interfaccia di registrazione e una classe
Una procedura consigliata per la registrazione consiste nell'usare un'interfaccia anziché eseguire chiamate hardcoded a System.Diagnostics.Trace o a una classe di registrazione. In questo modo è più semplice modificare il meccanismo di registrazione in un secondo momento, se necessario. In questa sezione si creeranno quindi l'interfaccia di registrazione e una classe per implementarla./p>
Creare una cartella nel progetto e denominarla Registrazione.
Nella cartella Logging creare un file di classe denominato ILogger.cs e sostituire il codice del modello con il codice seguente:
using System; namespace ContosoUniversity.Logging { public interface ILogger { void Information(string message); void Information(string fmt, params object[] vars); void Information(Exception exception, string fmt, params object[] vars); void Warning(string message); void Warning(string fmt, params object[] vars); void Warning(Exception exception, string fmt, params object[] vars); void Error(string message); void Error(string fmt, params object[] vars); void Error(Exception exception, string fmt, params object[] vars); void TraceApi(string componentName, string method, TimeSpan timespan); void TraceApi(string componentName, string method, TimeSpan timespan, string properties); void TraceApi(string componentName, string method, TimeSpan timespan, string fmt, params object[] vars); } }
L'interfaccia fornisce tre livelli di traccia per indicare l'importanza relativa dei log e uno progettato per fornire informazioni sulla latenza per le chiamate di servizio esterne, ad esempio le query di database. I metodi di registrazione hanno overload che consentono di passare un'eccezione. Ciò significa che le informazioni sulle eccezioni, tra cui l'analisi dello stack e le eccezioni interne, vengono registrate in modo affidabile dalla classe che implementa l'interfaccia, anziché basarsi su tale operazione eseguita in ogni chiamata al metodo di registrazione in tutta l'applicazione.
I metodi TraceApi consentono di tenere traccia della latenza di ogni chiamata a un servizio esterno, ad esempio database SQL.
Nella cartella Logging creare un file di classe denominato Logger.cs e sostituire il codice del modello con il codice seguente:
using System; using System.Diagnostics; using System.Text; namespace ContosoUniversity.Logging { public class Logger : ILogger { public void Information(string message) { Trace.TraceInformation(message); } public void Information(string fmt, params object[] vars) { Trace.TraceInformation(fmt, vars); } public void Information(Exception exception, string fmt, params object[] vars) { Trace.TraceInformation(FormatExceptionMessage(exception, fmt, vars)); } public void Warning(string message) { Trace.TraceWarning(message); } public void Warning(string fmt, params object[] vars) { Trace.TraceWarning(fmt, vars); } public void Warning(Exception exception, string fmt, params object[] vars) { Trace.TraceWarning(FormatExceptionMessage(exception, fmt, vars)); } public void Error(string message) { Trace.TraceError(message); } public void Error(string fmt, params object[] vars) { Trace.TraceError(fmt, vars); } public void Error(Exception exception, string fmt, params object[] vars) { Trace.TraceError(FormatExceptionMessage(exception, fmt, vars)); } public void TraceApi(string componentName, string method, TimeSpan timespan) { TraceApi(componentName, method, timespan, ""); } public void TraceApi(string componentName, string method, TimeSpan timespan, string fmt, params object[] vars) { TraceApi(componentName, method, timespan, string.Format(fmt, vars)); } public void TraceApi(string componentName, string method, TimeSpan timespan, string properties) { string message = String.Concat("Component:", componentName, ";Method:", method, ";Timespan:", timespan.ToString(), ";Properties:", properties); Trace.TraceInformation(message); } private static string FormatExceptionMessage(Exception exception, string fmt, object[] vars) { // Simple exception formatting: for a more comprehensive version see // https://code.msdn.microsoft.com/windowsazure/Fix-It-app-for-Building-cdd80df4 var sb = new StringBuilder(); sb.Append(string.Format(fmt, vars)); sb.Append(" Exception: "); sb.Append(exception.ToString()); return sb.ToString(); } } }
L'implementazione usa System.Diagnostics per eseguire la traccia. Si tratta di una funzionalità predefinita di .NET che semplifica la generazione e l'uso delle informazioni di traccia. Esistono molti "listener" che è possibile usare con la traccia System.Diagnostics, per scrivere log nei file, ad esempio, o per scriverli nell'archivio BLOB in Azure. Per altre informazioni, vedere alcune delle opzioni e collegamenti ad altre risorse in Risoluzione dei problemi dei siti Web di Azure in Visual Studio. Per questa esercitazione verranno esaminati solo i log nella finestra Output di Visual Studio.
In un'applicazione di produzione è consigliabile prendere in considerazione i pacchetti di traccia diversi da System.Diagnostics e l'interfaccia ILogger semplifica relativamente il passaggio a un meccanismo di traccia diverso se si decide di farlo.
Creare classi di intercettore
Successivamente si creeranno le classi che Entity Framework chiamerà ogni volta che invierà una query al database, una per simulare gli errori temporanei e una per eseguire la registrazione. Queste classi di intercettori devono derivare dalla DbCommandInterceptor
classe . In essi si scrivono override dei metodi che vengono chiamati automaticamente quando la query sta per essere eseguita. In questi metodi è possibile esaminare o registrare la query inviata al database ed è possibile modificare la query prima che venga inviata al database o restituire un elemento a Entity Framework senza nemmeno passare la query al database.
Per creare la classe dell'intercettore che registra ogni query SQL inviata al database, creare un file di classe denominato SchoolInterceptorLogging.cs nella cartella DAL e sostituire il codice del modello con il codice seguente:
using System; using System.Data.Common; using System.Data.Entity; using System.Data.Entity.Infrastructure.Interception; using System.Data.Entity.SqlServer; using System.Data.SqlClient; using System.Diagnostics; using System.Reflection; using System.Linq; using ContosoUniversity.Logging; namespace ContosoUniversity.DAL { public class SchoolInterceptorLogging : DbCommandInterceptor { private ILogger _logger = new Logger(); private readonly Stopwatch _stopwatch = new Stopwatch(); public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { base.ScalarExecuting(command, interceptionContext); _stopwatch.Restart(); } public override void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { _stopwatch.Stop(); if (interceptionContext.Exception != null) { _logger.Error(interceptionContext.Exception, "Error executing command: {0}", command.CommandText); } else { _logger.TraceApi("SQL Database", "SchoolInterceptor.ScalarExecuted", _stopwatch.Elapsed, "Command: {0}: ", command.CommandText); } base.ScalarExecuted(command, interceptionContext); } public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { base.NonQueryExecuting(command, interceptionContext); _stopwatch.Restart(); } public override void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { _stopwatch.Stop(); if (interceptionContext.Exception != null) { _logger.Error(interceptionContext.Exception, "Error executing command: {0}", command.CommandText); } else { _logger.TraceApi("SQL Database", "SchoolInterceptor.NonQueryExecuted", _stopwatch.Elapsed, "Command: {0}: ", command.CommandText); } base.NonQueryExecuted(command, interceptionContext); } public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { base.ReaderExecuting(command, interceptionContext); _stopwatch.Restart(); } public override void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { _stopwatch.Stop(); if (interceptionContext.Exception != null) { _logger.Error(interceptionContext.Exception, "Error executing command: {0}", command.CommandText); } else { _logger.TraceApi("SQL Database", "SchoolInterceptor.ReaderExecuted", _stopwatch.Elapsed, "Command: {0}: ", command.CommandText); } base.ReaderExecuted(command, interceptionContext); } } }
Per le query o i comandi riusciti, questo codice scrive un log delle informazioni con informazioni sulla latenza. Per le eccezioni, viene creato un log degli errori.
Per creare la classe dell'intercettore che genererà errori temporanei fittizi quando si immette "Throw" nella casella di ricerca , creare un file di classe denominato SchoolInterceptorTransientErrors.cs nella cartella DAL e sostituire il codice del modello con il codice seguente:
using System; using System.Data.Common; using System.Data.Entity; using System.Data.Entity.Infrastructure.Interception; using System.Data.Entity.SqlServer; using System.Data.SqlClient; using System.Diagnostics; using System.Reflection; using System.Linq; using ContosoUniversity.Logging; namespace ContosoUniversity.DAL { public class SchoolInterceptorTransientErrors : DbCommandInterceptor { private int _counter = 0; private ILogger _logger = new Logger(); public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { bool throwTransientErrors = false; if (command.Parameters.Count > 0 && command.Parameters[0].Value.ToString() == "%Throw%") { throwTransientErrors = true; command.Parameters[0].Value = "%an%"; command.Parameters[1].Value = "%an%"; } if (throwTransientErrors && _counter < 4) { _logger.Information("Returning transient error for command: {0}", command.CommandText); _counter++; interceptionContext.Exception = CreateDummySqlException(); } } private SqlException CreateDummySqlException() { // The instance of SQL Server you attempted to connect to does not support encryption var sqlErrorNumber = 20; var sqlErrorCtor = typeof(SqlError).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).Where(c => c.GetParameters().Count() == 7).Single(); var sqlError = sqlErrorCtor.Invoke(new object[] { sqlErrorNumber, (byte)0, (byte)0, "", "", "", 1 }); var errorCollection = Activator.CreateInstance(typeof(SqlErrorCollection), true); var addMethod = typeof(SqlErrorCollection).GetMethod("Add", BindingFlags.Instance | BindingFlags.NonPublic); addMethod.Invoke(errorCollection, new[] { sqlError }); var sqlExceptionCtor = typeof(SqlException).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).Where(c => c.GetParameters().Count() == 4).Single(); var sqlException = (SqlException)sqlExceptionCtor.Invoke(new object[] { "Dummy", errorCollection, null, Guid.NewGuid() }); return sqlException; } } }
Questo codice esegue solo l'override del
ReaderExecuting
metodo , chiamato per le query che possono restituire più righe di dati. Se si vuole controllare la resilienza della connessione per altri tipi di query, è anche possibile eseguire l'override deiNonQueryExecuting
metodi eScalarExecuting
, come avviee con l'intercettore di registrazione.Quando si esegue la pagina Student e si immette "Throw" come stringa di ricerca, questo codice crea un'eccezione fittizia database SQL per il numero di errore 20, un tipo noto in genere come temporaneo. Altri numeri di errore attualmente riconosciuti come temporanei sono 64, 233, 10053, 10054, 10060, 10928, 10929, 40197, 40501 e 40613, ma sono soggetti a modifiche nelle nuove versioni di database SQL.
Il codice restituisce l'eccezione a Entity Framework anziché eseguire la query e passare i risultati della query. L'eccezione temporanea viene restituita quattro volte e il codice viene ripristinato alla normale routine di passaggio della query al database.
Poiché tutti gli elementi vengono registrati, sarà possibile verificare che Entity Framework tenti di eseguire la query quattro volte prima di avere finalmente esito positivo e l'unica differenza nell'applicazione è che il rendering di una pagina con risultati della query richiede più tempo.
Numero di tentativi di configurazione di Entity Framework; il codice specifica quattro volte perché è il valore predefinito per il criterio di esecuzione database SQL. Se si modificano i criteri di esecuzione, è anche necessario modificare il codice qui che specifica il numero di volte in cui vengono generati errori temporanei. È anche possibile modificare il codice per generare altre eccezioni in modo che Entity Framework generi l'eccezione
RetryLimitExceededException
.Il valore immesso nella casella di ricerca sarà in
command.Parameters[0]
ecommand.Parameters[1]
(uno viene usato per il nome e uno per il cognome). Quando viene trovato il valore "%Throw%", "Throw" viene sostituito in tali parametri da "an" in modo che alcuni studenti vengano trovati e restituiti.Questo è solo un modo pratico per testare la resilienza della connessione in base alla modifica di un input all'interfaccia utente dell'applicazione. È anche possibile scrivere codice che genera errori temporanei per tutte le query o gli aggiornamenti, come illustrato più avanti nei commenti sul metodo DbInterception.Add .
In Global.asax aggiungere le istruzioni seguenti
using
:using ContosoUniversity.DAL; using System.Data.Entity.Infrastructure.Interception;
Aggiungere le righe evidenziate al
Application_Start
metodo :protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); DbInterception.Add(new SchoolInterceptorTransientErrors()); DbInterception.Add(new SchoolInterceptorLogging()); }
Queste righe di codice determinano l'esecuzione del codice dell'intercettore quando Entity Framework invia query al database. Si noti che poiché sono state create classi di intercettore separate per la simulazione e la registrazione degli errori temporanei, è possibile abilitarle e disabilitarle in modo indipendente.
È possibile aggiungere intercettori usando il
DbInterception.Add
metodo in qualsiasi punto del codice. Non è necessario che si trovi nelApplication_Start
metodo . Un'altra opzione consiste nell'inserire questo codice nella classe DbConfiguration creata in precedenza per configurare i criteri di esecuzione.public class SchoolConfiguration : DbConfiguration { public SchoolConfiguration() { SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy()); DbInterception.Add(new SchoolInterceptorTransientErrors()); DbInterception.Add(new SchoolInterceptorLogging()); } }
Ovunque si inserisca questo codice, prestare attenzione a non eseguire
DbInterception.Add
per lo stesso intercettatore più volte oppure si otterranno istanze di intercettatore aggiuntive. Ad esempio, se si aggiunge il intercettatore di registrazione due volte, verranno visualizzati due log per ogni query SQL.Gli intercettori vengono eseguiti nell'ordine di registrazione (l'ordine in cui viene chiamato il
DbInterception.Add
metodo). L'ordine potrebbe dipendere da ciò che si sta facendo nell'intercettatore. Ad esempio, un intercettatore potrebbe modificare il comando SQL che ottiene nellaCommandText
proprietà. Se cambia il comando SQL, l'intercettatore successivo otterrà il comando SQL modificato, non il comando SQL originale.È stato scritto il codice di simulazione degli errori temporanei in un modo che consente di causare errori temporanei immettendo un valore diverso nell'interfaccia utente. In alternativa, è possibile scrivere il codice dell'intercettatore per generare sempre la sequenza di eccezioni temporanee senza verificare la presenza di un determinato valore di parametro. È quindi possibile aggiungere l'intercettatore solo quando si desidera generare errori temporanei. Se si esegue questa operazione, tuttavia, non aggiungere l'intercettatore fino al completamento dell'inizializzazione del database. In altre parole, eseguire almeno un'operazione di database, ad esempio una query su uno dei set di entità prima di iniziare a generare errori temporanei. Entity Framework esegue diverse query durante l'inizializzazione del database e non vengono eseguite in una transazione, pertanto gli errori durante l'inizializzazione potrebbero causare l'inserimento del contesto in uno stato incoerente.
Testare la nuova configurazione
Premere F5 per eseguire l'applicazione in modalità di debug e quindi fare clic sulla scheda Studenti .
Esaminare la finestra Output di Visual Studio per visualizzare l'output della traccia. Potrebbe essere necessario scorrere verso l'alto in passato alcuni errori JavaScript per accedere ai log scritti dal logger.
Si noti che è possibile visualizzare le query SQL effettive inviate al database. Vengono visualizzate alcune query iniziali e comandi che Entity Framework esegue per iniziare, controllando la versione del database e la tabella della cronologia della migrazione (verranno illustrate le migrazioni nell'esercitazione successiva). Viene visualizzata una query per il paging, per scoprire quanti studenti sono presenti e infine viene visualizzata la query che ottiene i dati degli studenti.
Nella pagina Studenti immettere "Genera" come stringa di ricerca e fare clic su Cerca.
Si noterà che il browser sembra bloccarsi per diversi secondi mentre Entity Framework sta riprovando la query più volte. Il primo tentativo si verifica molto rapidamente, quindi l'attesa prima di aumentare prima di ogni nuovo tentativo aggiuntivo. Questo processo di attesa più lungo prima che ogni tentativo venga chiamato backoff esponenziale.
Quando viene visualizzata la pagina, che mostra gli studenti che hanno "un" nei loro nomi, guarda la finestra di output e si noterà che la stessa query è stata tentata cinque volte, la prima quattro volte restituisce eccezioni temporanee. Per ogni errore temporaneo verrà visualizzato il log scritto durante la generazione dell'errore temporaneo nella
SchoolInterceptorTransientErrors
classe ("Restituzione dell'errore temporaneo per il comando...") e verrà visualizzato il log scritto quandoSchoolInterceptorLogging
ottiene l'eccezione.Poiché è stata immessa una stringa di ricerca, la query che restituisce i dati degli studenti viene parametrizzata:
SELECT TOP (3) [Project1].[ID] AS [ID], [Project1].[LastName] AS [LastName], [Project1].[FirstMidName] AS [FirstMidName], [Project1].[EnrollmentDate] AS [EnrollmentDate] FROM ( SELECT [Project1].[ID] AS [ID], [Project1].[LastName] AS [LastName], [Project1].[FirstMidName] AS [FirstMidName], [Project1].[EnrollmentDate] AS [EnrollmentDate], row_number() OVER (ORDER BY [Project1].[LastName] ASC) AS [row_number] FROM ( SELECT [Extent1].[ID] AS [ID], [Extent1].[LastName] AS [LastName], [Extent1].[FirstMidName] AS [FirstMidName], [Extent1].[EnrollmentDate] AS [EnrollmentDate] FROM [dbo].[Student] AS [Extent1] WHERE ([Extent1].[LastName] LIKE @p__linq__0 ESCAPE N'~') OR ([Extent1].[FirstMidName] LIKE @p__linq__1 ESCAPE N'~') ) AS [Project1] ) AS [Project1] WHERE [Project1].[row_number] > 0 ORDER BY [Project1].[LastName] ASC:
Non si registra il valore dei parametri, ma è possibile farlo. Se si desidera visualizzare i valori dei parametri, è possibile scrivere codice di registrazione per ottenere i valori dei parametri dalla
Parameters
proprietà dell'oggettoDbCommand
ottenuto nei metodi di intercettatore.Si noti che non è possibile ripetere questo test a meno che non si arresti l'applicazione e la si riavvia. Se si vuole essere in grado di testare la resilienza della connessione più volte in un'unica esecuzione dell'applicazione, è possibile scrivere codice per reimpostare il contatore degli errori in
SchoolInterceptorTransientErrors
.Per visualizzare la differenza nella strategia di esecuzione (criteri di ripetizione dei tentativi), aggiungere un commento alla riga in SchoolConfiguration.cs, eseguire nuovamente la
SetExecutionStrategy
pagina Studenti in modalità di debug e cercare di nuovo "Throw".Questa volta il debugger si arresta nella prima eccezione generata immediatamente quando tenta di eseguire la query la prima volta.
Annullare ilcommento della riga SetExecutionStrategy in SchoolConfiguration.cs.
Ottenere il codice
Scaricare il progetto completato
Risorse aggiuntive
I collegamenti ad altre risorse di Entity Framework sono disponibili in ASP.NET Accesso ai dati - Risorse consigliate.
Passaggi successivi
In questa esercitazione:
- Resilienza della connessione abilitata
- Intercettazione dei comandi abilitata
- Test della nuova configurazione
Passare all'articolo successivo per informazioni sulle migrazioni code First e sulla distribuzione di Azure.