Catch upload of to big files - asp.net

Asp.Net has an upper limit for file uploads. I try to catch this situation on the server side. According to the documentation I found, it should be possible to override Application_Error in Global.asax, but it does not work for me. The second option would be to override OnError of the receiving page, but that also does not work.
Can anybody show some working code on how to catch this error on the server side?

Put following in Golobal.asax.cs:
void Application_Error(Object sender, EventArgs e)
{
HttpException ex = Server.GetLastError() as HttpException;
if (ex != null)
{
if ((ex.GetHttpCode() == 500 || ex.GetHttpCode() == 400) && ex.ErrorCode == -2147467259)
{
Server.ClearError();
Response.Redirect("~/MaximumFileError.aspx", false);
}
}
}
This worked for me, but I'm not sure if it works for all cases.

Uploadify is a jquery and flash uploader that allows you to specify a max size for files to be downloaded. This way you can prevent the user from downloading the file in the first place and dont have to worry about catching it after.

Rather than catch the error can't you check the size of the file against the maximum size specified in the web.config file? You can use the following to get the max size:
System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
HttpRuntimeSection section = config.GetSection("system.web/httpRuntime") as HttpRuntimeSection;
double maxFileSize = section.MaxRequestLength;

"Can anybody show some working code on
how to catch this error on the server
side?"
Nope. It's not possible to use code to catch this error, as it occurs before any code is started.
As far as I have found, you can't even specify an alternative error page for this error, the web server just refuses to accept the request when it's too large.

First you should understand few things about maxRequestLength. Using a server side approach validation you cannot predict what will be file size. Setting value to high is increasing the risk of DoS Attack.
I set in web.config maxRequestLength to 8MB:
<httpRuntime maxRequestLength="8192" executionTimeout="3600" />
I check in my code-behind of form if uploaded by user file is not greater than half of given in maxRequestLength, but this checking may never happen if the size of uploaded file turn out to be greater than max RequestLength specified in web.config, because the exception will be thrown. Such exception should be catch on the level of Global.asax. There I check whether the Exception is containing words identifying our problem, because System.Web.HttpUnhandledException can be thrown in many other situations! Good hint may be checking from which page the exception come, to be sure that we deal with certain form, what is important by redirecting user back to form.
void Application_Error(object sender, EventArgs e){
Exception wyjatek = Server.GetLastError();
if (wyjatek.InnerException != null && wyjatek.InnerException.Message.Contains("Maximum request length exceeded"))
{
Server.ClearError();
Response.Redirect("FormWithFile.aspx?alert=Za-duzy-plik");
}
}
If I recognize in Global.asax this exception I redirect user to the page with alert(given in GET).
In my code-behind of ASPX page:
First I retrive value of MaxRequestLength from web.config by this tree lines, and half it:
static System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
static HttpRuntimeSection section = config.GetSection("system.web/httpRuntime") as HttpRuntimeSection;
int maxFileSize = (section.MaxRequestLength/2)*1024;
Then in Action connected with insert button, I proceed as follows:
protected void InsertButton_Click(object sender, EventArgs e)
{
if (((FileUpload)FormView1.FindControl("FileUpload1")).HasFile) // WHEN USER WANT TO UPLOAD FORM WITH FILE (its, optional)
{
HttpPostedFile file = (HttpPostedFile)(((FileUpload)FormView1.FindControl("FileUpload1")).PostedFile);
int iFileSize = file.ContentLength;
if ((file != null) && (file.ContentLength > 0))
{
if (iFileSize > maxFileSize) // checking image SIZE!
{
MessageForUser.Text = "<h1 class=error>Bad File! File is to big!</h1>";
}
else
{
byte[] plik = ((FileUpload)FormView1.FindControl("FileUpload1")).FileBytes;
// HERE COMES CODE FOR INSERT OF FORM WITH FILE
MessageForUser.Text = "<h1>Insert was sucessfull</h2>";
}
}
}
else
{
// HERE COMES CODE FOR INSERT OF FORM WITHOUT FILE
MessageForUser.Text = "<h1>Insert was sucessfull</h2>";
}
}
In Page_Load I define also how to retrive communicate given by GET from Global.asax, to inform the user what happend.
if (Request.QueryString["alert"]!=null)
{
string temp = Request.QueryString["alert"].Replace('-',' ');
MessageForUser.Visible = true;
MessageForUser.Text = "<h1 class=error>ERROR: " + temp + "</h1>";
}
This solution has of course its drawbacks:
Still, we can be under DoS attack with 8MB files, what we recognize first at level of server, what is already very late.
The state of user form is lost in case of redirection from Global.asax, but this with some bit of code can be overcome.
User expirience is rather poor, because of checks on the server side, and by the load of many users, applicaiton can become slow.
Temporarly to the server come files even greater than 8MB, but such which manage in executionTimeout
Possible alternatives:
Use some flash technology to check on client side the file size
Use some stream techniques, to transfer bites in small packets, and in the moment, when given threshold is reached, throw own exception and handle it.
apropriate reading: Sending File in Chunks to HttpHandler

