I am getting a recurring error occuring in the Session_Start method in the Global.asax.cs file (ASP.NET, C#, .NET Framework 4). The error seems to be happening on the following line
if (!OnlineVisitorsUtility.Visitors.ContainsKey(currentContext.Session.SessionID))
which basically checks to see if this sessionId is in the current list of SessionIds.
The error is
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at TestSystem.WebSite.Global.Session_Start(Object sender, EventArgs e) Global.asax.cs:line 142
at System.Web.SessionState.SessionStateModule.CompleteAcquireState()
at System.Web.SessionState.SessionStateModule.BeginAcquireState(Object source, EventArgs e, AsyncCallback cb, Object extraData)
at System.Web.HttpApplication.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
There is no user logged against the error (because this is thrown before anybody logs in). But no user has reported errors attempting to log in, the only reason we see this is because it is showing up in the error logs.
The error occurs every minute or so for a few days, then stops for a few days before re-surfacing.
We record the remote host ip for each error, and it is different for each instance of the error I have looked at. I initially thought it was some sort of automated job kicking this off, but when I track the location IP address I have found it originating in places we have users, places we don't and a private (i'm guessing internal) IP address.
We cannot replicate this error on our internal test and QA systems. I am looking for help in two areas, first, anyone have any idea what could be causing this, and second, if not, what information could I log that would shed some light on what's causing this?
Thanks,
Neil
EDIT
The dictionary in the error trace above is a dictionary that stores a SessionId and a WebsiteVisitor class.
public static Dictionary<string, WebsiteVisitor> Visitors = new Dictionary<string, WebsiteVisitor>();
We only add to this after checking the ContainsKey if statement above. The whole statement is below
lock (visitorsLock)
{
if (!OnlineVisitorsUtility.Visitors.ContainsKey(currentContext.Session.SessionID))
{
OnlineVisitorsUtility.Visitors.Add(currentContext.Session.SessionID, new WebsiteVisitor(currentContext));
}
}
Sounds like you have a synchronization problem with your Visitors dictionary. The Dictionary collection is not thread-safe so read/write access needs to be controlled. I see your using a locking object to resolve this issue, however, the problem with that approach is IIS doesn't guarantee that each request will be running under the same AppDomain instance or even the same worker process.
Instead of cross thread locking you need to look at cross process locking, I would suggest using a Mutex.
Update
Actually #RichardDeeming made a very good point - the Visitors object won't be shared across multiple processes/AppDomain so it can't be a synchronisation problem in that respect, however, the Dictionary is getting corrupt somehow. I would recommend switching to using a ConcurrentDictionary and let the framework take care of the synchronisation for you.
Generally, static property in web apps aren't a good idea as they can't be shared across multiple AppDomains and you can end up running into mysterious issues like this.
Related
I have a web app with a hand-written DAL. It uses Microsoft Application Blocks to actually connect to a MS SQL server database.
When the application is under moderate to heavy load it will return a wrong result set. There is no systematic way to reproduce the error. I can rerun the query in SQL Server Management Studio and get the correct results every time.
I get an error's like the following
DataBinding: 'System.Data.Common.DataRecordInternal' does not contain a property
with the name 'TitleName'.
and
System.IndexOutOfRangeException: TitleId at
System.Data.ProviderBase.FieldNameLookup.GetOrdinal(String fieldName)
The issue ended up being an AJAX call to a method that used a static SqlConnection object.
This object would be in the connection pool, and would be reassigned to something else and would mutate. So if User A is loading the page when the AJAX method was called and User B is Requesting a page and get's User A's Static connection calamity occurs.
If I write this code
protected void Page_Load(object sender, EventArgs e)
{
Page_Load(sender, e);
}
I get the an Error (endless recursion):
and the w3wp.exe process is terminated from task manager.
Fine...
however if i do:
throw new ApplicationException(); //or SystemException();
it appears in just a regular exception page. ( w3wp.exe is still up).
questions :
what kind of exceptions causing the w3wp.exe to shutdown ?
what kind of exceptions causing the Application Pool to shutdown ?
p.s.
according to what ive just written , please think about the following scenario :
i can write a web page , host my site in a farm of sites , and i can terminate the whole w3wp.exe process by creating recursion ..... ( also others will have trouble)...
Can you please answer my questions ?
thanks.
This is most likely the famous StackoverflowException. It's caused by an infinite loop since you're calling the method Page_Load again and again.
From MSDN:
In prior versions of the .NET Framework, your application could catch
a StackOverflowException object (for example, to recover from
unbounded recursion). However, that practice is currently discouraged
because significant additional code is required to reliably catch a
stack overflow exception and continue program execution.
Starting with the .NET Framework version 2.0, a StackOverflowException
object cannot be caught by a try-catch block and the corresponding
process is terminated by default. Consequently, users are advised to
write their code to detect and prevent a stack overflow. For example,
if your application depends on recursion, use a counter or a state
condition to terminate the recursive loop. Note that an application
that hosts the common language runtime (CLR) can specify that the CLR
unload the application domain where the stack overflow exception
occurs and let the corresponding process continue. For more
information, see ICLRPolicyManager Interface and Hosting Overview.
You may want to have a look at this answer:
https://stackoverflow.com/a/4802309/284240
The reason for the exception is memory overflow. There are many ways how an application can cause this, there is no point to guess specific scenarios. I imaging good hosting providers should be protected from misbehaving applications.
to add to the answers which alrdy are available. u cant bring down the whole process because every website in a server runs in a seperate AppDomain. so if ur code misbehaves only ur appdomain wud be killed.
We have a web front end on our business layer server.
Certain pages in our web application instantiate very long running tasks (could be up to 10+ minutes). The way that these requests are handled is like so: -
(on the HTTP request thread)
we make a connection to the business server.
we create a new thread to make the long running call passing in the connection object.
The HTTP request then completes, passing a handle back to the browser,
the browser periodically polls the web server to get updates on the long running task progress.
All requests to the business server are authenticated - the connection's user principal page must have permission to call the method on the business server.
This mechanism works fine as long as our web application is running in Classic mode.
When we run in pipeline mode, we get ObjectDisposedExceptions when the browser polls.
System.ObjectDisposedException: Safe handle has been closed
at System.StubHelpers.StubHelpers.SafeHandleC2NHelper(Object pThis, IntPtr CleanupWorkList)
at Microsoft.Win32.Win32Native.GetTokenInformation(SafeTokenHandle TokenHandle, UInt32 TokenInformationClass, SafeLocalAllocHandle TokenInformation, UInt32 TokenInformationLength, ref UInt32 ReturnLength)
at System.Security.Principal.WindowsIdentity.GetTokenInformation(SafeTokenHandle tokenHandle, TokenInformationClass tokenInformationClass, ref UInt32 dwLength)
at System.Security.Principal.WindowsIdentity.get_User()
at System.Security.Principal.WindowsIdentity.GetName()
at System.Security.Principal.WindowsIdentity.get_Name()
the problem appears to be that the windows principal used to make the connection is disposed when the original request ends (which is understandable - in fact I am surprised that the code worked at all!).
As a way around this problem I was wondering if it was possible to either create a duplicate of the HTTP request principal and use that to create the connection (and dispose of it when the long running task completes) or would it be possible to impersonate the HTTP request principle on the worker thread even after the principal is disposed?
Update
(My comment under Aliostad's question was incorrect: the test page did fail. I managed to confuse myself sufficiently that I wrote my test page so that it did not exercise the same code path as the real (faulting) code. Nevermind!)
I have written a "workaround" for this problem: -
I am in the fortunate position of knowing what roles/groups the business server logic will be querying for before the call to the business server is made. So my workaround is to create a new generic principal based upon the request's principal's membership of these roles. The long running task is run using the generic principal.
I am not 100% happy with this workaround because it is very much a "hack" - i.e. I can see that it would easily fall down if some logic did the (eminently sensible) check of verifying that the principal's identity is authenticated.
So I would still very much appreciate any help / insight into this issue.
Thanks
OK, here is my catch on this.
First of all, if you create a thread, all the current thread's security context will be copied to the new thread - by default. This operation is heavy but much needed (as you can imagine most things will not work without it). In case you need to prevent it and you do not need the copying of context, there is a way to do it and it has been explained in Richter's C# via CLR. Lucky enough, he has shared this very bit of the book here and basically calling a static method to prevent context to be flowed:
ExecutionContext.SuppressFlow();
I cannot think this is being called in WCF although using Reflector, I found a single use of it in here:
[SecuritySafeCritical]
private IAsyncResult BeginGetContext(bool startListening)
{
Exception exception;
do
{
exception = null;
try
{
try
{
if (ExecutionContext.IsFlowSuppressed())
{
return this.listener.BeginGetContext(this.onGetContext, null);
}
using (ExecutionContext.SuppressFlow())
{
return this.listener.BeginGetContext(this.onGetContext, null);
}
}
// .... the rest
Interestingly enough, this is used in 3 places one of them in SharedHttpTransportManager.
Now all this might look like we have found the issue and it is a bug but I very much doubt it.
My hunch is that there is a process recycling happening in between and the context is lost. The way to prove or disprove this would be to use perfmon to register all process recycles and find out if any was in between.
My solution is basically - which you might not like! - to simply insert an item into a queue (MSMQ or a simple database queue) and have a windows service reading it. With this operation being so important, I would never trust IIS to carry out to the finish.
Hope this is useful to you.
Everyone probably notices that most modern applications nowadays has a way for user to send crash/bug report either automatically or with user permission. Some examples are Mozilla Crash Reporter or most Microsoft applications.
I really like this feature since it allows me to collect the bugs report quickly with helpful information than just let my user reports the bug/issue traditionally such as submit a help ticket.
I wonder if there is an easy or systematic way to implement that capability in ASP.NET web application.
Have you guys had any experience or knowledge to share for both WebForms and MVC applications? Or if this could be implemented in Client-side like JavaScript/JQuery, that'd be good.
Thanks!
ASP.NET 2.0 introducted Health monitoring, which allows you to do this by just adding some stuff to the web.config. See: http://msdn.microsoft.com/en-us/library/ms998306.aspx
It can log to mail, sql, eventlog, etc. and allows you to set buffers. So it for example won't kill your mailserver if the sql database goes down or if some user discovers a bug and tries to call it too often a second :-)
You can also log failed authentication and app pool restarts with it, it's pretty usefull if you just need it working quick. It's still questionnable if it is the best solution to manage all the errors. Because it might not got all the information you need, for example browser version or smt like that.
ELMAH is a library that plugs in and detects exceptions. You can also log an event yourself. The events and a great deal of data like url parameters and browser information can be emailed to administrators and optionally stored in a database for display. (Rather like an event log for the web site.) It doesn't have a built-in user form that I've seen, but can probably be extended to include such an option.
I've been using/customizing it for about two years now and it is really exceptional.
Another option might be to use Kampyle which includes a feedback box on the bottom right of your web site. You could use Javascript to trigger the box to appear if an issue is detected on the web site.
For an ASP.NET applicatino--or any Web application for that matter--isn't this just a two-step process of:
Logging the error (obviously); and
Put a form on the error document to allow the user to enter feedback.
Or is there more to this?
Your errors will pass through the Application_Error method of the Global.asax.cs file (which you may have to create). I use this fact to capture the error and log it to a database:
void Application_Error(object sender, EventArgs e)
{
try
{
SqlConnection errConnection = new SqlConnection("Your connection string");
// After setting up a command object, I call a stored procedure to save information about
// the crash. I pass two primary arguments. The first is the URL:
errCommand.Parameters.Add("#URL", SqlDbType.VarChar).Value = Request.Url.ToString();
// The second is the error information.
errCommand.Parameters.Add("#EI", SqlDbType.Text).Value = Server.GetLastError().ToString();
// I pass some other information from my session as well...
// After setting up an output parameter called ErrorID, I call the command...
errCommand.ExecuteNonQuery();
// Now Error ID is stored in the session.
Session["ErrorID"] = (int)ErrorID.Value;
}
catch { } // I do NOT want the error handling call to throw an error.
}
Now, you should have set up your Web.Config file so that a specific page gains control when an error occurs. In this page, you'll check the session for the error ID and show it to the user. In the output, I ask the user to write down the error if they would like to call us for more information. If we do receive a request, I can go into the database and get a complete trace of the error.
You can checkout my tutorial on how to implement exception logging in asp.net - http://jesal.us/blog/index.php/2008/04/08/exception-logging-using-the-database/
I admit it: I don't bother with too much exception handling. I know I should do more but I can never wrap my head around where to start and where to stop. I'm not being lazy. Far from it. It's that I'm overwrought with exception handling ambivalence. It just seems that there is a seemingly infinite number of places in even the smallest app where exception handling can be applied and it can begin to feel like overkill.
I've gotten by with careful testing, validating, and silent prayer but this is a bad programming accident waiting to happen.
So, what are your exception handling best practices? In particular, where are the most obvious/critical places where exception handling should be applied and where are places where it should be considered?
Sorry for the vague the question but I really want to close the book on this once and for all.
Microsoft's Patterns & Practices team did a good job incorporating best practices of exception management into Enterprise Library Exception Handling Application Block
Event if wouldn't use Enterprise Library, I highly recommend you to read their documentation. P&P team describes common scenarios and best practices for exceptions handling.
To get you started I recommend read following articles:
Exception Handling on MSDN
Exception Management in .NET on MSDN
Exception Handling Best Practices in .NET on CodeProject
ASP.NET specific articles:
User Friendly ASP.NET Exception Handling
Global Exception Handling with
ASP.NET
Exception handling in C# and ASP
.Net
The golden rule with exception handling is:
"Only catch what you know how to handle"
I've seen too many try-catch blocks where the catch does nothing but rethrow the exception. This adds no value. Just because you call a method that has the potential to throw an exception doesn't mean you have to deal with the possible exception in the calling code. It is often perfectly acceptable to let exceptions propagate up the call stack to some other code that does know what to do.
In some cases, it is valid to let exceptions propagate all the way up to the user interface layer then catch and display the message to the user. It might be that no code is best-placed to know how to handle the situation and the user must decide the course of action.
I recommend you start by adding a good error page that catches all exceptions and prints a slightly less unfriendly message to the user. Be sure to log all details available of the exception and revise that. Let the user know that you have done this, and give him a link back to a page that will (probably) work.
Now, use that log to detect where special exception handling should be put in place. Remember that there is no use in catching an exception unless you plan to do something with it. If you have the above page in place, there is no use in catching database exceptions individually on all db operations, unless you have some specific way to recover at that specific point.
Remember: The only thing worse than not catching exceptions, is catching them and not doing nothing. This will only hide the real problems.
Might be more about exception handling in general than ASP.NET speific but:
Try to catch exceptions as close to
the cause as possible so that you
can record (log) as much information
about the exception as possible.
Include some form of catch all, last
resort exception handler at the
entry points to your program. In
ASP.NET this could be the
Application level error handler.
If you don't know how to "correctly" handle an exception let it bubble up to the catch all handler where you can treat it as an "unexpected" exception.
Use the Try***** methods in .NET
for things like accessing a
Dictionary. This helps avoid major
performance problems (exception
handling is relatively slow) if you
throw multiple exceptions in say a
loop.
Don't use exception handling to
control normal logic of your
program, e.g. exiting from a loop via
a throw statement.
Start off with a global exception handler such as http://code.google.com/p/elmah/.
Then the question comes down to what kind of application are you writting and what kind of user experience do you need to provide. The more rich the user experience the better exception handling you'll want to provide.
As an example consider a photo hosting site which has disk quotas, filesize limits, image dimension limits, etc. For each error you could simply return "An error has occured. Please try again". Or you could get into detailed error handling:
"Your file is to large. Maximum
filesizes is 5mb."
"Your image is is
to large. Maximum dimensions are
1200x1200."
"Your album is full.
Maximum storage capacity is 1gb".
"There was an error with your
upload. Our hampsters are unhappy.
Please come back later."
etc. etc.
There is no one size fits all for exception handling.
Well at the very basic level you should be handling the HttpApplication.Error event in the Global.asax file. This should log any exception that occurs to a single place so you can review the stack trace of the exception.
Apart from this basic level you should ideally be handling exceptions where you know you can recover from them - for example if you expect a file might be locked then handling the IOException and reporting the error back to the user would be a good idea.