Bagikan melalui


ASP.NET Ketahanan Koneksi Formulir Web dan Intersepsi Perintah

oleh Erik Reitan

Dalam tutorial ini, Anda akan memodifikasi aplikasi sampel Wingtip Toys untuk mendukung ketahanan koneksi dan intersepsi perintah. Dengan mengaktifkan ketahanan koneksi, aplikasi sampel Wingtip Toys akan secara otomatis mencoba kembali panggilan data ketika kesalahan sementara yang khas dari lingkungan cloud terjadi. Selain itu, dengan menerapkan intersepsi perintah, aplikasi sampel Wingtip Toys akan menangkap semua kueri SQL yang dikirim ke database untuk mencatat atau mengubahnya.

Catatan

Tutorial Formulir Web ini didasarkan pada tutorial MVC tom Dykstra berikut:
Ketahanan Koneksi dan Intersepsi Perintah dengan Kerangka Kerja Entitas dalam Aplikasi MVC ASP.NET

Yang akan Anda pelajari:

  • Cara memberikan ketahanan koneksi.
  • Cara menerapkan intersepsi perintah.

Prasyarat

Sebelum memulai, pastikan Anda memiliki perangkat lunak berikut yang terinstal di komputer Anda:

Ketahanan koneksi

Saat Anda mempertimbangkan untuk menyebarkan aplikasi ke Windows Azure, salah satu opsi yang perlu dipertimbangkan adalah menyebarkan database ke Windows Azure SQL Database, layanan database cloud. Kesalahan koneksi sementara biasanya lebih sering ketika Anda tersambung ke layanan database cloud daripada ketika server web dan server database Anda terhubung langsung bersama-sama di pusat data yang sama. Bahkan jika server web cloud dan layanan database cloud dihosting di pusat data yang sama, ada lebih banyak koneksi jaringan di antara mereka yang dapat mengalami masalah, seperti load balancer.

Juga layanan cloud biasanya dibagikan oleh pengguna lain, yang berarti responsnya dapat dipengaruhi oleh mereka. Dan akses Anda ke database mungkin tunduk pada pembatasan. Pembatasan berarti layanan database melemparkan pengecualian ketika Anda mencoba mengaksesnya lebih sering daripada yang diizinkan dalam Perjanjian Tingkat Layanan (SLA) Anda.

Banyak atau sebagian besar masalah koneksi yang terjadi saat Anda mengakses layanan cloud bersifat sementara, yaitu, mereka menyelesaikannya sendiri dalam waktu singkat. Jadi ketika Anda mencoba operasi database dan mendapatkan jenis kesalahan yang biasanya sementara, Anda dapat mencoba operasi lagi setelah menunggu sebentar, dan operasi mungkin berhasil. Anda dapat memberikan pengalaman yang jauh lebih baik bagi pengguna Anda jika Anda menangani kesalahan sementara dengan secara otomatis mencoba lagi, membuat sebagian besar tidak terlihat oleh pelanggan. Fitur ketahanan koneksi di Entity Framework 6 mengotomatiskan proses mencoba kembali kueri SQL yang gagal.

Fitur ketahanan koneksi harus dikonfigurasi dengan tepat untuk layanan database tertentu:

  1. Ini harus tahu pengecualian mana yang cenderung sementara. Anda ingin mencoba kembali kesalahan yang disebabkan oleh hilangnya sementara konektivitas jaringan, bukan kesalahan yang disebabkan oleh bug program, misalnya.
  2. Ini harus menunggu jumlah waktu yang sesuai antara percobaan ulang operasi yang gagal. Anda dapat menunggu lebih lama di antara percobaan ulang untuk proses batch daripada yang Anda bisa untuk halaman web online di mana pengguna sedang menunggu respons.
  3. Ini harus mencoba kembali beberapa kali sebelum menyerah. Anda mungkin ingin mencoba lagi lebih banyak kali dalam proses batch yang Anda lakukan dalam aplikasi online.

