【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:\Users\jaczhang\AppData\Local\Temp\Temporary ASP.NET Files\root\644be5f6\480b064f\App_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后點確定,就會發現出現了數據庫錯誤:

 

看起來是起作用了;

最后記得把剛才注釋掉的行取消注釋。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM