|
|
Rank: Advanced Member
Groups: Registered
Joined: 10/27/2005 Posts: 35
|
Hello. We have SlickUpload 6 on Win2003 (and in the future on Win2008R2x64) in a .NET 4 website and this is my first try to get it working. I have an upload profile section configured as:
<slickUpload> <uploadProfiles> <add name="customFileName"> <uploadStreamProvider type="CustomLocation" location="" existingAction="Overwrite" /> <uploadFilter type="Filter" /> </add> </uploadProfiles> </slickUpload>
The httpModule is there:
<httpModules> <add name="SlickUploadModule" type="Krystalware.SlickUpload.Web.SlickUploadModule, Krystalware.SlickUpload" /> </httpModules>
Two questions. First, does uploadFilter work in our setup? I can't get it to use the IUploadFilter class "Filter" that sits in our App_Code folder. Second, is it possible to have something other than SlickUpload.axd process upload files? The two issues may be related.
Thanks!
|
|
|
Rank: Advanced Member
Groups: Registered
Joined: 10/27/2005 Posts: 35
|
More info...
As a test, the filter is set to throw an exception when either ShouldHandleFile or ShouldHandleRequest are called. Neither of them throw this exception even though I successfully access the .axd file like this:
http://[our server IP]/SlickUpload.axd?handlerType=upload&uploadProfile=customFileName
No errors are recorded in the Windows Event log, but I do see the request in the web log for that site.
Thanks.
|
|
|
Rank: Administration