Anda dapat mengonfigurasi pengaturan ini secara manual untuk database apa pun yang dukungan lingkungan oleh penyedia Kerangka Kerja Entitas.

Yang harus Anda lakukan untuk mengaktifkan ketahanan koneksi adalah membuat kelas di rakitan Anda yang berasal dari DbConfiguration kelas , dan di kelas tersebut tetapkan strategi eksekusi SQL Database, yang dalam Kerangka Kerja Entitas adalah istilah lain untuk kebijakan coba lagi.

Menerapkan ketahanan koneksi

  1. Unduh dan buka aplikasi Formulir Web sampel WingtipToys di Visual Studio.

  2. Di folder Logika aplikasi WingtipToys, tambahkan file kelas bernama WingtipToysConfiguration.cs.

  3. Ganti kode yang ada dengan kode berikut:

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

Kerangka Kerja Entitas secara otomatis menjalankan kode yang ditemukannya di kelas yang berasal dari DbConfiguration. Anda dapat menggunakan DbConfiguration kelas untuk melakukan tugas konfigurasi dalam kode yang akan Anda lakukan di file Web.config . Untuk informasi selengkapnya, lihat Konfigurasi Berbasis Kode EntityFramework.

  1. Di folder Logika, buka file AddProducts.cs.

  2. Tambahkan pernyataan untuk System.Data.Entity.Infrastructure seperti yang using ditunjukkan disorot dengan warna kuning:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using WingtipToys.Models;
    using System.Data.Entity.Infrastructure;
    
  3. catch Tambahkan blok ke AddProduct metode sehingga RetryLimitExceededException dicatat sebagai disorot dengan warna kuning:

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

Dengan menambahkan RetryLimitExceededException pengecualian, Anda dapat memberikan pengelogan yang lebih baik atau menampilkan pesan kesalahan kepada pengguna di mana mereka dapat memilih untuk mencoba proses lagi. Dengan menangkap RetryLimitExceededException pengecualian, satu-satunya kesalahan yang mungkin sementara akan sudah dicoba dan gagal beberapa kali. Pengecualian aktual yang dikembalikan akan dibungkus dalam RetryLimitExceededException pengecualian. Selain itu, Anda juga menambahkan blok tangkapan umum. Untuk informasi selengkapnya tentang RetryLimitExceededException pengecualian, lihat Ketahanan Koneksi Kerangka Kerja Entitas/Logika Coba Lagi.

Penyadapan perintah

Sekarang setelah Anda mengaktifkan kebijakan coba lagi, bagaimana Anda menguji untuk memverifikasi bahwa kebijakan berfungsi seperti yang diharapkan? Tidak mudah untuk memaksa kesalahan sementara terjadi, terutama ketika Anda berjalan secara lokal, dan akan sangat sulit untuk mengintegrasikan kesalahan sementara aktual ke dalam pengujian unit otomatis. Untuk menguji fitur ketahanan koneksi, Anda memerlukan cara untuk mencegat kueri yang dikirim Entity Framework ke SQL Server dan mengganti respons SQL Server dengan jenis pengecualian yang biasanya sementara.

Anda juga dapat menggunakan intersepsi kueri untuk menerapkan praktik terbaik untuk aplikasi cloud: mencatat latensi dan keberhasilan atau kegagalan semua panggilan ke layanan eksternal seperti layanan database.

Di bagian tutorial ini Anda akan menggunakan fitur penyadapan Entity Framework baik untuk pengelogan maupun untuk mensimulasikan kesalahan sementara.

Membuat antarmuka dan kelas pengelogan

Praktik terbaik untuk pengelogan adalah melakukannya dengan menggunakan interface panggilan bukan hard-coding ke System.Diagnostics.Trace atau kelas pengelogan. Itu membuatnya lebih mudah untuk mengubah mekanisme pengelogan Anda nanti jika Anda perlu melakukan itu. Jadi di bagian ini, Anda akan membuat antarmuka pengelogan dan kelas untuk mengimplementasikannya.

