C# Azure Redis Cache - Cannot access a disposed object exception - c#

Followed the below link to implement Redis Cache in Web API.
https://learn.microsoft.com/en-us/azure/redis-cache/cache-dotnet-how-to-use-azure-redis-cache
The Cache works fine for the first time but fails with the error
"Cannot access a disposed object"
...on the subsequent reads.
As mentioned in the above blog, I am disposing the connection at the end of the method and invoking the method again throwing the above exception:
lazyConnection.Value.Dispose();
Also tried to encapsulate the connection attributes in a different class, as mentioned here. But as they are declared static, the same value retain across all the instances and so when disposing the connection leads to the same exception on the subsequent call.
https://www.c-sharpcorner.com/article/using-redis-cache-in-web-api/
There are a couple of ways I can fix this:
Do not dispose the connection and reuse the same connection for all the calls.
Make the Cache connection non-static, so that a new connection gets created and disposed for every call.
What is the right way of doing this?

You should not create a connection on every call, that will be very inefficient.
A static connection should also be avoided if possible. It can make unit tests harder to write and prevents you having multiple connections within the same process.

Related

applWill a not-properly-closed DBConnection be finally closed after GC (after long time)?

I have legacy codes (VB6 Forms) that follow a bad design pattern. It connects to a database in constructor, and close it in the class's destructor (i.e., Class_Terminate for VB6).
There are hundreds of classes that follow this pattern (or use classes which follow this pattern).
We are now migrating it to .NET and met problem. Because when ADO is migrated to ADO.NET (this is a hard requirement), close ADO.NET connection in Finalize method will cause exception.
(More explanation: The exception is : InvalidOperationException: handle is not initialized. Watch into connection object, the State is still Open. From previous questions in StackOverflow, people's suggestion was to Open and Close the connection immediately after usage, and don't keep the connection open for the whole life-time of the class object.)
I've searched and found that in .NET, only unmanaged resources shall be released in Finalize. Object such as DBConnection shall not be closed in Finalize method.
This is a quite embarrassing situation. The best method for us currently is apparently not to Close each connection after usage, and reopen it before usage (it's some kind of time-consuming). We are actually considering to ignore the exception during Close in Finalize method.
I would like to ask,
1) Does DBConnection in ADO.Net implements a Finalize and will close the real underlying connection during GC? If this is true, then ignore close exception in Finalize) won't really do harm to us.
2) If not, will the underlying connections (maybe from connection pool?) be finally returned back to system or connection pool? Say the system or connection pool will check abnormal connection states and retrieve back the resources after some long time?
Thanks.
1) Does DBConnection in ADO.Net implements a Finalize and will close the real underlying connection during GC? If this is true, then ignore close exception in Finalize) won't really do harm to us.
2) If not, will the underlying connections (maybe from connection pool?) be finally returned back to system or connection pool? Say the system or connection pool will check abnormal connection states and retrieve back the resources after some long time?
The garbage collector will collect only managed code. This is why we have the IDisposable interface.
The underlying connection is not managed code, and therefor will not be closed by the garbage collector.
The connection pool will close the underlying connection after x time it's closed and not used. A "real" connection to the database that is tied to an open instance of IDbConnection will not be available for the connection pool to give out or to close.
Combine these two facts together and you'll soon understand that keeping an open connection on the class level will not only prevent it from being collected by the garbage collector as long you have an active reference to that class, but also prevent the connection pool to kill the underlying connection.
This leads to a number of problems already mentioned in the comments.
I understand you have a lot of classes connecting to the database like this (BTW, even back in the days of VB6 and ADO it was a bad practice) - so changing each class manually is not feasible.
However, you can create your own classes to add a layer between the application code and the ADO.Net code, and instead of mapping ADO directly to ADO.Net, map it to your own class.
So basically you'll have a Connection class that implements the IDbConnection interface and a Command class that implements the IDbCommand interface.
In your IDbCommand implementation you should open and close the actual connection when executing the command methods.
This way, you have a relatively small amount of work mapping the old code to the new code, and all the benefits of only using the connection when you actually need it.

Calling SqlDependency.Start two times continuously, the second time failed?

The purpose of calling SqlDependency.Start multiple times is to ensure it's fine before some other action such as creating a new instance of SqlCacheDependency based on a Command. According to Microsoft's document about SqlDependency.Start at here https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldependency.start(v=vs.110).aspx (the Remarks section), looks like calling SqlDependency.Start multiple times is totally fine:
Multiple calls with identical parameters (the same connection string and Windows credentials in the calling thread) are valid.
But actually it can fail (and really it has never succeeded for me) for the second call, making all next attempts to call SqlDependency.Start fail (silently by returning false, no exception is thrown).
What I did should meet the first restriction (mentioned in the Remarks section in the above link), that is all the calls to SqlDependency.Start have the same parameters (in fact there was just 1 same parameter which is the connection string). It looks just like this:
//at initialization step (such as in `Application_Start()` in ASP.NET MVC)
SqlDependency.Start(myConnectionString);//this usually returns OK
//later at the time before creating an instance of SqlCacheDependency
//I tried to call the Start method again to ensure everything is ok
var ok = SqlDependency.Start(myConnectionString);//almost always false
if(ok){
//almost never reach here ...
}
So it's really hard to understand about what stated by Microsoft (in the first restriction in the Remarks section), the 2 calls are exactly the same. But with the second call failed, any that same call used after that will still fail (meaning there is not any chance to start it successfully once I attempted to call it more than once).
When I see the log in Sql Server I can see that there are a lot of messages saying something like Cannot find the remote service ... because it does not exist
I don't need a solution or work-around this problem, I just need some explanation to why it does not work expectedly like what Microsoft stated, or I misunderstood what stated by Microsoft?
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.