Related

what to log and what to ignore in Global.asax Application_Error()?

Currently I have the following code snippet to handle errors in Global.asax Application_Error():
var ex = server.GetLastError();
server.ClearError();
if (ex is HttpUnhandledException && ex.InnerException != null)
ex = ex.InnerException;
Trace.TraceError(ex.ToString());
// send some output to the user that they should contact support etc
It catches all errors, including 404 errors for example (when the user types a nonexistent .aspx URL, or when the browser asks for stuff like favicon.ico and static file requests are set up to go through the pipeline). There are two problems with this: this should not be logged (the log is full of useless 404 errors) and the original HTTP code should be sent back (otherwise search bots may index error pages etc.).
How would you decide what to log and what to ignore here? Basically I want to include application/business errors, which indicate bugs, and ignore "normal" HTTP errors. I also don't just want to exclude 404 errors only, there is also 403 and who knows what else.
Your approach is good: you log unhandled errors. The point of that is to weed out bugs. Humans cannot avoid bugs but we can quickly fix them.
Start with logging all errors. Then blacklist individual errors or categories of errors that you learn are useless. Within a few iterations you'll have a fairly clean log.
Remove everything that is not actionable. For example, your website will have bots performing crazy requests and so on. No action necessary, so you can remove them from the log.
I recommend that you also log seemingly useless errors into a supplementary log file so that you can scroll through it from time to time to make sure that everything is alright.
You especially want to know the frequency of normally harmless errors. Three deadlocks per day might be cool with you, but 300 might be too much.
I'll contribute a sketch of what your global error handler might contain:
static bool IsExceptionIgnored(Exception exception)
{
if (exception == null) throw new ArgumentNullException("exception");
var nestedExceptions = exception.GetExceptionChain();
return nestedExceptions.Any(ex =>
ex is ViewStateException ||
ex.Message.Contains("Timeout") ||
ex.Message.StartsWith("Invalid viewstate") ||
ex.Message.Contains("potentially dangerous") ||
ex.Message.Contains("The remote host closed the connection") ||
ex.Message.Contains("System.Web.UI.ViewStateException: Invalid viewstate") ||
ex.Message.Contains("System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError") ||
ex.Message.Contains("0x80070032") ||
(ex is HttpException && ((HttpException)ex).GetHttpCode() == 404) ||
ex is ThreadAbortException);
}
public static IEnumerable<Exception> GetExceptionChain(this Exception exception)
{
if (exception == null) throw new ArgumentNullException("exception");
for (var current = exception; current != null; current = current.InnerException)
yield return current;
}
protected void Application_Error(Object sender, EventArgs e)
{
WebException ex = new WebException();
HttpWebResponse errorResponse = ex.Response as HttpWebResponse;
if (errorResponse.StatusCode == HttpStatusCode.NotFound)
{
}
I came up with a simple idea. The key to the solution is the fact that all business and other kinds of unexpected exceptions have an HTTP code of 500, while the normal HTTP exceptions don't, they have codes like 403, 404, etc. Here's a code snippet:
var ex = server.GetLastError();
if (ex is HttpException && ((HttpException)ex).GetHttpCode() != 500)
return; // the usual yellow error screen appears with the normal HTTP error code
// we handle the error ourselves
server.ClearError();
if (ex is HttpUnhandledException && ex.InnerException != null)
ex = ex.InnerException;
// log the error, tell the user to contact support

Response.Redirect(Request.Url.AbsoluteUri) doesn't update page data

I have Page_load method like this:
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
// Load Content
LoadContent();
return;
}
// some code here
}
And I use Response.Redirect(Request.Url.AbsoluteUri) at the end of methods to prevent re-post actions cased by page refrashing. When I run my app from source code that works well (debug or run mode), but when I publish the app (even on the same machine) page data (which loads on LoadContent) is not updated on updated page (but re-post actions is prevented).
Please, could anyone tell me why it happens?
ADDED:
There is LoadContent() method:
// firstly I get an supervisedGroups list TIBCO iProcess Engine via .NET vendor library, and then:
if (supervisedGroups != null)
{
rptSupervisedGroups.DataSource = supervisedGroups; // rpt.. is Repeater
rptSupervisedGroups.DataBind();
}
ADDED:
Method where Response.Redirect are used:
private void removeFromGroup(string strGroupName)
{
using(SqlConnection con = DBHelper.GetNewConnection())
{
con.Open();
// here comes query to DB
}
// Reload Page
Response.Redirect(Request.Url.AbsoluteUri);
}
You have two ways to solve this cache issue.
One is to give instructions to the browser to not cache this page, for example on page load you run:
Response.Cache.SetExpires(DateTime.UtcNow.AddYears(-4));
Response.Cache.SetValidUntilExpires(false);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
Response.Cache.SetNoStore();
But a better solution is to add a random number at the end of the url when you make the redirect, or even better add the new id from the data that you have insert, eg:
Response.Redirect("samepage.aspx?newid=" + NewId);
that way the page will forced to be readed again, and you still have the cache functionality.
Most likely your page is cached. Try to hit shift-f5 to check the content. You can make all redirect urls unique to prevent the browser showing a cached page. Or disable caching for the specific page.

