Öğretici: ASP.NET MVC uygulamasında Entity Framework ile bağlantı dayanıklılığını ve komut kesmeyi kullanma

Şimdiye kadar uygulama geliştirme bilgisayarınızdaki IIS Express yerel olarak çalışıyor. Gerçek bir uygulamayı diğer kişilerin İnternet üzerinden kullanabilmesi için bir web barındırma sağlayıcısına dağıtmanız ve veritabanını bir veritabanı sunucusuna dağıtmanız gerekir.

Bu öğreticide bağlantı dayanıklılığını ve komut kesmeyi kullanmayı öğreneceksiniz. Bunlar, özellikle bulut ortamına dağıtım yaparken değerli olan iki önemli Entity Framework 6 özelliğidir: bağlantı dayanıklılığı (geçici hatalar için otomatik yeniden denemeler) ve komut kesme (bunları günlüğe kaydetmek veya değiştirmek için veritabanına gönderilen tüm SQL sorgularını yakalayın).

Bu bağlantı dayanıklılığı ve komut kesme öğreticisi isteğe bağlıdır. Bu öğreticiyi atlarsanız, sonraki öğreticilerde birkaç küçük ayarlama yapılması gerekir.

Bu öğreticide şunları yaptınız:

  • Bağlantı dayanıklılığını etkinleştirme
  • Komut kesmeyi etkinleştirme
  • Yeni yapılandırmayı test etme

Önkoşullar

Bağlantı dayanıklılığını etkinleştirme

Uygulamayı Windows Azure'a dağıttığınızda, veritabanını bulut veritabanı hizmeti olan Windows Azure SQL Veritabanı'na dağıtırsınız. Geçici bağlantı hataları genellikle bir bulut veritabanı hizmetine bağlandığınızda, web sunucunuzla veritabanı sunucunuzun aynı veri merkezinde doğrudan birbirine bağlanmasına göre daha sık görülür. Bulut web sunucusu ve bulut veritabanı hizmeti aynı veri merkezinde barındırılıyor olsa bile, aralarında yük dengeleyiciler gibi sorunlarla karşılaşabilecek daha fazla ağ bağlantısı vardır.

Ayrıca bulut hizmeti genellikle diğer kullanıcılar tarafından paylaşılır ve bu da yanıt hızının onlardan etkilenebileceği anlamına gelir. Ayrıca veritabanına erişiminiz azaltmaya tabi olabilir. Azaltma, veritabanı hizmetinin hizmet Düzeyi Sözleşmenizde (SLA) izin verilenden daha sık erişmeye çalıştığınızda özel durumlar oluşturacakları anlamına gelir.

Bir bulut hizmetine erişirken karşılaşılan bağlantı sorunlarının çoğu veya çoğu geçicidir, yani kısa bir süre içinde kendilerini çözerler. Bu nedenle, bir veritabanı işlemini denediğinizde ve genellikle geçici bir hata türü aldığınızda, kısa bir beklemeden sonra işlemi yeniden deneyebilirsiniz ve işlem başarılı olabilir. Geçici hataları otomatik olarak yeniden deneyerek ve çoğunu müşteri tarafından görünmez hale getirerek işlerseniz kullanıcılarınız için çok daha iyi bir deneyim sağlayabilirsiniz. Entity Framework 6'daki bağlantı dayanıklılığı özelliği, başarısız SQL sorgularını yeniden deneme işlemini otomatikleştirir.

Bağlantı dayanıklılığı özelliği, belirli bir veritabanı hizmeti için uygun şekilde yapılandırılmalıdır:

  • Hangi özel durumların geçici olabileceğini bilmesi gerekir. Örneğin, program hatalarının neden olduğu hataları değil, ağ bağlantısındaki geçici bir kaybın neden olduğu hataları yeniden denemek istiyorsunuz.
  • Başarısız bir işlemin yeniden denemeleri arasında uygun bir süre beklemesi gerekir. Toplu işlem için yeniden denemeler arasında, kullanıcının yanıt beklediği çevrimiçi bir web sayfası için beklemekten daha uzun süre bekleyebilirsiniz.
  • Vazgeçmeden önce uygun sayıda yeniden denemesi gerekir. Bir toplu işlemde daha fazla kez yeniden denemek isteyebilirsiniz ve bunu çevrimiçi bir uygulamada yapabilirsiniz.