Berdasarkan prosedur di atas, Anda telah mengunduh dan membuka aplikasi sampel WingtipToys di Visual Studio.

  1. Buat folder di proyek WingtipToys dan beri nama Pengelogan.

  2. Di folder Pengelogan, buat file kelas bernama ILogger.cs dan ganti kode default dengan kode berikut:

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

    Antarmuka menyediakan tiga tingkat pelacakan untuk menunjukkan kepentingan relatif log, dan satu yang dirancang untuk memberikan informasi latensi untuk panggilan layanan eksternal seperti kueri database. Metode pengelogan memiliki kelebihan beban yang memungkinkan Anda melewati pengecualian. Ini agar informasi pengecualian termasuk jejak tumpukan dan pengecualian dalam dicatat dengan andal oleh kelas yang mengimplementasikan antarmuka, alih-alih mengandalkan yang dilakukan dalam setiap panggilan metode pengelogan di seluruh aplikasi.

    Metode ini TraceApi memungkinkan Anda melacak latensi setiap panggilan ke layanan eksternal seperti SQL Database.

  3. Di folder Pengelogan, buat file kelas bernama Logger.cs dan ganti kode default dengan kode berikut:

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

Implementasi menggunakan System.Diagnostics untuk melakukan pelacakan. Ini adalah fitur bawaan .NET yang memudahkan untuk menghasilkan dan menggunakan informasi pelacakan. Ada banyak "listener" yang dapat Anda gunakan dengan System.Diagnostics pelacakan, untuk menulis log ke file, misalnya, atau menulisnya ke penyimpanan blob di Windows Azure. Lihat beberapa opsi, dan tautan ke sumber daya lain untuk informasi selengkapnya, di Memecahkan Masalah Situs Web Windows Azure di Visual Studio. Untuk tutorial ini, Anda hanya akan melihat log di jendela Output Visual Studio.

Dalam aplikasi produksi, Anda mungkin ingin mempertimbangkan untuk menggunakan kerangka kerja pelacakan selain System.Diagnostics, dan ILogger antarmukanya membuatnya relatif mudah untuk beralih ke mekanisme pelacakan yang berbeda jika Anda memutuskan untuk melakukannya.

Membuat kelas pencegat