FileUpload control in asp.net throwing exception

I am trying to read an Excel sheet using C# which is to be loaded by end user from fileUpload control.
I am writing my code to save the file on server in event handler of another button control(Upload). But when I click on Upload Button I am getting this exception:
The process cannot access the file 'E:\MyProjectName\App_Data\sampledata.xlsx' because it is being used by another process.
Here is the code that I have used in event handler:
string fileName = Path.GetFileName(file_upload.PostedFile.FileName);
string fileExtension = Path.GetExtension(file_upload.PostedFile.FileName);
string fileLocation = Server.MapPath("~/App_Data/" + fileName);
//if (File.Exists(fileLocation))
// File.Delete(fileLocation);
file_upload.SaveAs(fileLocation);
Even deleting the file is not working, throwing the same exception.
Make sure, some other process is not accessing that file.
This error might occurs whenever you are trying to upload file, without explicitly removing it from memory.
So try this:
try
{
string fileName = Path.GetFileName(file_upload.PostedFile.FileName);
string fileExtension = Path.GetExtension(file_upload.PostedFile.FileName);
string fileLocation = Server.MapPath("~/App_Data/" + fileName);
//if (File.Exists(fileLocation))
// File.Delete(fileLocation);
file_upload.SaveAs(fileLocation);
}
catch (Exception ex)
{
throw ex.Message;
}
finally
{
file_upload.PostedFile.InputStream.Flush();
file_upload.PostedFile.InputStream.Close();
file_upload.FileContent.Dispose();
//Release File from Memory after uploading
}
The references are hanging in memory, If you are using Visual Studio try with Clean Solution and Rebuild again, if you are in IIS, just do a recycle of your application.
To avoid this problems try to dispose the files once you used them, something like:
using(var file= new FileInfo(path))
{
//use the file
//it will be automatically disposed after use
}
If i have understood the scenario properly.
For Upload control, I don't think you have to write code for Upload Button. When you click on your button,your upload control has locked the file and using it so it is already used by one process. Code written for button will be another process.
Prior to this, check whether your file is not opened anywhere and pending for edit.

