Timeout when setting up Entity Framework connecting to Azure
Short Answer
It takes about 120 seconds for SQL Azure to create a database. That is why you are timing out. So, increase the CommandTimeout
. One way is to drop a single line of code into your DbContext
constructor.
public MyContext() : base("name=MyContext"){ // three minute command timeout this.Database.CommandTimeout = 180;}
Troubleshooting Steps
I just recreated the exception using a brand new SQL Azure server in West US. When I turned on Entity Framework logging, the output showed that the Create database
statement caused the timeout. Here is the log output.
Opened connection at 9/8/2015 9:24:14 AM -07:00select cast(serverproperty('EngineEdition') as int)-- Executing at 9/8/2015 9:24:14 AM -07:00-- Completed in 40 ms with result: SqlDataReaderClosed connection at 9/8/2015 9:24:14 AM -07:00Opened connection at 9/8/2015 9:24:15 AM -07:00IF db_id(N'mvp1') IS NOT NULL SELECT 1 ELSE SELECT Count(*) FROM sys.databases WHERE [name]=N'mvp1'-- Executing at 9/8/2015 9:24:15 AM -07:00-- Completed in 306 ms with result: 1Closed connection at 9/8/2015 9:24:15 AM -07:00Opened connection at 9/8/2015 9:24:15 AM -07:00drop database [mvp1]-- Executing at 9/8/2015 9:24:15 AM -07:00-- Completed in 10635 ms with result: -1Closed connection at 9/8/2015 9:24:26 AM -07:00Opened connection at 9/8/2015 9:24:26 AM -07:00create database [mvp1]-- Executing at 9/8/2015 9:24:26 AM -07:00-- Failed in 30050 ms with error: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.Closed connection at 9/8/2015 9:24:56 AM -07:00
To troubleshoot further, I connected to the SQL Azure database with SQL Server Management Studio and ran the log output. The commands succeeded but took 1:53 to complete (just about two minutes). That exceeds the default DbContext
command timeout.
The fix: increase the DbContext
command timeout to exceed that duration. Bingo. It worked.
Working Console App on My Computer
packages.config
The only package is EntityFramework
version 6.1.3.
<?xml version="1.0" encoding="utf-8"?><packages> <package id="EntityFramework" version="6.1.3" targetFramework="net452" /></packages>
App.config
This config uses the interceptors
section to log the generated T-SQL. That enabled me to run the logged T-SQL on SQL Server Management Studio to determine how long it takes to create the database.
<?xml version="1.0" encoding="utf-8"?><configuration> <configSections> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/> </configSections> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" /> </startup> <connectionStrings> <add name="MyContext" connectionString="Server=tcp:d01kzjctcf.database.windows.net,1433;Database=mvp1;User ID=mvp@d01kzjctcf;Password=3pN*iV55XmtW;Trusted_Connection=False;Encrypt=True;Connection Timeout=120;" providerName="System.Data.SqlClient" /> </connectionStrings> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" /> <providers> <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> </providers> <interceptors> <interceptor type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework"> <parameters> <parameter value="C:\Temp\LogOutput.txt"/> </parameters> </interceptor> </interceptors> </entityFramework></configuration>
Program.cs
The demo simply drops and creates the database, seeds it with books, selects all the books, and outputs the number of books to the console.
using System;using System.Data.Entity;using System.Collections.Generic;using System.Data.Entity.SqlServer;public class Program{ public static void Main() { Database.SetInitializer<MyContext>(new MyContextInitializer()); var count = 0; using (var context = new MyContext()) { count = context.Books.CountAsync().Result; } Console.WriteLine(string.Format("There are {0} books.", count)); Console.ReadLine(); }}public class MyContextInitializer : DropCreateDatabaseAlways<MyContext>{ protected override void Seed(MyContext context) { context.Database.CommandTimeout = 0; var books = new List<Book> { new Book() {Name = "War and Pease", Author = "Tolstoy",Price=19.95m }, new Book() {Name = "As I Lay Dying", Author = "Faulkner",Price=99.95m }, new Book() {Name = "Harry Potter 1", Author = "J.K. Rowling",Price=19.95m }, new Book() {Name = "Pro Win 8", Author = "Liberty",Price=49.95m }, new Book() {Name = "Book one", Author = "Author1",Price=10.95m }, new Book() {Name = "Book two", Author = "Author2",Price=20.95m }, new Book() {Name = "Book three", Author = "Author3",Price=30.95m } }; books.ForEach(b => context.Books.Add(b)); context.SaveChanges(); base.Seed(context); }}public class MyContext : DbContext{ public MyContext() : base("name=MyContext") { this.Database.CommandTimeout = 180; } public DbSet<Book> Books { get; set; }}public class Book{ public int Id { get; set; } public string Name { get; set; } public string Author { get; set; } public decimal Price { get; set; }}
See Also
Set database timeout in Entity Framework
How do I view the SQL generated by the Entity Framework?
Closing Thoughts
A global CommandTimeout
of three minutes is probably appropriate only for development. In production, you will probably want to decrease that or to set it only for certain specific long-running commands such as database creation.