Bir Entity Framework sağlayıcısı tarafından desteklenen herhangi bir veritabanı ortamı için bu ayarları el ile yapılandırabilirsiniz, ancak Genellikle Windows Azure SQL Veritabanı kullanan bir çevrimiçi uygulama için iyi çalışan varsayılan değerler sizin için zaten yapılandırılmıştır ve bunlar Contoso University uygulaması için uygulayabileceğiniz ayarlardır.

Bağlantı dayanıklılığını etkinleştirmek için yapmanız gereken tek şey, derlemenizde DbConfiguration sınıfından türetilen bir sınıf oluşturmak ve bu sınıfta SQL Veritabanı yürütme stratejisini ayarlamaktır. Bu da EF'te yeniden deneme ilkesi için başka bir terimdir.

  1. DAL klasörüne SchoolConfiguration.cs adlı bir sınıf dosyası ekleyin.

  2. Şablon kodunu aşağıdaki kodla değiştirin:

    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, içinden türetilen DbConfigurationbir sınıfta bulduğu kodu otomatik olarak çalıştırır. sınıfını DbConfiguration kullanarak Web.config dosyasında gerçekleştirdiğiniz yapılandırma görevlerini kodda gerçekleştirebilirsiniz. Daha fazla bilgi için bkz . EntityFramework Code-Based Yapılandırması.

  3. StudentController.cs dosyasına için System.Data.Entity.Infrastructurebir using deyim ekleyin.

    using System.Data.Entity.Infrastructure;
    
  4. Bunun yerine özel durumları yakalayacak şekilde özel durumları yakalayan DataExceptionRetryLimitExceededException tüm catch blokları değiştirin. Örnek:

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

    Kolay bir "yeniden deneyin" iletisi vermek için geçici olabilecek hataları belirlemeye çalışmak için kullanıyordunuz DataException . Ancak bir yeniden deneme ilkesini açtığınıza göre geçici olma olasılığı olan tek hatalar zaten birkaç kez denenip başarısız olacaktır ve döndürülen gerçek özel durum özel durumda sarmalanır RetryLimitExceededException .

Daha fazla bilgi için bkz . Entity Framework Bağlantı Dayanıklılığı / Yeniden Deneme Mantığı.

Komut kesmeyi etkinleştirme

Bir yeniden deneme ilkesini açtığınıza göre, beklendiği gibi çalıştığını doğrulamak için nasıl test edebilirsiniz? Özellikle yerel olarak çalışırken geçici bir hatanın gerçekleşmesini zorlamak o kadar kolay değildir ve gerçek geçici hataları otomatik birim testiyle tümleştirmek özellikle zor olabilir. Bağlantı dayanıklılığı özelliğini test etmek için Entity Framework'ün SQL Server gönderdiği sorguları kesmenin ve SQL Server yanıtı genellikle geçici bir özel durum türüyle değiştirmenin bir yoluna ihtiyacınız vardır.

Bulut uygulamaları için en iyi yöntemi uygulamak için sorgu kesme özelliğini de kullanabilirsiniz: veritabanı hizmetleri gibi dış hizmetlere yapılan tüm çağrıların gecikmesini ve başarısını veya başarısızlığını günlüğe kaydetme . EF6, günlüğe kaydetmeyi kolaylaştırabilecek ayrılmış bir günlüğe kaydetme API'si sağlar, ancak öğreticinin bu bölümünde hem günlüğe kaydetme hem de geçici hataların benzetimini yapmak için Entity Framework'ün kesme özelliğini doğrudan kullanmayı öğreneceksiniz.

Günlük arabirimi ve sınıfı oluşturma

