Resilienza della connessione e intercettazione dei comandi di Web Forms ASP.NET

di Erik Reitan

In questa esercitazione si modificherà l'applicazione di esempio Wingtip Toys per supportare la resilienza della connessione e l'intercettazione dei comandi. Abilitando la resilienza della connessione, l'applicazione di esempio Wingtip Toys ritenta automaticamente le chiamate ai dati quando si verificano errori temporanei tipici di un ambiente cloud. Implementando anche l'intercettazione dei comandi, l'applicazione di esempio Wingtip Toys intercetterà tutte le query SQL inviate al database per registrarle o modificarle.

Nota

Questa esercitazione Web Forms è basata sull'esercitazione MVC seguente di Tom Dykstra:
Resilienza della connessione e intercettazione dei comandi con Entity Framework in un'applicazione MVC ASP.NET

Contenuto dell'esercitazione:

  • Come garantire la resilienza della connessione.
  • Come implementare l'intercettazione dei comandi.

Prerequisiti

Prima di iniziare, assicurarsi di avere installato il software seguente nel computer:

Resilienza delle connessioni

Quando si valuta la possibilità di distribuire un'applicazione in Windows Azure, è consigliabile distribuire il database in WindowsAzure 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 che si verificano 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:

  1. 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.
  2. 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.
  3. È 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.

Tutto ciò che è necessario fare per abilitare la resilienza della connessione è creare una classe nell'assembly che deriva dalla DbConfiguration classe e in tale classe impostare la strategia di esecuzione database SQL, che in Entity Framework è un altro termine per i criteri di ripetizione dei tentativi.

Implementazione della resilienza delle connessioni

  1. Scaricare e aprire l'applicazione wingtipToys di esempio Web Forms in Visual Studio.

  2. Nella cartella Logic dell'applicazione WingtipToys aggiungere un file di classe denominato WingtipToysConfiguration.cs.

  3. Sostituire il codice esistente con quello riportato di seguito:

    using System.Data.Entity;
    using System.Data.Entity.SqlServer;
     
    namespace WingtipToys.Logic
    {
        public class WingtipToysConfiguration : DbConfiguration
        {
            public WingtipToysConfiguration()
            {
              SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy());
            }
        }
    }
    

Entity Framework esegue automaticamente il codice trovato in una classe che deriva da DbConfiguration. È possibile usare la DbConfiguration classe per eseguire attività di configurazione nel codice che altrimenti si farebbe nel file Web.config . Per altre informazioni, vedere EntityFramework Code-Based Configuration.

  1. Nella cartella Logic aprire il file AddProducts.cs .

  2. Aggiungere un'istruzione using per System.Data.Entity.Infrastructure come illustrato in giallo:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using WingtipToys.Models;
    using System.Data.Entity.Infrastructure;
    
  3. Aggiungere un catch blocco al AddProduct metodo in modo che venga RetryLimitExceededException registrato come evidenziato in giallo:

    public bool AddProduct(string ProductName, string ProductDesc, string ProductPrice, string ProductCategory, string ProductImagePath)
    {
        var myProduct = new Product();
        myProduct.ProductName = ProductName;
        myProduct.Description = ProductDesc;
        myProduct.UnitPrice = Convert.ToDouble(ProductPrice);
        myProduct.ImagePath = ProductImagePath;
        myProduct.CategoryID = Convert.ToInt32(ProductCategory);
    
        using (ProductContext _db = new ProductContext())
        {
            // Add product to DB.
            _db.Products.Add(myProduct);
            try
            {
                _db.SaveChanges();
            }
            catch (RetryLimitExceededException ex)
            {
                // Log the RetryLimitExceededException.
                WingtipToys.Logic.ExceptionUtility.LogException(ex, "Error: RetryLimitExceededException -> RemoveProductButton_Click in AdminPage.aspx.cs");
            }
        }
        // Success.
        return true;
    }
    

