Sdílet prostřednictvím


Kurz: Použití odolnosti připojení a zachycování příkazů pomocí Entity Frameworku v aplikaci ASP.NET MVC

Dosud byla aplikace spuštěna místně v IIS Express na vašem vývojovém počítači. Pokud chcete zpřístupnit skutečnou aplikaci jiným uživatelům, aby ji mohli používat přes internet, musíte ji nasadit u poskytovatele webového hostingu a databázi nasadit na databázový server.

V tomto kurzu se naučíte používat odolnost připojení a zachycování příkazů. Jsou to dvě důležité funkce Entity Frameworku 6, které jsou zvlášť cenné při nasazování do cloudového prostředí: odolnost připojení (automatické pokusy o opakování přechodných chyb) a zachytávání příkazů (zachycení všech dotazů SQL odeslaných do databáze za účelem jejich protokolování nebo změny).

Tento kurz zachycování příkazů a odolnosti připojení je volitelný. Pokud tento kurz přeskočíte, bude potřeba v dalších kurzech provést několik menších úprav.

V tomto kurzu jste:

  • Povolení odolnosti připojení
  • Povolení zachycování příkazů
  • Otestování nové konfigurace

Požadavky

Povolení odolnosti připojení

Když nasadíte aplikaci do Windows Azure, nasadíte databázi do cloudové databázové služby Windows Azure SQL Database. Přechodné chyby připojení jsou obvykle častější, když se připojujete ke cloudové databázové službě, než když jsou webový server a databázový server přímo propojené ve stejném datovém centru. I když jsou cloudový webový server a cloudová databázová služba hostované ve stejném datacentru, existuje mezi nimi více síťových připojení, která můžou mít problémy, například nástroje pro vyrovnávání zatížení.

Cloudovou službu také obvykle sdílejí jiní uživatelé, což znamená, že její odezva může být ovlivněna. A váš přístup k databázi může podléhat omezování. Omezování znamená, že databázová služba vyvolá výjimky, když se k ní pokusíte přistupovat častěji, než je povoleno ve vaší smlouvě o úrovni služeb (SLA).

Mnoho nebo většina problémů s připojením při přístupu ke cloudové službě je přechodná, to znamená, že se vyřeší samy za krátkou dobu. Když se tedy pokusíte o operaci databáze a zobrazí se typ chyby, která je obvykle přechodná, můžete operaci zkusit znovu po krátkém čekání a operace může být úspěšná. Uživatelům můžete poskytnout mnohem lepší prostředí, pokud budete zpracovávat přechodné chyby automatickým pokusem znovu, takže většina z nich bude pro zákazníka neviditelná. Funkce odolnosti připojení v Entity Frameworku 6 automatizuje proces opakování neúspěšných dotazů SQL.

Funkce odolnosti připojení musí být správně nakonfigurovaná pro konkrétní databázovou službu:

  • Musí vědět, které výjimky budou pravděpodobně přechodné. Chcete opakovat chyby způsobené například dočasnou ztrátou připojení k síti, nikoli chybami způsobenými chybami programu.
  • Mezi opakováním neúspěšné operace musí čekat přiměřenou dobu. Mezi opakováními dávkového procesu můžete čekat déle než u online webové stránky, kde uživatel čeká na odpověď.
  • Před tím, než se zopakuje, se musí opakovat. V dávkovém procesu můžete chtít opakovat vícekrát, než v online aplikaci.

Tato nastavení můžete nakonfigurovat ručně pro jakékoli databázové prostředí podporované zprostředkovatelem Entity Framework, ale výchozí hodnoty, které obvykle fungují dobře pro online aplikaci, která používá Windows Azure SQL Database, už jsou nakonfigurované. To jsou nastavení, která implementujete pro aplikaci Contoso University.

K povolení odolnosti připojení stačí vytvořit třídu, která je odvozená od třídy DbConfiguration, a v této třídě nastavit strategii provádění SQL Database, což je v EF jiný termín pro zásadu opakování.

  1. Do složky DAL přidejte soubor třídy s názvem SchoolConfiguration.cs.

  2. Kód šablony nahraďte následujícím kódem:

    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 automaticky spustí kód, který najde ve třídě, která je odvozená z DbConfiguration. Pomocí třídy můžete DbConfiguration provádět konfigurační úlohy v kódu, které byste jinak udělali v souboruWeb.config . Další informace najdete v tématu EntityFramework Code-Based Configuration.

  3. V souboru StudentController.cs přidejte using příkaz pro System.Data.Entity.Infrastructure.

    using System.Data.Entity.Infrastructure;
    
  4. Změňte všechny catch bloky, které zachytává DataException výjimky, aby místo nich zachytávali RetryLimitExceededException výjimky. Příklad:

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

    Pomocí DataException příkazu jste se pokusili identifikovat chyby, které by mohly být přechodné, aby se zobrazila popisná zpráva "zkuste to znovu". Teď, když jste zapnuli zásadu opakování, se už několikrát vyzkoušely a selhaly pouze chyby, které jsou pravděpodobně přechodné. Skutečná vrácená výjimka se zabalí do RetryLimitExceededException výjimky.

