博客
关于我
EF6与MVC5系列(4):在MVC应用程序中使用弹性连接和命令拦截
阅读量:805 次
发布时间:2023-01-24

本文共 4191 字,大约阅读时间需要 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);
    }
    }
    1. 实现 Logger 类,使用 System.Diagnostics 导出日志到输出窗口。
    2. using System;
      using System.Diagnostics;
      namespace ContosoUniversity.Logging
      {
      public class Logger : ILogger
      {
      private readonly TraceListener _traceListener = new TraceListener();
      // 其他方法...
      }
      }

      创建拦截器类

      为了记录和模拟错误,创建拦截器类继承自 DbCommandInterceptor。在拦截器中可以看到所有发送到数据库的SQL查询,并根据需要处理或记录它们。

    3. 创建用于记录的拦截器类 SchoolInterceptorLogging
    4. 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;
      }
      }
      }
      // 其他方法...
      }
      }

      测试和部署

    5. 将拦截器注册到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());
      }
    6. 测试时,运行项目并通过搜索框输入特定值,观察输出窗口中的日志和异常信息。


    7. 通过以上配置,您可以全面了解和使用EF6的弹性连接和命令拦截特性,同时实现对数据库操作的透明记录和错误处理。

    转载地址:http://bheyk.baihongyu.com/

    你可能感兴趣的文章
    NuGet(微软.NET开发平台的软件包管理工具)在VisualStudio中的安装的使用
    查看>>
    nuget.org 无法加载源 https://api.nuget.org/v3/index.json 的服务索引
    查看>>
    Nuget~管理自己的包包
    查看>>
    NuGet学习笔记001---了解使用NuGet给net快速获取引用
    查看>>
    nullnullHuge Pages
    查看>>
    NullPointerException Cannot invoke setSkipOutputConversion(boolean) because functionToInvoke is null
    查看>>
    null可以转换成任意非基本类型(int/short/long/float/boolean/byte/double/char以外)
    查看>>
    Number Sequence(kmp算法)
    查看>>
    Numix Core 开源项目教程
    查看>>
    numpy
    查看>>
    Numpy 入门
    查看>>
    NumPy 库详细介绍-ChatGPT4o作答
    查看>>
    NumPy 或 Pandas:将数组类型保持为整数,同时具有 NaN 值
    查看>>
    numpy 或 scipy 有哪些可能的计算可以返回 NaN?
    查看>>
    numpy 数组 dtype 在 Windows 10 64 位机器中默认为 int32
    查看>>
    numpy 数组与矩阵的乘法理解
    查看>>
    NumPy 数组拼接方法-ChatGPT4o作答
    查看>>
    numpy 用法
    查看>>
    Numpy 科学计算库详解
    查看>>
    Numpy.fft.fft和numpy.fft.fftfreq有什么不同
    查看>>