Session variables lost - Singleton instance becomes null - c#

I'm working on a Web app using ASP.NET. I have a class called "Sistema" that uses the Singleton pattern.
When the instance of Sistema is created, the database connection is opened and a process runs that loads some static information for later use. This lasts almost 2 minutes.
private static Sistema instance;
private Sistema()
{
OpenDataBase();
LoadStaticInformation();
}
public static Sistema GetInstance()
{
if (instance == null)
{
instance = new Sistema();
}
return instance;
}
The reason why I keep the connection to the database open is because I'm using db4o, that strongly suggests this. Here are some references:
db4o best practice to query objects from db
Is it OK to open a DB4o file for query, insert, update multiple times?
Query regarding database connectivity in db4o
On my Web App I have a Master Page that controls if the user is logged in by checking a Session variable. If this Session is null, then the user is sent to the Login Page.
On the Login Page, the first thing I do is to check if the instance of "Sistema" is null. If it is, then when the user hits the Submit button, a message is shown saying "Login can take up to two minutes. Please wait". If it is not null, then no message is shown as the login action takes only a couple of seconds.
I have been told by the users, that when going through the System, they are sometimes sent back to the login page, and when they try to login, the message saying "Login can take up to two minutes" is displayed and login indeed takes a while.
The fact that they are sent back to the login page means that the Session variable is lost, and the message being displayed means that the instance of "Sistema" is also null.
In order to determine why this is happening, I created a web page that sends an email to me when the instance of Sistema detected to be null. I thought that if I was able to know when this occurred, I might discover what is going on.
This web page is really simple. It runs every 10 minutes and checks if the instance of Sistema is null. If it is, then an email is sent and the instance of Sistema is created.
bool isInstanceNull = Sistema.IsInstanceNull();
if (isInstanceNull)
{
String emailTo = "...";
String emailContent = "...";
Functions.SendMail(emailTo, "Sistema is null", emailContent, "");
Sistema.GetInstance();
Functions.SendMail(emailTo, "Sistema has been created", emailContent, "");
}
The only thing I discovered is that it's not happening at a specific time. For example, last week it happened around 7pm, but today it happened at 2 am.
Regarding the Session timeout, I'm using a solution in the code behind: http://www.beansoftware.com/ASP.NET-Tutorials/Keep-Session-Alive.aspx.
Any suggestions to why is this happening?

The application pool has a property that causes it to be automatically recycled every N minutes (defaults to 1740, or every 29 hours.) Make this zero to disable recycling. The propertry is (on IIS7) under the "Recycling" heading and is called "Regular Time Interval (minutes)"
Apart from that, you should always close connections immediately and dont use static connections at all in ASP.NET (when Connection-Pooling is enabled which is default).
I mention it because of:
private static Sistema instance;
private Sistema()
{
OpenDataBase();
LoadStaticInformation();
}

You should not keep a connection to the database open. Typically a new connection is opened for every request. Maybe the database sometimes decides it has too many users or the connection is open for too long, as a result it closes the connection and your object crashes. An open connection to the database is also a security risk.
I'm not 100% sure about this though...
You should probably move connecting to the database down to some kind of query execute method. Also it seems unwise to load such a blob of data all at once, can't you do it on the background or only load the information a user needs to see at the time?

Related

wsmprovhost.exe do not terminate after closing WsManConnectionInfo

