ASP.Net file upload module
Please note that version 2 of this project is now available. This version includes many more features including: SQL Server support; an inbuilt download handler; IIS 7 support; a new user interface; and, improved error reporting. Please see this post for more details.
For some time now I’ve been meaning to write a file upload HTTP module for ASP.Net. I know there are a lot of this kind of thing out there but I had some specific requirements that I couldn’t seem to find elsewhere.
For now, back to my requirements. First up the solution needed to be written in ASP.Net, and secondly it needed to be open source. Most pressing of all though was the need to be able to upload very large files without running into “request too large” problems or timeouts, as well as always keeping the user informed as to progress. In fact, the more I thought about it I realised that this project wasn’t quite as easy as I has first imagined.
My wish list for the component basically came down to the following:
- RFC 1867 compatible.
- Open source and written in ASP.Net.
- Able to upload multiple files with or without a client side progress bar and whilst maintaining compatibility with my existing applications.
- Uploads of large files without breaking the ASP.Net built in request size limit and using a small internal buffer (i.e. not loading huge chunks of data into memory as ASP.Net does by default).
- Custom handlers to stream the uploaded files to various data sources including the file system and SQL databases.
- Automatic error handling with completion of a request even if one or more files fails to upload correctly.
- And on, and on, and on……
You can download the source code- you are free to use it under the terms of the GNU LGPL. A screenshot of the uploader in action is shown below.
How it works
Using the upload module is pretty straightforward. Essentially what happens is that a HTTP module removes incoming files from the request stream and passes them off to a user definable processor which should persist them (to the file system, a database, or similar). With this release I’ve provided a file system processor which saves the files to a given directory, but in a future post I’ll explain how to make a SQL server version. You are free of course to make your own processors- you just need to implement the IFileProcessor interface.
To get started using the upload module copy the DLL from the download to your project bin folder. Next you need to add references to the HTTP module (which processes uploads) and an additional HTTP handler (which is used to provide real time information to the progress bar via XML HTTP). To install these components add the following to your web.config file:
<httpHandlers> <add verb="GET" type="DJ.Blog.FileUpload.UploadProgressHandler, FileUploadLibrary" path="DJUploadProgress.ashx" /> </httpHandlers> <httpModules> <add name="DJUpload" type="DJ.Blog.FileUpload.UploadModule, FileUploadLibrary"/> </httpModules>
Next you need to select a file processor and configure it. The default file processor uploads files to the root folder of your web application. You can change this in your global.asax file. To do so use the following code based around the application_start event.
void Application_Start(object sender, EventArgs e)
{
// Set up the file processor for the upload manager
UploadManager.Instance.ProcessorType = typeof(FileSystemProcessor);
UploadManager.Instance.ProcessorInit += new FileProcessorInitEventHandler(Processor_Init);
}
void Processor_Init(object sender, FileProcessorInitEventArgs args)
{
FileSystemProcessor processor;
processor = args.Processor as FileSystemProcessor;
if (processor != null)
{
// Set up the download path here - default to the root of the web application
processor.OutputPath = @"c:\uploads";
}
}
Essentially this code initialises the UploadManager singleton with the given type of file processor and then hooks into the ProcessorInit event which is fired when a new upload request is started. The ProcessorInit event is an opportunity to set any required properties of the file processor before it is used to persist files.
If you were to make your own file processor, you would implement the IFileProcessor interface and initialise your processor in global.asax in a similar way.
public interface IFileProcessor:IDisposable
{
void StartNewFile(string fileName, string contentType);
void Write(byte[] buffer, int offset, int count);
void EndFile();
string GetFileName();
}
From this point on the upload module will handle all requests for multipart/form-data requests by streaming them bit by bit to your chosen processor in a memory efficient manner. Once the upload is finished, the postback of your page will continue as normal and you’ll be able to get a list of uploaded files from the UploadManager singleton. The names of files which were uploaded correctly are held in the UploadedFiles collection whilst the names of any files which the processor could not upload are contained in the ErrorFiles collection. More information on the upload such as the total bytes and the time taken can be found in the UploadManager.Instance.Status property. All this of course only gets you the names of the uploaded files. Remember that the file data is not held in memory as this would be wasteful. The final location of the uploaded data and how you get at it will depend on the file processor implementation you are using. Check out default.aspx.cs in the sample project to see how all this comes together.
So what about the progress bar, how does that work? Well what happens is that as the incoming data is being processed, the status of the request is constantly being maintained by the upload module. This data is made available in XML format via the UploadProgressHandler HTTP handler. This is actually a virtual .ashx file which is called by javascript in your upload page to get the status of the uploads. The javascript then updates the progress bar accordingly. You don’t need the progress bar and the upload won’t fail if it isn’t there- but it’s nice to keep your users informed of what’s going on.
To use the progress bar you need to include a single instance of the UploadProgress control in the place on your page where you want the progress bar to appear. You also need to include the uploadutils.js javascript file and the stylesheet.css style sheet in your page (rename or include them as you wish).
The final step is to include a small piece of javascript on your page and attach it to the onclick event of your submit button (or the onsubmit event on the form if you wish).
<button runat="server" Text="Upload files" OnClientClick="startUpload()" id="btnUpload">
<script type="text/javascript">
function startUpload()
{
window.setInterval('up_ReportProgress()', 100);
}
</script>
In this example the progress bar will be updated every 100 milliseconds, you can change this to whatever value is appropriate to your needs.
That’s it, any files uploaded with standard input type=”file” controls will be handled by the module automatically from here on in.
Technical notes
The solution file contains a number of c# classes in addition to the DLL and sample pages needed. The class library is self contained and should be easy to extend. A class diagram is provided below to aid in understanding of the solution structure. There are some technical points to make about the solution for those who are interested.
![]()
In essence the HTTP module intercepts the request stream and passes it into an instance of FormStream. The form stream is specially designed to process RFC 1867 file upload requests by reading the data in small chunks. This allows the processors to get to work persisting files without waiting for the whole request stream to be loaded. This is a great deal more efficient in time and more importantly in memory usage than the default ASP.Net mechanism.
Non-file request information is unchanged, however only the boundaries and header information of the files make it to the final request stream (the headers need to be there so as not to break the view state of ASP.Net). This means that there is no excessive build up of file data in memory. If you are writing a new file processor bear this in mind because you don’t want to undo this good work by having a large buffer in your processor!
As the request progresses, the UploadManager is notified of the current file and the number of bytes remaining in the request so that it can notify the calling page of the upload progress (through XML HTTP and the progress handler). The status information is held in the application cache and is tied to the requesting page through a guid generated by the progress bar control on server side. This guid is passed back to the HTTP module in the query string (not as a hidden field as this would need to be parsed from the request stream before it could be used).
A breakdown of this process is shown in the diagram below:
One of the less obvious problems to solve in this project was how to prevent ASP.Net from throwing an exception if the size of the requested files was above the maxRequestSize setting of the HTTP runtime. Although this can be changed in web.config I wanted to avoid this so that other pages in my sites were still protected from denial of service attacks (the purpose of maxRequestSize). In the end I used reflection to populate the preloaded content with non-file related data then set the _contentLength variable of the request object to the correct size (original size - file data size). This process basically fools subsequent HTTP modules into thinking that the request is fully preloaded and available without further reading. The final step of setting the _contentLength variable in the request prevents ASP.Net errors if the request is above maxRequestSize but maintains the Content-Length HTTP header.
From UploadModule.cs:
// Set the preloaded content as the contentMinusFiles and
// fool the worker process into thinking that is all the content
// there is by setting the appropriate lengths.
workerType.GetField("_preloadedContent", ba).SetValue(worker, fs.ContentMinusFiles);
workerType.GetField("_preloadedContentRead", ba).SetValue(worker, true);
workerType.GetField("_contentAvailLength", ba).SetValue(worker, fs.ContentMinusFiles.Length);
workerType.GetField("_contentTotalLength", ba).SetValue(worker, fs.ContentMinusFiles.Length);
// Set the content length to the true value to prevent "request exceeded maximum size" errors.
app.Request.GetType().GetField("_contentLength", ba).SetValue(app.Request, fs.ContentMinusFiles.Length);
I’m not particularly happy about using reflection in this way as it breaks the fundemental premise of information hiding. However a better solution evades me at present. I think it ought to be possible for an HTTP module (given the nature of their activities) to be able to change the request stream without resorting to reflection.
Downloads
You can download the source code for this article and use it as you wish under the terms of the LGPL License. If you find any bugs in it or have any suggestions post a comment here and I’ll do my best for you. If you do use the code in your applications it would be nice if you could let me know by posting a comment.