Günlüğe kaydetmeye yönelik en iyi yöntem, System.Diagnostics.Trace veya günlük sınıfına yönelik sabit kodlama çağrıları yerine bir arabirim kullanarak yapmaktır. Bu, daha sonra bunu yapmanız gerekirse günlüğe kaydetme mekanizmanızı değiştirmeyi kolaylaştırır. Bu nedenle bu bölümde günlük arabirimini ve bunu uygulamak için bir sınıf oluşturacaksınız./p>

  1. Projede bir klasör oluşturun ve bunu Günlüğe Kaydetme olarak adlandırın.

  2. Günlük klasöründe ILogger.cs adlı bir sınıf dosyası oluşturun ve şablon kodunu aşağıdaki kodla değiştirin:

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

    Arabirim, günlüklerin göreli önemini belirtmek için üç izleme düzeyi ve veritabanı sorguları gibi dış hizmet çağrıları için gecikme süresi bilgileri sağlamak üzere tasarlanmış bir tane sağlar. Günlük yöntemlerinde özel durum geçirmenize olanak sağlayan aşırı yüklemeler vardır. Bu, yığın izlemesi ve iç özel durumlar dahil olmak üzere özel durum bilgilerinin, uygulama genelindeki her günlük yöntemi çağrısında yapılan işleme güvenmek yerine arabirimi uygulayan sınıf tarafından güvenilir bir şekilde günlüğe kaydedilmesini sağlar.

    TraceApi yöntemleri, SQL Veritabanı gibi bir dış hizmete yapılan her çağrının gecikme süresini izlemenizi sağlar.

  3. Günlük klasöründe Logger.cs adlı bir sınıf dosyası oluşturun ve şablon kodunu aşağıdaki kodla değiştirin:

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

    Uygulama, izlemeyi yapmak için System.Diagnostics kullanır. Bu, izleme bilgilerini oluşturmayı ve kullanmayı kolaylaştıran yerleşik bir .NET özelliğidir. System.Diagnostics izleme ile kullanabileceğiniz birçok "dinleyici" vardır. Örneğin, dosyalara günlükleri yazabilir veya Bunları Azure'da blob depolamaya yazabilirsiniz. Visual Studio'da Azure Web Sitelerinde Sorun Giderme bölümünde daha fazla bilgi için bazı seçeneklere ve diğer kaynaklara yönelik bağlantılara bakın. Bu öğretici için yalnızca Visual Studio Çıkış penceresindeki günlüklere bakacaksınız.

    Bir üretim uygulamasında System.Diagnostics dışındaki izleme paketlerini göz önünde bulundurmak isteyebilirsiniz ve ILogger arabirimi, bunu yapmaya karar verirseniz farklı bir izleme mekanizmasına geçmeyi nispeten kolaylaştırır.

Kesme noktası sınıfları oluşturma

