I have a WCF web service hosted on IIS 7. This web service serves up JSON content for use in mobile apps. It uses the Entity Framework on top of MS SQL 2005, and the Interface contract looks like the below:
[ServiceContract]
public interface MyService
{
[WebInvoke(Method = "GET", UriTemplate = "/GetStuff?skip={skip}&take={take}&loanAmt={loanAmt}&propertyVal={propertyVal}&Term={Term}&MonthlyRent={MonthlyRent}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
ProductsDTO GetProducts(int skip, int take, decimal loanAmt, decimal propertyVal, int Term, decimal MonthlyRent);
}
The implementation looks like this:
public ProductsDTO GetProducts(int skip, int take, decimal loanAmt, decimal propertyVal, int Term, decimal MonthlyRent)
{
//Some set up code
using (MyEntities context = new MyEntities())
{
//Get our products
}
return ReturnedList
}
On the first run of this, it can take anywhere up to 15 seconds (unacceptable for a mobile app), on subsequent runs, the data comes back in under a second. After 5 minutes of inactivity, the WCF service reverts to taking 15 seconds to start.
I initially thought the bottle neck was at IIS7 and thought my App Pool was shutting off. After setting the App Pool to never recycle and studying w3wp.exe processes on the IIS server, I realized this was not the case. It is the database session that is shutting off after those five minutes.
This being the case, I want to hold a SQL session open to immediately serve up requests from the WCF application, however, I don’t want to set the Entity Context as a singleton or leave this open in the service as I understand this is poor practise. I could pass a SQL connection object TO the context (using (MyEntities context = new MyEntities(MySQLConnection))) and hold that open? Or can someone suggest something else?
I had seen lots of posts with scripts that touch the web service to keep it alive which gave me the creeping horrors, so have avoided going down this route.
What are your thoughts?
Update 1
As per Andomars response, I have added the following initialization code to the WCF service.
public Service1()
{
// Blocking call that initializes
// the service instance
this.Initialize();
}
BackgroundWorker KeepSQLAlive = new BackgroundWorker();
private void Initialize()
{
KeepSQLAlive.DoWork += new DoWorkEventHandler(KeepSQLAlive_DoWork);
KeepSQLAlive.RunWorkerAsync();
}
void KeepSQLAlive_DoWork(object sender, DoWorkEventArgs e)
{
Timer pingback = new Timer(180000);
pingback.Elapsed += new ElapsedEventHandler(pingback_Elapsed);
pingback.Start();
}
void pingback_Elapsed(object sender, ElapsedEventArgs e)
{
using (MyEntities context = new MyEntities ())
{
context.ExecuteStoreCommand("select @@servername");
}
}
This feels like a bit of a fudge, and I’m a bit worried without creating the service as a singleton the service will continue to spawn SQL sessions without ever killing any. However, if it works it is the path of least resistance as hosting this code in a windows service would take more time and I am unclear how to integrate this in with IIS security (I want to use SSL). I will report back whether the above works. (thanks for the assistance all)
You could add a background thread that runs
select @@servername(or another trivial query) every minute. That should keep the connection pool warm.