opening an attachment in <ASP: UpdatePanel throw this error - asp.net

*Microsoft JScript runtime error: Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, HttpModules, or server trace is enabled.
Details: Error parsing near '�PNG
'.*
if i remove the <asp:updatepanel its all working fine
protected void gvFiles_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Download")
{
byte[] byteArray = item.AttachContent.ToArray();
Response.Clear();
Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + item.AttachFileName + "\"");
Response.AppendHeader("Content-Length", byteArray.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.BinaryWrite(byteArray);
Response.End();
}
}

This is occurring because you are trying to do a Response.BinaryWrite.
You get this error because because you are trying to return non HTML to the UpdatePanel using an asynchronous callback which is not allowed. The only thing I can suggest is to try using a PostBackTrigger and targetting a control outside of your UpdatePanel.
The best solution would be to make you download button spawn another window that calls an .ashx (generic handler) and server up the binary via the ashx. You can just attach a javascript function to handle the click which will open a new window to the ashx with whatever params are needed passed in.
This link has more information on the exact problem and ways of solving it.
There are several ways to fix this
problem each fix has specific scops.
1.Register ButtonDownload PostBackTrigger control in Triggers
child tag of the update panel as shown
below.
2.You can also use RegisterPostBackControl method of the
ScriptManager control in Page_Load as
shown below.

As the error describes, Response.BinaryWrite is among the blacklisted activities during an asynchronous callback. This is due to the UpdatePanel's special handling of the content returned during its asynchronous callback.
I would recommend moving your attachment-download logic into a separate page, HTTP handler, or service, allow it to be accessed with a GET (by controlling parameters in the query string), and changing the element in gvFiles from whatever it is (Button, ListButton, ImageButton, etc) into a hyperlink to the new resource. By downloading on a GET from a separate resource, you will avoid the error.

Related

ASP.NET Refresh page on timer; query database in between timer

