
本文共 4106 字,大约阅读时间需要 13 分钟。
这节教程将引入Entity Framework 6(EF6)的两个重要特性:弹性连接和命令拦截。这对于部署在云环境中的网站至关重要。弹性连接允许EF在遇到暂态网络问题时自动重试,从而提高系统的稳定性。命令拦截则可以记录所有发送到数据库的SQL查询,方便后续的审查和修改。
启用弹性连接
在部署网站到云服务(如Windows Azure SQL Database)时,由于资源共享和限流限制,网络连接中间常会出现暂态错误。这时候,弹性连接特性能帮助EF自动重试连接,确保数据访问的连续性。EF6的弹性连接配置需要满足以下要求:
- 区分暂态错误和永久性异常。
- 定期重试连接。
- 确定重试的最大次数。
这几项配置可以在任何支持EF6的环境中手动设置,而Windows Azure SQL Database已预先配置好了这些参数。
启用命令拦截
为了测试弹性连接是否正常工作,我们需要模拟和记录暂态误差。手动制造暂态错误并不容易,尤其是在本地开发环境中。这里可以利用EF6的命令拦截特性来记录和模拟错误。
无障碍性的日志记录
为了便于日后审查和分析,我们需要一个灵活的日志记录接口。遵循单一责任原则,编写接口而不是直接使用 System.Diagnostics.Trace。如果未来需要更改日志方式,接口可以轻松实现新的类。
ILogger
接口,并在 Logging
文件夹中实现它。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 component, string method, TimeSpan timespan, string fmt, params object[] vars); }}
- 实现
Logger
类,使用 System.Diagnostics 导出日志到输出窗口。 - 创建用于记录的拦截器类
SchoolInterceptorLogging
。 将拦截器注册到EF中:
using ContosoUniversity.DAL;using System.Data.Entity.Infrastructure.Interception;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());}
测试时,运行项目并通过搜索框输入特定值,观察输出窗口中的日志和异常信息。
using System;using System.Diagnostics;namespace ContosoUniversity.Logging{ public class Logger : ILogger { private readonly TraceListener _traceListener = new TraceListener(); // 其他方法... }}
创建拦截器类
为了记录和模拟错误,创建拦截器类继承自 DbCommandInterceptor
。在拦截器中可以看到所有发送到数据库的SQL查询,并根据需要处理或记录它们。
using System.Diagnostics;namespace ContosoUniversity.DAL{ public class SchoolInterceptorLogging : DbCommandInterceptor { private readonly ILogger _logger = new Logger(); private readonly Stopwatch _stopwatch = new Stopwatch(); public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext context) { base.ScalarExecuting(command, context); _stopwatch.Restart(); } public override void ScalarExecuted(DbCommand command, DbCommandInterceptionContext context) { _stopwatch.Stop(); if (context.Exception != null) { _logger.Error(context.Exception, "执行命令时发生错误:{0}", command.CommandText); } else { _logger.TraceApi("SQL Database", "SchoolInterceptor.ScalarExecuted", _stopwatch.Elapsed, "Command:{0}", command.CommandText); } base.ScalarExecuted(command, context); } // 其他方法同上... }}
模拟暂态错误
创建另一个拦截器 SchoolInterceptorTransientErrors
,用于在特定情况下生成虚拟的SqlException。
using System;using System.Linq;namespace ContosoUniversity.DAL{ public class SchoolInterceptorTransientErrors : DbCommandInterceptor { private readonly ILogger _logger = new Logger(); private int _counter = 0; public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext context) { // 检查是否有需要触发的条件 if (command.Parameters[0].Value.ToString() == "%Throw%") { _counter++; if (!_counter > 4 && !context.Exception) { _logger.Information("返回暂态错误命令:{0}", command.CommandText); var exception = CreateDummySqlException(); context.Exception = exception; } } } // 其他方法... }}
测试和部署
通过以上配置,您可以全面了解和使用EF6的弹性连接和命令拦截特性,同时实现对数据库操作的透明记录和错误处理。
发表评论
最新留言
关于作者
