How to catch exception when database connection is lost when using EF?

1

I'm using ADO.NET Entity Data Model EF Designer from the database. My SQL server is on another PC and when I lost connection with the database my app stops and I can only shut it down. I get:

System.Data.Entity.Core.EntityException
  HResult=0x80131501
  Message=The underlying provider failed on Open.
  Source=EntityFramework

Inner Exception 1:
SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible.

Inner Exception 2:
Win32Exception: The network path was not found

Is there any way to solve this problem?

c#
.net
entity-framework
database-connection
asked on Stack Overflow Aug 21, 2020 by nightclawler22 • edited Aug 21, 2020 by Sowmyadhar Gourishetty

1 Answer

2

For both resiliency and custom handling, the answer is the same. You need to configure a strategy:

Check connection resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency#custom-execution-strategy

The following code, enables retrying on failure:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=EFMiscellanous.ConnectionResiliency;Trusted_Connection=True;ConnectRetryCount=0",
            options => options.EnableRetryOnFailure());
}

If one of the built in strategies is not enough for you, you can define your own and handle the exception there:

This is an example of custom strategies:

using (DemoEntities objContext = GetDemoEntities())
{
    using (TransactionScope objTransaction = new TransactionScope())
    {

        Demo1(objContext);

        Demo2(objContext);

        // Commit the changes in the database.
        objTransaction.Complete();
    }
}

public void Demo1(DemoEntities objContext)
{
    Demo1 objDemo1 = new Demo1();
    objDemo1.Title = "ABC";

    objContext.Demo1.Add(objDemo1);

    objContext.SaveChanges();   
}

public void Demo2(DemoEntities objContext)
{
    Demo2 objDemo2 = new Demo2();
    objDemo2.Title = "ABC";

    objContext.Demo2.Add(objDemo2);

    objContext.SaveChanges();   
}

My Application is running on the one server and database is running on the another server in the AWS.

My application is working smoothly, But 2-3 times weakly I got the error like the below.

System.Data.Entity.Core.EntityException: The underlying provider failed on Open. ---> System.Data.SqlClient.SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server) ---> System.ComponentModel.Win32Exception: Access is denied In first request I got the above error and after the immediate another request I does not get any error and request is successful.

After doing some Google I got the concept like the Connection Resiliency I implemented in my application and it works and retry the query for some specific times after some specific period.

But it fails in the case of the where I used my Custom Transactions like in the above code. It throws the error like this.

System.InvalidOperationException: The configured execution strategy 'MYExecutionStrategy' does not support user initiated transactions. See http://go.microsoft.com/fwlink/?LinkId=309381 for additional information. I configured the Execution Strategy like this:

public class MYExecutionStrategy : DbExecutionStrategy
{
    /// <summary>
    /// The default retry limit is 5, which means that the total amount of time spent 
    /// between retries is 26 seconds plus the random factor.
    /// </summary>
    public MYExecutionStrategy()
    {
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="maxRetryCount"></param>
    /// <param name="maxDelay"></param>
    public MYExecutionStrategy(int maxRetryCount, TimeSpan maxDelay)
        : base(maxRetryCount, maxDelay)
    {
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="exception"></param>
    /// <returns></returns>
    protected override bool ShouldRetryOn(Exception exception)
    {
        bool bRetry = false;

        SqlException objSqlException = exception as SqlException;

        if (objSqlException != null)
        {
            List<int> lstErrorNumbersToRetry = new List<int>()
            {
                5 // SQL Server is down or not reachable
            };

            if (objSqlException.Errors.Cast<SqlError>().Any(A => lstErrorNumbersToRetry.Contains(A.Number)))
            {
                bRetry = true;
            }
        }

        return bRetry;
    }
}
answered on Stack Overflow Aug 21, 2020 by Athanasios Kataras • edited Aug 21, 2020 by Gert Arnold

User contributions licensed under CC BY-SA 3.0