I have class (let's call it DbHostWindows) that contains various things about a windows server. I make an instance of this whenever I want to do something remotely on the server. One of the things this class consist of is a WsManConnection - this is part of the constructor:
vWinRM = new WsManConnection(vServerName);
public WsManConnection(string wsManHostName) {
vWsManConnectionInfo = new WSManConnectionInfo(new Uri($"http://{wsManHostName}:5985/wsman")) {
OpenTimeout = WsManDefaultTimeoutInMs,
OperationTimeout = WsManDefaultTimeoutInMs,
IdleTimeout = WsManIdleTimeoutInMs
};
Init();
}
I have noticed that whenever I run the DbHostWindows constructor I get a wsmprovhost.exe process running on the server.
"C:\windows\system32\wsmprovhost.exe -Embedding"
I also noticed that the default timeout of such a process apparently is around 24 days. Setting IdleTimeout to 60000 (minimum value) reduce the timeout to a minute.
My problem is that I would like to get rid of the wsmprovhost.exe process earlier than a minute - in fact as soon as I dispose of the DbHostWindows object and hence the WsManConnectionInfo. I know at this point I will never use this connection again. I can't figure out how to do this, however.
For testing purposes I tried adding these commands in the end of the constructor in order to try and kill it asap and being sure the connection wasn't used for anything:
vWinRm.PowerShell.Stop();
vWinRm.PowerShell.Runspace.Disconnect();
vWinRm.PowerShell.Dispose();
vWinRm.Dispose();
Neither seem to affect the wsmprovhost.exe process at all. The wsmprovhost.exe does close after the IdleTimeout is up. As a workaround I could just raise the MaxProcessesPerShell on the server, but I would rather get these processes to close when the DbHostWindows is disposed.

Crystal Reports reaches job limit despite garbage collection

I have a C# application I recently converted into a service. As part of its normal operation, it creates PDF invoices via CR using the following code:
foreach (string docentry in proformaDocs)
using (ReportDocument prodoc = new ReportDocument()) {
string filename = outputFolder + docentry + ".pdf";
prodoc.Load(/* .rpt file */);
prodoc.SetParameterValue(0, docentry);
prodoc.SetParameterValue(1, 17);
prodoc.SetDatabaseLogon(/* login data */);
prodoc.ExportToDisk(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat,
filename);
prodoc.Close();
prodoc.Dispose();
}
foreach (string docentry in invoiceDocs)
using (ReportDocument invdoc = new ReportDocument()) {
string filename = differentOutputFolder + docentry + ".pdf";
invdoc.Load(/* different .rpt file */);
invdoc.SetParameterValue(0, docentry);
invdoc.SetParameterValue(1, 13);
invdoc.SetDatabaseLogon(/* login data */);
invdoc.ExportToDisk(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat,
filename);
invdoc.Close();
invdoc.Dispose();
}
GC.Collect();
Problem is, after about 3-4 hours of runtime with the above code executing at most every two minutes, the Load() operation hits the processing job limit despite me explicitly disposing the report objects. However, if I leave the service running and launch a non-service instance of the same application, that one executes properly even while the service is still throwing the job limit exception. With the non-service instance having taken care of the processing, the service has nothing to do for the moment - but the instant it does, it throws the error again until I manually stop and restart the service, at which point the error goes away for another 3-4 hours.
How am I hitting the job limit if I'm manually disposing every single report object as soon as I'm done with it and calling garbage collection after each round of processing and disposing? And if the job limit is reached, how can a parallel instance of the same code not be affected by it?
UPDATE: I managed to track down the problem and as it turns out, it's not with CR. I take CR's database login credentials from a SAP Company object inside a Database wrapper class stored in a Dictionary, fetched with this:
public Company GetSAP(string name) {
Database db; //wrapper class
SAP.TryGetValue(name, out db); //fetching from the Dictionary
return db.SAP; //Company object in the wrapper class
}
For some reason, calling this freezes the thread, but the Timer launching the service's normal operation naturally doesn't wait for it to complete and launches another thread, which freezes too upon calling this. This keeps up until the number of frozen threads hits the job limit, at which point an exception is thrown by each new thread due to the still frozen threads filling the job limit. I put in a check to not launch a new thread if one is still running and the application froze upon calling the above function.
The getter of the object the return db.SAP above calls has literally nothing in it other than a return.
Alright, the problem was kinda solved. For some reason, the getters in the COM object I was trying to fetch the login credentials from freeze if accessed from a service but not from a non-service application. Testing this COM-object-stuffed-into-wrapper-class-stuffed-into-Dictionary setup in an IIS application also yielded no freezes. I have no idea why and short of SAP sharing the source code for said COM object, I'm unlikely to ever find out. So I simply declared a few string fields for storing the credentials and cut accessing the COM object out entirely since I didn't need it, only its fields.

RESTful service to make a request to foreign API and update SQL Server database

I want to make a RESTful API (or any other way that can get it done, really) to have it work in a loop to do a specified task everyday at the same hour.
Specifically, I want it to access a foreign API, let's say, at midnight everyday, request the specified data and update the database accordingly. I know how to make a request to an API and make it do something. But I want it to do it automatically so I don't even have to interact with it, not even having to make requests.
The reason for this is that I'm working on a project that requires multiple platforms (and even if it was only one platform the users would be several) and I can't make a request to a foreign API (mainly because it's trial, it's a school project) every time a user logs in or clicks a button on each platform.
I don't know how to even do that (or if it's even possible) with a web service. I've tried with a web form doing it async with BackgroundWorker but nothing.
I thought I might have better luck here with more experienced people.
Hope you can help me out.
Thanks, in advance,
Fábio.
Don't know if I get it right, but it seems to me that the easiest way to do what you want (have a program scheduled to work at a given time, every day) is to use Windows Scheduler to schedule your application to run always on the specific time you want.
I managed to get there, thanks to the help of #Pedro Gaspar - LoboFX.
I didn't want the Windows Scheduler as I want it reflected on the code and I don't exactly have access to the server where it's going to be. That said, what got me there was something like this:
private static string LigacaoBD="something";
private static Perfil perfil = new Perfil(LigacaoBD);
protected void Page_Load(object sender, EventArgs e)
{
Task.Factory.StartNew(() => teste());
}
private void teste()
{
bool verif = false;
while (true)
{
if (DateTime.UtcNow.Hour + 1 == 22 && DateTime.UtcNow.Minute == 12 && DateTime.UtcNow.Second == 0)
verif = false;
if (!verif)
{
int resposta = perfil.Guardar(DateTime.UtcNow.ToString());
verif = true;
}
Thread.Sleep(1000);
}
}
It's inserting into the database through a class library. And with this loop it garantees that it only inserts once (hence the bool) and when it gets to the specified hour, minute and second it resets, allowing it to insert again. If something happens that the servers goes down, when it gets back up it inserts anyway. The only problem is that if it's already inserted and the server goes down it will insert again. But for that there are stored procedures. Well, not for the DateTime.UtcNow.ToString() but that was just a test.