web methods and DB connections

If I open some DB connection in some global viable in one call of the web service's method and if concurrently at second call of this method will it see this instance in this global viable ? Are this resources shared or each call has it's own resources ?
Thanks
Global variables tend to be just that, global. If your global variable is a C# static, it will be shared by webservice methods in the AppDomain. This is obviously error-prone - It is better, if each webservice method obtains a new connection when needed, and close it before the method finishes.
Usually Web service use Http request.
In this case it's possible that each call you have to define the object, because the service are stateless...
For services it is better to use some kind of database connection management. Usually you can adapt Open/Close new connection on per-request basis. Note, most likely you will be working with logical connections and connection pool. Those are helpful to significantly reduce load to open physical connection. Physical connection is created without your direct control and is really heavy weight operation.
Do not put connection in a shared static variable, because connection is typically a disposable resource, which means you must dispose it. If something goes wrong and your connection to the database is corrupted then all your subsequent calls are deemed in doom.

NetworkStream Pooling

I have a multi-threaded application which communicates with a server over a TCP connection. The application would be deployed as a windows service.
The way it has been implemeted is, there is Controller which creates Communicator objects, assigns the port number, message count etc. properties to the Communicator and invokes its StartClient method to commence the dialog with the server.
Within the StartClient method, each Communicator object creates a connection to the server, using the port number and url specified by the Controller. After establishing the connection, it internally creates a thread and calls the ReadMessages method which keeps reading from the server till the message count is met and then gets closed down.
Based on the runtime conditions, there might be a need to reuse the Communicator object to talk with the server again and hence, the ReadMessages method woudl be called again.
Initially, we had been calling Dispose() method for the NetworkStream, StreamReader and StreamWriter objects when the ReadMessages method completed, but with the reconnecting scenario, it used to throw "Cannot access a disposed object" error. So, we commented out the Dispose method call for testing.
As of now, it works fine, but I am concerned that, this isnt the best way to achieve this functionlity as I am not disposing the objects ever.
I was thinking in terms of object pooling, If it is possible to have a pool of Stream objects which could be reused by different threads?
One way to tackle this can be to create a new instance of Stream objects each time the Communicator connects with the server, but I think that would be an expensive operation.
Can you please help me identify a better approach to handle the situation here so that I can reuse the Communicator object without a performance hit?
The approach will be based on how frequently you need to read messages - if its occasional the n, I would recommend that you re-factor your communicator object to make "ReadMessages" operation atomic - i.e. it would connect to the server, create network stream, read messages and then dispose every thing.

Maintain a single connection or open only when i need to change something?

I have an SQL server on a server at home (which is an Atom processor with 1GB ram), and i'm using it to store data for one or two of my applications. I was wondering if i should create a DataContext object when the program starts then hold onto it for the entire life of the app, or only create the connection when necessary. What happens if the application dies suddenly? does the connection get cleaned up?
Unless you're handing DataContext object an already open SqlConnection, DataContext will automatically close the database connection after the completion of a database operation anyway. So it won't keep the connection open. You can see this by looking at DataContext class in Reflector or you can read ASP.NET MVC Tip #34: Dispose of your DataContext(or Don't) blog post. So even if your DataContext object continues to live, there should not be any open database connection.
If you're handling the database connection outside of DataContext and keeping it open, then you really should not do this. Generally, you should create and use resources when and where you need them including DataContext object. There is no need to keep a database connection open without any demand for it, close it so that it gets released back into the pool to serve another database connection request. As I said, if you're letting DataContext handle the database connection, you don't need to do anything special as far as the database connection is concerned.
If your application crashes suddenly and terminates, you should be ok since everyhing will die including open database connections and the underlying connection pool associated with your application domain.
Bring up the data context when you need it and get rid of it when you're done.
Having one global datacontext means you have to pass it around to everything that needs it. (Every method you write that needs database access has an extra parameter in its signature).
Having a single global datacontext is also just going to become a pain if you ever decide to multi-thread one of your apps.
Have you looked at SQL connection pooling in .NET? Have a look at the article at http://msdn.microsoft.com/en-us/library/8xx3tyca%28VS.80%29.aspx. Connection pooling takes care of all the dirty work for you and automatically cleans up after itself if an error occurs in your program. It's pretty efficient at re-using connections so there is very little overhead in re-using the connections (creating the first connection when your program starts still has the same cost). It might be overkill for small applications but it's probably a good habit to get into for larger projects.

Categories