Exception info from a ThreadAbortedException - asp.net

I get an exception at response.redirect() and Visual Studio does not help me with appropriate info. I only get this for ex:expression cannot be evaluated, message:subprocess annulled and _HResult:-2146233040. I don't get a helplink or anything else.
Try
Dim unidadD As String = Request.QueryString("unity")
Dim categD As String = Request.QueryString("category")
Dim resulD As String = Request.QueryString("result")
Dim anioD As String = Request.QueryString("year")
Dim cicloD As String = Request.QueryString("cicle")
Response.Redirect("~/Evaluacion/Detalle_Resultados.aspx?op=1" & "&unity=" & unidadD & "&category=" & categD & "&result=" & resulD & "&cicle=" & cicloD & "&year=" & anioD)
Catch exa As System.Threading.ThreadAbortException
Dim link As String = exa.HelpLink
End Try

Response.Redirect is expected to throw a ThreadAbortedException. Simply move the Response.Redirect out of the try/catch block.
Another option is to use:
Response.Redirect(url, False)
This will redirect without ending the current request. You can later call Application.CompleteRequest.
Another alternative would be
Try
Response.Redirect(url)
Catch tax as ThreadAbortedException
' Do nothing, as this is an expected exception
' No need to rethrow, as this exception is automatically re-thrown
End Try

This is expected behaviour, as a workaround just pass false in Response.Redirect e.g.
Response.Redirect("...", false);
Or as already suggested, get rid of the Try...Catch - not quite sure what you expect to do with a ThreadAbortException anyway...

Related

Error when accessing cookies when a cookies without a name exists

On a few of the Classic ASP websites I manage for the last few days I have been getting some error notifications (with no error number) that always show an error on a line number where a cookie value is being requested.
Looking at the request for each of these errors, they all have unusual cookies, and look like some sort of hack attempt.
The lines that are indicated as causing the error are all like this:
strCookieCart = Request.Cookies("cart")
Here's a couple of samples of the cookies being sent (truncated)... Note the =true (no name, just a value).
HTTP_COOKIE:=true; yuv=u97Yoe-o0UWp7ho_vaB2csT-xxaQ37gMWzhB1MARTSNk1QKpjJTXmZYMRQ095rM96MaNbhx1tEdJ
HTTP_COOKIE:pll_language=en; =true; yandexuid=6536735381437958890; st=6c9838994ffb
Is Classic ASP incapable of handling these? Is there any way to avoid these errors and ignore the bad values? Are these always likely to be hack attempts or could there be legitimate requests without cookie names?
I suppose I could check for these looking at Request.ServerVariables("HTTP_COOKIE") by manually parsing or using a regular expression check of some sort. Does anyone else do this? Any code to share?
A second answer to my own question and the solution I have now implemented is to add the following code to my common include file.
It tests whether Classic ASP can read the cookies and, using error trapping, ends the response if an error is detected.
On Error Resume Next
Request.Cookies("test")
If Err.Number <> 0 Then Response.End
On Error Goto 0
This is a better solution to my other answer as there is no point in generating a page for what is obviously an attack of some sort so ending the script as soon as possible is a better choice.
My proposed answer to my own question is to create a class that extracts all the valid keys and values for the cookies on initialisation, and has a function to return a value for a specified key.
Unfortunately it doesn't work for cookies that contain a collection of multiple values, but I don't generally use these anyway.
Here is the class:
<%
Class MyRequest
Private m_objCookies
Private Sub Class_Initialize()
Dim strCookies, i, strChar, strName, strValue, blnInValue
strCookies = Request.ServerVariables("HTTP_COOKIE")
Set m_objCookies = Server.CreateObject("Scripting.Dictionary")
i = 1
strName = ""
strValue = ""
blnInValue = False
Do
strChar = Mid(strCookies, i, 1)
If strChar = ";" Or i = Len(strCookies) Then
strValue = Trim(strValue)
If strName <> "" And strValue <> "" Then
If m_objCookies.Exists(strName) Then
m_objCookies.Item(strName) = strValue
Else
m_objCookies.Add strName, strValue
End If
End If
If i = Len(strCookies) Then Exit Do
strName = ""
strValue = ""
blnInValue = False
ElseIf strChar = "=" Then
strName = Trim(strName)
blnInValue = True
ElseIf blnInValue Then
strValue = strValue & strChar
Else
strName = strName & strChar
End If
i = i + 1
Loop
End Sub
Public Function Cookies(strKey)
Cookies = m_objCookies.Item(strKey)
End Function
End Class
%>
The changes to my code to use this class are minimal. Where I currently have...
strCookieCart = Request.Cookies("cart")
I will need to change to...
Dim objMyRequest : Set objMyRequest = New MyRequest
strCookieCart = objMyRequest.Cookies("cart")
I have tested the above with many of the bad requests I have logged and it works fine.
Add three line codes for #johna is answer, after this line:
If strChar = ";" Or i = Len(strCookies) Then
add these lines:
If i = Len(strCookies) And strChar <> ";" Then
strValue = strValue & strChar
End If