Aggiungendo l'eccezione RetryLimitExceededException , è possibile fornire una registrazione migliore o visualizzare un messaggio di errore all'utente in cui è possibile scegliere di ritentare il processo. Rilevando l'eccezione RetryLimitExceededException , è probabile che gli unici errori siano già stati provati e non riusciti più volte. L'eccezione effettiva restituita verrà sottoposta a wrapping nell'eccezione RetryLimitExceededException . Inoltre, è stato aggiunto anche un blocco catch generale. Per altre informazioni sull'eccezione, vedere Entity Framework Connection Resiliency/Retry Logic.For more information about theRetryLimitExceededException exception, see Entity Framework Connection Resiliency/Retry Logic.

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.

In questa sezione dell'esercitazione si userà 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'eseguire questa operazione usando un interface oggetto anziché le 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.

In base alla procedura precedente, è stata scaricata e aperta l'applicazione di esempio WingtipToys in Visual Studio.

  1. Creare una cartella nel progetto WingtipToys e denominarla Logging.

  2. Nella cartella Logging creare un file di classe denominato ILogger.cs e sostituire il codice predefinito con il codice seguente:

    using System;
     
    namespace WingtipToys.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 TraceApi metodi consentono di tenere traccia della latenza di ogni chiamata a un servizio esterno, ad esempio database SQL.

  3. Nella cartella Logging creare un file di classe denominato Logger.cs e sostituire il codice predefinito con il codice seguente:

    using System;
    using System.Diagnostics;
    using System.Text;
     
    namespace WingtipToys.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)
        {
          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 System.Diagnostics la traccia, per scrivere log nei file, ad esempio, o per scriverli nell'archivio BLOB in Windows Azure. Per altre informazioni, vedere alcune delle opzioni e collegamenti ad altre risorse in Risoluzione dei problemi relativi ai siti Web di Windows Azure in Visual Studio. Per questa esercitazione verranno esaminati solo i log nella finestra Output di Visual Studio.

In un'applicazione di produzione è consigliabile usare framework di traccia diversi System.Diagnosticsda 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.

  1. Per creare la classe dell'intercettore che registra ogni query SQL prima che venga inviata al database, creare un file di classe denominato InterceptorLogging.cs nella cartella Logic e sostituire il codice predefinito 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 WingtipToys.Logging;
    
    namespace WingtipToys.Logic
    {
      public class InterceptorLogging : 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", "Interceptor.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", "Interceptor.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", "Interceptor.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.

  2. Per creare la classe dell'intercettore che genererà errori temporanei fittizi quando si immette "Throw" nella casella di testo Name (Genera) nella pagina denominata AdminPage.aspx, creare un file di classe denominato InterceptorTransientErrors.cs nella cartella Logic e sostituire il codice predefinito 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 WingtipToys.Logging;
     
    namespace WingtipToys.Logic
    {
      public class InterceptorTransientErrors : 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 = "TransientErrorExample";
            command.Parameters[1].Value = "TransientErrorExample";
          }
     
          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 dei NonQueryExecuting metodi e ScalarExecuting , come avviee con l'intercettore di registrazione.

    Successivamente, si accede come "Amministrazione" e si seleziona il collegamento Amministrazione nella barra di spostamento superiore. Quindi, nella pagina AdminPage.aspx si aggiungerà un prodotto denominato "Throw". Il codice crea un'eccezione fittizia database SQL per il numero di errore 20, un tipo noto per essere in genere 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 prodotto verrà rinominato in "TransientErrorExample", che è possibile seguire nel codice del file InterceptorTransientErrors.cs .

    Il codice restituisce l'eccezione a Entity Framework anziché eseguire la query e passare i risultati indietro. 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 .

  3. In Global.asax aggiungere le istruzioni using seguenti:

    using System.Data.Entity.Infrastructure.Interception;
    
  4. Aggiungere quindi le righe evidenziate al Application_Start metodo :

    void Application_Start(object sender, EventArgs e)
    {
        // Code that runs on application startup
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    
        // Initialize the product database.
        Database.SetInitializer(new ProductDatabaseInitializer());
    
        // Create administrator role and user.
        RoleActions roleActions = new RoleActions();
        roleActions.createAdmin();
    
        // Add Routes.
        RegisterRoutes(RouteTable.Routes);
    
        // Logging.
        DbInterception.Add(new InterceptorTransientErrors());
        DbInterception.Add(new InterceptorLogging());
      
    }
    

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 nel Application_Start metodo . Un'altra opzione, se nel metodo non sono stati aggiunti intercettori Application_Start , consiste nell'aggiornare o aggiungere la classe denominata WingtipToysConfiguration.cs e inserire il codice precedente alla fine del costruttore della WingtipToysConfiguration classe .

Ovunque si inserisca questo codice, prestare attenzione a non eseguire DbInterception.Add più volte lo stesso intercettore oppure si otterranno altre istanze dell'intercettore. Ad esempio, se si aggiunge l'intercettore 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 può dipendere da ciò che stai facendo nell'intercettatore. Ad esempio, un intercettore potrebbe modificare il comando SQL che ottiene nella CommandText proprietà . Se cambia il comando SQL, l'intercettore successivo otterrà il comando SQL modificato, non il comando SQL originale.

Il codice di simulazione degli errori temporanei è stato scritto in modo da causare errori temporanei immettendo un valore diverso nell'interfaccia utente. In alternativa, è possibile scrivere il codice dell'intercettore per generare sempre la sequenza di eccezioni temporanee senza verificare la presenza di un valore di parametro specifico. È quindi possibile aggiungere l'intercettore solo quando si desidera generare errori temporanei. In questo caso, tuttavia, non aggiungere l'intercettore 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'incoerenza del contesto.

Testare la registrazione e la resilienza delle connessioni

  1. In Visual Studio premere F5 per eseguire l'applicazione in modalità di debug e quindi accedere come "Amministrazione" usando "Pa$$word" come password.

  2. Selezionare Amministrazione nella barra di spostamento in alto.

  3. Immettere un nuovo prodotto denominato "Throw" con la descrizione, il prezzo e il file di immagine appropriati.

  4. Premere il pulsante Aggiungi prodotto .
    Si noterà che il browser sembra bloccarsi per diversi secondi mentre Entity Framework sta ritentando la query più volte. Il primo tentativo viene eseguito molto rapidamente, quindi l'attesa aumenta prima di ogni nuovo tentativo aggiuntivo. Questo processo di attesa più lungo prima che ogni nuovo tentativo venga chiamato backoff esponenziale .

  5. Attendere che la pagina non tenti più di caricare.

  6. Arrestare il progetto ed esaminare la finestra Output di Visual Studio per visualizzare l'output della traccia. È possibile trovare la finestra Output selezionando Debug ->Windows ->Output. Potrebbe essere necessario scorrere oltre diversi altri log scritti dal logger.

    Si noti che è possibile visualizzare le query SQL effettive inviate al database. Vengono visualizzate alcune query e comandi iniziali che Entity Framework esegue per iniziare, controllando la tabella della cronologia della migrazione e della versione del database.
    Finestra di output
    Si noti che non è possibile ripetere questo test a meno che l'applicazione non venga arrestata e riavviata. Se si vuole poter testare la resilienza della connessione più volte in una singola esecuzione dell'applicazione, è possibile scrivere codice per reimpostare il contatore degli errori in InterceptorTransientErrors .

  7. Per vedere la differenza tra la strategia di esecuzione (criteri di ripetizione dei tentativi), impostare come commento la SetExecutionStrategy riga nel file WingtipToysConfiguration.cs nella cartella Logic, eseguire di nuovo la pagina Amministrazione in modalità di debug e aggiungere di nuovo il prodotto denominato "Throw".

    Questa volta il debugger si arresta immediatamente alla prima eccezione generata quando tenta di eseguire la query la prima volta.
    Debug - Visualizzare i dettagli

  8. Rimuovere il commento dalla SetExecutionStrategy riga nel file WingtipToysConfiguration.cs .

Riepilogo

In questa esercitazione è stato illustrato come modificare un'applicazione di esempio Web Forms per supportare la resilienza della connessione e l'intercettazione dei comandi.

Passaggi successivi

Dopo aver esaminato la resilienza della connessione e l'intercettazione dei comandi in Web Forms ASP.NET, esaminare l'argomento metodi asincroni Web Forms ASP.NET in ASP.NET 4.5. L'argomento illustra le nozioni di base per la compilazione di un'applicazione Web Forms ASP.NET asincrona con Visual Studio.