How can I place an ASP.NET menu control into cache?

I have a SharePoint2010 site that I have created an ASP.NET menu control for.
The ASP.NET menu's content is initially empty, and on Page_Load I load its content from standard HTML files on the server:
protected void Page_Init(object sender, EventArgs e)
{
string MenuPath = (string)ConfigurationSettings.AppSettings["RootMenuPath"].ToString();
Menu1.Items[0].ChildItems[0].Text = File.ReadAllText(MenuPath + "\\About.htm");
//etc...
}
I notice this is a horrible way to do things. It hits the disk every single time a user loads a page.
How can I either:
a) Cache the code and asp.net menu item so that it stays in memory?
b) Use another method to ensure it isn't loaded from the disk?
Thanks
You can wrap data load into property and use at least page Cache there:
readonly object cacheLock = new object();
string AboutHTM
{
get
{
if (Cache.Get("page.about") == null)
lock (cacheLock)
{
if (Cache.Get("page.about") == null)
Cache.Insert(File.ReadAllText(MenuPath + "\\About.htm"));
}
return Cache["page.about"].ToString();
}
}
You could indeed use the cache or some variable that is initialized only once in Application_Start and reused later but I am afraid that you are doing some premature optimization here. You probably shouldn't be doing it unless you have identified that this is a bottleneck for your application performance. Reading files from disk is a fast operation especially if they are small.
If possible, I would store the menu data in an XML file, and cache the XML file.
XmlDocument xDoc = new XmlDocument();
if (Cache.Get("MenuData") == null)
{
xDoc.Load(Server.MapPath("/MenuData.xml"));
Cache.Insert("SiteNav", xDoc, new CacheDependency(Server.MapPath("/MenuData.xml")));
}
else
{
xDoc = (XmlDocument)HttpContext.Current.Cache.Get("MenuData");
}

How do i create a 404 image? for images that cannot be read by ASP.NET

Using ASP.NET C#, visual studios to host the files/pages. I allow users to upload images and i redirect them to the media page. The images are in a specific path easily recognizable with regex. When i redirect i get 1 of 2 errors. 1) Image doesnt exist (hasnt been generated) or 2) Cannot open file (imagemagik or something writing to the image).
When i get theses errors how do i stop the 404 or other error and display 'processing' or currently unavailable placeholder image?
protected void Application_Error(Object sender, EventArgs e)
{
var ex = Server.GetLastError();
var exx = ex as HttpException;
HttpContext ctx = HttpContext.Current;
var url = MyCode.CleanPath(ctx);
if (MyCode.SomeRegexPattern.IsMatch(url))
{
var code = ctx.Response.StatusCode;
if (exx != null)
ctx.Response.StatusCode = exx.GetHttpCode();
else if (ex.Message.IndexOf("cannot access the file") != -1)
ctx.Response.StatusCode = 500;
ctx.Response.ContentType = "image/gif";
Server.Transfer("path/to/processing.gif");
}
}
From the theoretical perspective, couldn't you implement a custom HTTP handler based on your path, similar to what's detailed here: http://support.microsoft.com/kb/308001
Implement the logic to determine if the file requested exists and can be read in the handler. If not, programmatically generate the output you want instead of a 404.
Well 404 is the correct response code, but you might be able to set a custom handler on that in the images folder to instead return a dummy image.
EDIT: To set up the custom handler in IIS manager, go to the site, and go to Error Pages.

Resources