0

I'm trying to upload file using ASP .NET MVC 4. I followed exactly these instructions, but when I submit file I always find myself in the wrong Index method (though that renders the form). My code:

Controller:

public class ActivationController : Controller
{
    public ViewResult Index()
    {
        return View(new ActivationIndexViewModel());
    }

    [HttpPost]
    public ActionResult Index(HttpPostedFileBase file)
    {
        // NEVER GET HERE!
        if (file != null && file.ContentLength > 0)
        {
            var fileName = Path.GetFileName(file.FileName);
            var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
            file.SaveAs(path);
        }
        return RedirectToAction("Index");  
    }
}

View:

<form class="form-horizontal" role="form">
<div class="container-fluid">
    <div class="row">
        <div class="form-group">
            <label class="col-sm-2 control-label" for="file">Serial number</label>
            <div class="col-sm-10">
                @using (Html.BeginForm("Index", "Activation", FormMethod.Post, new { enctype = "multipart/form-data" }))
                {
                    <input type="file" name="file" />
                    <input type="submit" value="Load" class="btn btn-primary" />
                    <p class="help-block">Select a file</p>
                }
            </div>
        </div>
    </div>
    <div class="row">
        <div class="form-group">
            <label class="col-sm-2 control-label">Продукт</label>
            <div class="col-sm-10">
                @Html.DropDownListFor(m => m.SelectedProductId,
                    @Model.ActivatableProductsAsSelectList, new { @class = "form-control" })
                <p class="help-block">Select a product</p>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="form-group">
            <label class="col-sm-2 control-label">Options</label>
            <div class="col-sm-10">
                 <div class="table-responsive">
                    <table class="table"/>
                </div>
            </div>
        </div>
    </div>
</div>

RouteConfig:

routes.MapRoute(
           name: "Activation",
           url: "{controller}/{action}",
           defaults: new { controller = "Activation", action = "Index" }
       );

What am I doing wrong?

Community
  • 1
  • 1
Zharro
  • 819
  • 1
  • 11
  • 23
  • there is no problem with your code. I tested it and it is working as expected. Please check some other parts of the code. Or do share related code, there by we can check where file upload is going wrong. – ramiramilu Feb 21 '14 at 11:31
  • I think there might be other parts of your View, which is causing the problem. Please post complete view. – ramiramilu Feb 21 '14 at 11:31
  • @ramiramilu I also use Bootstrap, may it be an issue? – Zharro Feb 21 '14 at 11:32
  • I dont think bootstrap can create any problem. Because I do not see any specific bootstrap code in your attached code. But try to create a sample MVC project and implement this code, it will be working as expected. – ramiramilu Feb 21 '14 at 11:34
  • @ramiramilu added complete view – Zharro Feb 21 '14 at 11:41
  • Remember that at the end of your file upload you're redirecting to `Index` again. So if you debug you will see it first going through the file upload, then doing a redirect and immediately back into your other Index-method. Maybe that's the behavior you're seeing? – Kenneth Feb 21 '14 at 11:43
  • Your form contains a file upload and a select list. In your action you are trying to bind only the file - therefore the action with the correct parameters is not bound/found. – user600314 Feb 21 '14 at 11:46

1 Answers1

1

Ok, I identified the problem. Problem is your nested forms. Submit button will always post your parent form, and your parent form doesn't have a action,method or anything defined. So it is hitting index again and again.

Simple solution is to remove outer form, or replace the outer form with inner form. Other options is to use AJAX forms, but do not nest them.

Have your view like this -

@using (Html.BeginForm("Index", "Activation", FormMethod.Post, new { enctype = "multipart/form-data", id = "Form1" }))
{
    <div class="container-fluid">
        <div class="row">
            <div class="form-group">
                <label class="col-sm-2 control-label" for="file">Serial number</label>
                <div class="col-sm-10">

                    <input type="file" name="file" />
                    <input type="submit" value="Load" class="btn btn-primary" />
                    <p class="help-block">Select a file</p>

                </div>
            </div>
        </div>
        <div class="row">
            <div class="form-group">
                <label class="col-sm-2 control-label">Продукт</label>
                <div class="col-sm-10">
                    @Html.DropDownListFor(m => m.SelectedProductId, new SelectList(Model.ActivatableProductsAsSelectList, "Value", "Text"), "Select", new { @class = "form-control" })
                    <p class="help-block">Select a product</p>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="form-group">
                <label class="col-sm-2 control-label">Options</label>
                <div class="col-sm-10">
                    <div class="table-responsive">
                        <table class="table" />
                    </div>
                </div>
            </div>
        </div>
    </div>
}

Then your controller action is -

    [HttpPost]
    public ActionResult Index(ActivationIndexViewModel model, HttpPostedFileBase file)
    {
        // NEVER GET HERE!
        if (file != null && file.ContentLength > 0)
        {
            var fileName = Path.GetFileName(file.FileName);
            var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
            file.SaveAs(path);
        }
        return RedirectToAction("Index");
    }

Output would be -

enter image description here

ramiramilu
  • 17,044
  • 6
  • 49
  • 66