Thread was being aborted in Response.Redirect

I'm writing a class to validate sessions.
I get the this error
Thread was being aborted
and on researching found that the way around it is to use the false parameter, but using that parameter does not redirect and instead allows the code after the redirect line to execute.
There must be something simple and fundamental here that I'm missing, below is my code.
It breaks in the InvalidAccess() method.
Public Sub New()
CheckSessionCustomerID()
If GotConnectionString() = False Then
InvalidAccess()
End If
End Sub
Public Function GotConnectionString() As Boolean
GotConnectionString = False
Try
If PublicDBConnectionStringName.Trim = String.Empty Then
GotConnectionString = False
Else
PublicConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings(PublicDBConnectionStringName).ToString
If PublicConnectionString.Trim <> String.Empty Then
GotConnectionString = True
End If
End If
Catch ex As Exception
ErrorLogging.LogError(MethodBase.GetCurrentMethod().DeclaringType.Name, MethodInfo.GetCurrentMethod().Name.ToString(), PublicBBTCustomerID & "|" & ex.Message.ToString())
GotConnectionString = False
End Try
End Function
Public Sub CheckSessionCustomerID()
Dim SessionEmployeeID As Integer
Try
If PublicTesting Then
SessionEmployeeID = 1
Else
If IsNothing(HttpContext.Current.Session("EmployeeIDLoggedIn")) Then
InvalidAccess()
ElseIf HttpContext.Current.Session("EmployeeIDLoggedIn").ToString = "0" Then
InvalidAccess()
Else
SessionEmployeeID = Val(HttpContext.Current.Session("EmployeeIDLoggedIn"))
HttpContext.Current.Session("EmployeeIDLoggedIn") = SessionEmployeeID.ToString()
End If
End If
Catch ex As Exception
InvalidAccess()
End Try
End Sub
Private Sub InvalidAccess()
Try
System.Web.HttpContext.Current.Response.Redirect("/InvalidAccess.aspx")
Catch ex As Exception
System.Web.HttpContext.Current.Response.Redirect("/Login.aspx?ID=" & PubliCustomerID & "&ID2=5")
End Try
End Sub
The Thread was being aborted is completely normal when you redirect and wish to stop further execution of request.
In your InvalidAccess method remove Try...Catch block - it is meaningless.
The Response.Redirect will never throw an exception you are interested in.
It is not very clear what have you tried to achieve with this try...catch in your method.
Alternatively, you can use false parameter in Response.Redirect.
You can use the false parameter on the Response.Redirect but then also you have to complete the request to stop execution if that's what you want:
Response.Redirect("/InvalidAccess.aspx", False)
HttpContext.Current.ApplicationInstance.CompleteRequest()
http://www.blakepell.com/asp-net-avoid-threadabortexception-on-response-redirect

Try/Catch Failing Incorrectly

I'm trying to use Try/Catch to handle a potential failed connection to a database. There's a Response.Redirect command in the Catch section. Whenever the page loads it redirects as per the Catch section whether the code in the Try section fails or not.
If I comment out the Response.Redirect command in the Catch section the page loads just fine. Similarly, if I replace the Response.Redirect command with code to populate a control on the page with the supposed error being trapped the Try section succeeds. It's something about having Response.Redirect in the Catch section...
Private Sub Page_Load(Sender As Object, e As eventargs) Handles Me.Load
Try
Dim sqlcon As New System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("SarcoidsConnectionString").ConnectionString)
Dim cmd As New System.Data.SqlClient.SqlCommand("SELECT PortalEnabled FROM [tlkSettings]", sqlcon)
sqlcon.Open()
Dim dbReader As System.Data.SqlClient.SqlDataReader = cmd.ExecuteReader()
If dbReader.HasRows Then
While dbReader.Read()
If dbReader("PortalEnabled") = True Then
Response.Redirect("~/SubmitWizard.aspx")
Else
Response.Redirect("~/Maintenance.aspx")
End If
End While
End If
sqlcon.Close()
Catch ex As Exception 'Display Maintenance page if database cannot be connected to
Response.Redirect("~/Maintenance.aspx")
End Try
End Sub
Response.Redirect() without the second parameter of False will generate a ThreadAbortException because .End() is called on the Response object, so the following lines are the issue:
If dbReader("PortalEnabled") = True Then
Response.Redirect("~/SubmitWizard.aspx")
Else
Response.Redirect("~/Maintenance.aspx")
End If
Change it to this:
If dbReader("PortalEnabled") = True Then
Response.Redirect("~/SubmitWizard.aspx", False)
Else
Response.Redirect("~/Maintenance.aspx", False)
End If
The second parameter to Redirect() is the endResponse value, when setting it to False this tells the response to not call .End() and thus does not generate a ThreadAbortException.
Per MSDN documentation:
When you use this method in a page handler to terminate a request for one page and start a new request for another page, set endResponse to false and then call the CompleteRequest method. If you specify true for the endResponse parameter, this method calls the End method for the original request, which throws a ThreadAbortException exception when it completes. This exception has a detrimental effect on Web application performance, which is why passing false for the endResponse parameter is recommended. For more information, see the End method.
Read HttpResponse.Redirect Method documentation for more information.
I think the Problem is related to the other Response.Redirect Statements:
If dbReader("PortalEnabled") = True Then
Response.Redirect("~/SubmitWizard.aspx")
Else
Response.Redirect("~/Maintenance.aspx")
End If
Response.Redirect always throws a ThreadAbortException. This is caught in your exception handler as it catches any exception. Either you substitute the Reponse.Redirect calls or you add a handler the catches ThreadAbortExceptions:
Try
'...
Catch threadAbort As ThreadAbortException
Throw
Catch ex As Exception
'...
End Try
By the way: you should add some Using statements to close the connection and free other objects reliably.

