简体   繁体   中英

ASP.Net MVC: Image upload does not work

I'm new to ASP.Net (and webdev in general) and I'm trying to implement a site offering CV-like capabilities. One of such things would be to upload and view a CV photo of a person. Using scaffolding and a code sample found at SO: Uploading/Displaying Images in MVC 4 I managed to get as far as coming up with the following code where the problematic part is enclosed with a larger body of space:

<div class="form-horizontal">
<h4>Author</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.PersonID)
<div class="form-group">
    @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
    </div>
</div>
<div class="form-group">
    @Html.LabelFor(model => model.Picture, htmlAttributes: new { @class = "control-label col-md-2" })

    <div class="col-md-10">            
        @using (Html.BeginForm("FileUpload", "CV", FormMethod.Post, new { enctype = "multipart/form-data" }))
         {
             <input type="file" name="file" id="file" style="width: 100%;" />
             <br/>
             <input type="submit" value="Upload" class="submit" />
         }
    </div>

</div>
<div class="form-group">
    @Html.LabelFor(model => model.MobileNum, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.MobileNum, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.MobileNum, "", new { @class = "text-danger" })
    </div>
</div>

<div class="form-group">
    @Html.LabelFor(model => model.Location, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Location, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Location, "", new { @class = "text-danger" })
    </div>
</div>

<div class="form-group">
    @Html.LabelFor(model => model.LinkedIn, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.LinkedIn, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.LinkedIn, "", new { @class = "text-danger" })
    </div>
</div>

which is the relevant part of the view responsible for uploading, while the method in the Controller CV that I want to handle the request goes like this:

    [HttpPost]
    public ActionResult FileUpload(HttpPostedFileBase file)
    {
        if (file != null)
        {
            string pic = System.IO.Path.GetFileName(file.FileName);
            string path = System.IO.Path.Combine(
                                   Server.MapPath("~/Content/Images"), pic);
            // file is uploaded
            file.SaveAs(path);

            // save the image path path to the database or you can send image 
            // directly to database
            // in-case if you want to store byte[] ie. for DB
            using (MemoryStream ms = new MemoryStream())
            {
                file.InputStream.CopyTo(ms);
                byte[] array = ms.GetBuffer();
                //now I only have 1 mock author
                db.Authors.FirstOrDefault().Picture = array;
            }

        }
        // after successfully uploading redirect the user
        return View();
    }

My problem is that the post never hits this method for some reason despite having specified both the Action and the Controller name and VS being capable of connecting the View to the Controller (at least it swipes to the appropriate one on the Go To Controller command). I'm sure it's some rookie mistake, but I just can't seem to find the cause.

The code in your question does not show it, but the fact you have form controls before and after the <form> element suggest you have an outer <form> element and explains why your inner <form> dos not hit the FileUpload() method.

Nested forms are invalid html and not supported. There is no guarantee what the behavior will be in different browsers or versions, but most browsers generate the name/value pairs for the successful form controls of the inner form, but post it to the action attribute of the outer form.

Its not clear why you want to upload the file separately and it would mean that if a user entered data in the other form controls and submitted the inner form, all that would be lost. It would be easier to remove the inner form and just post back the whole model including the file input to one controller method (by adding a HttpPostedFileBase file parameter to that method, or better, using a view model with a HttpPostedFileBase File property). Note that the form will need the enctype = "multipart/form-data" attribute.

If you do want to upload it separately, then one option would be to use ajax to submit the file input to the controller using FormData so at least any data the user has already entered will not be lost. Refer How to append whole set of model to formdata and obtain it in MVC for an example. In your case, you would initialize a new instance of FormData and .append() the value of the file input to it.

As a side note, your @Html.LabelFor(model => model.Picture) does not create a label associated with the file input (you do not have a form control with id="Picture" )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM