AdminHọ tên : Nguyễn Ích Hoàn Bài viết : 3191 Xu : 9210 Thanks : 8 Age : 34 Đến từ : Thanh Hóa
Admin
Họ tên : Nguyễn Ích Hoàn Bài viết : 3191 Xu : 9210 Thanks : 8 Age : 34 Đến từ : Thanh Hóa
Tài Sản: .:
The Contoso University sample web application demonstrates how to create ASP.NET MVC 5 applications using the Entity Framework 6 Code First and Visual Studio 2013. For information about the tutorial series, see the first tutorial in the series.
So far the application has been running locally in IIS Express on your development computer. To make a real application available for other people to use over the Internet, you have to deploy it to a web hosting provider, and you have to deploy the database to a database server.
In this tutorial you'll learn how to use two features of Entity Framework 6 that are especially valuable when you are deploying to the cloud environment: connection resiliency (automatic retries for transient errors) and command interception (catch all SQL queries sent to the database in order to log or change them).
This connection resiliency and command interception tutorial is optional. If you skip this tutorial, a few minor adjustments will have to be made in subsequent tutorials.
Enable connection resiliency
When you deploy the application to Windows Azure, you'll deploy the database to Windows Azure SQL Database, a cloud database service. Transient connection errors are typically more frequent when you connect to a cloud database service than when your web server and your database server are directly connected together in the same data center. Even if a cloud web server and a cloud database service are hosted in the same data center, there are more network connections between them that can have problems, such as load balancers.
Also a cloud service is typically shared by other users, which means its responsiveness can be affected by them. And your access to the database might be subject to throttling. Throttling means the database service throws exceptions when you try to access it more frequently than is allowed in your Service Level Agreement (SLA).
Many or most connection problems when you're accessing a cloud service are transient, that is, they resolve themselves in a short period of time. So when you try a database operation and get a type of error that is typically transient, you could try the operation again after a short wait, and the operation might be successful. You can provide a much better experience for your users if you handle transient errors by automatically trying again, making most of them invisible to the customer. The connection resiliency feature in Entity Framework 6 automates that process of retrying failed SQL queries.
The connection resiliency feature must be configured appropriately for a particular database service:
It has to know which exceptions are likely to be transient. You want to retry errors caused by a temporary loss in network connectivity, not errors caused by program bugs, for example.
It has to wait an appropriate amount of time between retries of a failed operation. You can wait longer between retries for a batch process than you can for an online web page where a user is waiting for a response.
It has to retry an appropriate number of times before it gives up. You might want to retry more times in a batch process that you would in an online application.
You can configure these settings manually for any database environment supported by an Entity Framework provider, but default values that typically work well for an online application that uses Windows Azure SQL Database have already been configured for you, and those are the settings you'll implement for the Contoso University application.
All you have to do to enable connection resiliency is create a class in your assembly that derives from the DbConfiguration class, and in that class set the SQL Database execution strategy, which in EF is another term for retry policy.
[list defaultattr=] [*]In the DAL folder, add a class file named SchoolConfiguration.cs. [*]Replace the template code with the following code: using System.Data.Entity; using System.Data.Entity.SqlServer;
namespace ContosoUniversity.DAL { public class SchoolConfiguration : DbConfiguration { public SchoolConfiguration() { SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy()); } } } The Entity Framework automatically runs the code it finds in a class that derives from
Code:
DbConfiguration
. You can use the
Code:
DbConfiguration
class to do configuration tasks in code that you would otherwise do in the Web.config file. For more information, see EntityFramework Code-Based Configuration. [*]In StudentController.cs, add a
Code:
using
statement for
Code:
System.Data.Entity.Infrastructure
. using System.Data.Entity.Infrastructure; [*]Change all of the
Code:
catch
blocks that catch
Code:
DataException
exceptions so that they catch
Code:
RetryLimitExceededException
exceptions instead. For example: 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."); } You were using
Code:
DataException
to try to identify errors that might be transient in order to give a friendly "try again" message. But now that you've turned on a retry policy, the only errors likely to be transient will already have been tried and failed several times and the actual exception returned will be wrapped in the
Now that you've turned on a retry policy, how do you test to verify that it is working as expected? It's not so easy to force a transient error to happen, especially when you're running locally, and it would be especially difficult to integrate actual transient errors into an automated unit test. To test the connection resiliency feature, you need a way to intercept queries that Entity Framework sends to SQL Server and replace the SQL Server response with an exception type that is typically transient.
A best practice for logging is to do it by using an interface rather than hard-coding calls to System.Diagnostics.Trace or a logging class. That makes it easier to change your logging mechanism later if you ever need to do that. So in this section you'll create the logging interface and a class to implement it./p>
[list defaultattr=] [*]Create a folder in the project and name it Logging. [*]In the Logging folder, create a class file named ILogger.cs, and replace the template code with the following code: using System;
} } The interface provides three tracing levels to indicate the relative importance of logs, and one designed to provide latency information for external service calls such as database queries. The logging methods have overloads that let you pass in an exception. This is so that exception information including stack trace and inner exceptions is reliably logged by the class that implements the interface, instead of relying on that being done in each logging method call throughout the application. The TraceApi methods enable you to track the latency of each call to an external service such as SQL Database. [*]In the Logging folder, create a class file named Logger.cs, and replace the template code with the following code: using System; using System.Diagnostics; using System.Text;
namespace ContosoUniversity.Logging { public class Logger : ILogger {
public void Information(string message) { Trace.TraceInformation(message); }
private static string FormatExceptionMessage(Exception exception, string fmt, object[] vars) { // Simple exception formatting: for a more comprehensive version see // http://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(); } } } The implementation uses System.Diagnostics to do the tracing. This is a built-in feature of .NET which makes it easy to generate and use tracing information. There are many "listeners" you can use with System.Diagnostics tracing, to write logs to files, for example, or to write them to blob storage in Azure. See some of the options, and links to other resources for more information, in Troubleshooting Azure Web Sites in Visual Studio. For this tutorial you'll only look at logs in the Visual Studio Output window. In a production application you might want to consider tracing packages other than System.Diagnostics, and the ILogger interface makes it relatively easy to switch to a different tracing mechanism if you decide to do that. [/list]
Create interceptor classes
Next you'll create the classes that the Entity Framework will call into every time it is going to send a query to the database, one to simulate transient errors and one to do logging. These interceptor classes must derive from the
Code:
DbCommandInterceptor
class. In them you write method overrides that are automatically called when query is about to be executed. In these methods you can examine or log the query that is being sent to the database, and you can change the query before it's sent to the database or return something to Entity Framework yourself without even passing the query to the database.
[list defaultattr=] [*]To create the interceptor class that will log every SQL query that is sent to the database, create a class file named SchoolInterceptorLogging.cs in the DAL folder, and replace the template code with the following code: 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