Webové formuláře ASP.NET – odolnost připojení a zachycení příkazů
V tomto kurzu upravíte ukázkovou aplikaci Wingtip Toys tak, aby podporovala odolnost připojení a zachycení příkazů. Když povolíte odolnost připojení, ukázková aplikace Wingtip Toys automaticky opakuje volání dat, když dojde k přechodným chybám typickým pro cloudové prostředí. Také implementací zachycení příkazů ukázková aplikace Wingtip Toys zachytí všechny dotazy SQL odeslané do databáze, aby je bylo možné protokolovat nebo změnit.
Poznámka:
Tento kurz k webovým formulářům byl založen na následujícím kurzu MVC toma Dykstra:
Odolnost připojení a zachycení příkazů pomocí entity Framework v aplikaci ASP.NET MVC
Naučíte se:
- Jak zajistit odolnost připojení
- Postup implementace zachytávání příkazů
Požadavky
Než začnete, ujistěte se, že máte v počítači nainstalovaný následující software:
Microsoft Visual Studio 2013 nebo Microsoft Visual Studio Express 2013 pro web Rozhraní .NET Framework se nainstaluje automaticky.
Ukázkový projekt Wingtip Toys, abyste mohli implementovat funkce uvedené v tomto kurzu v projektu Wingtip Toys. Následující odkaz obsahuje podrobnosti o stažení:
Před dokončením tohoto kurzu zvažte kontrolu související série kurzů Začínáme s ASP.NET webovými formuláři 4.5 a sadou Visual Studio 2013. Série kurzů vám pomůže seznámit se s projektem a kódem WingtipToys .
Odolnost připojení
Při zvažování nasazení aplikace do Windows Azure je jednou z možností nasazení databáze do služby Windows Azure SQL Database, která je cloudovou databázovou službou. Přechodné chyby připojení jsou obvykle častější, když se připojujete ke cloudové databázové službě, než když webový server a databázový server jsou přímo propojené ve stejném datovém centru. I když je cloudový webový server a cloudová databázová služba hostované ve stejném datovém centru, existuje mezi nimi více síťových připojení, která můžou mít problémy, jako jsou nástroje pro vyrovnávání zatížení.
Cloudová služba je obvykle sdílena jinými uživateli, což znamená, že jejich 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 při pokusu o přístup k této službě častěji, než je povoleno ve smlouvě o úrovni služeb (SLA).
Mnoho nebo většina problémů s připojením, ke kterým dochází, když přistupujete ke cloudové službě, jsou přechodné, to znamená, že se vyřeší za krátkou dobu. Při pokusu o operaci databáze a získání typu 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 tím, že se automaticky pokusíte znovu a většinu z nich pro zákazníka zviditelníte. Funkce odolnosti připojení v Entity Frameworku 6 automatizuje tento 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é dočasnou ztrátou připojení k síti, nikoli chybami způsobenými programovými chybami, například.
- Mezi opakovanými pokusy o neúspěšnou operaci musí počkat odpovídající dobu. Mezi opakovanými pokusy o dávkové zpracování můžete čekat déle, než můžete použít pro online webovou stránku, kde uživatel čeká na odpověď.
- Musí opakovat odpovídající počet opakování, než se zopakuje. V dávkovém procesu, který byste v online aplikaci mohli opakovat vícekrát.
Tato nastavení můžete nakonfigurovat ručně pro libovolnou databázi podpora prostředí od poskytovatele Entity Framework.
Stačí jen povolit odolnost připojení, je vytvořit třídu v sestavení, která je odvozena z DbConfiguration
třídy, a v této třídě nastavit strategii provádění služby SQL Database, která je v Entity Frameworku dalším termínem pro zásady opakování.
Implementace odolnosti připojení
Stáhněte a otevřete ukázkovou aplikaci Webové formuláře WingtipToys v sadě Visual Studio.
Do složky Logika aplikace WingtipToys přidejte soubor třídy s názvem WingtipToysConfiguration.cs.
Existující kód nahraďte následujícím kódem:
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 automaticky spustí kód, který najde ve třídě, která je odvozena z DbConfiguration
. Třídu můžete použít DbConfiguration
k provedení úloh konfigurace v kódu, které byste jinak udělali v souboru Web.config . Další informace naleznete v tématu EntityFramework Code-Based Configuration.
Ve složce Logika otevřete soubor AddProducts.cs.
using
Přidejte příkaz, kterýSystem.Data.Entity.Infrastructure
je zvýrazněný žlutě:using System; using System.Collections.Generic; using System.Linq; using System.Web; using WingtipToys.Models; using System.Data.Entity.Infrastructure;
catch
Přidejte doAddProduct
metody blok, abyRetryLimitExceededException
se protokoloval jako zvýrazněný žlutě: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; }
RetryLimitExceededException
Přidáním výjimky můžete poskytnout lepší protokolování nebo zobrazit uživateli chybovou zprávu, kde se může rozhodnout proces zkusit znovu. Když výjimku RetryLimitExceededException
zachytíte, jediné chyby, které pravděpodobně budou přechodné, se už několikrát zkusí a nezdaří. Vrácená skutečná výjimka se zabalí do RetryLimitExceededException
výjimky. Kromě toho jste také přidali obecný blok catchu. Další informace o výjimce RetryLimitExceededException
naleznete v tématu Odolnost připojení Entity Framework / Logika opakování.
Průsečík příkazů
Teď, když jste zapnuli zásadu opakování, jak otestovat, jestli funguje 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 bylo by obzvláště obtížné 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á na SQL Server, a nahradit odpověď SQL Serveru typem výjimky, který je obvykle přechodný.
K implementaci osvědčených postupů pro cloudové aplikace můžete použít také zachycování dotazů: zaprotokolujte latenci a úspěch nebo selhání všech volání externích služeb, jako jsou databázové služby.
V této části kurzu použijete funkci průsečíku Entity Frameworku jak pro protokolování, tak pro simulaci přechodných chyb.
Vytvoření rozhraní protokolování a třídy
Osvědčeným postupem pro protokolování je použít interface
namísto pevně zakódovaných 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 rozhraní protokolování a třídu, která ho implementuje.
Na základě výše uvedeného postupu jste stáhli a otevřeli ukázkovou aplikaci WingtipToys v sadě Visual Studio.
Vytvořte složku v projektu WingtipToys a pojmenujte ji Protokolování.
Ve složce Protokolování vytvořte soubor třídy s názvem ILogger.cs a nahraďte výchozí kód následujícím kódem:
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); } }
Rozhraní poskytuje tři úrovně trasování, které označují relativní důležitost protokolů, a jednu navrženou tak, aby poskytovala informace 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. To znamená, že informace o výjimce, včetně trasování zásobníku a vnitřních výjimek, jsou spolehlivě protokolovány třídou, která implementuje rozhraní, místo aby se spoléhala na to, že 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.Ve složce Protokolování vytvořte soubor třídy s názvem Logger.cs a nahraďte výchozí kód následujícím kódem:
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(); } } }
Implementace se používá System.Diagnostics
k trasování. Jedná se o integrovanou funkci .NET, která usnadňuje generování a používání informací o trasování. Existuje mnoho "naslouchacích procesů", které můžete použít s System.Diagnostics
trasováním, k zápisu protokolů do souborů, například k jejich zápisu do úložiště objektů blob ve Windows Azure. Další informace najdete v tématu Řešení potíží s weby Windows Azure v sadě Visual Studio a odkazy na další zdroje informací. V tomto kurzu se podíváte jenom na protokoly v okně Výstup sady Visual Studio.
V produkční aplikaci můžete zvážit použití jiných trasovacích architektur než System.Diagnostics
a ILogger
rozhraní umožňuje relativně snadné přepnutí na jiný mechanismus trasování, pokud se rozhodnete.
Vytvoření tříd průsečíku
Dále vytvoříte třídy, do které bude Entity Framework volat při každém odeslání dotazu do databáze, jednu pro simulaci přechodných chyb a jednu pro protokolování. Tyto třídy průsečíku DbCommandInterceptor
musí být odvozeny od třídy. V nich napíšete přepsání metody, které se automaticky volají při spuštění dotazu. V těchto metodách můžete prozkoumat nebo protokolovat dotaz, který se odesílá do databáze, a dotaz můžete změnit před odesláním do databáze nebo vrátit něco do entity Framework sami bez předání dotazu do databáze.
Chcete-li vytvořit třídu průsečíku, která bude protokolovat každý dotaz SQL před odesláním do databáze, vytvořte soubor třídy s názvem InterceptorLogging.cs ve složce logiky a nahraďte výchozí kód 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 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); } } }
Pro úspěšné dotazy nebo příkazy tento kód zapíše protokol informací s informacemi o latenci. Pro výjimky vytvoří protokol chyb.
Chcete-li vytvořit třídu průsečíku, která vygeneruje fiktivní přechodné chyby při zadání "Throw" do textového pole Název na stránce s názvem AdminPage.aspx, vytvořte soubor třídy s názvem InterceptorTransientErrors.cs ve složce logiky a nahraďte výchozí kód 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 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; } } }
Tento kód přepíše pouze metodu
ReaderExecuting
, která se volá pro dotazy, které můžou vracet více řádků dat. Pokud chcete zkontrolovat odolnost připojení u jiných typů dotazů, můžete také přepsat metody aScalarExecuting
přepsatNonQueryExecuting
tak, jak to dělá průsečík protokolování.Později se přihlásíte jako správce a v horním navigačním panelu vyberete odkaz Správce . Potom na stránce AdminPage.aspx přidáte produkt s názvem "Throw". Kód vytvoří fiktivní výjimku sql Database pro chybu 20, což je typ, o který se obvykle jedná o přechodný typ. Další čísla chyb aktuálně rozpoznaná jako přechodná jsou 64, 233, 10053, 10054, 10060, 10928, 10929, 40197, 40501 a 40613, ale můžou se změnit v nových verzích služby SQL Database. Produkt se přejmenuje na TransientErrorExample, který můžete sledovat v kódu souboru InterceptorTransientErrors.cs .
Kód vrátí výjimku z Entity Frameworku místo spuštění dotazu a předávání výsledků zpět. Přechodná výjimka se vrátí čtyřikrát a kód se 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 předtím, než uspěje, a jediným rozdílem v aplikaci je, že vykreslení stránky s výsledky dotazu trvá déle.
Počet opakování entity Framework je možné konfigurovat. kód určuje čtyřikrát, protože je to výchozí hodnota pro zásady spouštění služby SQL Database. Pokud změníte zásady spouštění, změníte zde také kód, který určuje, kolikrát se vygenerují přechodné chyby. Kód můžete také změnit tak, aby vygeneroval další výjimky, aby entity Framework vyvolal
RetryLimitExceededException
výjimku.V souboru Global.asax přidejte následující příkazy using:
using System.Data.Entity.Infrastructure.Interception;
Potom do
Application_Start
metody přidejte zvýrazněné řádky: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()); }
Tyto řádky kódu jsou to, co způsobí spuštění kódu zachytávání, když Entity Framework odesílá dotazy do databáze. Všimněte si, že protože jste vytvořili samostatné třídy průsečíku pro simulaci přechodných chyb a protokolování, můžete je nezávisle povolit a zakázat.
Průsečíky můžete přidat pomocí DbInterception.Add
metody kdekoli v kódu. Nemusí být v Application_Start
metodě. Další možností, pokud jste do metody nepřidali průsečíky Application_Start
, by bylo aktualizovat nebo přidat třídu s názvem WingtipToysConfiguration.cs a vložit výše uvedený kód na konec konstruktoru WingtipToysConfiguration
třídy.
Bez ohledu na to, kam tento kód vložíte, dávejte pozor, abyste nespustí DbInterception.Add
stejný průsečík více než jednou, nebo získáte další instance průsečíku. Pokud například přidáte zachytávání protokolování dvakrát, zobrazí se pro každý dotaz SQL dva protokoly.
Průsečíky se provádějí v pořadí registrace (pořadí, ve kterém DbInterception.Add
je volána metoda). Pořadí může záviset na tom, co v průsečíku děláte. Například průsečík může změnit příkaz SQL, který se dostane do CommandText
vlastnosti. Pokud příkaz SQL změní, další průsečík získá změněný příkaz SQL, nikoli původní příkaz SQL.
Napsali jste kód simulace přechodných chyb způsobem, který vám umožní způsobit přechodné chyby zadáním jiné hodnoty v uživatelském rozhraní. Jako alternativu můžete napsat kód průsečíku, který bude vždy generovat posloupnost přechodných výjimek bez kontroly konkrétní hodnoty parametru. Průsečík pak můžete přidat pouze v případech, kdy chcete vygenerovat přechodné chyby. Pokud to ale uděláte, nepřidávejte průsečík, dokud se nedokončí inicializace databáze. Jinými slovy, před zahájením generování přechodných chyb proveďte alespoň jednu operaci databáze, například dotaz na jednu ze sad entit. Entity Framework provádí během inicializace databáze několik dotazů a nespustí se v transakci, takže chyby během inicializace by mohly způsobit, že kontext přejde do nekonzistentního stavu.
Testování odolnosti protokolování a připojení
V sadě Visual Studio stiskněte klávesu F5 , aby se aplikace spustila v režimu ladění, a pak se přihlaste jako správce pomocí hesla Pa$$word.
V horním navigačním panelu vyberte Správce .
Zadejte nový produkt s názvem "Throw" s odpovídajícím popisem, cenou a souborem obrázku.
Stiskněte tlačítko Přidat produkt.
Všimněte si, že se zdá, že prohlížeč několik sekund přestane reagovat, zatímco Entity Framework několikrát opakuje dotaz. První opakování proběhne velmi rychle a pak se čekání zvýší před každým dalším opakováním. Tento proces čekání déle před každým opakováním se nazývá exponenciální reoff .Počkejte, až se stránka nebude pokoušet načíst.
Zastavte projekt a podívejte se do okna Výstup sady Visual Studio a podívejte se na výstup trasování. Okno Výstup najdete tak, že vyberete Debug ->Windows ->Output. Možná se budete muset posunout za několik dalších protokolů, které zapisuje váš protokolovacím nástrojem.
Všimněte si, že se zobrazují skutečné dotazy SQL odeslané do databáze. Zobrazí se některé počáteční dotazy a příkazy, které Entity Framework dělá, abyste mohli začít a kontrolovat verzi databáze a tabulku historie migrace.
Mějte na paměti, že tento test nelze opakovat, pokud aplikaci nezastavíte a restartujete ji. Pokud jste chtěli být schopni otestovat odolnost připojení vícekrát v jednom spuštění aplikace, můžete napsat kód pro resetování čítače chyb vInterceptorTransientErrors
.Pokud chcete vidět rozdíl ve strategii provádění (zásady opakování), zakomentujte řádek v souboru WingtipToysConfiguration.cs ve složce Logika, znovu spusťte stránku Správce v režimu ladění a znovu přidejte produkt s názvem
SetExecutionStrategy
Throw.Tentokrát se ladicí program zastaví na první vygenerované výjimce okamžitě, když se pokusí spustit dotaz poprvé.
Odkomentujte
SetExecutionStrategy
řádek v souboru WingtipToysConfiguration.cs .
Shrnutí
V tomto kurzu jste viděli, jak upravit ukázkovou aplikaci Webových formulářů tak, aby podporovala odolnost připojení a zachycení příkazů.
Další kroky
Po kontrole odolnosti připojení a zachycení příkazů ve webových formulářích ASP.NET zkontrolujte téma ASP.NET Webové formuláře téma Asynchronní metody v ASP.NET 4.5. Toto téma vás naučí základy vytváření asynchronní ASP.NET webové formuláře pomocí sady Visual Studio.