'I have a solution in my head, but am unsure if it is possible in ASP.NET. I don't have a lot of experience with timers. My idea is as follows:
'Code Behind
'At the end of the timer(lets say 1 minute)
Dim qry = "SELECT ISNULL(Value, '') FROM Database.Schema.Table WHERE
Column = #Something"
'set up sql connection and execute query
Using sqlcon as new SQLConnection() 'Don't focus on this part
Using sqlcmd = New SQLCommand(sqlcon,qry) 'Don't focus on this part either syntax is probably incorrect
sqlcmd.Parameters.Add("Something", VarChar)
sqlcmd.Parameters("Something").Value = "Row Found"
'Refresh page; assign label control on .aspx page to value of returned query
'SafeToString() is a function that will safely return a string whether the value is some string, DBNULL, Nothing, or ''
lblString.Text = SafeToString(sqlcmd.ExecuteScalar())
End Using
End Using
I want to be able to do this while maintaining scrolls position as well. So I don't interrupt the work/browsing the user is doing.
Thank you all for your input!
Look up Page Methods. JS can call a code-behind method which can return a value to the js method which can then update the page. The code behind method cannot access the page directly, only return a value to the js method.
I had never used WebForms (which I assume this question is about) but regardless I think you're approaching the problem in a wrong way. A page refresh is destructive and distracting, when a page is refreshed the browser has to fetch the page again (this includes all assets and scripts) and re-render the page.
Client-side implementation
So the solution must be implemented at the client side and not require a full page refresh, this can be achieved using Javascript and ajax(from Wikipedia) requests.
In short ajax is a mechanism for issuing additional requests to a web server while the page is loaded and running. That way you can fetch new data in the background without interrupting the user.
When the page loads set up a timeout or an interval:
let intervalId = setInterval(updateFromServer, 1000);
This interval will call updateFromServer every 1 second (1000ms).
Define the function updateFromServer:
function updateFromServer() {
let newData = fetchData();
updateData(newData);
}
This function is call by the interval we've set up and does 2 things: it fetches new data from the server and pushes it to the DOM using updateData.
You can use ajax (for example with jquery) to fetch the data:
function fetchData() {
return $.ajax({
type: "GET",
url: remote_url,
async: false
}).responseText;
}
This is where ajax comes in, the above lines use jquery ajax api to send a GET request to the server at the url remote_url. The browser issues the request and waits for the server to respond.
And finally update the page (again I'm using jquery):
function updateData(newData) {
$('#data-el').text(newData)
}
Again we are using jquery here (you can use pure javascript though) to find an element with the ID data-el and setting its content to newData.

Proper way to skip page execution after Response.RedirectToRoute

I'm writing an asp.net 4.5 application using the new routing features. I have a page that displays some information about an item. In the Page_Load event I check the route data (item id) and user permissions, and if something isn't right (e.g. the id is for a deleted item) I use Response.RedirectToRoute to send them packing, right back to the home page. Do not pass GO, do not collect $200.
This made perfect sense until I tried to access a deleted item and instead of the home page I got an error page. I did some digging and discovered that even after I use RedirectToRoute (unlike the standard Redirect method) the rest of the page code continues to execute, which at the very least seems wasteful (since I'm just going to throw away the results) and throws errors when the necessary data doesn't exist.
I did a little more SO mining and discovered the incredible evil that is Response.End(). It does what I need, but even the MSDN page tells me that Response.End is the bastard child of an ancient accursed language and isn't fit to see the light of day. The primary objection seems to be the fact that Response.End throws an exception, and that's bad for performance. I'm not the most experienced developer, so I don't understand the issue entirely, but I have trouble believing that throwing an exception is more expensive than loading the entire web page. The workarounds seem rather complex and excessive for a task so simple, especially since most pages require some kind of validity check.
What am I supposed to do in this situation? Use Response.End and beg forgiveness for my insolence? Cobble together some ugly workaround? Or is my perspective on the problem all wrong to begin with? I'd really like to know.
Update: Now that I've thought it over a bit more, I wonder if I do have the wrong perspective on the problem. Perhaps an immediate redirect is the not the best response for the user experience. Would I be better off wrapping all the controls in a panel, and using something like this?
Private Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init
'Validation Code
If notValid Then
ControlsPanel.Visible = false
ErrorPanel.Visible = true
End If
End Sub
RedirectToRoute is actually wraps Response.Redirect passing false for ending the request - hence, the request continues. You can use HttpApplication.CompleteRequest as immediate call to terminate the request so that next application events would not be invoked.
Response.End (and other Redirect variation) throws ThreadAbortException to abort the request processing thread which is really a bad way to stop request processing. In .NET world, exception processing is always considered expensive because CLR then needs to search up the stack all the way up for exception processing blocks, create stack trace etc. IMO, CompleteRequest was introduced in .NET 1.1 to avoid the same which actually relies on setting flag in ASP.NET infrastructure code to skip further processing except EndRequest event.
Yet another (and better) way is to use Server.Transfer and avoid client round-trip for setting redirect all together. Only issue is that client would not see the redirected URL in the browser address bar. I typically prefer this method.
EDIT
CompleteRequest wouldn't never work in page case where subsequent page events would be still invoked because page being a handler, all its events happens within a single (and current) application event ProcessRequest. So only way seems to be setting a flag and check that flag in overrides such as Render, PreRender, RaisePostBackEvent etc.
From maintenance perspective, it make sense to have such functionality in base page class (i.e. maintaining the flag, offering CompleteRequest method to subclasses and overriding life cycle event methods). For example,
internal class PageBase: System.Web.UI.Page
{
bool _requestCompleted;
protected void CompleteRequest()
{
Context.ApplicationInstance.CompleteRequest();
_requestCompleted = true;
}
protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl,
string eventArgument)
{
if (_requestCompleted) return;
base.RaisePostBackEvent(sourceControl, eventArgument);
}
protected internal override void Render(HtmlTextWriter writer)
{
if (_requestCompleted) return;
base.Render(writer);
}
protected internal override void OnPreRender(EventArgs e)
{
if (_requestCompleted) return;
base.OnPreRender(e);
}
... and so on
}
I may be going out on a limb by not answering the question directly, but I liked seeing your update regarding user experience. I prefer your suggested approach.
I like to give a 410 error for id's that are not valid and extend it a bit with (translated from C#):
Protected Sub ItemDoesNotExist()
'item does not exist, serve up error page
ControlsPanel.Visible = False
ErrorPanel.Visible = True
'add meta tags for noindex
Dim mymeta As New HtmlMeta()
mymeta.Name = "robots"
mymeta.Content = "noindex"
Page.Header.Controls.Add(mymeta)
'RESPOND WITH A 410
Response.StatusCode = 410
Response.Status = "410 Gone"
Response.StatusDescription = "Gone"
Response.TrySkipIisCustomErrors = True
'important for IIS7, otherwise the Custom error page for 404 shows.
Page.Title = "item gone"
End Sub

WebRequest Async CallBack Code only gets call the first time

I am an absolute beginner on ASP.net (VB.) Please pardon me if the question is too obvious for the experienced members.
I tried to make a simple WebRequest in the async mode in case the target URL takes long to provide the data. In my code below, I just want to see if the callback block (RespCallback) is called correctly every time. If all goes well, lblResult should have the string '123' appended to it every time I click the button which calls the 'GetData' sub.
However, the lblResult only shows 123 after the first click. After the subsequent click, the lblResult only gets appended with '12', as if RespCallback is never called. When I tried to debug this in Visual Studio, the execution actually stepped right into the RespCallback part and the lblResult.Text watch actually shows '123123' but the resulting Web page always shows only '12312'
I am sure I am missing something basic here, but I just don't know what. I was even guessing that it has to do with browser cache (hence the result changes for the second time) but I don't know how to fix that either.
Can someone please help? Thanks in advance.
Jim
Dim myWebRequest As WebRequest
Public Shared allDone As New ManualResetEvent(False)
Private Shared BUFFER_SIZE As Integer = 1024
Public Class RequestState
' This class stores the state of the request
Private Shared BUFFER_SIZE As Integer = 1024
Public requestData As StringBuilder
Public bufferRead() As Byte
Public request As WebRequest
Public response As WebResponse
Public responseStream As Stream
Public Sub New()
bufferRead = New Byte(BUFFER_SIZE) {}
requestData = New StringBuilder("")
request = Nothing
responseStream = Nothing
End Sub ' New
End Class ' RequestState
Public Sub GetData(Sender As Object, Args As System.EventArgs)
lblResult.Text += "1"
myWebRequest = WebRequest.Create(dataURL)
Dim myRequestState As New RequestState()
myRequestState.request = myWebRequest
' Start the asynchronous request.
Dim asyncResult As IAsyncResult = CType(myWebRequest.BeginGetResponse(AddressOf RespCallback, myRequestState), IAsyncResult)
lblResult.Text += "2"
allDone.WaitOne()
End Sub
Private Sub RespCallback(asynchronousResult As IAsyncResult)
lblResult.Text += "3"
allDone.Set()
End Sub
I don't know VB so it's hard to read for me but I'm suspecting GetData is your onClick handler.
First thing that is not right is that you have Shared members. Why your reset event is Shared? It makes all requests use the same object.
Basically Your code with ManualResetEvent won't work because after first allDone.Set(), your object remains set (as long as web application lives). To get "123" every time you should add allDone.Reset() after allDone.WaitOne().
In Your situation web request returns to client before RespCallback is called every time except first call (when your reset event is in non-signaled state).
AutoResetEvent resets automatically. That's why it worked.
But! You can't do this this way. Making your ResetEvent Shared you make all request use the same object. When more than one request will be processed by your application at the same time you will get undetermined behavior.
Remove Shared from your code. Than your code will work (but not asynchronously) without allDone.Reset() and without AutoResetEvent. But it will provide known results (not depending on amount of requests).
About asynchronous call (now that we have code "working"). Well. There is no async request to your web page. allDone.WaitOne() waits until your async webRequest finish. So basically you could just as well do synchronous request.
You need a special pattern for asynchronous web pages. You can read how to do this here.
But i'm not sure it's what you wanted. Do you want your request to be called asynchronously so that it will not use server resources or do you want to display some message to the user (like "Data is being downloaded...") while your web page will remain fully responsible?
If it's the second one you should use AJAX functionality (Like UpdatePanel or using JavaScript directly). You can read about it here.
Couple things to check:
If your label is a fixed width, then it's possible the text is being clipped
If you are using an UpdatePanel, you will need to set its mode to 'Conditional' and call Update() on it in the RespCallback callback method so that the UI gets refreshed with the latest label text value.

dispalying error returned by stored procedure in .aspx form

i have a stored procedure which i use to insert values in a table...if i implement error handling in it using ##ERROR and if i it returns error in a variable #myError can i display this error in my .aspx form??i m using sql server 2005
thanx....
You can use the InfoMessage event of the SqlConnection to output SQL warnings and information messages to the client. By default the event is only fired for information messages with a severity of less than 10. By setting the FireInfoMessageEventOnUserErrors property of the SqlConnection to true you can trigger the InfoMessage event for errors of severity 11 to 16 instead of throwing an exception and halting execution. By adding an event handler for the InfoMessage event we can output the message to the client.
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
conn.FireInfoMessageEventOnUserErrors = true;
conn.InfoMessage += delegate(object sender, SqlInfoMessageEventArgs e)
{
txtMessage.Text += e.Message;
};
...
}
See: HOW TO: Return Errors and Warnings from a SQL Server Stored Procedure in ADO.NET
Yes you can, but normally you don't want to display system error messages to users - it would be better to display a user friendly message instead.
That being said however, just create a label and set the label's Text property with the value of #myError.
I would recommend using TRY/CATCH in T-SQL instead of ##ERROR. The later is notoriously problematic because is reset after each statement. For more details see
Error Handling in SQL Server – a Background
Implementing Error Handling with Stored Procedures
I much prefer TRY/CATCH, using a procedure template like the one described here: Exception handling and nested transactions. This way an error is raised into your ASP.Net as a SqlException which you can catch, like any other CLR exception.

