SAVING UPLOADED FILES
=====================

THE ONE THING TO UNDERSTAND
---------------------------
Uploads land in a TEMPORARY store first (App_Data\UploaderTemp by default) and
are swept after AjaxUploader.TempFileExpiryMinutes (default 60). An upload that
"succeeds" is NOT saved anywhere permanent until YOUR code saves it. If files
seem to vanish after a successful upload, this page is almost certainly why.

WHAT YOU SEE ON DISK, STAGE BY STAGE
------------------------------------
  Stage                          Temp store (App_Data\UploaderTemp)   Your save folder
  -----------------------------  ----------------------------------  -----------------
  1. File selected + uploaded    <guid>.upload + <guid>.meta appear  (unchanged)
  2. Postback happens            (unchanged)                         (unchanged)
  3. FileUploaded runs CopyFile  pair STAYS (swept after 60 min)     saved file appears
     ...or runs MoveFile         pair REMOVED immediately            saved file appears
  4. No postback ever happens    pair swept after 60 minutes         nothing - ever

Stage 4 is the classic report: "upload succeeds but nothing is saved."
See it live: DemoApp > Getting Started > How Saving Works.

THE COMPLETE PATTERN
--------------------
Markup:

    <au:AjaxFileUpload ID="Uploader1" runat="server"
        AutoPostBack="true"
        OnFileUploaded="Uploader1_FileUploaded" />

Code-behind (or <script runat="server">):

    protected void Uploader1_FileUploaded(object sender,
        AjaxUploader.Events.FileUploadedEventArgs e)
    {
        // Never build the destination from the client's file name alone -
        // it is attacker-controlled text. Keep only the extension.
        var savedName = Guid.NewGuid().ToString("N") +
                        System.IO.Path.GetExtension(e.FileName ?? "");

        new AjaxUploader.Services.UploadService()
            .CopyFile(e.FileGuid, "~/uploads/" + savedName);
    }

That is the whole story. See it running: DemoApp > Basic Upload > Single File.

WHEN DOES FileUploaded RUN?
---------------------------
On the next Web Forms POSTBACK - not during the transfer. Three ways to get one:

  1. AutoPostBack="true" on the control (shown above). The page posts back
     automatically when the whole batch finishes. This matches the v4
     (CuteWebUI) behaviour. Use it when the page has no submit flow of its own.
  2. A normal <asp:Button>. The event fires when the user submits - the right
     choice when uploads are part of a larger form.
  3. Your own __doPostBack call from OnClientQueueComplete-style JS.

If the handler never seems to run: no postback is happening. That is the #1
support case for "upload succeeds but nothing is saved".

DESTINATION PATHS
-----------------
CopyFile / MoveFile accept:
  - App-relative:  "~/uploads/file.jpg"   (resolved against the site root)
  - Absolute:      "D:\\data\\uploads\\file.jpg"
  - Bare relative: "uploads/file.jpg"     (also anchored at the site root)

CopyFile keeps the temp copy (swept later); MoveFile removes it immediately.

IF IT STILL DOES NOT SAVE
-------------------------
Copy DemoApp\SaveDiagnostic.aspx into your site root, upload a file, click the
STEP 2 button. It prints, separately: which DLL is loaded (and its build date),
where the temp folder resolves, what the browser posted back, whether the event
fired, and the exact exception if the copy failed. Whichever line is wrong
names your problem.

Common causes, in order:
  0. You are not running the DLL you think you are. Right-click AjaxUploader.dll
     -> Properties -> Details: File version must be 5.2.3.806 or later. A DLL
     reporting 5.0.0.0 is an old build - and in Visual Studio, check the
     REFERENCE path (reference -> Properties -> Path): VS re-copies that file
     into bin on every build, so replacing bin alone gets overwritten.
  1. Old AjaxUploader.dll still loaded  -> replace at the reference path, RECYCLE THE APP POOL
  2. No postback (see above)            -> AutoPostBack or a submit button
  3. App pool identity cannot write     -> grant write on the destination folder
  4. Handler throws                     -> the diagnostic prints the exception

FOLDER UPLOADS: KEEPING THE STRUCTURE
-------------------------------------
Folder drops and directory-picker selections carry each file's relative path
("photos/2026/beach.jpg"). It is sanitized server-side (traversal segments
removed, invalid characters neutralized) and surfaced as e.RelativePath in
FileUploaded - null for plain files. Recreate the tree under a root you choose:

    protected void Uploader1_FileUploaded(object sender, FileUploadedEventArgs e)
    {
        var relative = e.RelativePath ?? Path.GetFileName(e.FileName ?? "file");
        var dest = Path.Combine(Server.MapPath("~/App_Data/uploads"),
                                relative.Replace('/', '\'));
        Directory.CreateDirectory(Path.GetDirectoryName(dest));
        new AjaxUploader.Services.UploadService().CopyFile(e.FileGuid, dest);
    }

See it live: DemoApp > Drag & Drop > Folder Upload (demo 47).
Requires AjaxUploader.dll File version 5.2.3.808 or later.