Selanjutnya, Anda akan membuat kelas yang akan dipanggil Oleh Kerangka Kerja Entitas setiap kali akan mengirim kueri ke database, satu untuk mensimulasikan kesalahan sementara dan satu untuk melakukan pengelogan. Kelas pencegat ini harus berasal dari DbCommandInterceptor kelas . Di dalamnya, Anda menulis penimpaan metode yang secara otomatis dipanggil saat kueri akan dijalankan. Dalam metode ini Anda dapat memeriksa atau mencatat kueri yang sedang dikirim ke database, dan Anda bisa mengubah kueri sebelum dikirim ke database atau mengembalikan sesuatu ke Kerangka Kerja Entitas sendiri tanpa meneruskan kueri ke database.

  1. Untuk membuat kelas pencegat yang akan mencatat setiap kueri SQL sebelum dikirim ke database, buat file kelas bernama InterceptorLogging.cs di folder Logika dan ganti kode default dengan kode berikut:

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

    Untuk kueri atau perintah yang berhasil, kode ini menulis log Informasi dengan informasi latensi. Untuk pengecualian, ia membuat log Kesalahan.

  2. Untuk membuat kelas pencegat yang akan menghasilkan kesalahan sementara dummy saat Anda memasukkan "Lempar" di kotak teks Nama pada halaman bernama AdminPage.aspx, buat file kelas bernama InterceptorTransientErrors.cs di folder Logika dan ganti kode default dengan kode berikut:

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

    Kode ini hanya mengambil ReaderExecuting alih metode , yang dipanggil untuk kueri yang dapat mengembalikan beberapa baris data. Jika Anda ingin memeriksa ketahanan koneksi untuk jenis kueri lain, Anda juga dapat mengambil alih NonQueryExecuting metode dan ScalarExecuting , seperti yang dilakukan pencegat pengelogan.

    Nantinya, Anda akan masuk sebagai "Admin" dan memilih tautan Admin di bilah navigasi atas. Kemudian, pada halaman AdminPage.aspx Anda akan menambahkan produk bernama "Throw". Kode membuat pengecualian SQL Database dummy untuk nomor kesalahan 20, jenis yang dikenal biasanya sementara. Nomor kesalahan lain yang saat ini dikenali sebagai sementara adalah 64, 233, 10053, 10054, 10060, 10928, 10929, 40197, 40501, dan 40613, tetapi ini dapat berubah dalam versi baru Database SQL. Produk akan diganti namanya menjadi "TransientErrorExample", yang dapat Anda ikuti dalam kode file InterceptorTransientErrors.cs .

    Kode mengembalikan pengecualian ke Kerangka Kerja Entitas alih-alih menjalankan kueri dan meneruskan kembali hasil. Pengecualian sementara dikembalikan empat kali, lalu kode kembali ke prosedur normal meneruskan kueri ke database.

    Karena semuanya dicatat, Anda akan dapat melihat bahwa Kerangka Kerja Entitas mencoba menjalankan kueri empat kali sebelum akhirnya berhasil, dan satu-satunya perbedaan dalam aplikasi adalah bahwa dibutuhkan waktu lebih lama untuk merender halaman dengan hasil kueri.

    Berapa kali Kerangka Kerja Entitas akan mencoba kembali dapat dikonfigurasi; kode menentukan empat kali karena itu adalah nilai default untuk kebijakan eksekusi SQL Database. Jika Anda mengubah kebijakan eksekusi, Anda juga akan mengubah kode di sini yang menentukan berapa kali kesalahan sementara dihasilkan. Anda juga dapat mengubah kode untuk menghasilkan lebih banyak pengecualian sehingga Entity Framework akan melemparkan RetryLimitExceededException pengecualian.

  3. Di Global.asax, tambahkan pernyataan penggunaan berikut:

    using System.Data.Entity.Infrastructure.Interception;
    
  4. Kemudian, tambahkan baris yang disorot ke Application_Start metode :

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

Baris kode inilah yang menyebabkan kode pencegat Anda dijalankan saat Kerangka Kerja Entitas mengirim kueri ke database. Perhatikan bahwa karena Anda membuat kelas pencegat terpisah untuk simulasi kesalahan sementara dan pengelogan, Anda dapat mengaktifkan dan menonaktifkannya secara independen.

Anda dapat menambahkan pencegat menggunakan DbInterception.Add metode di mana saja dalam kode Anda; itu tidak harus dalam Application_Start metode . Opsi lain, jika Anda tidak menambahkan pencegat dalam Application_Start metode , adalah memperbarui atau menambahkan kelas bernama WingtipToysConfiguration.cs dan menempatkan kode di atas di akhir konstruktor WingtipToysConfiguration kelas.

Di mana pun Anda meletakkan kode ini, berhati-hatilah untuk tidak mengeksekusi DbInterception.Add pencegat yang sama lebih dari sekali, atau Anda akan mendapatkan instans pencegat tambahan. Misalnya, jika Anda menambahkan pencegat pengelogan dua kali, Anda akan melihat dua log untuk setiap kueri SQL.

Pencegat dijalankan dalam urutan pendaftaran (urutan di mana metode dipanggil DbInterception.Add ). Urutan mungkin penting tergantung pada apa yang Anda lakukan di pencegat. Misalnya, pencegat mungkin mengubah perintah SQL yang didapatkannya di CommandText properti . Jika mengubah perintah SQL, pencegat berikutnya akan mendapatkan perintah SQL yang diubah, bukan perintah SQL asli.