Handling Request Validation 'silently'

I'm trying to override the onError event handler of a web form to allow "A potentially dangerous Request.Form value was detected from the client" type errors to be handled within the form rather than ending up at the application level error handler.
I found some sample code like this :
protected override void OnError(EventArgs e)
{
// At this point we have information about the error
HttpContext ctx = HttpContext.Current;
Exception exception = ctx.Server.GetLastError();
string errorInfo =
"<br>Offending URL: " + ctx.Request.Url.ToString() +
"<br>Source: " + exception.Source +
"<br>Message: " + exception.Message +
"<br>Stack trace: " + exception.StackTrace;
ctx.Response.Write(errorInfo);
// --------------------------------------------------
// To let the page finish running we clear the error
// --------------------------------------------------
ctx.Server.ClearError();
base.OnError(e);
}
Which satisfactorily catches the error and writes an error message out to the screen but what I really want to do is to be aware of the error when Page_Load fires and so be able to display a 'normal' error message on the webform.
I'm sure there's a good way to do this but I don't know it ! Suggestions ?
(BTW for various reason I don't want to turn off the checking at either form or app level and neither do I wish to rely on Javascript - thanks)
You actually can catch the error at the page level, but it will kill the page lifecycle. So you have to use a trick to get around it. Example:
public override void ProcessRequest(HttpContext context)
{
try
{
base.ProcessRequest(context);
}
catch(HttpRequestValidationException ex)
{
context.Response.Redirect("HandleValidationError.aspx");
}
}
HandleValidationError.aspx can be anything, including a redirection back to the same page (perhaps with a querystring with information regarding the error, e.g. "ContactForm.aspx?error=Invalid+Request")
I think I understand what you want to do, but I'm afraid it might be impossible. When your ASP.NET page performs a postback, a new thread is created on the server to handle the request. Before your page lifecycle even has a chance to begin, the offending XSS is found and an exception is thrown. Once this exception is thrown, you are "evicted" from the ASP.NET page lifecycle and there is no way to re-enter it. At this point, the only thing you can do on the client side is output the error, or redirect to an error page.
What you seem to want to do is catch the exception, write it out somewhere on the page, and continue with the ASP.NET page lifecycle (i.e. restoring the control tree, restoring viewstate, invoking event handlers, etc). The problem is once an unhandled exception is thrown you no longer have access to the ASP.NET page lifecycle. In this particular case, there is nowhere to put a try/catch block because the exception is thrown internally from the ASP.NET lifecycle before your own code is called.
I know you said you don't want to rely on Javascript, but in this case I think using Javascript is the only way to get the behavior you want. You can still keep server-side validation, just in case your users disable Javascript or type some input that your Javascript doesn't handle.
I don't think you'll be able to handle the error in the Page_load event. In the ASP.NET Page Life cycle validation events occur after the page loads.
Maybe you can add a hidden div (<asp:Panel Visible=false ...) that contains your "normal error message". if the OnError event fires display the error message div.
jason

Resources