Daha sonra Entity Framework'ün veritabanına her sorgu göndereceği her seferinde çağıracağı sınıfları oluşturacaksınız. Bu sınıflardan biri geçici hataların benzetimini yapmak ve diğeri de günlüğe kaydetme işlemi yapmak için kullanılacaktır. Bu kesme noktası sınıfları sınıfından DbCommandInterceptor türetilmelidir. Bunlarda, sorgu yürütülmek üzereyken otomatik olarak çağrılan yöntem geçersiz kılmaları yazarsınız. Bu yöntemlerde veritabanına gönderilen sorguyu inceleyebilir veya günlüğe kaydedebilir ve sorgu veritabanına gönderilmeden önce sorguyu değiştirebilir veya sorguyu veritabanına geçirmeden Entity Framework'e kendiniz bir şey döndürebilirsiniz.

  1. Veritabanına gönderilen her SQL sorgusunu günlüğe kaydedecek kesme noktası sınıfını oluşturmak için DAL klasöründe SchoolInterceptorLogging.cs adlı bir sınıf dosyası oluşturun ve şablon kodunu aşağıdaki kodla değiştirin:

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

    Başarılı sorgular veya komutlar için bu kod gecikme süresi bilgilerini içeren bir Bilgi günlüğü yazar. Özel durumlar için bir Hata günlüğü oluşturur.

  2. Arama kutusuna "Throw" girdiğinizde geçici hatalar oluşturacak kesme noktası sınıfını oluşturmak için DAL klasöründeSchoolInterceptorTransientErrors.cs adlı bir sınıf dosyası oluşturun ve şablon kodunu aşağıdaki kodla değiştirin:

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

    Bu kod yalnızca birden çok veri satırı döndürebilen sorgular ReaderExecuting için çağrılan yöntemini geçersiz kılar. Diğer sorgu türleri için bağlantı dayanıklılığını denetlemek istiyorsanız, günlüğe kaydetme kesme aracının NonQueryExecuting yaptığı gibi ve ScalarExecuting yöntemlerini de geçersiz kılabilirsiniz.

    Öğrenci sayfasını çalıştırdığınızda ve arama dizesi olarak "Throw" girdiğinizde, bu kod genellikle geçici olduğu bilinen 20 numaralı hata için sahte bir SQL Veritabanı özel durumu oluşturur. Şu anda geçici olarak tanınan diğer hata numaraları 64, 233, 10053, 10054, 10060, 10928, 10929, 40197, 40501 ve 40613'tür, ancak bunlar yeni SQL Veritabanı sürümlerinde değiştirilebilir.

    Kod, sorguyu çalıştırmak ve sorgu sonuçlarını geri geçirmek yerine Entity Framework'e özel durumu döndürür. Geçici özel durum dört kez döndürülür ve kod, sorguyu veritabanına geçirmenin normal yordamına geri döner.

    Her şey günlüğe kaydedildiğinden, Entity Framework'ün son başarılı olmadan önce sorguyu dört kez yürütmeye çalıştığını ve uygulamadaki tek farkın sorgu sonuçları içeren bir sayfayı işlemenin daha uzun sürmesi olduğunu görebilirsiniz.

    Entity Framework'ün yeniden deneme sayısı yapılandırılabilir; SQL Veritabanı yürütme ilkesi için varsayılan değer olduğundan kod dört kez belirtir. Yürütme ilkesini değiştirirseniz, burada geçici hataların kaç kez oluşturulduğunu belirten kodu da değiştirirsiniz. Entity Framework'ün özel durumu oluşturması RetryLimitExceededException için kodu daha fazla özel durum oluşturacak şekilde de değiştirebilirsiniz.

    Arama kutusuna girdiğiniz değer ve command.Parameters[1] içinde olur command.Parameters[0] (biri ad, diğeri soyadı için kullanılır). "%Throw%" değeri bulunduğunda, bazı öğrencilerin bulunup döndürülmesi için bu parametrelerde "Throw" yerine "a" kullanılır.

    Bu, uygulama kullanıcı arabiriminde bazı girişlerin değiştirilmesine bağlı olarak bağlantı dayanıklılığını test etmenin kullanışlı bir yoludur. Daha sonra DbInterception.Add yöntemiyle ilgili açıklamalarda açıklandığı gibi, tüm sorgular veya güncelleştirmeler için geçici hatalar oluşturan kod da yazabilirsiniz.

  3. Global.asax içinde aşağıdaki using deyimleri ekleyin:

    using ContosoUniversity.DAL;
    using System.Data.Entity.Infrastructure.Interception;
    
  4. Yöntemine vurgulanan satırları Application_Start ekleyin:

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

    Entity Framework veritabanına sorgu gönderdiğinde kesme noktası kodunuzun çalıştırılmasına neden olan kod satırlarıdır. Geçici hata benzetimi ve günlüğe kaydetme için ayrı kesme noktası sınıfları oluşturduğunuz için bunları bağımsız olarak etkinleştirip devre dışı bırakabileceğinize dikkat edin.

    Kodunuzun DbInterception.Add herhangi bir yerinde yöntemini kullanarak kesme noktası ekleyebilirsiniz; yönteminde Application_Start olması gerekmez. Bir diğer seçenek de bu kodu yürütme ilkesini yapılandırmak için daha önce oluşturduğunuz DbConfiguration sınıfına yerleştirmektir.

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

    Bu kodu nereye koyarsanız koyun, aynı kesme noktası için birden çok kez yürütmemeye DbInterception.Add dikkat edin; aksi taktirde ek kesme noktası örnekleri alırsınız. Örneğin, günlük kesme noktasını iki kez eklerseniz her SQL sorgusu için iki günlük görürsünüz.

    Kesme araçları kayıt sırasına göre yürütülür (yöntemin DbInterception.Add çağrıldığı sıra). Siparişin önemli olması, kesicide ne yaptığınıza bağlı olarak olabilir. Örneğin, bir kesme noktası özelliğinde CommandText aldığı SQL komutunu değiştirebilir. SQL komutunu değiştirirse, sonraki kesme noktası özgün SQL komutunu değil değiştirilmiş SQL komutunu alır.

    Geçici hata benzetimi kodunu, kullanıcı arabirimine farklı bir değer girerek geçici hatalara neden olacak şekilde yazdınız. Alternatif olarak, belirli bir parametre değerini denetlemeden geçici özel durumların sırasını her zaman oluşturmak için kesme noktası kodunu yazabilirsiniz. Ardından, yalnızca geçici hatalar oluşturmak istediğinizde kesme noktasını ekleyebilirsiniz. Ancak bunu yaparsanız, veritabanı başlatma işlemi tamamlanana kadar kesme noktasını eklemeyin. Başka bir deyişle, geçici hatalar oluşturmaya başlamadan önce varlık kümelerinizin birinde sorgu gibi en az bir veritabanı işlemi yapın. Entity Framework, veritabanı başlatma sırasında birkaç sorgu yürütür ve bunlar bir işlemde yürütülemez, bu nedenle başlatma sırasındaki hatalar bağlamın tutarsız bir duruma düşmesine neden olabilir.

