0

I'm having the weirdest problem with file uploads in ASP.NET MVC 3. When I start a new project with the default project template (Internet application) with Razor and add the following to /views/home/index.cshtml

<form action="/Home/Index" method="post" enctype="multipart/form-data">
  <input type="file" name="upfile" />
  <input type="submit" value="post" />
</form>

the upload fails (firebug shows status 'Aborted') whenever I try to upload a file. Some extra info:

  • Windows 7 / 64bit
  • Cassini
  • VS SP1
  • It happens in both Firebug 6.0.2 and IE8

Controller code:

public class HomeController : Controller {
    public ActionResult Index() {
        ViewBag.Message = "Welcome to ASP.NET MVC!";

        return View();
    }

    public ActionResult About() {
        return View();
    }

}

I've been debugging this for a bit and already found out the following:

  • it only happens for files > ~120kb
  • if I add a target Action with attribute [HttpPost] upload succeeds
  • if I debug using fiddler (proxy) upload succeed
  • if I use aspx and add the same code, upload succeeds
  • for aspx/razor, all file are identical, except for (of course) the files in /Views but not /Views/Web.config

Has anyone else experienced this problem, and what is causing it?

update: I know I should use a separate action and mark it with HttpPost, that's not why I'm asking this question. I'm looking for the reason why this doesn't work, not how to solve it.

Freek
  • 1,506
  • 1
  • 11
  • 25
  • "if I add a target Action with attribute [HttpPost] upload succeeds" Possible silly question here but are you trying to post this to an action that is not explicitly marked as HttpPost? And if you are, is there a reason why you don't want to mark it as HttpPost? – Anthony Sep 12 '11 at 19:16
  • so when you do what is recommended (decorating your methods with post/get/etc) it works? go figure? how about posting your controller code? – Adam Tuliper Sep 12 '11 at 19:40
  • That is indeed what I'm trying to do. I could mark it as HttpPost, but I shouldn't have to. I'm just trying to figure out if this behavior is by design (which seems unlikely since the lack of any error reporting), or something else. – Freek Sep 12 '11 at 19:42
  • no you don't 'have to' but yes - you 'should' mark it as httppost. If you are posting back, you should mark with [HttpPost], You should not share the same method for Get/Post. Its not standard and can easily lead to issues. No - you don't 'have' to, but you really really shouldn't. I can't stress this enough. I cannot provide the internal reason why its not working if you want to go the other route of sharing the same method, but IMHO its just an educational question at that point when you deviate from a well known recommended practice. – Adam Tuliper Sep 12 '11 at 19:52

3 Answers3

1

Without seeing your code, I'm assuming you have a method for HttpGet your default /home/index

You need to post this somewhere, and that wouldn't be your same controller method. You should have a separate method with [HttpPost] on it (separate controller methods for post/get/update/delete)

EDIT for clarification: Create a separate method for your post action. You shouldn't be sharing the same method for get/post. Also you are returning a view from your post. This is also generally not recommended because MVC expects a PRG (post redirect get) behavior so you ideally want to redirect back to an action when done. using Post is also supported here (as well as many other postings on the net)

File upload MVC

In your case above it will work ok as its simple with no validations, but if you have validations on the page before a file upload things can easily get goofy if you post back and don't redirect back to an action.

Community
  • 1
  • 1
Adam Tuliper
  • 29,982
  • 4
  • 53
  • 71
  • My Home.Index method indeed does not have any verb filter attribute on it. However, as far as I know, the HttpPost filter is _not_ required for uploading files, or any filter for any action for that matter. – Freek Sep 12 '11 at 19:31
  • If you are posting back in MVC, you should decorate your action method. This is a standard practice. No its not required, but highly recommended as the runtime may not be choosing the proper method. Its possible to incorrectly have a post action go to an action method meant for a GET action which may be possible here - but without you posting any code at all - we're somewhat taking quasi educated guesses at what you are doing – Adam Tuliper Sep 12 '11 at 19:35
  • Not being helpful. I already posted it works when I specify HttpPost on the action. – Freek Sep 12 '11 at 19:36
  • I specified exactly what I did, "When I start a new project with the default project template (Internet application) with Razor and add the following to /views/home/index.cshtml". This should get you to the exact code I'm using – Freek Sep 12 '11 at 19:37
  • ok - my response stands. You have the same method you are posting back to as you are using for your GET method. You shouldn't be doing this regardless of the reason it doesn't work. Create a new method and use HttpPost like its recommended for MVC. If it doesnt work then let us know but as it stands now your code is coded how it 'shouldnt be coded' – Adam Tuliper Sep 12 '11 at 19:39
  • it helps for people to not have to open a default project and they can see everything involved here. People are taking the time to help you, provide as much as you can as most people do. – Adam Tuliper Sep 12 '11 at 19:43
0

A separate action to handle the file upload is strongly recommended:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Index(HttpPostedFileBase upfile)
    {
        // TODO: process the uploaded file here
        if (upfile != null && upfile.ContentLength > 0) 
        {
            var fileName = Path.GetFileName(upfile.FileName);
            var path = Path.Combine(Server.MapPath("~/App_Data"), fileName);
            upfile.SaveAs(path);
        }
        return RedirectToAction("Index");
    }
}

Also make sure you checkout the following blog post.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
0

Have you made sure the MaxRequestStringLength is set correctly in Web.config?

That's usually the problem when I encounter this.

Yngve B-Nilsen
  • 9,606
  • 2
  • 36
  • 50