Další informace najdete v tématu Logika opakování a odolnosti připojení Entity Framework.

Povolení zachycování příkazů

Teď, když jste zapnuli zásadu opakování, jak otestujete, abyste ověřili, že fungují podle očekávání? Není tak snadné vynutit, aby došlo k přechodné chybě, zejména když spouštíte místně, a zvlášť obtížné by bylo integrovat skutečné přechodné chyby do automatizovaného testu jednotek. K otestování funkce odolnosti připojení potřebujete způsob, jak zachytit dotazy, které Entity Framework odesílá do SQL Server, a nahradit odpověď SQL Server typem výjimky, která je obvykle přechodná.

Zachytávání dotazů můžete použít také k implementaci osvědčeného postupu pro cloudové aplikace: protokolování latence a úspěchu nebo selhání všech volání externích služeb , jako jsou databázové služby. EF6 poskytuje vyhrazené rozhraní API pro protokolování , které může usnadnit protokolování, ale v této části kurzu se dozvíte, jak přímo používat funkci zachycování entity frameworku, a to jak pro protokolování, tak pro simulaci přechodných chyb.

Vytvoření protokolovací rozhraní a třídy

Osvědčeným postupem pro protokolování je použití rozhraní místo pevného kódování volání System.Diagnostics.Trace nebo třídy protokolování. To usnadňuje pozdější změnu mechanismu protokolování, pokud byste to někdy potřebovali. V této části tedy vytvoříte protokolovací rozhraní a třídu pro jeho implementaci./p>

  1. Vytvořte složku v projektu a pojmenujte ji Protokolování.

  2. Ve složce Protokolování vytvořte soubor třídy s názvem ILogger.cs a nahraďte kód šablony následujícím kódem:

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

    Rozhraní poskytuje tři úrovně trasování, které označují relativní důležitost protokolů, a jednu úroveň určenou k poskytování informací o latenci pro volání externích služeb, jako jsou databázové dotazy. Metody protokolování mají přetížení, která umožňují předat výjimku. Je to proto, aby informace o výjimce, včetně trasování zásobníku a vnitřní výjimky, jsou spolehlivě protokolovány třídou, která implementuje rozhraní, místo toho, aby se spoléhalo na to, co se provádí v každém volání metody protokolování v celé aplikaci.

    Metody TraceApi umožňují sledovat latenci každého volání externí služby, jako je SQL Database.

  3. Ve složce Protokolování vytvořte soubor třídy s názvem Logger.cs a nahraďte kód šablony následujícím kódem:

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

    Implementace používá System.Diagnostics k trasování. Jedná se o integrovanou funkci rozhraní .NET, která usnadňuje generování a používání trasovacích informací. S trasováním System.Diagnostics můžete použít mnoho "naslouchacích procesů", například k zápisu protokolů do souborů nebo k jejich zápisu do úložiště objektů blob v Azure. Další informace najdete v tématu Řešení potíží s weby Azure v sadě Visual Studio, kde najdete některé možnosti a odkazy na další zdroje informací. V tomto kurzu se na protokoly podíváte jenom v okně Výstup sady Visual Studio.

    V produkční aplikaci můžete zvážit trasování balíčků jiných než System.Diagnostics a rozhraní ILogger umožňuje poměrně snadno přepnout na jiný mechanismus trasování, pokud se to rozhodnete.

Vytvoření tříd zachytávání

