zoukankan      html  css  js  c++  java
  • EF6学习笔记(四) 弹性连接及命令拦截调试

    EF6学习笔记总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理)

    本章原文地址:Connection Resiliency and Command Interception

    原文有些地方讲的比较细,个人根据实际理解做些缩减,或者加入一些个人理解;

    第1部分 弹性连接

    为什么要弹性连接?什么是弹性连接?

    在实际的网络应用中,尤其是在Internet上的网络应用,就算Web服务器和数据库服务器在一个数据中心,也不能保证WEB服务器和数据库服务器没有任何延迟或者其他网络问题;

    尤其如PaaS层的Azure的SQL或者阿里的SQL、MySQL数据库服务器,都是做了网络负载均衡的,在一定的条件下能提供的服务是有限的,在其SLA里都会有定义;

    而超出其SLA的部分请求就会被取消响应,那么在WEB网页应用设计的时候,就需要考虑这一点,在出现一些异常情况的时候,需要能够在短时间内进行一次或多次Retry.

    这就称为:弹性的连接

    原文中对EF6实现弹性连接功能仅做了简单代码就实现了,至于具体在实际项目中是不是就这么简单,本人还需要进一步深入学习。

    先看看原文如何做的:

    在DAL文件夹定义 SchoolConfiguration类,继承自DbConfiguration类, 在这个类中设置SQL数据库的执行策略 (execution strategy ,这个名词是EF6 对于Retry Policy 的命名

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

    EF6会自动运行继承自DbConfiguration类的代码;当然也可以通过配置Web.config 来实现,可以参考 EntityFramework Code-Based Configuration
    然后在 Student 控制器里增加申明:

    using System.Data.Entity.Infrastructure;

    最后就是将所有 Try-catch代码块的 catch 后面捕获的 Exception 类型转为 RetryLimitExceededException

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

    这样就会是出现数据库连接异常的时候,进行Retry,多次Retry达到Limit值还是错误,则抛出异常。

    更多的说明,需要参考: Entity Framework Connection Resiliency / Retry Logic
     

    第2部分 命令拦截调试

    设置好了弹性连接后,如何能够看到到底是不是Retry了,则需要一些调试手段;

    当然你可以使用Web请求Log等来查看,或者EF6 提供的Dedicated Logging API (dedicated logging API)

    本次直接采用EF6的 Interception 功能来实现。

    对于日志记录来说,最好的方式是做一个接口来定义,而不是直接每次用硬代码来Call System.Diagnostics.Trace

    因为这样,对于以后如果日志记录机制有调整的话,就容易很多了。

    实际操作体验:

    1、新建一个Logging 的文件夹

    2、在文件夹中新建一个ILogger 接口,接口中定义了不同等级的信息处理方式;

    TraceApi 可以跟踪连接外部服务例如SQL服务的每一步延迟情况;

    using System;
    
    namespace EFTest.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);
        }
    }

    3、在文件夹内新建Logger这个类,集成自ILogger接口,并实现接口内方法;

    using System;
    using System.Diagnostics;
    using System.Text;
    
    namespace EFTest.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)
            {
                // 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();
            }
        }
    }

    看代码可以知道,实际是通过.NET 的 System.Diagnostics 来跟踪记录日志的;日志信息可以写到很多其他位置,例如Azure 的blob storage ;

    本次,只是把日志输出到VS 的Output窗口;

    在实际项目中,如果用其他记录日志机制来代替 System.Diagnostics的话,ILogging接口方式比较容易来实现这个切换。

    下一步需要建一个拦截类来进行对EF6每一次向数据库发SQL请求的时候进行拦截记录日志或者发一个模拟的短暂错误;

    这个类必须继承自 DbCommandInterceptor

    在DAL文件夹新建 SchoolInterceptorLogging类,集成自DbCommandInterceptor

    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 EFTest.Logging;
    
    namespace EFTest.DAL
    {
        public class SchoolInterceptorLogging : 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", "SchoolInterceptor.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", "SchoolInterceptor.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", "SchoolInterceptor.ReaderExecuted", _stopwatch.Elapsed, "Command: {0}: ", command.CommandText);
                }
                base.ReaderExecuted(command, interceptionContext);
            }
        }
    }

     另外,为了模拟在筛选查询的时候产生一个短暂错误,写一个类让用户在输入框内输入 Throw 的触发这个错误,在DAL文件夹里建SchoolInterceptorTransientErrors类:

    重载了ReaderExecuting方法,当用户输入的是Throw的时候,做一个特殊处理来进行测试;

    如果希望测试其他数据库操作,则可以考虑重载 NonQueryExecutingScalarExecuting这两个方法。

    using System;
    using System.Data.Common;
    using System.Data.Entity.Infrastructure.Interception;
    using System.Data.SqlClient;
    using System.Reflection;
    using System.Linq;
    using EFTest.Logging;
    
    namespace EFTest.DAL
    {
        public class SchoolInterceptorTransientErrors : 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 = "%an%";
                    command.Parameters[1].Value = "%an%";
                }
    
                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;
            }
        }
    }

    在Global.asax中添加声明:
    using System.Data.Entity.Infrastructure.Interception;

    并在Application_Start()方法中增加后面两行代码:

            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                //Database.SetInitializer<SchoolContext>(new SchoolInitializer());
                DbInterception.Add(new SchoolInterceptorTransientErrors());
                DbInterception.Add(new SchoolInterceptorLogging());            
            }

    当然,这两行代码可以加在SchoolConfiguration类里,初始化的时候直接加载执行:(注:上面和下面两段代码只能选其中一种

    using System.Data.Entity;
    using System.Data.Entity.Infrastructure.Interception;
    using System.Data.Entity.SqlServer;
    
    namespace EFTest.DAL
    {
        public class SchoolConfiguration : DbConfiguration
        {
            public SchoolConfiguration()
            {
                SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy());
                DbInterception.Add(new SchoolInterceptorTransientErrors());
                DbInterception.Add(new SchoolInterceptorLogging());
            }
        }
    }

    下面就可以进行测试了,进Home/Index后点Students,进入Student/Index 就会发现VS 的Output 窗口有一些Debug信息输出:

    SELECT Count(*)
    FROM INFORMATION_SCHEMA.TABLES AS t
    WHERE t.TABLE_SCHEMA + '.' + t.TABLE_NAME IN ('dbo.Course','dbo.Enrollment','dbo.Student')
        OR t.TABLE_NAME = 'EdmMetadata': 
    Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.RemoteDependency","time":"2017-08-25T07:04:11.0689220Z","tags":{"ai.internal.sdkVersion":"rddf: 2.0.0.25000","ai.device.roleInstance":"chnsbopc02.dc01.fujixerox.net","ai.operation.name":"GET Student/Index","ai.operation.parentId":"yqYB5YWz4YY=","ai.operation.id":"yqYB5YWz4YY="},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"(localdb)\ProjectsV13 | master","id":"+xoBYBiNrPM=","value":0.3565,"dependencyKind":0,"success":true,"properties":{"DeveloperMode":"true"}}}}
    iisexpress.exe Information: 0 : Component:SQL Database;Method:SchoolInterceptor.ScalarExecuted;Timespan:00:00:00.0233412;Properties:Command: IF db_id(N'EFTest') IS NOT NULL SELECT 1 ELSE SELECT Count(*) FROM sys.databases WHERE [name]=N'EFTest': 
    Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.RemoteDependency","time":"2017-08-25T07:04:11.2577658Z","tags":{"ai.internal.sdkVersion":"rddf: 2.0.0.25000","ai.device.roleInstance":"chnsbopc02.dc01.fujixerox.net","ai.operation.name":"GET Student/Index","ai.operation.parentId":"yqYB5YWz4YY=","ai.operation.id":"yqYB5YWz4YY="},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"(localdb)\ProjectsV13 | EFTest","id":"hGEE5js+frc=","value":1.2592,"dependencyKind":0,"success":true,"properties":{"DeveloperMode":"true"}}}}
    iisexpress.exe Information: 0 : Component:SQL Database;Method:SchoolInterceptor.ReaderExecuted;Timespan:00:00:00.0260725;Properties:Command: SELECT 
        [GroupBy1].[A1] AS [C1]
        FROM ( SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[__MigrationHistory] AS [Extent1]
            WHERE [Extent1].[ContextKey] = @p__linq__0
        )  AS [GroupBy1]: 
    Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.RemoteDependency","time":"2017-08-25T07:04:11.3081972Z","tags":{"ai.internal.sdkVersion":"rddf: 2.0.0.25000","ai.device.roleInstance":"chnsbopc02.dc01.fujixerox.net","ai.operation.name":"GET Student/Index","ai.operation.parentId":"yqYB5YWz4YY=","ai.operation.id":"yqYB5YWz4YY="},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"(localdb)\ProjectsV13 | EFTest","id":"ULROylXtnGQ=","value":1.6166,"dependencyKind":0,"success":true,"properties":{"DeveloperMode":"true"}}}}
    iisexpress.exe Information: 0 : Component:SQL Database;Method:SchoolInterceptor.ReaderExecuted;Timespan:00:00:00.0155956;Properties:Command: SELECT TOP (1) 
        [Project1].[C1] AS [C1], 
        [Project1].[MigrationId] AS [MigrationId], 
        [Project1].[Model] AS [Model], 
        [Project1].[ProductVersion] AS [ProductVersion]
        FROM ( SELECT 
            [Extent1].[MigrationId] AS [MigrationId], 
            [Extent1].[Model] AS [Model], 
            [Extent1].[ProductVersion] AS [ProductVersion], 
            1 AS [C1]
            FROM [dbo].[__MigrationHistory] AS [Extent1]
            WHERE [Extent1].[ContextKey] = @p__linq__0
        )  AS [Project1]
        ORDER BY [Project1].[MigrationId] DESC: 
    Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.RemoteDependency","time":"2017-08-25T07:04:11.3703060Z","tags":{"ai.internal.sdkVersion":"rddf: 2.0.0.25000","ai.device.roleInstance":"chnsbopc02.dc01.fujixerox.net","ai.operation.name":"GET Student/Index","ai.operation.parentId":"yqYB5YWz4YY=","ai.operation.id":"yqYB5YWz4YY="},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"(localdb)\ProjectsV13 | EFTest","id":"/xZUhdnSdM8=","value":1.7563,"dependencyKind":0,"success":true,"properties":{"DeveloperMode":"true"}}}}
    iisexpress.exe Information: 0 : Component:SQL Database;Method:SchoolInterceptor.ReaderExecuted;Timespan:00:00:00.0176946;Properties:Command: SELECT 
        [GroupBy1].[A1] AS [C1]
        FROM ( SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[Student] AS [Extent1]
        )  AS [GroupBy1]: 
    'iisexpress.exe' (CLR v4.0.30319: /LM/W3SVC/3/ROOT-1-131481182423379125): Loaded 'EntityFrameworkDynamicProxies-EFTest'. 
    Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.RemoteDependency","time":"2017-08-25T07:04:11.4280626Z","tags":{"ai.internal.sdkVersion":"rddf: 2.0.0.25000","ai.device.roleInstance":"chnsbopc02.dc01.fujixerox.net","ai.operation.name":"GET Student/Index","ai.operation.parentId":"yqYB5YWz4YY=","ai.operation.id":"yqYB5YWz4YY="},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"(localdb)\ProjectsV13 | EFTest","id":"bDKxb2FBJ1g=","value":0.9676,"dependencyKind":0,"success":true,"properties":{"DeveloperMode":"true"}}}}
    iisexpress.exe Information: 0 : Component:SQL Database;Method:SchoolInterceptor.ReaderExecuted;Timespan:00:00:00.0194244;Properties:Command: SELECT 
        [Extent1].[ID] AS [ID], 
        [Extent1].[LastName] AS [LastName], 
        [Extent1].[FirstMidName] AS [FirstMidName], 
        [Extent1].[EnrollmentDate] AS [EnrollmentDate]
        FROM [dbo].[Student] AS [Extent1]
        ORDER BY [Extent1].[LastName] ASC
        OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY : 
    'iisexpress.exe' (CLR v4.0.30319: /LM/W3SVC/3/ROOT-1-131481182423379125): Loaded 'C:UsersjaczhangAppDataLocalTempTemporary ASP.NET Files
    oot644be5f6480b064fApp_Web_jlggwjiw.dll'. 
    Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Request","time":"2017-08-25T07:04:10.5173746Z","tags":{"ai.operation.id":"yqYB5YWz4YY=","ai.internal.sdkVersion":"web: 2.0.0.25000","ai.device.roleInstance":"chnsbopc02.dc01.fujixerox.net","ai.operation.name":"GET Student/Index"},"data":{"baseType":"RequestData","baseData":{"ver":2,"id":"yqYB5YWz4YY=","name":"GET Student/Index","startTime":"2017-08-25T15:04:10.5173746+08:00","duration":"00:00:01.6326287","success":true,"responseCode":"200","url":"http://localhost:9910/Student","httpMethod":"GET","properties":{"DeveloperMode":"true"}}}}

    然后在筛选输入框输入Throw 点确定: 可以看到里面触发一个 代码为20的短暂错误:

    iisexpress.exe Information: 0 : Returning transient error for command: SELECT 
        [GroupBy1].[A1] AS [C1]
        FROM ( SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[Student] AS [Extent1]
            WHERE ([Extent1].[LastName] LIKE @p__linq__0 ESCAPE N'~') OR ([Extent1].[FirstMidName] LIKE @p__linq__1 ESCAPE N'~')
        )  AS [GroupBy1]
    iisexpress.exe Error: 0 : Error executing command: SELECT 
        [GroupBy1].[A1] AS [C1]
        FROM ( SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[Student] AS [Extent1]
            WHERE ([Extent1].[LastName] LIKE @p__linq__0 ESCAPE N'~') OR ([Extent1].[FirstMidName] LIKE @p__linq__1 ESCAPE N'~')
        )  AS [GroupBy1] Exception: System.Data.SqlClient.SqlException (0x80131904): Dummy
    ClientConnectionId:9b424f7d-306b-450b-8a3e-58198487b8bb
    Error Number:20,State:0,Class:0
    iisexpress.exe Information: 0 : Returning transient error for command: SELECT 
        [GroupBy1].[A1] AS [C1]
        FROM ( SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[Student] AS [Extent1]
            WHERE ([Extent1].[LastName] LIKE @p__linq__0 ESCAPE N'~') OR ([Extent1].[FirstMidName] LIKE @p__linq__1 ESCAPE N'~')
        )  AS [GroupBy1]
    iisexpress.exe Error: 0 : Error executing command: SELECT 
        [GroupBy1].[A1] AS [C1]
        FROM ( SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[Student] AS [Extent1]
            WHERE ([Extent1].[LastName] LIKE @p__linq__0 ESCAPE N'~') OR ([Extent1].[FirstMidName] LIKE @p__linq__1 ESCAPE N'~')
        )  AS [GroupBy1] Exception: System.Data.SqlClient.SqlException (0x80131904): Dummy
    ClientConnectionId:941ac661-66d3-4779-a690-188d13144150
    Error Number:20,State:0,Class:0
    iisexpress.exe Information: 0 : Returning transient error for command: SELECT 
        [GroupBy1].[A1] AS [C1]
        FROM ( SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[Student] AS [Extent1]
            WHERE ([Extent1].[LastName] LIKE @p__linq__0 ESCAPE N'~') OR ([Extent1].[FirstMidName] LIKE @p__linq__1 ESCAPE N'~')
        )  AS [GroupBy1]
    iisexpress.exe Error: 0 : Error executing command: SELECT 
        [GroupBy1].[A1] AS [C1]
        FROM ( SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[Student] AS [Extent1]
            WHERE ([Extent1].[LastName] LIKE @p__linq__0 ESCAPE N'~') OR ([Extent1].[FirstMidName] LIKE @p__linq__1 ESCAPE N'~')
        )  AS [GroupBy1] Exception: System.Data.SqlClient.SqlException (0x80131904): Dummy
    ClientConnectionId:47685ec4-e837-4e05-bbb3-948e3f3f87a8
    Error Number:20,State:0,Class:0
    iisexpress.exe Information: 0 : Returning transient error for command: SELECT 
        [GroupBy1].[A1] AS [C1]
        FROM ( SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[Student] AS [Extent1]
            WHERE ([Extent1].[LastName] LIKE @p__linq__0 ESCAPE N'~') OR ([Extent1].[FirstMidName] LIKE @p__linq__1 ESCAPE N'~')
        )  AS [GroupBy1]
    iisexpress.exe Error: 0 : Error executing command: SELECT 
        [GroupBy1].[A1] AS [C1]
        FROM ( SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[Student] AS [Extent1]
            WHERE ([Extent1].[LastName] LIKE @p__linq__0 ESCAPE N'~') OR ([Extent1].[FirstMidName] LIKE @p__linq__1 ESCAPE N'~')
        )  AS [GroupBy1] Exception: System.Data.SqlClient.SqlException (0x80131904): Dummy
    ClientConnectionId:35de62b7-cda6-4db7-88e0-48d708f42826
    Error Number:20,State:0,Class:0
    Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.RemoteDependency","time":"2017-08-25T07:06:51.9163289Z","tags":{"ai.internal.sdkVersion":"rddf: 2.0.0.25000","ai.device.roleInstance":"chnsbopc02.dc01.fujixerox.net","ai.operation.name":"GET Student/Index","ai.operation.parentId":"kZm9/0YA8y4=","ai.operation.id":"kZm9/0YA8y4="},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"(localdb)\ProjectsV13 | EFTest","id":"0iOb6Vj5zqI=","value":3.3859,"dependencyKind":0,"success":true,"properties":{"DeveloperMode":"true"}}}}
    iisexpress.exe Information: 0 : Component:SQL Database;Method:SchoolInterceptor.ReaderExecuted;Timespan:00:00:00.0382038;Properties:Command: SELECT 
        [GroupBy1].[A1] AS [C1]
        FROM ( SELECT 
            COUNT(1) AS [A1]
            FROM [dbo].[Student] AS [Extent1]
            WHERE ([Extent1].[LastName] LIKE @p__linq__0 ESCAPE N'~') OR ([Extent1].[FirstMidName] LIKE @p__linq__1 ESCAPE N'~')
        )  AS [GroupBy1]: 
    Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.RemoteDependency","time":"2017-08-25T07:06:51.9705260Z","tags":{"ai.internal.sdkVersion":"rddf: 2.0.0.25000","ai.device.roleInstance":"chnsbopc02.dc01.fujixerox.net","ai.operation.name":"GET Student/Index","ai.operation.parentId":"kZm9/0YA8y4=","ai.operation.id":"kZm9/0YA8y4="},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"(localdb)\ProjectsV13 | EFTest","id":"b1S5ExJ8ugQ=","value":2.5604,"dependencyKind":0,"success":true,"properties":{"DeveloperMode":"true"}}}}
    iisexpress.exe Information: 0 : Component:SQL Database;Method:SchoolInterceptor.ReaderExecuted;Timespan:00:00:00.0195543;Properties:Command: SELECT 
        [Project1].[ID] AS [ID], 
        [Project1].[LastName] AS [LastName], 
        [Project1].[FirstMidName] AS [FirstMidName], 
        [Project1].[EnrollmentDate] AS [EnrollmentDate]
        FROM ( SELECT 
            [Extent1].[ID] AS [ID], 
            [Extent1].[LastName] AS [LastName], 
            [Extent1].[FirstMidName] AS [FirstMidName], 
            [Extent1].[EnrollmentDate] AS [EnrollmentDate]
            FROM [dbo].[Student] AS [Extent1]
            WHERE ([Extent1].[LastName] LIKE @p__linq__0 ESCAPE N'~') OR ([Extent1].[FirstMidName] LIKE @p__linq__1 ESCAPE N'~')
        )  AS [Project1]
        ORDER BY [Project1].[LastName] ASC
        OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY : 
    Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Request","time":"2017-08-25T07:06:40.0512275Z","tags":{"ai.operation.id":"kZm9/0YA8y4=","ai.internal.sdkVersion":"web: 2.0.0.25000","ai.device.roleInstance":"chnsbopc02.dc01.fujixerox.net","ai.operation.name":"GET Student/Index"},"data":{"baseType":"RequestData","baseData":{"ver":2,"id":"kZm9/0YA8y4=","name":"GET Student/Index","startTime":"2017-08-25T15:06:40.0512275+08:00","duration":"00:00:11.9404844","success":true,"responseCode":"200","url":"http://localhost:9910/Student?SearchString=Throw","httpMethod":"GET","properties":{"DeveloperMode":"true"}}}}

    为了看Retry是否其作用,可以先注释掉以下行:
      public SchoolConfiguration()
            {
                //SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy());           
            }

    然后再进入网页,输入Throw后点确定,就会发现出现了数据库错误:

    看起来是起作用了;

    最后记得把刚才注释掉的行取消注释。

  • 相关阅读:
    Python 类中方法的内部变量,命名加'self.'变成 self.xxx 和不加直接 xxx 的区别
    用foreach遍历 datagridView 指定列所有的内容
    treeView1.SelectedNode.Level
    YES NO 上一个 下一个
    正则 单词全字匹配查找 reg 边界查找 精确匹配 只匹配字符 不含连续的字符
    抓取2个字符串中间的字符串
    sqlite 60000行 插入到数据库只用不到2秒
    将多行文本以单行的格式保存起来 读和写 ini
    将秒转换成时间格式
    richtextbox Ctrl+V只粘贴纯文本格式
  • 原文地址:https://www.cnblogs.com/jacky-zhang/p/7426939.html
Copyright © 2011-2022 走看看