Yeni yapılandırmayı test etme

  1. Uygulamayı hata ayıklama modunda çalıştırmak için F5 tuşuna basın ve ardından Öğrenciler sekmesine tıklayın.

  2. İzleme çıkışını görmek için Visual Studio Çıkış penceresine bakın. Günlükçünüz tarafından yazılan günlüklere ulaşmak için bazı JavaScript hatalarını kaydırmanız gerekebilir.

    Veritabanına gönderilen gerçek SQL sorgularını görebildiğinize dikkat edin. Entity Framework'ün başlamak için yaptığı bazı ilk sorgular ve komutlar görürsünüz ve veritabanı sürümünü ve geçiş geçmişi tablosunu denetlersiniz (sonraki öğreticide geçişler hakkında bilgi edineceksiniz). Disk belleği için bir sorgu görürsünüz, kaç öğrenci olduğunu öğrenirsiniz ve son olarak öğrenci verilerini alan sorguyu görürsünüz.

    Normal sorgu için günlüğe kaydetme

  3. Öğrenciler sayfasında, arama dizesi olarak "Throw" yazın ve Ara'ya tıklayın.

    Arama dizesi oluşturma

    Entity Framework sorguyu birkaç kez yeniden denerken tarayıcının birkaç saniye boyunca yanıt vermediğini fark edeceksiniz. İlk yeniden deneme çok hızlı bir şekilde gerçekleşir, ardından her ek yeniden denemeden önce bekleme artar. Her yeniden denemeden önce daha uzun süre bekleme işlemi üstel geri alma olarak adlandırılır.

    Sayfa görüntülendiğinde, adlarında "a" bulunan öğrenciler gösterildiğinde çıkış penceresine bakın ve ilk dört kez geçici özel durumlar döndüren aynı sorgunun beş kez denendiğini görürsünüz. Her geçici hata için, sınıfında geçici hata oluştururken yazdığınız günlüğü ("Komut için geçici hata SchoolInterceptorTransientErrors döndürüluyor...") görürsünüz ve özel durum geldiğinde SchoolInterceptorLogging günlüğün yazıldığını görürsünüz.

    Yeniden denemeleri gösteren günlüğe kaydetme çıkışı

    Bir arama dizesi girdiğinizden, öğrenci verilerini döndüren sorgu parametreleştirilir:

    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:
    

    Parametrelerin değerini günlüğe kaydetmezsiniz, ancak bunu yapabilirsiniz. Parametre değerlerini görmek istiyorsanız, kesme noktası yöntemlerinde elde ettiğiniz nesnenin ParametersDbCommand özelliğinden parametre değerlerini almak için günlük kodu yazabilirsiniz.

    Uygulamayı durdurup yeniden başlatmadığınız sürece bu testi tekrarlayamazsınız. Uygulamanın tek bir çalıştırmasında bağlantı dayanıklılığını birden çok kez test edebilmek istiyorsanız, içindeki hata sayacını SchoolInterceptorTransientErrorssıfırlamak için kod yazabilirsiniz.

  4. Yürütme stratejisinin (yeniden deneme ilkesi) farkını görmek için SchoolConfiguration.cs dosyasında satırı açıklama SetExecutionStrategy satırı yapın, Öğrenciler sayfasını yeniden hata ayıklama modunda çalıştırın ve yeniden "Throw" araması yapın.

    Bu kez hata ayıklayıcı, sorguyu ilk kez yürütmeye çalıştığında oluşturulan ilk özel durumda hemen durur.

    Sahte Özel Durum

  5. SchoolConfiguration.cs dosyasında SetExecutionStrategy satırının açıklamasını kaldırın.

Kodu alma

Tamamlanan Projeyi İndir

Ek kaynaklar

Diğer Entity Framework kaynaklarına bağlantılar ASP.NET Veri Erişimi - Önerilen Kaynaklar bölümünde bulunabilir.

Sonraki adımlar

Bu öğreticide şunları yaptınız:

  • Bağlantı dayanıklılığı etkinleştirildi
  • Komut kesme etkinleştirildi
  • Yeni yapılandırmayı test etti

Code First geçişleri ve Azure dağıtımı hakkında bilgi edinmek için sonraki makaleye ilerleyin.