Dále vytvoříte třídy, které bude Entity Framework volat pokaždé, když se chystá odeslat dotaz do databáze, jednu pro simulaci přechodných chyb a jednu pro protokolování. Tyto třídy zachytávání musí být odvozeny DbCommandInterceptor od třídy . V nich můžete psát přepsání metod, které se automaticky volají, když se dotaz spustí. V těchto metodách můžete prozkoumat nebo protokolovat dotaz, který se odesílá do databáze, a můžete změnit dotaz před jeho odesláním do databáze nebo něco vrátit do Entity Frameworku sami, aniž byste dotaz předali do databáze.

  1. Pokud chcete vytvořit třídu interceptoru, která bude protokolovat každý dotaz SQL odeslaný do databáze, vytvořte ve složce DAL soubor třídy SchoolInterceptorLogging.cs a nahraďte kód šablony následujícím kódem:

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

    V případě úspěšných dotazů nebo příkazů tento kód zapíše informační protokol s informacemi o latenci. V případě výjimek vytvoří protokol chyb.

  2. Pokud chcete vytvořit třídu interceptoru, která bude generovat fiktivní přechodné chyby, když do vyhledávacího pole zadáte "Throw", vytvořte ve složce DAL soubor třídy SchoolInterceptorTransientErrors.cs a nahraďte kód šablony následujícím kódem:

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

    Tento kód pouze přepíše metodu ReaderExecuting , která je volána pro dotazy, které mohou vrátit více řádků dat. Pokud byste chtěli zkontrolovat odolnost připojení u jiných typů dotazů, můžete také přepsat NonQueryExecuting metody a ScalarExecuting , jak to dělá zachytávací nástroj protokolování.

    Když spustíte stránku Student a jako hledaný řetězec zadáte "Throw", tento kód vytvoří fiktivní SQL Database výjimku pro chybu s číslem 20, což je typ známý jako obvykle přechodný. Další čísla chyb, která se v současné době rozpoznávají jako přechodná, jsou 64, 233, 10053, 10054, 10060, 10928, 10929, 40197, 40501 a 40613, ale v nových verzích SQL Database se můžou změnit.

    Kód vrátí výjimku do Entity Frameworku místo spuštění dotazu a předání výsledků dotazu zpět. Přechodná výjimka se vrátí čtyřikrát a pak se kód vrátí k normálnímu postupu předání dotazu do databáze.

    Vzhledem k tomu, že se všechno protokoluje, uvidíte, že se Entity Framework pokusí dotaz spustit čtyřikrát, než se nakonec úspěšně provede. Jediným rozdílem v aplikaci je to, že vykreslení stránky s výsledky dotazu trvá déle.

    Počet opakování Entity Frameworku je konfigurovatelný. kód zadá čtyřikrát, protože to je výchozí hodnota pro zásady spouštění SQL Database. Pokud změníte zásady spouštění, změníte také kód, který určuje, kolikrát se generují přechodné chyby. Kód můžete také změnit tak, aby vygeneroval další výjimky, aby entity Framework výjimku vyvolalo RetryLimitExceededException .

    Hodnota, kterou zadáte do vyhledávacího pole, bude v command.Parameters[0] a command.Parameters[1] (jedna se použije pro křestní jméno a jedna pro příjmení). Když se najde hodnota %Throw%, nahradí se hodnota Throw v těchto parametrech řetězcem "an", aby se našli a vrátili někteří studenti.

    Jedná se pouze o pohodlný způsob, jak otestovat odolnost připojení na základě změny určitého vstupu do uživatelského rozhraní aplikace. Můžete také napsat kód, který generuje přechodné chyby pro všechny dotazy nebo aktualizace, jak je vysvětleno dále v komentářích k metodě DbInterception.Add .

  3. V souboru Global.asax přidejte následující using příkazy:

    using ContosoUniversity.DAL;
    using System.Data.Entity.Infrastructure.Interception;
    
  4. Přidejte zvýrazněné řádky do Application_Start metody :

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

    Tyto řádky kódu způsobují, že se kód zachycovače spustí, když Entity Framework odesílá dotazy do databáze. Všimněte si, že vzhledem k tomu, že jste vytvořili samostatné třídy zachytávání pro simulaci a protokolování přechodných chyb, můžete je nezávisle povolit a zakázat.

    Zachytávací moduly můžete přidat pomocí DbInterception.Add metody kdekoli v kódu; nemusí být v Application_Start metodě . Další možností je vložit tento kód do třídy DbConfiguration, kterou jste vytvořili dříve za účelem konfigurace zásad spouštění.

    public class SchoolConfiguration : DbConfiguration
    {
        public SchoolConfiguration()
        {
            SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy());
            DbInterception.Add(new SchoolInterceptorTransientErrors());
            DbInterception.Add(new SchoolInterceptorLogging());
        }
    }
    

    Bez ohledu na to, kam tento kód vložíte, dávejte pozor, abyste nespustí DbInterception.Add pro stejný zachytávací objekt více než jednou, jinak získáte další instance zachytávání. Pokud například dvakrát přidáte zachytávání protokolování, zobrazí se dva protokoly pro každý dotaz SQL.

    Zachytávací moduly se spouštějí v pořadí registrace (pořadí, ve kterém DbInterception.Add je metoda volána). Pořadí může záviset na tom, co v zachytávacím zařízení děláte. Zachytávací modul může například změnit příkaz SQL, který získá ve CommandText vlastnosti. Pokud se příkaz SQL změní, další zachytávací modul získá změněný příkaz SQL, nikoli původní příkaz SQL.

    Kód simulace přechodných chyb jste napsali způsobem, který umožňuje způsobovat přechodné chyby zadáním jiné hodnoty v uživatelském rozhraní. Alternativně můžete napsat kód interceptoru, který vždy vygeneruje sekvenci přechodných výjimek bez kontroly konkrétní hodnoty parametru. Zachytávání pak můžete přidat pouze v případě, že chcete generovat přechodné chyby. Pokud to ale uděláte, nepřidávejte zachytávání až po dokončení inicializace databáze. Jinými slovy, než začnete generovat přechodné chyby, proveďte alespoň jednu operaci databáze, například dotaz na jednu ze sad entit. Entity Framework spouští několik dotazů během inicializace databáze a nejsou spuštěny v transakci, takže chyby během inicializace mohou způsobit, že kontext přejde do nekonzistentního stavu.

