Search code examples
performanceasp.net-mvc-3redirecttoactionhttppostedfilebase

MVC3 - When using HttpPostedFileBase with large files, RedirectToAction is very slow


Okay, I have a situation that seems to make no sense. I have a controller thus:

public ActionResult Index()
{
    return View(_courseService.ListAllCourses());
}


[HttpPost]
public ActionResult CreateNewCourse(CourseVDO course, HttpPostedFileBase CourseDataFile)
{
        return RedirectToAction("Index");       
}

And a View thus:

@using (Html.BeginForm("CreateNewCourse", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.ValidationSummary(false)
    <fieldset>
        <legend>Course</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        <div class="editor-label">           
            Course Data File 
        </div>
        <div class="editor-field">                        
            <input type="file" name="CourseDataFile" id="CourseDataFile" />            
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Visible)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Visible)
            @Html.ValidationMessageFor(model => model.Visible)
        </div>

        <p>
            <input  type="submit" value="Create" />
        </p>
    </fieldset>
}

When I submit a file of around 200KB, it uploads to the server fast enough (it's local after all), but then takes 5 seconds to go from the "return RedirectToAction("Index"); " line back to the breakpoint on the "return View(_courseService.ListAllCourses());" line (not actually executing the ListAllCourses). This means it's entirely down to the internal plumbing. Worse, this delay scales with file size. What on earth is going on, and how can I stop it?

Thanks


Solution

  • I have never used that method before, and this is no direct answer, but maybe its a better solution:

     // used when editing an item
     public void UploadFiles(FormCollection form, NameValueCollection currentFiles, string folder, bool useTicks)
        {
            foreach (string file in Request.Files)
            {
                var hpf = Request.Files[file];
    
                if (hpf.ContentLength == 0)
                {
                    form[file] = currentFiles[file];
                }
                else
                {
                    var filename = useTicks ? hpf.FileName
                        .Replace(" ", "_")
                        .Replace(".", RandomFileName() + ".") : hpf.FileName;
    
                    var myPath = Server.MapPath("~/Content/" + folder);
                    hpf.SaveAs(myPath + "/" + filename);
    
                    form[file] = filename;
                }
            }
    
            if (Request.Files.Count > 0) return;
            foreach (var file in currentFiles.AllKeys)
            {
                form[file] = currentFiles[file];
            }
        }
    
    //used when creating a new item
        public void UploadFiles(FormCollection form, string folder, bool useTicks)
        {
    
            foreach (string file in Request.Files)
            {
                var hpf = Request.Files[file];
    
                if (hpf.ContentLength == 0)
                {
                    form[file] = null;
                }
                else
                {
                    var filename = "";
                    filename = useTicks ?
                        hpf.FileName.Replace(" ", "_").Replace(".", RandomFileName() + ".") :
                        hpf.FileName;
    
                    UploadFileName = filename;
                    var myPath = Server.MapPath("~/Content/" + folder);
                    hpf.SaveAs(myPath + "/" + filename);
    
                    form[file] = UploadFileName;
                }
    
            }
    
        }
    

    I use models so in my model item i use the UIHint("uploadbox")

    here is the code inside views/Shared/EditorTemplates/UploadField.cshtml

    @Html.TextBox("",null,new{type="File"})
    

    here is an example of the usage of the upload feature:

    public ActionResult AddFiles(FormCollection form, SomeModel myModel)
        {
           UploadFiles(form,"products", true);
            myModel.pdfFile = form["pdffile"];
            myModel.thumbnail = form["thumbnail"];
    

    here is the code when editing the item, in case the file was not changed, but others items have

     var existingFile = ctx2.modelname.SingleOrDefault(x => x.Id == id).Filename;
            NameValueCollection myCol = new NameValueCollection();
            myCol.Add("Filename", existingFile);
            UploadFiles(form, myCol, "uploads/custom", true);
    
            myModel.Filename = form["Filename"];
    

    just a thought :-)