Anda telah menulis kode simulasi kesalahan sementara dengan cara yang memungkinkan Anda menyebabkan kesalahan sementara dengan memasukkan nilai yang berbeda di UI. Sebagai alternatif, Anda dapat menulis kode pencegat untuk selalu menghasilkan urutan pengecualian sementara tanpa memeriksa nilai parameter tertentu. Anda kemudian dapat menambahkan pencegat hanya ketika Anda ingin menghasilkan kesalahan sementara. Namun, jika Anda melakukan ini, jangan tambahkan pencegat hingga setelah inisialisasi database selesai. Dengan kata lain, lakukan setidaknya satu operasi database seperti kueri pada salah satu kumpulan entitas Anda sebelum Anda mulai menghasilkan kesalahan sementara. Kerangka Kerja Entitas menjalankan beberapa kueri selama inisialisasi database, dan tidak dijalankan dalam transaksi, sehingga kesalahan selama inisialisasi dapat menyebabkan konteks masuk ke status yang tidak konsisten.

Menguji pengelogan dan ketahanan koneksi

  1. Di Visual Studio, tekan F5 untuk menjalankan aplikasi dalam mode debug, lalu masuk sebagai "Admin" menggunakan "Pa$$word" sebagai kata sandi.

  2. Pilih Admin dari bilah navigasi di bagian atas.

  3. Masukkan produk baru bernama "Throw" dengan deskripsi, harga, dan file gambar yang sesuai.

  4. Tekan tombol Tambahkan Produk .
    Anda akan melihat bahwa browser tampaknya macet selama beberapa detik saat Kerangka Kerja Entitas mencoba kembali kueri beberapa kali. Percobaan ulang pertama terjadi dengan sangat cepat, maka tunggu meningkat sebelum setiap coba lagi tambahan. Proses menunggu lebih lama sebelum setiap coba lagi disebut backoff eksponensial .

  5. Tunggu hingga halaman tidak lagi mencoba memuat.

  6. Hentikan proyek dan lihat jendela Output Visual Studio untuk melihat output pelacakan. Anda dapat menemukan jendela Output dengan memilih Debug ->Windows ->Output. Anda mungkin harus menggulir melewati beberapa log lain yang ditulis oleh pencatat Anda.

    Perhatikan bahwa Anda dapat melihat kueri SQL aktual yang dikirim ke database. Anda melihat beberapa kueri dan perintah awal yang dilakukan Kerangka Kerja Entitas untuk memulai, memeriksa versi database dan tabel riwayat migrasi.
    Jendela output
    Perhatikan bahwa Anda tidak dapat mengulangi pengujian ini kecuali Anda menghentikan aplikasi dan memulai ulang. Jika Anda ingin dapat menguji ketahanan koneksi beberapa kali dalam satu proses aplikasi, Anda dapat menulis kode untuk mengatur ulang penghitung kesalahan di InterceptorTransientErrors .

  7. Untuk melihat perbedaan strategi eksekusi (kebijakan coba lagi) buat, komentari SetExecutionStrategy baris dalam file WingtipToysConfiguration.cs di folder Logika , jalankan halaman Admin dalam mode debug lagi, dan tambahkan produk bernama "Throw" lagi.

    Kali ini debugger berhenti pada pengecualian pertama yang dihasilkan segera ketika mencoba menjalankan kueri untuk pertama kalinya.
    Penelusuran kesalahan - Lihat Detail

  8. Batalkan SetExecutionStrategy komentar baris dalam file WingtipToysConfiguration.cs .

Ringkasan

Dalam tutorial ini Anda telah melihat cara memodifikasi aplikasi sampel Formulir Web untuk mendukung ketahanan koneksi dan intersepsi perintah.

Langkah berikutnya

Setelah Anda meninjau ketahanan koneksi dan intersepsi perintah di Formulir Web ASP.NET, tinjau topik Formulir Web ASP.NET Metode Asinkron di ASP.NET 4.5. Topik ini akan mengajari Anda dasar-dasar membangun aplikasi ASP.NET Web Forms asinkron menggunakan Visual Studio.