ASP MVC FIle Upload HttpPostedFileBase is Null
Asked Answered
I

4

13

In my controller I have, because I wanted to be able to fill out some details about the video and actually upload it, the Video class doesn't need the actual video because it's going to be passed to another web service.

public class VideoUploadModel
    {
        public HttpPostedFileBase vid { get; set; }
        public Video videoModel { get; set; }
    }

    //
    // POST: /Video/Create
    [HttpPost]
    public ActionResult Create(VideoUploadModel VM)
    {
        if (ModelState.IsValid)
        {
            db.Videos.AddObject(VM.videoModel);
            db.SaveChanges();
            return RedirectToAction("Index");  
        }

        ViewBag.UserId = new SelectList(db.DBUsers, "Id", "FName", VM.videoModel.UserId);
        return View(VM);
    }

and in my view I have

@model LifeHighlightsShoeLace.Controllers.VideoController.VideoUploadModel
@{
   ViewBag.Title = "Create";
}

<h2>Create</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
@using (Html.BeginForm("Create", "Video", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.ValidationSummary(true)
<fieldset>
    <legend>Video</legend>

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

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

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

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

    <div class="editor-label">
        @Html.LabelFor(model => model.videoModel.UserId, "User")
    </div>

    <div class="editor-field">
        @Html.DropDownList("UserId", String.Empty)
        @Html.ValidationMessageFor(model => model.videoModel.UserId)
    </div>
    <div class="editor-field">
    <input name="model.vid" type="file" />
    </div>
    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>

}

When I submit the form the videoModel part of VM is filled out but vid the actual file is null. Any ideas?

Ivanna answered 1/6, 2012 at 19:27 Comment(0)
C
19

Update according to OP comment

set the Max file length in the web.config file Change the "?" to a file size that you want to be your max, for example 65536 is 64MB

<configuration>
  <system.web>
    <httpRuntime maxRequestLength="?" /> 
  </system.web>
</configuration>

You can't add the file to the model, it will be in it's own field not part of the model

<input name="videoUpload" type="file" />

Your action is incorrect. It needs to accept the file as it's own parameter (or if multiple use IEnumerable<HttpPostedFileBase> as the parameter type)

[HttpPost]
public ActionResult Create(VideoUploadModel VM, HttpPostedFileBase videoUpload)
{
    if (ModelState.IsValid)
    {
        if(videoUpload != null) { // save the file
            var serverPath = server.MapPath("~/files/" + newName);
            videoUpload.SaveAs(serverPath);
        }

        db.SaveChanges();
        return RedirectToAction("Index");  
    }

    ViewBag.UserId = new SelectList(db.DBUsers, "Id", "FName", VM.videoModel.UserId);
    return View(VM);
}

If you were allowing multiple files to be selected you have to allow for that

[HttpPost]
public ActionResult Create(VideoUploadModel VM, IEnumerable<HttpPostedFileBase> videoUpload)
{
    if (ModelState.IsValid)
    {
        if(videoUpload != null) { // save the file
            foreach(var file in videoUpload) {
                var serverPath = server.MapPath("~/files/" + file.Name);
                file.SaveAs(serverPath);
            }
        }

        db.SaveChanges();
        return RedirectToAction("Index");  
    }

    ViewBag.UserId = new SelectList(db.DBUsers, "Id", "FName", VM.videoModel.UserId);
    return View(VM);
}
Contrapuntist answered 1/6, 2012 at 19:41 Comment(8)
Thanks (and @BuildStarted). Now when I click create IE gives me a "IE cannot display the webpage" error and chrome tells me that the connection to localhost was interrupted. If I don't include a file it posts with no issue.Ivanna
Sounds like you selected a file larger than 4mbContrapuntist
Updated the answer check it outContrapuntist
Thanks, I'm guessing for large file uploads I'd be better off using some sort of ajax/flash/silverlight file uploader?Ivanna
No, it's a browser thing, you'd have to set that no matter what to allow larger files to be acceptedContrapuntist
We had the same problem with large PDF files so had to up the request sizeContrapuntist
Thanks, this is going to be for uploading some video files so I'm sure the request size is going to need to be set very high.Ivanna
Nowadays you can add the file(s) in the model. Input must reference the name of the property, in this case "vid". Even better you can improve it using c#'s expression "nameof". E.g: "<input name='@nameof(Model.vid)' />" so you can mantain homogeneity.Utterance
A
2

The reason it isn't binding is because the model binder only looks at QueryString, Form, and RouteData when binding a complex model such as yours. The way to get around this is to have another parameter in your action method. (change your "name" to just "vid" as well)

[HttpPost]
public ActionResult Create(VideoUploadModel VM, HttpPostedFileBase vid)
{
    //add your vid to the model or whatever you want to do with it :)

    if (ModelState.IsValid)
    {
        db.Videos.AddObject(VM.videoModel);
        db.SaveChanges();
        return RedirectToAction("Index");  
    }

    ViewBag.UserId = new SelectList(db.DBUsers, "Id", "FName", VM.videoModel.UserId);
    return View(VM);
}
Ashlar answered 1/6, 2012 at 19:36 Comment(0)
R
2

Works for me:

public class CreateVeiwModel
    {
        public Speaker Speaker { get; set; }
        public Guid Guid { get; set; }
        public HttpPostedFileBase File { get; set; }
    }

Controller:

[HttpPost]
        public ActionResult Create(CreateVeiwModel model)
        {
            if (ModelState.IsValid)
            try
            {
                Repository.AddSpeaker(model.Speaker);
            ...
        }

View:

@Html.Label("Most Up-to-Date CV")
             <input type="file" name="File"/>

I think solution placed there: Model.File ~ <input name="File"/>

Rois answered 9/7, 2012 at 9:46 Comment(0)
M
0

change

<input name="model.vid" type="file" />

to

@Html.TextBoxFor(model => model.vid, new {type="file"}) 

depending on what else is on your page, and where the view is being rendered, the MVC will generate unique ID's, I think your hard coded ID is not correctly associated with the form fields.

Music answered 1/6, 2012 at 19:31 Comment(1)
Yea I had that before and I just tried it again. VM.vid is still null.Ivanna

© 2022 - 2024 — McMap. All rights reserved.