As Jeroen Mostert mentioned in the comments and the docs for SqlCommand.Start()
state:
Returns
Boolean
true
if the listener initialized successfully; false
if a compatible listener already exists.
As the remarks in the docs describe, SqlDependency.Start()
and SqlDependency.Stop()
will keep track of the number of calls to each one. It will ensure a background connection is running or being set up if the number of calls to SqlDependency.Start()
exceeds the number of calls to SqlDependency.Stop()
(though I think it loses track and resets its count if you call SqlDependency.Stop()
more times than than you call SqlDependency.Start()
).
Start()
Errors
It may help to clarify that it is possible for SqlDependency.Start()
to fail. One way to get it to fail is to call it multiple times from one AppDomain
with different connection strings. Within a particular AppDomain
, SqlDependency.Start()
will throw an exception if you pass in a different connection string unless if at least one of the following properties in the connection string is different from a previously passed connection string:
- Database name
- Username
I.e., you are expected to normalize or cache the connection string you first pass to SqlDependency.Start()
so that you never pass it a string that has, for example, a different value for Max Pool Size
. I think it does this to try to avoid creating a lot of broker queues and connections for a single process. Additionally, when it tries to match up a command to a broker queue when you actually set up an SqlDependency
later, it probably uses these distinguishing connection string properties to decide which queue to use.
ASP.NET Life Cycle
From the ASP.NET Application Life Cycle documentation under “Life Cycle Events and the Global.asax file”, note the following:
The Application_Start
method, while an instance method, is called only when the application is starting which often occurs during the first HTTP request for your application. The documentation specifically states:
You should set only static data during application start. Do not set any instance data because it will be available only to the first instance of the HttpApplication
class that is created.
The method you should use to clean up things which you initialized in Application_Start
is Application_End
. When a webapp is gracefully stopped, an instance of your application class will be created and Application_End
called on it. Note that this might be a different instance of the application class than Application_Start
was called on.
Because of ASP.NET’s architecture, a distinct HttpApplication
class instance is required for each request that is processing. That means that multiple instances will be created to handle concurrent requests. The docs also state that, for performance reasons, application class instances may be cached by the framework and used for multiple requests. To give you an opportunity to initialize and cleanup your application class at an instance level, you may implement Init
and Dispose
methods. These methods should configure the application class’s instance variables that are not specific to a particular requests. The docs state:
Init
Called once for every instance of the HttpApplication
class after all modules have been created.
Dispose
Called before the application instance is destroyed.
However, you mentioned that you were initializing global state (i.e., SqlDependency.Start()
) in Application_Start
and cleaning up global state (i.e., SqlDependency.Stop()
) in Dispose()
. Due to the fact that Application_Start
will be called once and is intended for configuring statics/globals and Dispose()
is called for each application class instance that the framework retires (which may happen multiple times before Application_End()
is called), it is likely that you are stopping the dependency quickly.
Thus, it may be that SqlDependency.Stop()
is called after the server runs out of requests, in which case it would clean up the HttpApplication
instance by calling Dispose()
. Any attempts to actually start monitoring for changes by attaching an SqlDependency
to an SqlCommand
should likely fail at after that. I am not sure what already-subscribed commands will do, but they may fail at that point which would trigger your code to resubscribe a new dependency which should then hit an error. This could be the explanation for your “Cannot find the remote service” errors—you called SqlDependency.Stop()
too early and too often.