Comment by Nicholas on 10 June 2007:
Hi
Sorry, I can’t get your example to work. I double click on the sln file, VS2005 opens but says that FileUpload is not available. When I try to execute the FileUpload part (not the library) in order to resolve this, I does not run because there are missing references (which are due to a library missing). So am I stuck in a circular dependency?
Thanks
Comment by Nicholas on 11 June 2007:
Hi
I’ve managed to get it to work but I have a couple of problems.
First, in my local development ASP server provided by VisualWebDeveloper, I get a NullReferenceException in line 136 of the UploadModule.cs file when I click Submit to upload any file.
This is the offending line:
fs.Write(data, 0, data.Length);
and data is not initialized because the line above it:
// Read the first portion of data from the client
byte[] data = worker.GetPreloadedEntityBody();
probably does not work properly…
Second, when this is uploaded to a production server it basically says that the FileUpload.dll cannot be loaded because this is not allowed by the IIS server…
Some help would be greatly appreciated!
Thanks
Nicholas
Comment by Darren on 11 June 2007:
Hi Nicholas,
I’ll try to answer your questions.
First up, the solution refers to a web project for testing purposes. You need to create an appropriate web folder to contain the project.
Second, since the code works at quite a low level in the ASP.Net request, it DOES NOT work with the in-built VS.Net web server- you need to use IIS.
ASP.Net is complaining that it can’t find the fileupload.dll library.
The solution I deployed does not include the bin files to save download time etc. You need to build these yourself.
To do so open up the project in VS.Net 2005. If you can’t get the whole solution to load just open up the FileUploadLibrary project.
Build this project and then grab FileUpload.dll from the build output (set the mode to release first and it should show up in the bin\release folder). Copy FileUpload.dll into the bin folder of your web app (just bin, not bin/release as in Visual Studio).
Try again and hopefully all will be well.
Comment by Nicholas on 11 June 2007:
Hi Darren
It worked!
Thank you very much
And not only that, but it worked like this too:
The
<asp:FileUpload runat=”server” ID=”fuTestFile1″ />
Can become:
<input type=”file” ID=”fuTestFile1″ runat=”server” />
This essentially allows me to have an arbitrary (user-specified) number of upload input fields with their IDs dynamically specified.
Looking forward to your production version!
Comment by Marc on 18 June 2007:
Hello,
nice done! It works for me as expected.
I just have one question:
The outputPath its “more or less Hardcoded” is there a moment on runtime where i can change the outputPath?
For example:
I create an Object in Sql with an normal ID, then i have the folderTree on server (root\objects\uploads\ID)
i want to upload the files to the folder with the obtained ID…i cant find the way to tell to the systemProcessor that he haves to upload it to there.
Or is the way the following:
Upload to server (allways same folder) and then to copy the files to the final destination?
Thanks and regards
Marc
Comment by Darren on 18 June 2007:
Hi Marc,
You can set the upload path using the OutputPath property on the file system processor. You need to do this by handling the ProcessorInit event of the UploadManager in your application_start event (global.asax) as described in the article. Since the module runs before your pages, it is difficult to set the path at runtime. You could perhaps use a URL parameter for your ID and create your own processor that uses it or simply copy the files once uploaded as you say.
Comment by Jared Lillywhite on 22 June 2007:
Hey, is there any chance that you can release this under the LGPL? I would like to integrate the library into an application that I’m writing for work, but they won’t want to open source their code.
Comment by Darren on 22 June 2007:
Yes, I did think about this at the beginning. A few people how now asked. So why not? This library is now licensed under the LGPL and is available in final form in the downloads section.
Comment by Jared Lillywhite on 22 June 2007:
Thanks. And nice work, by the way. I’ve been trying to get something similar to work for quite a while.
Comment by Glenn A. Harlan on 25 June 2007:
I would like to try this solution for our project because the .NET FileUpload control is giving us problems. My issue with this one so far from looking at it is our requirement not to overwrite an existing file. Currently in .NET we have it coded to append an index/sequence number to a filename if it already exists. (i.e., ReadMe.txt, ReadMe_001.txt, ReadMe_002.txt, etc) Would like to try the same solution with this implementation.
Any suggestions as to where this logic should be implemented?
Thanks.
Comment by Glenn A. Harlan on 25 June 2007:
Never mind.
Another requirement is multiple upload locations (depending on user role) and allow/disallow overwrite again based on user role. Specifing Upload location in Application Start will limit us to one directory. Uploading to 1 directory and copying may be a possiblity, however file sizes may be an issue for doing this (architectural drawings), will have to do some testing.
Comment by Darren on 25 June 2007:
Hi Glenn,
Both of these things are possible if you write a custom file processor by implementing the IFileProcessor interface. You can check the users role there and pick a directory as required. You can also decide to overwrite the file or not. Neither of these should be too difficult as the IFileProcessor interface is very simple.
You just need to install it like this is Application_Start:
UploadManager.Instance.ProcessorType = typeof(MyProc);
Hope this helps. I will add an overwrite property to the next version.
Comment by Marc on 26 June 2007:
Hi outta there,
ok I translated it to Vb.Net and now i made the needed modifications, now i can establish the destination path over querystring. I set the fixed path in application start and later I add him the obtaind rest path to it.
Thanks and regards
Marc
Comment by janos on 27 June 2007:
i look forward to seeing how to overwrite the processor outputPath.
i’m testing by making a custom IFileProcessor where the outputPath looks for something like System.Web.HttpContext.Current.Items["UploadModulePathModifier"], and if it is not null, it appends i to the path.
basically it is set in the page prior during page_load like so: Context.Items["UploadModulePathModifier"] = “SomePathAdditonEtc”;
unfortunately, the Context.Items["UploadModulePathModifier"] does not seem to be making it to processor prior to the upload.
is there something obvious that i’m failing at?
Comment by janos on 27 June 2007:
oh yes, i forgot to add -
the reason i’m trying to inject per-user-context additions to the processor outputPath is for a few reasons, but the big one being that i wish to avoid possible file-overwrites when multiple users are signed on, i also need to know where the file has been dumped so that i can pick it up for further processing which i do outside the scope of the upload manager.
btw, this is a very nice piece of code. your openness with it is much appreciated.
Comment by Darren on 27 June 2007:
Hi Janos,
The thing to remember about the context is that although HttpContext.Items can be used to pass information between HTTP modules and handlers, in your case you are setting the value in Page_Load. Unfortunately, by the time this is called the upload module has already been and gone. If you need to pass information to the module from server side you need to use either the query string (not form items) or alternatively a database or other persistent storage mechanism. If you look at the code for the progress bar, you will see that a query string parameter (DJUploadStatus) is used to tie progress output to an instance of the upload control. What you want to do is similar so you should have a look at that.
Comment by janos on 28 June 2007:
Darren,
yep, i did a few life-cycle tests. i’m doing some pretty gimpy work-arounds right now. for one test i’ve just pulled the ProcessorInit out of Global and into my specific test page doing Page_Load.
i’m not sure how this may affect performance, but for now it’s letting me get past what i needed to do for testing some things furhter down the line.
once again, thank you for the excellent code.
Comment by Walker on 3 July 2007:
Great CODE! Got it to work. I am writing a File Upload app in ASP.NET 2.0 with client side validation. My problem is how to control the start and finish of uploads since it launches the File Upload process once a postback (image click,etc) is performed. I am trying to intercept the postback but there has to be an easier way. Any ideas in terms of extending the Library such as an enable/disable property?
Comment by poco_loco on 4 July 2007:
This is very nice solution.
But i can’t find how to limit size of uploading file. And it would be great to implement resumable download feature
Comment by Darren on 4 July 2007:
There have been quite a few feature requests now. Thanks for the feedback! I’ll be incorporating these things into a v1.1 release which should come pretty soon.
Comment by Larry on 6 July 2007:
If I am implementing a database (oracle) processor for uploading CSV files into the database, do I have to read the entire byte[] into memory stream? If the file is being read in chunks, how would I know when I have a complete set of csv lines for inserting into db? I will need to do the inserts line-by-line.
Thanks.
Comment by Darren on 8 July 2007:
Hi Larry,
In your processor for CSV files you can check the incoming byte stream for line endings and process the lines one at a time. You’ll be best to examing the byte array directly for line endings rather than constantly converting to text strings as this will be more efficient.
You could also load the file all at once as you describe and then process the entire file. You might even want to consider using a FileSystemMonitor to defer this processing off to a Windows Service or something to make the upload process faster and prevent your users from waiting around for CSV processing. I’ll try and post an example at some point if I get a chance.
Comment by Abhi on 25 July 2007:
Hi..
This is the really fantastic work….
But,
I have a problem with it..
I’ve downloaded this source code and I am trying to use it.
I have configure this two project in my Visual Studio.
But, when I run the Default.aspx and ‘browse’ the files to
upload, but after clicking on ‘Upload files’ button then I
got ‘The connection was reset’ page.
Please, Help help me as soon as possible..
Thanking you,
Ragards,
Abhi
Comment by Abhi on 25 July 2007:
Hi..
I’ve problem when I am uploading an image…
The, I got error like :
The following files encountered errors:
* Winter.jpg
Please help me as soon as possible..
Ragards,
Abhi
Comment by Developer on 25 July 2007:
This is really nice. It’s well-packaged and easy to use. Thanks a lot.
BTW, when is v1.1 coming out?
Comment by Abhi on 1 August 2007:
Hello…
Sir.
I’ve used this class library..
This is really a fantastic work…
Can you please give me a solution, that…
I want to set the Maximum file size limit for a file to
upload, in the the web.config file…
So, please give me a trick or solution for that as soon as
possible…
Thanking you,
Regard,
Abhi
Comment by Jonathan Matt on 2 August 2007:
I’ll carry out some test on this component whether it pass the Loadrunner or not.
Comment by Mert on 17 August 2007:
Nice code you got here, I wish I could see that before I started to implement my own
I hope you can help me with my following problem which is related to Nicolas’ post:
Even though I deploy my application to IIS, byte[] data = worker.GetPreloadedEntityBody() part seems to freeze often. It works rarely with VS2005 built-in server, and rarely with IIS. Sometimes it works without any problems, very weird :-). Somewhere in some forum somebody said it was something related with how the client submits the form but I am using enctype=”multipart/form-data” anyway.
I could not figure out why this is happening as it seems that the inputstream just freezes and the request never finishes.
Please help since this is driving me insane.
Thank you!!
Comment by Jon Galloway on 17 August 2007:
You should update this post to indicate that you’ve changed the licence from GPL to LGPL. I was just about to pass on this due to the license, and I bet a lot of your other readers might too. Great stuff, glad you changed the license.
Comment by Felipe Garcia on 26 August 2007:
Hi,
first of all, great work? just wondering if anyone encoutered problems running the example on a safari browser?
Greetings
Comment by John on 11 September 2007:
This is a great project!! Works very well too! Thanks for taking the time to work on this project. I was going to port my version over to OpenSource if I could ever get it working the way I wanted it to but your code is much nicer and is working already!
Two small bugs I’ve found that maybe you are already aware of:
1. When using IE7, if you open an upload page in a new tab while a file is already uploaded in a different tab, the second tab will not get progress updates or any status information. I haven’t tracked this down yet to a cause.
2. When uploading a large file and the server times out during the upload, sometimes the upload page will not error and the progress bar stops moving but keeps trying to get an update from the server. Eventually IE will time out with a “page cannot be displayed” error.
I’m going to keep looking for a solution to both issues and will let you know if I come across an answer. However, I figured if you had a suggestion you might chime in before I get the solution.
Comment by John Ciliberti on 18 September 2007:
I have gotten the code to work in Full trust on my dev machine but it fails when it is run under MEduim trust.
It fails at the following line of code in the HTTP Module
HttpWorkerRequest GetWorkerRequest(HttpContext context)
{
IServiceProvider provider = (IServiceProvider)HttpContext.Current;
** return (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
}
Not sure if there is a work around other then installing the module in the GAC (not an option for me).
Comment by John on 20 September 2007:
It looks like the answer to problem 1 I posted above is that the browsers just aren’t going to make the additional connections back to the server that are required to get the async data. There’s no good work-around that I can find.
I think number 2 above is just a fact of life as well if the server script timeout setting isn’t high enough.
A new issue I see is that if you are running the progress bar on a page that uses AJAX, changing the form action using javascript will break the AJAX functionality. I found that you also have to change the form._initialAction to the new value at the same time for AJAX functionality to work as expected. Otherwise AJAX may be unpredictable and may cause full postbacks that don’t do what was expected.
Your mileage may vary…..
Comment by Juan Daniel Cebri on 25 September 2007:
Hello Darren:
We’re glad to see such a clean work.
We wanted to implement some kind of new FileUpload control and after searching in Internet for a better way of managing uploads we met your blog and your ASP.NET FileUpload Module let us very satisfied, however it didn’t implement some kind of Cancel Upload feature that we were searching for. Anyway, as you changed the license from GPL to LGPL, we decided to use it and implement that new feature.
Please feel free to delete this post and to merge our code with yours.
We’ve tested it with FireFox 2 and Internet Explorer 6/7 (and it works!).
In our internal development, we’re planning to have it working with the “ASP.NET 2.0 AJAX Extensions 1.0″, so the AJAX calls can be made directly with the AJAX Extensions so we could benefit of a possibly wider browser support in the future among other things.
As we can’t attach files to this reply, we’ve made a little room in our server so you can download it.
Here is the link: http://www.solnatec.com/archive/public/FileUpload_Cancel_Feature.zip
Inside the compressed file there’s a changelog file called “Cancel Feature Changes.rtf” that indicates the lines we’ve added or modified in each file and somehow why.
Juan Daniel Cebri
Comment by Diederik on 4 October 2007:
Hi Darren,
First of all, thank you very much for sharing this excellent code with the community! It has saved me a lot of time. However, I would like to kindly request a feature for the next version. Hopefully you have already incorporated it in v1.1, but I would like to see a way to control the start of the upload. Walker already mentioned this in his post on July 3rd. The problem is that the uploading is started when a postback is performed, even when client-side validations (such as required field validators) fail.
Anyway, thanks again.
Diederik
The Netherlands
Comment by Michel on 10 October 2007:
Hi !
asp.net Fileupload module. I’m really happy with it but I tried to find a way to configure it to upload the file to a database (change the code in the processor init ?!?) and i don’t find how can i accomplish that.. can you help me on that ??
I founded with pleasure your FREE
thank’s
Michel
Comment by Greg Pasquariello on 18 October 2007:
Hi Darren,
Thanks for the module. I made some very simple changes that allow it to work on the built-in Vis Studio webserver.
First, when on the read of preloaded content, it’s necessary to make sure there is some, so I changed the code as follows:
byte[] data = new byte[0];
if (worker.GetPreloadedEntityBodyLength() > 0)
{
// Read the first portion of data from the client
data = worker.GetPreloadedEntityBody();
fs.Write(data, 0, data.Length);
_status.UpdateBytes(data.Length, _processor.GetFileName());
}
int read = 0;
int counter = data.Length;
Second, when you use reflection to spoof the content size, I changed it to set the field values for all worker types. This has the effect of setting the preloaded content field for the first worker in the chain… I’m not exactly certain WHY that works, because there is no preloaded content to begin with in the builtin server.
// Find the actual ISAPIWorkerRequest object
while ((workerType != null) && (workerType.FullName != “System.Web.Hosting.ISAPIWorkerRequest”))
{
// Set the preloaded content as the contentMinusFiles and
// fool the worker process into thinking that is all the content
// there is by setting the appropriate lengths.
FieldInfo fieldInfo;
fieldInfo = workerType.GetField(”_preloadedContent”, ba);
if (fieldInfo != null)
{
fieldInfo.SetValue(worker, fs.ContentMinusFiles);
}
fieldInfo = workerType.GetField(”_preloadedContentRead”, ba);
if (fieldInfo != null)
{
fieldInfo.SetValue(worker, true);
}
fieldInfo = workerType.GetField(”_contentAvailLength”, ba);
if (fieldInfo != null)
{
fieldInfo.SetValue(worker, fs.ContentMinusFiles.Length);
}
fieldInfo = workerType.GetField(”_contentTotalLength”, ba);
if (fieldInfo != null)
{
fieldInfo.SetValue(worker, fs.ContentMinusFiles.Length);
}
workerType = workerType.BaseType;
}
That’s it. Making those changes allows it to work in both IIS (IIS 7 is what I have) as well as the built-in VS server.
Cheers!
-Greg Pasquariello
P5 Technologies
Comment by Greg Pasquariello on 19 October 2007:
Here’s another change that I made that I found useful…
First, I changed the default file upload folder to be the windows system temp folder.
Next in the uploaded files list (and the error files list), I changed the list to be a list of fileinfo.
These two changes mean that I don’t have to add anything to the global.asax in order to have a very meaningful file uploader. In the upload form page, I simply have to iterate through the file list and perform FileInfo.MoveTo() to get the files from the temp folder to a place that I want them. This makes a lot of sense in a situation where I have multiple file upload locations (like an images folder and a thumbnails folder, for example).
Lastly, neither of these changes affects the ability to set it up in global.asax, so if I just have one upload location, I can still set it there.
Regards
-Greg Pasquariello
Comment by Vishu on 19 October 2007:
Hai,
I have downloaded your handler. It is working great.
But i want to limit the upload size and display the error message “Exceeded the maximum limit”.
How to stop the process without uploading.
If you have solution please let me know.
Thanks
Vishu
Comment by mjoksa on 29 October 2007:
Hi,
I’ve been using this control last two months and I had no problem with it. I’ve used this control for a small upload application based on Ext (www.extjos.com) framework. When I made this app with Ext 1.1 everything worked fine. I’ve migrated my app to Ext 2 but then a problem occured with file upload control. I’ ve configured it same as in first app but when I sent Ajax call to upload handler (for uploading files) every time I get XML answer with attribute ‘empty’ set to ‘true’. Does anyone get same problem, or is there any solution to it?
Another thing, i’ve managed to upload files (in first version of app) into different folders in this way:
1) In Global.asax files I’ve added lines:
UploadManager.Instance.ProcessorType = typeof(FileSystemProcessor);
UploadManager.Instance.ProcessorInit += new FileProcessorInitEventHandler(HFT_Ext2.UploadHandler.Processor_Init);
2) I’ve created UploadHandler.ashx page and in it I placed method:
public static void Processor_Init(object sender, FileProcessorInitEventArgs args)
{
FileSystemProcessor processor;
processor = args.Processor as FileSystemProcessor;
if (processor != null)
{
processor.OutputPath = HttpContext.Current.Request["uploadFolder"].ToString();
}
}
This worked fine for me (in first version of my app).
Please, can anyone help me with my problem?
Comment by mjoksa on 29 October 2007:
Addition to my previous post:
I’ve tried to upload files the old way (hard coded in Global.asax) but I always get XMl response with attribute empty set to true. This is bothering me for two days, so anyone please, help me.
10x
Comment by David on 31 October 2007:
Darren,
Splendid code! Thanks for sharing! Any chance this code will help in overcoming the 2GB (actually, 2097151KB) limit for uploading files through http?
Cheers!
David
Comment by Fernando on 1 November 2007:
Hi,
First of all, thanks for your excellent work, your implementation is very clever!
I have included it in a web site using MS Ajax Extensions 1.0 and I’ve made some tests with large files (1GB). I’m getting an HTTP Exception “Maximum Request Length Exceeded” on the following line:
if ( ( ! String.IsNullOrEmpty(context.Request[UploadManager.UPLOAD_SESSION_ID_KEY])) &&
(string.Compare(ct, 0, C_MARKER, 0, C_MARKER.Length, true, CultureInfo.InvariantCulture) == 0) )
Maybe I’m wrong, but my guess is that Ajax Extensions add some new elements to the request pipeline and those new steps added include some validation on request length, so the exception is thrown before you are able to “fool” the worker process.
Have you (or any other people using this module) used your module in an web site using Ajax Extensions 1.0 with success?
Comment by Peter on 1 December 2007:
Hi Darren,
Thanks for this excellent code. About 6 months ago I was able to get it working fine under Windows XP and IIS6.
I’m now developing under Windows Vista and IIS7 and can’t seem to get it working.
I’m wondering if you have tried it under Vista/IIS7?
I’m getting the same error that Nicholas reported in the second post:
[NullReferenceException: Object reference not set to an instance of an object.]
DJ.Blog.FileUpload.UploadModule.Context_AuthenticateRequest(Object sender, EventArgs e) in FileUpload-final\FileUploadLibrary\UploadModule.cs:138
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +92
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +64
I’ve tried all the things you suggested in your reply to Nicholas but I’m still not able to get it working under IIS7.
Any suggestions would be greatly appreciated.
Thanks,
Comment by Matt on 13 December 2007:
Many thanks for your code Darren, very useful.
For the people struggling with large files, the limit is configurable to an extent. These two articles ought to help. The first worked for me on IIS7, the second seems to be more about IIS6.
http://www.element-it.com/RequestFilteringModule-maxAllowedContentLength.aspx
http://support.microsoft.com/default.aspx?scid=kb;EN-US;295626
Comment by Karl S. on 15 December 2007:
Looking forward to implementing this. This is exactly what I was looking for in an upload component: open source (mostly for my selfish interest in learning, but also for tweaking), free (thank you!), interactive.
I plan to implement this as an asynchronous Ajax upload component for my websites.
Thanks again, I will be reporting soon with feedback!
Karl..
Comment by sarath on 11 April 2008:
Hi,
Great illustration
Can i know how to restrict the type of files which are being uploaded
Like i want a “Error message” when a user uploads .exe file
please mail it to my email id
Thank you
sarath
Comment by Bri Manning on 15 April 2008:
Way to go Matt on 12/13/2007 - didn’t realize migrating to IIS7 would have broken that, sweet find. Darren, thanks for the great work.
Comment by Daman on 4 June 2008:
Hello,
First of all Great Code it works fine, i have implemented it in my we b project. But wanted to know can i rename the files such as we do in normal file upload and specify new file name in SaveAs mehtod of file upload control.
cheers.
with regards
Daman
Comment by OutOfTouch on 27 June 2008:
Hi Darren,
Very good, functional, clean and readable code, thank you for sharing with the community.
I have a quick question, what is the public key token of the assembly? I tried to get it using reflection but I don’t see any value?
Thank You!
Comment by OutOfTouch on 27 June 2008:
Where is the best place in the code to filter and only upload a certain file type. I was thinking maybe in the in the write method?
Comment by OutOfTouch on 27 June 2008:
I am getting javascript error when adding the unmodified lib to my project and running in debug mode. The error is it can’t find the empty attribute, I double checked that I have the module and handler declared in my web.config.
The biggest difference for me I am trying to use this in a content page inherits a master page.
Comment by OutOfTouch on 27 June 2008:
Waiting for uploads <— This is never getting written for me when I use the control ina content page or a normal aspx page.
Comment by OutOfTouch on 27 June 2008:
Last post no good, the content that should be written to my page from the UploadProgress class Render method is never getting written to my page, even in a normal page it is not getting written.
What am I missing, I clearly see it in the example?
Comment by OutOfTouch on 28 June 2008:
I guess I do see it being rendered but I can’t figure out why I get an error in the javascript on this line:
if (res.documentElement.getAttribute(’empty’) == ‘true’)
I did look at res in watch window and the xml is null.
Comment by OutOfTouch on 28 June 2008:
I could really use and appreciate some help with the javascript error above. For some reason the context response must not be getting written out in my project but I have no idea why. I have the checked the handler and module elements that I added to my config match what is in the sample site.
Comment by Karl Cassar on 30 June 2008:
Is there any way to know from which FileUpload the file uploaded, was uploaded?
Say you have 3 file uploads, and you need to know specifically if it was uploaded from the 1st, 2nd or 3rd. My reason is that according to which one it was uploaded from, it is then resized to a different size.
cheers,
Karl
Comment by OutOfTouch on 30 June 2008:
I can clearly see _status in the PersistStatus method with the empty attribute but for some reason the XMLHttpRequest is not getting anything in the xml value in my application and I don’t know why or what to do to fix it. PLEASE HELP.
I can create a new application and use the library without any problems.
Comment by darren on 30 June 2008:
Hi Karl,
In v1 you can’t do this as it is. The ID of the form element is available to the form stream but at present it doesn’t do anything with it. I’m working on a version 2 of the component which has many more features including a custom server control which allows this. It should be out by the end of the month.
Cheers
Darren
Comment by darren on 30 June 2008:
OutOfTouch, you are clearly having problems. I tried to email you to ask if you would send me your project so I can help. Send it to darren@darrenjohnstone.net and I’ll take a look for you.
Darren
Comment by OutOfTouch on 30 June 2008:
I Finally figured out my problem, the problem is the security context and location in which my UploadPage is running.
I added Location Path property allowing the roles or all users access to the path=”DJUploadProgress.ashx” and then the Get worked as just fine.
Comment by meera on 1 July 2008:
Is it possible to do this in a UserControl??I want to include this FileUpload module in a SharePoint site.Pls advise.
Comment by darren on 1 July 2008:
Hi Meera,
There’s no reason you shouldn’t be able to host this on a user control. I haven’t tested it in SharePoint but I don’t see any reason why it shouldn’t work.
Darren
Comment by OutOfTouch on 1 July 2008:
Are you including the ability to filter file types in the next version?
Can I do that now in the Write method of the FileStream class or is there a better place to do this?
Again, thanks for the sharing good code!
Comment by darren on 1 July 2008:
Yes, filtering of file types will be in the next version. You could filter them on the server in the StartNewFile method of the processor. Just set a flag if you want to ignore a file and then skip processing in Write and EndFile. You could also throw an exception in StartNewFile which will cause the file to go to the ErrorFiles collection in UploadStatus.
Darren
Comment by Buhari on 7 July 2008:
Thanks for your code.
I tried to filter some of the file types. I did code in StartNewFile and filtered(based on the types). As you suggested, i raised an exception in StartNewFile. But in the status.ErrorFiles, i am getting null value. Could you please help me?
string sDeniedFiles = System.Web.HttpContext.Current.Application["DENIED_FILES"].ToString();
string sFileExt = fileName.Substring(fileName.LastIndexOf(’.'), fileName.Length - fileName.LastIndexOf(’.'));
if (!sDeniedFiles.Contains(sFileExt))
{
_fileName = fileName;
_fs = new FileStream(_outputPath + Path.GetFileName(fileName), FileMode.Create);
}
else
{
_error = true;
throw new Exception(”Invalid File ” + fileName);
}
Comment by Pete Hurst on 7 July 2008:
The problem with IIS7 is simple:
It uses an IIS7WorkerRequest, not the old IsapiWorkerRequest.
So, the reflection you have used is broken. As you commented:
“I’m not particularly happy about using reflection in this way as it breaks the fundemental premise of information hiding.”
And this is exactly the reason. Because you are not using a defined public contract for an interface, you have no guarantee that the code will work under all circumstances.
Comment by darren on 7 July 2008:
Hi Pete,
Thanks for your comment. You are correct. The worker process is a different class type in IIS 7. I’ve already dealt with this in version 2 http://darrenjohnstone.net/2008/07/03/aspnet-file-upload-revisted-part-1-iis-7-support/.
I’m never happy about using reflection in this way as I’ve said in the posts. However, in this case I have been unable to find another way to achieve the desired results. Maybe that will change in time.
Darren
Comment by darren on 7 July 2008:
Hi Buhari,
First up, file extension filtering is going to be in version 2 of the module which will be coming along in a few days- so if your requirement isn’t urgent maybe you should wait for that. Version 2 also has IIS 7 support and a lot of other enhancements.
I’ll give your code a try later today and see if I can pinpoint the exact problem.
Hope this helps.
Darren
Comment by Oyster on 17 July 2008:
Hi there.
First of all, thanks a lot for such a great and free library - it helped us very much in our project. However, I think I found tiny problem in it - method FormStream.IndexOf() works incorrectly because it returns valid index even in case when searched sub-array is not fully present in buffer. For example, if buffer has a string “sometext” and searched sub-array is “textual” then returned index will be 4, not -1 as I was expecting it to be. This issue usually not causes any problems but we saw a few ArgumentOutOfRangeException in CheckForBoundary() caused by it on production (in code which invokes header.Substring()).
I have fixed this issue in my copy of code by modifying last LOC in IndexOf() method to the following one:
return count == checkFor.Length ? startPos : -1;
With this modification IndexOf() will return valid index only in case when sub-array is fully contained in buffer. I don’t know if this issue was fixed or not in version 2 (because wasn’t trying it) so I am informing you about it here.
Comment by Oyster on 18 July 2008:
Btw, I looked onto v2 code and it seems like in v2 this issue is fixed.
Comment by darren on 18 July 2008:
Thanks Oyster, yes v2 has a whole new parser and the issue is resolved. Thanks for the fix though, others who don’t want to move to v2 for whatever reason will find it useful.
ATB
Darren
Comment by Timo on 23 July 2008:
Amazing piece of code!
Comment by bart on 13 August 2008:
Excellent bit of code here. What areas would you desire help to extend what you already have? How would you be best helped?
Comment by Diego on 24 September 2008:
Hi to all:
First of all, of course, congratullations and thanks for this great control.
I have a little question. The AJAX progress bar appears in the top of the page, and in my case, it appears behind my site’s flash banner (located at the top of the page too). Is it possible to locate the AJAX progress bar for example in the middle of the page or in other coordinates?. I tried to change style pages, but I can’t move the AJAX bar position.
Thanks.
Comment by darren on 24 September 2008:
Hi Diego,
The control (I assume you’re talking about version 2) uses the Modalbox library to host the progress bar in a slide down window. You can also choose to use the accessible progress bar which can be positioned anywhere. Alternatively, it wouldn’t take much to change the script to use a different light window style library or simply show progress in a named div. You won’t be able to change this through CSS alone, you’ll need to change the script in
fileupload.js, specifically theup_setProgressmethod. This current builds an HTML string and then uses Modalbox to display it. Instead of doing this you could set theinnerHTMLproperty of a named div to position the progress bar anywhere on the page:function up_SetProgress(progress, file)
{
var html;
html = "<div class='upContainer'>";
html += "<div class='upOuterBar'>";
html += "<div id='upProgressBar' class='upInnerBar' style='width:" + progress + "%'>";
html += "</div>";
html += "<div id='upLabel' class='upLabel'>";
html += (progress == 0 ? "Waiting for uploads to start" : "Now uploading " + file + " " + progress + "%");
html += "</div>";
html += "</div>";
html += "</div>";
// Cancel button
if (up_showCancel)
{
html += "<img src='" + up_imagePath + "cancelbutton.gif' onclick='document.location=document.location' style='cursor:hand;margin-top:5px' />";
}
//--------------- set the innerHTML property of a div to show the progress bar
document.getElementById('mydiv').innerHTML = html;
//---------------
up_loading = true;
}
Hope this helps.
Cheers,
Darren
Comment by Mike on 25 September 2008:
Hi Darren,
I am realtively new to ASP.Net and I am currently constructing a portal which involves uploading files. I have got your component installed and working fine using IIS7 (Vista) and VS 2008.
Firstly, thankyou for sharing this work as it has saved me a lot of time and has made the uploading process look so much slicker in the portal.
A couple of things, the DJUpload control is fine as tested in Explorer 7 as you have mentioned. However, in Explorer 8 the text boxes change behaviour (latent text is displayed and dissapears when the Add button is clicked). Different result in Chrome altogether with the Add buttons being pushed to the left and the text boxes containing text.
I guess this is the way that the new browsers are interpreting IIS. Have you any ideas for fixes for the new browsers?
One more question, I know you have implemented a download handler for files in an SQL database. Is it possible to use the download handler for say a text file on the file system using the Response.TransmitFile( Server.MapPath(”~/download/xxx.xx”) );.
Any pointers you can provide would be gratefully appreciated.
Thanks again for a great component.
P.S, Relatively new to this so apologies if my questions seem a bit naive.
Cheers,
Mike
Comment by darren on 25 September 2008:
Hi Mike,
I’m currently looking at IE8 and Chrome. I’ll release a patch to the CSS and javascript to those who are interested and a new version of the module when the browsers are out of beta. I will send you the patch when it is ready.
It is relatively easy to change the download handler (or create a new handler) for downloading files. Just take the url or a unique identifier as a url parameter and then
Response.TransmitFilein the handler instead of accessing the database. I’ve got some sample code I will dig out and email to you.Cheers,
Darren
Comment by Jeff on 7 November 2008:
Can you resize images before saving them into a SQL db with this?
Comment by sufeein on 14 November 2008:
Hi Darren
can you please tell me how to rename the files on upload
Thanks
Suruchi
Comment by Kinjal Desai on 27 November 2008:
Hello Darren,
Its a nice piece of work! Thanks and Congratulations!
Two years back I had developed Upload Control for one of our clients. The control’s design and working was quite inline with that of your control’s. I mean, file was posted (uploaded).. The request was read by our code, and it continuously updated the status.. JS in browser kept probing for status using XmlHttp..
Couple of days back the customer requested us to upgrade it to asp.net 3.5, and make it work in IIS7 intergrated mode.
Your article was really a bliss! It saved me a lot of efforts.. I made necessary changes in our application. It worked! Thank you.
When i was testing it for larger files uploads, it resulted in errors.. I drilled in it, and found that, while the code was reading the request (in the while loop with IIS7WorkerRequest.ReadEntityBody() call), the client-IIS connections was being disconnected suddenly (that is, IIS7WorkerRequest.IsClientConnected() returned false)! I was not able to figure-out from where i can know the reason of the connection break.
Following are some facts:
- The whole request is not buffered in the RAM. I have pipelined it to file system. As you did in your code.
- I observed RAM consumption in the TaskManager. It fluctuates around 50% to 60%. So nothing alarming here.
- Following are the configuration settings being applied:
-
-
-
- Every time it disconnected after reading different amount of data from the request! Sometimes it banged at 5MBs, and couple of times it went up to 65+MBs..!
I was stuck in middle of it. I tried to find possible missing configuration setting or any similar case on the net.. But promising nothing turned up..
Then it clicked to me to take your code from one of my colleagues, who had downloaded it couple of days back;
I played with it, and it was working fine. Then i set it’s server to IIS7 (from Web project’s Properties > Web tab).
I observed exactly same issue with your application too! I was bit sad as my attempt to compare-find-fix the buggy portion was not successful. But simultaneously i was glad, as it implied that the problem must not be in our code!
But now i am here without the solution! I wondered if you can give me pointers to what could have been wrong in my setup/config/IIS/etc..!
Thanks, anyways!
Cheers,
Kinjal.
Comment by narayana on 26 December 2008:
how to upload a file into a disk,
how to count number of lines,pages,paragraphs,etc….properties of storedfile using asp.net code.
Comment by Douglas on 9 January 2009:
I managed to get the control to work on my vista development box but when I move it over to 2003 server with IIS 6 the upload progress bar does not show. The file uploads alright but after testing your sample code on a XP box as well I noticed I get the same behavior but also get the message “Uploads were not processed via the module” Is there a special procedure for hosting this on a IIS 6 server?
Comment by Riaz Afridi on 19 January 2009:
Hi Darren,
Thanks for putting such a nice tool. I managed to run the sample projeect and the control works A1. But when I use the same code in my another ASP.NET application, and upload a file, the bellow code var empty = e.getAttribute(’empty’); always returns [empty = true] and then nothing happend…
may be I am missing some configuration… any help will be highlt appriciated..
Thanks
Comment by umesh on 23 January 2009:
Hi,
I had FileUploadLibrary.dll version 1.0
Progress bar is show in Mozilla and IE very well but in
safari it will not show progress bar.
Please,Any one know where change is required for the safari
Thanks,
umesh
Comment by Paul on 7 February 2009:
Working great!
One question, how could I pass additional information to my custom SQLProcessor. Suppose I have an additional textbox which contains a description of the file, how could I go about this?
Comment by darren on 15 February 2009:
Hi Paul,
You can access the other fields on the page provided they are placed before the upload control- see here http://darrenjohnstone.net/aspnet-file-uploaddownload-module-v2-documentation/ under “Accessing form fields in file processors”.
Cheers