Do we need to create an HttpHandler(ashx) for each image?

In my page i'm trying to show two images which have the same id. For that, I have two image controls(imgX,imgY). To write the image to the image control I am using an HttpHandler(ashx).
My problem is that i'm getting the same image appending to both controls(imgX,imgY)
In page load event this is my code:
imgPhoto.ImageUrl = "Image.ashx?EmpBadge=" & Session("EmpBadge")
imgSign.ImageUrl = "Image.ashx?EmpBadge=" & Session("EmpBadge")
And in ashx:
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Try
Dim imageId As String = context.Request.QueryString("EmpBadge")
Dim drPhoto As SqlDataReader
Dim param(1) As SqlParameter
param(1) = New SqlParameter("#EmpBadge", imageId)
drPhoto = IMSIndia.ExecuteReaderWithParam("SpGetPhotoAndSignature", param)
If drPhoto.HasRows Then
While drPhoto.Read()
context.Response.ContentType = "image/" & drPhoto("PhotoType")
context.Response.BinaryWrite(DirectCast(drPhoto("Photo"), Byte()))
context.Response.ContentType = "image/" & drPhoto("Signaturetype")
context.Response.BinaryWrite(DirectCast(drPhoto("Signature"), Byte()))
End While
End If
Catch ex As Exception
Finally
If IMSIndia.con.State = ConnectionState.Open Then
IMSIndia.ConnectionClose()
End If
End Try
End Sub
Thanks.
Umm... of course you are getting the same image for each; you are passing exactly the same URL for each. You are using the same Session value for both.
Then, in your code you seem to be trying to send two images within the same response. That makes no sense at all, to the point that I'm not sure if it's related to this problem in the first place.
You need to differ the image based on the QueryString value. Your handler can't tell the difference unless you do.
You should be altering your code like this.
At Page_Load
imgPhoto.ImageUrl = "Image.ashx?ImageType=photo&EmpBadge=" & Session("EmpBadge")
imgSign.ImageUrl = "Image.ashx?ImageType=signature&EmpBadge=" & Session("EmpBadge")
Inside the while loop inside the ProcessRequest, place an if-else like this.
If drPhoto.HasRows Then
While drPhoto.Read()
If context.Request.QueryString("ImageType") = "photo" Then
context.Response.ContentType = "image/" & drPhoto("PhotoType")
context.Response.BinaryWrite(DirectCast(drPhoto("Photo"), Byte()))
Else
context.Response.ContentType = "image/" & drPhoto("Signaturetype")
context.Response.BinaryWrite(DirectCast(drPhoto("Signature"), Byte()))
End If
End While
End If

Wrong line number on stacktrace exception

I've got some code which errors and I'm using the stacktrace to find out what the line number is but it seems to be giving me the wrong number
Here's my code
Try
Dim query As String = "Select * from table"
Dim ds As DataSet = data.db(query)
Catch e As Exception
Dim st As New StackTrace(True) 'This is the line number it gives me'
Dim sf As StackFrame = st.GetFrame(0)
Response.Write(" Method: " & sf.GetMethod().Name)
Response.Write(" File: " & sf.GetFileName())
Response.Write(" Line Number: " & sf.GetFileLineNumber().ToString())
End Try
It seems to give me the line number of where the StackTrace is starting rather than the line number of what is causing the exception
Any ideas?
If you particularly want a StackTrace object, and don't just want the string from e.StackTrace, then change your constructor call to;
Dim st As New StackTrace(e, True)
"st" will now be initialised with the source details as you're expecting.
See http://msdn.microsoft.com/en-us/library/dsay49kt.aspx for details.
Why don't you use the info from the Exception object?
Catch e As Exception
Response.Write(e.StackTrace)
Response.Write(" Method: " & e.TargetSite)
Response.Write(" File: " & e.Source)
End Try
The StackTrace(true) constructor creates a new stacktrace for this point in the code.
Use the .Stacktrace property of the exception.
Surely you want the StackTrace of the Exception? You are creating a new stacktrace at the line of code in the exception handler.
You want e.StackTrace instead.

Resources