Groups: Administrators
Joined: 7/7/2005 Posts: 1,586 Location: Scottsdale, AZ
|
Are you sure you're using the correct uploadProfile name? When you set an uploadFilter, it will be created and used during an upload. If it can't be created, the upload will error. I've retested upload filters several different ways and everything seems to work.
One thing to note, though -- you won't hit the upload filter at all for a GET request -- uploads are only possible through POSTs, so SlickUpload does a quick exit and doesn't handle GETs to the upload handler at all.
If nothing seems to be working, can you send me your .aspx, filter, and web.config? chrish at krystalware dot com.
As for the handler url, I'm curious to know -- what are you trying to change that to be and why? SlickUpload automatically registers SlickUpload.axd, but you can register other handler URL's if you want. Here's how:
- Add the handler to the system.web <httpHandlers> section (when you upgrade to IIS7, you'll need this in the system.webServer <handlers> section as well:
<httpHandlers> <add path="TestUpload.axd" verb="GET, POST" type="Krystalware.SlickUpload.Web.SlickUploadHandlerFactory, Krystalware.SlickUpload"/> </httpHandlers>
- Enable uploads for that handler:
<location path="TestUpload.axd"> <slickUpload handleRequests="true" /> <system.webServer> <security> <requestFiltering> <requestLimits maxAllowedContentLength="2072576000"/> </requestFiltering> </security> </system.webServer> </location>
- In your SlickUpload control, add the UploadHandlerUrl="~/TestUpload.axd" attribute. This will tell the control to use that new url rather than the default "~/SlickUpload.axd".
|
|
|
Rank: Advanced Member
Groups: Registered
Joined: 10/27/2005 Posts: 35
|
Chris,
I figured out the GET thing on my own; when I actually uploaded a file, the filter worked.
We have a legacy issue with the handler. All the way through v.5 we have had our own extension page (UploadHandler.uplx) to accept all these uploads. A number of programs point specifically to this path, so the idea is to try and keep this path to ease into a v.6 transition.
Our .uplx page is set to be processed by PageBuildProvider:
<buildProviders> <add extension=".uplx" type="System.Web.Compilation.PageBuildProvider"/> </buildProviders>
We have a Page_Load event that's designed to handle upload-complete actions. Since your httpmodule processed the file before Page_Load, this worked fine.
So, new question: a lot of our upload methods are either in-house HTTP uploads (file browse) or other controls we've bought specifically to upload files (ActiveX and Java). What's the safest/most reliable way to upload from an external program on the client (NOT Slickupload's HTML/ASCX pages) and still have SlickUpload process it on the server? It appears at minimum, our destination URLs will have to change to something like this (using our .uplx extension for example):
http://[server]/UploadHandler.uplx?handlerType=upload&uploadProfile=customFileName
Also, is there a native way in SlickUpload to fire-off custom code on the server when a file or files have successfully uploaded?
If there's an easier way or you need more info, I'll answer anything. SlickUpload is great and is the standard for the (literally) millions of files we receive. Thanks.
|
|
|
Rank: Administration

Groups: Administrators
Joined: 7/7/2005 Posts: 1,586 Location: Scottsdale, AZ
|
Ahh, I see. I remember working with you guys to implement this for SlickUpload 5 back in the day.
I'll take a look at this tomorrow and see if I can put together a sample for this.
A couple of questions in the meantime:
- Do you need to support both the SlickUpload client controls as well as your ActiveX/Java controls, or just the ActiveX/Java controls?
- Are you uploading multiple files in one request, or does each request have a single file?
|
|
|
Rank: Advanced Member
Groups: Registered
Joined: 10/27/2005 Posts: 35
|
"Yes" to all of your questions. I would like to replace our (ugly) file browse code with the SlickUpload client code eventually, but we will have to also use the ActiveX/Java controls (probably forever, or until all browsers can drop a folder of images natively). The ActiveX/Java controls can select almost as many files as you want, but each is uploaded as a single POST iteratively. If we use browser-native uploading, we will have to support 1-to-N files potentially in a single post (we limit that to 5 for performance on the client). Basically, imagine I have a simple ASPX page (say, on www.mysite.com) with a file browse and Submit button that posts to a different server (say, uploads.mysite.com). All inputs (the form action, etc.) are hand-coded. What would we have to put in the form action at minimum, and how could we post-process on the upload server after a success? Thanks!
|
|
|
Rank: Administration

Groups: Administrators
Joined: 7/7/2005 Posts: 1,586 Location: Scottsdale, AZ
|
I did a bit of testing, and it looks as if your current .uplx handler should work with a bit of tweaking.
Here's how to set that up:
- If you added an .uplx httpHandler mapping for the SlickUpload handler, remove that. All you need is your existing buildProviders mapping.
- Enable upload handling for the .uplx handler:
<location path="UploadHandler.uplx"> <slickUpload handleRequests="true" /> <system.webServer> <security> <requestFiltering> <requestLimits maxAllowedContentLength="2072576000"/> </requestFiltering> </security> </system.webServer> </location>
- Add the defaultProfile="customFileName" attribute to the uploadProfiles element (or whatever you have named your profile). This will set it as the default, so it is used if you don't specify the upload profile.
- Change your handling code in the UploadHandler.uplx to resemble this:
protected void Page_Load(object sender, EventArgs e) { UploadSession session = SlickUploadContext.CurrentUploadSession; if (session != null && session.UploadedFiles.Count > 0) { foreach (UploadedFile file in session.UploadedFiles) { // TODO: process file } SlickUploadContext.CommitSession(session); } else { // TODO: handle no upload } }
The above configurations should get you back to a url like http://[server]/UploadHandler.uplx, for the ActiveX/Java/raw browser stuff you have currently.
One note: the CommitSession call is required. If you don't commit the session, SlickUpload's stale session pruning will roll it back. SlickUpload 6 introduces the concept of upload sessions, which can be composed of multiple upload requests. Since everything isn't in one request (like it was in previous versions), there's the potential that some requests could succeed, some could fail, and then the client could abandon the session without completing it. To mitigate this, SlickUpload checks for uncompleted sessions that haven't been touched in 30 minutes (or whatever timeframe you configure) and rolls them back, deleting all uploaded files and removing all traces of the session. SlickUpload automatically commits the session when a completion handler is executed (like from the SlickUpload client controls), but in this case that won't happen. Thus, you need to call CommitSession manually.
I'd recommend using the SlickUpload.axd handler (or something mapped to it, as I described in my earlier post) for any pages that use the SlickUpload client controls and not the .uplx handler. You could make the .uplx handler work by having the form with the SlickUpload client controls post to the .uplx handler after, or using an AJAX completion to the .uplx handler, but then the handler would need to return different results depending on whether an browser or a ActiveX/Java component was doing the upload.
Depending on what you're doing in your post processing, another way to add post processing logic is to create a custom UploadStreamProvider and do the processing in the CloseFileStream method (if isComplete=true, the file was successfully uploaded).
|
|
|
Rank: Advanced Member
Groups: Registered
Joined: 10/27/2005 Posts: 35
|
Chris,
I have the basic structure working per your instructions. The .uplx extension works as expected, and CloseFileStream seems like the best way to post process (since two different upload clients will use the same code). Thanks! This seems like the best way to utilize v.6 for us.
But, I have another question. We monitor uploads from the outside using a custom program. It calls the .uplx handler with a specific querystring to fork into code that returns some XML of all the current uploads (regardless of session, etc.). Is something like that possible with v.6? In this case, since the program is internal only, we aren't constrained to use the .uplx handler at all. I guess the easiest way to ask this -- is it possible to get a listing of all current uploads across all sessions WITHOUT using a SQL provider? (I don't know if SQL could handle our volume appropriately, although I haven't tested it)
Thanks.
|
|
|
Rank: Administration

Groups: Administrators
Joined: 7/7/2005 Posts: 1,586 Location: Scottsdale, AZ
|
Great!
You should still be able to use your .uplx handler for the session status XML handler if you want to, since SlickUpload won't handle GET's.
What info are you looking for on the upload sessions? Is this something you had working with SlickUpload5, but isn't supported in SlickUpload6? I've got a couple ideas about how to provide the information, but want to see what you need exactly to figure out which one will work the best.
|
|
|
Rank: Advanced Member
Groups: Registered
Joined: 10/27/2005 Posts: 35
|
Well, I looked back over our current v.5 code and it doesn't look like it "natively" did what we wanted then either. When a new upload began with that code, I set an Application variable of a certain type that contained the upload id and some other information. Then, I looped through the Application collection and called HttpUploadModule.GetUploadStatus([upload id]) to get the status of every current upload across ALL users (sometimes this was in the 40's or higher). As the last step after upload, the Application variable was set to null. In that way, we were able to monitor every upload across all sessions. You could probably infer that we had to limit our web garden setting to one process for this to work properly, but it works rather well.
So, I looked at the SessionStorageProvider and it provides functions like GetRequest and GetRequestsForSession, which take at least a session id (I assume that is a single upload session from one user, with 1-to-N files) as a parameter. But I don't see something like "GetRequests" that takes no parameters and returns them all.
What do you think? Will we need to continue our Application variable method for this to work? Does my description make enough sense for you to know what we're after? It's also possible that I am misinterpreting what "session" means now, so please correct me as needed.
Thanks!
|
|
|
Rank: Administration

Groups: Administrators
Joined: 7/7/2005 Posts: 1,586 Location: Scottsdale, AZ
|
First, a little explanation about Sessions and Requests. In SlickUpload 5, sessions and requests were one and the same. The SlickUpload client components sent an upload as one request, with all of the files were included in that request. In SlickUpload 6, the client components send the upload with individual requests, one per file. The session is the entity that ties everything together.
So, the typical flow for an upload of multiple files from a client will have one session (which is created upon receipt of the first request), multiple requests (each with one file), and then a separate completion request when the upload is done that completes and commits the session so that it isn't automatically rolled back.
If SlickUpload receives some requests but then the client goes dark, after a timeout (defaults to 30 minutes) SlickUpload will assume the client is gone, roll back the session, and delete any files that were uploaded.
This is why I mentioned that you'd need to call SlickUploadContext.CommitSession(SlickUploadContext.CurrentSession) -- since your scenario has only a single request per session and no completion request, you need to complete the session in the scope of that request so it doesn't get rolled back.
All that being said, there are two basic options for how to approach the stats functionality:
- Inherit from InProcSessionStorageProvider and add a method that goes through its lists to pull out the information you need.
- Inherit from whatever session storage provider you want, delegate to it to do most of the work, but override the SaveSession/SaveRequest/RemoveSession methods so you can store your own stats in whatever stats table you want (call the base implementation after you have stored your stats).
Either way should work, it primarily depends on whether you want to use a different session storage provider and/or store stats in your own table.
If you go with option number one, you'd end up with a something like this:
public class StatsInProcSessionStorageProvider : InProcSessionStorageProvider
{
public object GenerateStats()
{
try
{
_sessionsLock.AcquireReaderLock(-1);
_requestsLock.AcquireReaderLock(-1);
foreach (UploadSession session in _uploadSessions.Values)
{
// TODO: save session stats
Dictionary<string, UploadRequest> requests;
if (_uploadRequests.TryGetValue(session.UploadSessionId, out requests))
{
foreach (UploadRequest staleRequest in requests.Values)
{
// TODO: save request stats
}
}
}
// TODO: return stats to be rendered
return new object();
}
finally
{
_requestsLock.ReleaseReaderLock();
_sessionsLock.ReleaseReaderLock();
}
}
}
|
|
|
Rank: Advanced Member
Groups: Registered
Joined: 10/27/2005 Posts: 35
|
Chris,
I finally got back to this project and so far, almost everything is running. There is one small issue I wanted to ask you. Using the UploadHandler.uplx method works fine, but it looks like I still have to send a profile in the querystring (uploadProfile=someprofile) to make SU6 fire-off. I do have a "defaultProfile" attribute defined and would rather that was chosen. Am I doing something incorrectly? Thanks.
|
|
|
Rank: Administration

Groups: Administrators
Joined: 7/7/2005 Posts: 1,586 Location: Scottsdale, AZ
|
Setting defaultProfile in the web.config should make it pick up that profile if you don't specify one. Can you send me your code (to chrish@krystalware.com) so I can take a look and see if I see any issues there?
|
|
|
|
Guest |