Otestování nové konfigurace

  1. Stisknutím klávesy F5 spusťte aplikaci v režimu ladění a potom klikněte na kartu Studenti .

  2. Výstup trasování najdete v okně Výstup sady Visual Studio. Možná se budete muset posunout nahoru za některé chyby JavaScriptu, abyste se dostali k protokolům zapsaným protokolovacím nástrojem.

    Všimněte si, že vidíte skutečné dotazy SQL odeslané do databáze. Uvidíte několik počátečních dotazů a příkazů, které Entity Framework provede, abyste mohli začít kontrolovat verzi databáze a tabulku historie migrace (o migracích se dozvíte v dalším kurzu). A uvidíte dotaz pro stránkování, abyste zjistili, kolik studentů existuje, a nakonec uvidíte dotaz, který získá data studentů.

    Protokolování pro normální dotaz

  3. Na stránce Studenti zadejte jako hledaný řetězec "Throw" a klikněte na Hledat.

    Vyvolání vyhledávacího řetězce

    Všimněte si, že se zdá, že prohlížeč několik sekund zablokuje, zatímco Entity Framework několikrát opakuje dotaz. První opakování proběhne velmi rychle a pak se čekání před každým dalším opakováním zvýší. Tento proces delšího čekání před každým opakováním se nazývá exponenciální zpochybnění.

    Když se zobrazí stránka zobrazující studenty, kteří mají ve svých jménech "an", podívejte se do okna výstupu a uvidíte, že se o stejný dotaz pokusili pětkrát. První čtyřikrát vrací přechodné výjimky. U každé přechodné chyby se zobrazí protokol, který zapíšete při generování přechodné chyby ve SchoolInterceptorTransientErrors třídě ("Vrací se přechodná chyba pro příkaz..."), a protokol se zapíše, když SchoolInterceptorLogging dojde k výjimce.

    Protokolování výstupu se zobrazením opakovaných pokusů

    Vzhledem k tomu, že jste zadali hledaný řetězec, je dotaz, který vrací data studentů, parametrizován:

    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:
    

    Nepíšete hodnotu parametrů, ale můžete to udělat. Pokud chcete zobrazit hodnoty parametrů, můžete napsat kód protokolování, který získá hodnoty parametrů z Parameters vlastnosti objektu DbCommand , kterou získáte v metodách interceptoru.

    Upozorňujeme, že tento test nemůžete opakovat, dokud nezastavíte aplikaci a nerestartujete ji. Pokud byste chtěli být schopni několikrát otestovat odolnost připojení při jednom spuštění aplikace, mohli byste napsat kód pro resetování čítače chyb v SchoolInterceptorTransientErrorsnástroji .

  4. Pokud chcete zjistit rozdíl, který strategie provádění (zásady opakování) dělá, zakomentujte SetExecutionStrategy řádek v souboru SchoolConfiguration.cs, znovu spusťte stránku Studenti v režimu ladění a znovu vyhledejte "Throw".

    Tentokrát se ladicí program zastaví na první vygenerované výjimce okamžitě při prvním pokusu o spuštění dotazu.

    Fiktivní výjimka

  5. Zrušte komentář řádku SetExecutionStrategy v souboru SchoolConfiguration.cs.

Získání kódu

Stáhnout dokončený projekt

Další materiály

Odkazy na další prostředky Entity Framework najdete v tématu ASP.NET Data Access – Doporučené zdroje informací.

Další kroky

V tomto kurzu jste:

  • Povolená odolnost připojení
  • Povolené zachycování příkazů
  • Otestovali novou konfiguraci.

V dalším článku se dozvíte o migracích Code First a nasazení Azure.