0

I have a code snippet which uploads an image. On uploading, it temporarily stores the file in a Session. Then on click of "Save", it saves the file in a database.

There's no problem on my machine, but on the server, whenever I try to upload some files, and then click on "Save", it shows me an error "Closed file cannot be accessed". On Googling it, I read here that this was due to large files being uploaded. I wanted to confirm, is the problem that I'm uploading large files?? Or could it be something else? Also, why am I not getting this on my machine and only on the server??

EDIT: By the way, the error showed up when the file size > 80kb

Code on Uploading file:

public ActionResult StoreLogoInSession(HttpPostedFileBase file, int assetID)
        {
            string filename = null;
            if (ValidateOnUpload(file))
            {
                Session.Add("TempLogo", file);
                filename = file.FileName;
                Session.Add("filename", filename);
            }
            return RedirectToAction("Edit", new { id = assetID });
        }

Code on Saving (this is when the error occurs):

public ActionResult SaveLogo(LogoModel m, int assetID)
        {
                HttpPostedFileBase file = (HttpPostedFileBase)Session["TempLogo"];
                var logoModel = new LogoModel();
                var asset = this.GenerateAssetForUploadFile(file, (int)m.Asset.AccountID, m.Asset.TextContents, m.Asset.AssetName);
                this.LogoManagementFacade.SaveLogo(asset);
                logoModel.Asset = asset;
                this.LogoModelList.Add(logoModel);
}
karan k
  • 947
  • 2
  • 21
  • 45
  • 1
    Using Session is bad. Using Session to store uploaded file is an abomination. Please don't. – Darin Dimitrov Jul 26 '12 at 11:11
  • okay, but what about this problem I'm facing now? – karan k Jul 26 '12 at 11:14
  • 1
    The problem you are facing is a design problem. Don't use Session for this task. I mean you are using the wrong tool for the job and now you are asking why it doesn't work. Don't know what to tell you. Good luck with this problem. I can't help. The best advice I could give you is to get rid of this Session ASAP. – Darin Dimitrov Jul 26 '12 at 11:14
  • okay, here's the scenario briefly: There's Save and Cancel button. the user has the option of uploading a file, and then cancelling it (I clear the session on this event). In that case, if I don't use session, should I Save the logo in my database on Upload, and on Cancel, Remove it from the database – karan k Jul 26 '12 at 11:17
  • Well, whether you should be storing uploaded files into the database is very debatable topic. Some people are proponents of storing the file in the database, others on the file system and store only the path to the file in the database. It will really depend. I think that for large files you should go with the file system. But Sessions? NOOOOOO!!!! Just put the following in your web.config `` to ensure that you have completely eradicated sessions from your application. – Darin Dimitrov Jul 26 '12 at 11:19
  • So then save it in the file system and then remove it from there in case of Cancel? – karan k Jul 26 '12 at 11:26
  • okay.But I'm probably going to ask a question about why Sessions are so harmful after reading your comments! – karan k Jul 26 '12 at 11:29
  • 1
    Sessions are harmful because they introduce state into your applications. By default they are stored in-memory making them completely useless in web farm scenarios. They don't scale well. In a web farm scenario you will need to consider an off-proc session provider rendering them completely useless because now you will be doing I/O calls => so why not directly query the corresponding data storage? And if you don't use a web farm and stick with the default in-memory provider, as you know, IIS could recycle your application at any time voiding everything you might have stored in Sessions. – Darin Dimitrov Jul 26 '12 at 11:47

1 Answers1

0

The first thing into fixing this issue is to get rid of the Sessions and temporarily store the uploaded file on the file system or if you are running in a web farm on a shared folder or if the files are not large enough you could even store them in the database.

So let's suppose that currently you are not running in a web farm and you have a single web server and that we could store the uploaded files in a temporary folder (for which of course you will write a scheduled script that could run every night and delete older than X days files to avoid wasting disk space for nothing):

public const string AssetsFolderBase = "~/App_Data";

public ActionResult StoreLogo(HttpPostedFileBase file, int assetID)
{
    string filename = null;
    if (ValidateOnUpload(file))
    {
        var folder = Path.Combine(Server.MapPath(AssetsFolderBase), assetID.ToString());
        if (!Directory.Exists(folder))
        {
            Directory.CreateDirectory(folder);
        }
        folder = Path.Combine(folder, Path.GetFileName(file.FileName));
        file.SaveAs(folder);
    }
    return RedirectToAction("Edit", new { id = assetID });
}

and then when you need to access it:

public ActionResult SaveLogo(LogoModel m, int assetID)
{
    var folder = Path.Combine(Server.MapPath(AssetsFolderBase), assetID.ToString());
    var file = Directory.GetFiles(folder).FirstOrDefault();
    if (file == null)
    {
        // no file with this assetID was uploaded => throw an exception
        // or return 404 or something
        return HttpNotFound();
    }

    // at this stage the file variable is pointing to the uploaded filename
    // => you could process it here ...
}

Now if you want to handle large file uploads you should obviously make sure to adjust the proper settings in your web.config. By default you are limited to 4MB.

Oh and while you are editing your web.config make sure you add the following line to ensure that no other developers make the same mistake as you and accidentaly use the ASP.NET Session:

<sessionState mode="Off" />
Community
  • 1
  • 1
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928