All,
When I upgraded from asp.net 2.0 to asp.net 3.5 and now in my custom end request handler, the args.get_error() returns null (I traced it all the way to function Sys$WebForms$PageRequestManager$_endPostBack(error, response), the error object is null there too). This happens on my production server, on my development machine it works, I get the error object.
Both are win 7 machines, IIS 7.5.
FYI: On the server, I log the error, and clear it via ctx.Server.ClearError();
Then I set the AsyncPostBackErrorMessage on the script manager.
**UPDATE:
By setting AllowCustomErrorsRedirect="false" on the ScriptManager explicitly resolves the issue. **
Found this on MSDN little explanation:
https://msdn.microsoft.com/en-us/library/system.web.ui.scriptmanager.allowcustomerrorsredirect(v=vs.110).aspx
Remarks
The AsyncPostBackError event is raised when there is a page error during asynchronous postbacks. How errors on the server are sent to the client depends on the AllowCustomErrorsRedirect property, the AsyncPostBackErrorMessage property, and the custom errors section of the Web.config file.
Here's client script code for handling ajax errors:
mgr.add_beginRequest(function(sender, args) {
postBackElem = args.get_postBackElement();
if (typeof(postBackElem) === 'undefined')
return;
targetPnl = self.getTargetPnl(mgr, postBackElem);
$(targetPnl).addClass('updateprogress-started', duration);
}); //beginRequest
mgr.add_endRequest(function(sender, args) {
if (typeof(postBackElem) === 'undefined')
return;
$(targetPnl).removeClass('updateprogress-started', duration);
if (args.get_error() != undefined){
var msg;
if (args.get_response().get_statusCode() == '200') {
msg = args.get_error().message.replace("Sys.WebForms.PageRequestManagerServerErrorException: ", "");
}
else {
msg = 'An unspecified error occurred.'; // error occurred somewhere other than the server page
}
args.set_errorHandled(true); // show error in our custom panel
$(self._errText).text(msg);
$(self._errPanel).show();
}
}); //endRequest
By setting AllowCustomErrorsRedirect="false" on the ScriptManager explicitly resolves the issue.
Related
I'm building an ASP.NET Web API endpoint that accepts 'multipart/form-data' requests. I implemented it as described in this article using .NET Framework 4.5 and Web API 2.1. A simplified version of the action method I created, looks like this:
public async Task<HttpResponseMessage> PostFile()
{
if (!Request.Content.IsMimeMultipartContent()) throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
var rootPath = System.Configuration.ConfigurationManager.AppSettings["StorageLocation"].ToString();
var provider = new MultipartFormDataStreamProvider(rootPath);
var response = Request.CreateResponse(HttpStatusCode.OK);
try
{
await Request.Content.ReadAsMultipartAsync(provider);
// Imagine awesome logic here, unicorns and rainbows! Instead of that, we do the following:
response.Content = new StringContent("You uploaded " + provider.FileData.Count.ToString() + " files.");
}
catch (Exception e) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e)); }
return response;
}
Because the uploaded files can be very big (up to 2GiB), I want my requests to not be buffered by ASP.NET, thus avoiding high memory usage. To realize this I told Web API to stream incoming requests, instead of buffering them, as described in this article. The custom WebHostBufferPolicySelector looks something like this:
public class CustomWebHostBufferPolicySelector : WebHostBufferPolicySelector
{
public override bool UseBufferedInputStream(object hostContext)
{
System.Web.HttpContextBase contextBase = hostContext as System.Web.HttpContextBase;
if (contextBase != null && contextBase.Request.ContentType != null && contextBase.Request.ContentType.Contains("multipart")) return false;
else return base.UseBufferedInputStream(hostContext);
}
public override bool UseBufferedOutputStream(System.Net.Http.HttpResponseMessage response)
{
return base.UseBufferedOutputStream(response);
}
}
I load this guy in the Global.asax, at application start, like this:
protected void Application_Start(object sender, EventArgs e)
{
// Here, other stuff got did.
GlobalConfiguration.Configuration.Services.Replace(typeof(IHostBufferPolicySelector), new CustomWebHostBufferPolicySelector());
}
Alright, the board is set, lets get the pieces moving. If I don't use my CustomWebHostBufferPolicySelector, everything works just fine. However, when its used, I get the following exception:
Message: "An error has occurred."
ExceptionMessage: "Error reading MIME multipart body part."
ExceptionType: "System.IO.IOException"
StackTrace: " at System.Net.Http.HttpContentMultipartExtensions.<ReadAsMultipartAsync>d__0`1.MoveNext()\ \ --- End of stack trace from previous location where exception was thrown ---\ \ at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\ \ at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\ \ at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\ \ at ..."
With the following inner exception:
Message: "An error has occurred."
ExceptionMessage: "Unable to read the entity body in Bufferless mode. The request stream has already been buffered."
ExceptionType: "System.InvalidOperationException"
StackTrace: " at System.Web.Http.WebHost.HttpControllerHandler.<>c__DisplayClass13.<GetStreamContent>b__10()\ \ at System.Web.Http.WebHost.HttpControllerHandler.LazyStreamContent.get_StreamContent()\ \ at System.Web.Http.WebHost.HttpControllerHandler.LazyStreamContent.CreateContentReadStreamAsync()\ \ at System.Net.Http.HttpContent.ReadAsStreamAsync()\ \ at System.Net.Http.HttpContentMultipartExtensions.<ReadAsMultipartAsync>d__0`1.MoveNext()"
It looks like the request is still buffered somehow, by something else. Is there another place in the ASP.NET pipeline I should be looking? Or even IIS maybe? What are the other places in this request's lifecycle where it can be buffered, and how do I control them?
In an attempt to make the problem more clear and shareable with others, I created a simple project to try and reproduce the problem. While doing this I found the answer: disable all kinds of tracing.
In my case I had ASP.NET's own tracing functionality enabled, and also Glimpse. Both of these buffer the request before it arrives at the Web API action.
For completeness' sake, here the proper way to turn them off in your Web.Config, while testing and in production.
<configuration>
<system.web>
<trace enabled="false" />
</system.web>
<glimpse defaultRuntimePolicy="Off">
</glimpse>
</configuration>
In my case, these two were the culprits, but I can imagine there may be others, so be wary of this.
Working with some legacy code that has a great many UpdatePanels. We are experiencing problems where some postbacks to UpdatePanels are timing out (exceeding the default 90 second limit), and I want to know when this happens.
We are currently logging all unhandled exceptions in Global.asax.cs::Application_Error. If I manually throw in an error in a postback on the update panel, this is captured just fine. If I drop in a Thread.Sleep(100 * 1000), I will not see anything in Application_Error, but on the client I will see:
Uncaught Sys.WebForms.PageRequestManagerServerErrorException:
Sys.WebForms.PageRequestManagerServerErrorException:
An unknown error occurred while processing the request on the server.
The status code returned from the server was: 500
From what I can tell, it is the server layer throwing the error, not the application itself, and so we will never see anything hit Application_Error. Is that correct?
Also, are there any options for actually capturing/logging this error, aside from noticing it in the client, and then doing another POST operation back to log it?
You have two approaches that I know of:
Server-side:
protected void ScriptManager1_AsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)
{
ScriptManager1.AsyncPostBackErrorMessage = "An error occurred during the request: " + e.Exception.Message;
}
Client-side:
<script type="text/javascript">
// Subscribe to the end request event of the update panel
function pageLoad() {
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(onEndRequest);
}
// You can of course have this emit the error information to whatever control you want, I made up the Label1 object for demonstration purposes
function onEndRequest(sender, args) {
var lbl = document.getElementById("Label1");
lbl.innerHTML = args.get_error().message;
args.set_errorHandled(true);
}
</script>
Here is some documentation:
Customizing Error Handling for ASP.NET UpdatePanel Controls
Error Handling Customization for ASP.NET UpdatePanel
In Meteor.publish, what is a difference between using this.error and simply throwing an Meteor.Error?
this.error is only available inside the publish method. Per the docs:
Stops this client's subscription, triggering a call on the client to the onError callback passed to Meteor.subscribe, if any. If error is not a Meteor.Error, it will be mapped to Meteor.Error(500, "Internal server error").
Throwing a Meteor.Error would not stop the client's subscription, it would just terminate execution and raise the exception. So if you want to ensure Meteor will clean up after you and allow you to handle the error on the client when something unexpected happens, it's recommended to use this.error rather than throwing your own inside the publish method.
It seems they are the same. In the source code:
try {
var res = self._handler.apply(self, EJSON.clone(self._params));
} catch (e) {
self.error(e);
return;
}
So if there is an exception thrown, error is called anyway. error also stops the subscription.
I have a updatepanel that is updated using timer every one second.
I also have async postback error handler set up in javascript as following:
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(onEndRequest);
function onEndRequest(sender, args) {
var error = args.get_error();
if (error != null) {
args.set_errorHandled(true);
alert(error.message);
}
}
when I refresh the page manually or click a hyperlink I get the following error in endRequest handler:
An unknown error occurred while processing the request on the server.
The status code returned from the server was: 0
How can i prevent this behavior?
Thanks
I figured it out.
For thoue who have the same problem, here is the code to determine if script manager async postback is currently running:
Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack()
to cancel it call:
Sys.WebForms.PageRequestManager.getInstance().abortPostBack();
I just call the cancel method directly. It does not not anything when request is not running.
I have a report page that uses the Microsoft.Reporting.WebForms.ReportViewer component to render Report Server (SSRS) reports asynchronously. At the moment if an error occurs a message is displayed inside the ReportViewer control.
I want to add custom error handling logic so that the user gets a friendly message. How can I achieve this and still run the viewer in Async mode, rendering the reports on the SSRS server?
Listening to the ReportViewer.HandleError event won't work as the page postback has already completed.
After inspecting the ReportViewer JavaScript, I came up with the following solution. It's prone to breaking things if Microsoft changes this particular method. The following code would be added to the header of the page to make sure it runs after the ReportViewer javascript is loaded, but before an instance of the RSClientController is created.
// This replaces a method in the ReportViewer javascript. If Microsoft updates
// this particular method, it may cause problems, but that is unlikely to
// happen.The purpose of this is to redirect the user to the error page when
// an error occurs. The ReportViewer.ReportError event is not (always?) raised
// for Remote Async reports
function OnReportFrameLoaded() {
this.m_reportLoaded = true;
this.ShowWaitFrame(false);
if (this.IsAsync)
{
if(this.m_reportObject == null)
{
window.location =
'<%= HttpRuntime.AppDomainAppVirtualPath %>/Error.aspx';
}
else
{
this.m_reportObject.OnFrameVisible();
}
}
}
RSClientController.prototype.OnReportFrameLoaded = OnReportFrameLoaded;
The original code from the Microsoft ReportViewer script file (inside the Microsoft.ReportViewer.WebForms, 8.0.0.0, .Net Framework 3.5 SP1) is:
function OnReportFrameLoaded()
{
this.m_reportLoaded = true;
this.ShowWaitFrame(false);
if (this.IsAsync && this.m_reportObject != null)
this.m_reportObject.OnFrameVisible();
}
RSClientController.prototype.OnReportFrameLoaded = OnReportFrameLoaded;