Exceptions connection delay opening of the software

I am having some problems to handle the connection to a database. What I did essentially was to create a class called Database, in this I placed all the methods required to connect to the database, check whether the connection is active and update a control depending on the status of the connection. This works well, control is updated and there are no problems, but when the connection on your computer is absent, the program delays its opening because they generated a series of exceptions in particular that:
MySql.Data.MySqlClient.MySqlException (0x80004005)
The exception occurs in the method isAvailable(), this method checks whether the connection is available or not, and returns true if there is, respectively, or false if it is absent.
public static bool isAvailable()
{
try
{
string connStr = #"Server=xxx;Port=xxx;Database=xxx;Uid=xxx;Pwd=xxx;";
connection = new MySqlConnection(connStr);
connection.Open();
return true;
}catch(Exception ex)
{
connection.Close();
Console.WriteLine(ex.ToString());
return false;
}
}
This method is invoked by checkStatus that contains the following:
public static void checkStatus()
{
if(isAvailable() == false)
{
updateStatus("false");
}
else
{
updateStatus("true");
}
}
checks whether it is true or false and returned respectively to the back passes the value to another method that simply brings up a warning Canvas red or green in the interface ...
checkStatus is called in every aspect of my other classes to check the connection status (before executing a query, pretty much the structure is as follows):
string stm = "SELECT * FROM history";
MySqlCommand cmd = new MySqlCommand(stm, Database.Database.Connection);
Database.Database.checkStatus(); //here
MySqlDataReader rdr = cmd.ExecuteReader();
Within the class constructor call the method isAvailable Database to check if the connection is actually open or not.
At this point I do not understand why the exceptions while managing the program delays the appearance when the user executes it. If no exceptions occur when you start, the program takes about 5 seconds to boot, while with the exceptions I arrived at 1 minute!
What am I doing wrong?
Making a connection to the database server may take quite some time due to many factors: network conditions, server load, authentication overhead etc. Hence the driver (the code behind MySqlConnection) needs to wait an appropriate amount of time to decide whether the connection can or cannot be established. The default timeout is, apparently in your case, 60 seconds (or a multiple of the default 15 seconds as per documentation due to several requests?).
What you can do is lower the timeout by means of the ConnectionTimeout argument in the connection string — see the documentation here. However, bear in mind that by setting it to, say, 5 seconds, you program may end up failing in legitimate cases where it would otherwise succcessfuly connect to the server. I suggest you perform database operations or at least the initial check asynchronously and display a 'please wait' message meanwhile.

CacheItemRemovedCallback causes webserver to crash

THis is an interesting question. I am developing a web-chat software piece and for the past couple of hours I've been trying to figure out why this happens. Basically, I add an actual chat object (the part that does communications) to the Cache collection when you start chatting. In order to detect that you closed the window, I set the sliding expiration to say 10-30 seconds. I also set the callback to let the chat client know that he needs to disconnect to end the chat session. For some odd reason, when I use the code to dispose of the chat client, whatever it is, it causes the entire w3svc process to crash (event log checked). I also tried just sending myself an email when the item is removed, which worked. I even tried to put the entire code in try-catch block but it seems to ignore that as well. Any ideas? O_o
UPD: No, i am not trying to refresh the object (in reference to this).
Adding:
HttpContext.Current.Cache.Insert("ChatClient_" + targetCid + HttpContext.Current.Session.SessionID, cl, null, Cache.NoAbsoluteExpiration,
TimeSpan.FromSeconds(15), CacheItemPriority.Normal, new CacheItemRemovedCallback(removeMyself));
Removing:
public static void removeMyself(string key, Object value, CacheItemRemovedReason reason) {
var wc = (WebClient)value;
try {
wc.Remove();
}
catch { }
}
I am in fact using the lock on HttpContext.Current.cache when adding to the cache objects.
Can you post both the cache.insert and item removed callbacks code? Are you using any kind of locking when inserting into the cache? Have you done anything to the default settings for the ASP.net cache? Are you able to reproduce this on another web server? Are you sure you are expiring the cache in ms instead of seconds...
Is your sliding expiration like this? TimeSpan.FromSeconds(30)

Categories