0

I am trying to create a custom filename for files that are uploaded to my application so they can be viewed and downloaded easily. I am having trouble with accessing the data that is supposed to be stored in my model when the controller action for upload is called and was wondering if anyone could try and help me, code for View, Controller and Model are below.

Model

    using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace FinalYearProject.Models
{
    public class UploadModel
    {
        [Required(ErrorMessage = "Course is required")]
        public string Course { get; set; }
        [Required(ErrorMessage = "Title is required")]
        public string Title { get; set; }

        public string Uploader { get; set; }
    }
}

Controller

    using System;
using System.Collections.Generic;
using System.IO;
using Project.Models;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Project.Controllers
{
    public class FileController : Controller
    {

        [Authorize(Roles = "Admin, Lecturer")]
        public ActionResult Index()
        {
            return View(new UploadModel());
        }

        [HttpPost]
        [Authorize(Roles = "Admin, Lecturer")]
        public ActionResult Index([Bind(Include = "Course,Title")] UploadModel testing)
        {


            if (ModelState.IsValid)
            {
                foreach (string upload in Request.Files)
                {

                    if (Request.Files[upload].FileName != "")
                    {
                        string path = AppDomain.CurrentDomain.BaseDirectory + "/App_Data/uploads/";
                        string filename = Path.GetFileName(Request.Files[upload].FileName);
                        //string newfilename = Path.GetFileName((testing.Title + " - " + testing.Course) + "." + "pdf");
                        Request.Files[upload].SaveAs(Path.Combine(path, filename));
                    }
                }
                return RedirectToAction("Index");
            }
            //You can use model.Course and model.Title values now

            return View(testing);
        }


        [Authorize(Roles = "Admin, Lecturer, Student")]
        public ActionResult Downloads()
        {
            var dir = new System.IO.DirectoryInfo(Server.MapPath("~/App_Data/uploads/"));
            System.IO.FileInfo[] fileNames = dir.GetFiles("*.*"); List<string> items = new List<string>();
            foreach (var file in fileNames)
            {
                items.Add(file.Name);
            }
            return View(items);
        }
        public FileResult Download(string FileName)
        {
            var FileVirtualPath = "~/App_Data/uploads/" + FileName;
            return File(FileVirtualPath, "application/force-download", Path.GetFileName(FileVirtualPath));
        }
    }
}

View

@using Project.Models;
@using Project.Controllers

@model UploadModel


@{
    ViewBag.Title = "Upload";
    Layout = "~/Views/Shared/_Layout.cshtml";
    var courses = ForumController.checkCourseList;
}

<link href="~/Content/sweetalert.css" rel="stylesheet" />

<h2>Upload Content</h2>

@section scripts {
    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <script src="~/Content/sweetalert.min.js"></script>
    <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
    <script>
        $(document).ready(function () {
            $('#btnUploadFile').click(function () {
                var data = new FormData();
                var files = $("#fileUpload").get(0).files;

                if (files.length > 0) {
                    data.append("UploadedFile", files[0]);
                }



                var ajaxRequest = $.ajax({
                    type: "POST",
                    url: "File/Index",
                    contentType: false,
                    processData: false,
                    success: function () {
                        swal({
                            type: "success",
                            title: "Uploaded",
                            text: "The file has been uploaded",
                            timer: 2000,
                            showConfirmButton: false
                        });
                    },
                    error: function () {
                        swal({
                            type: "error",
                            title: "Error",
                            text: "Something went wrong, please try again!",
                            timer: 2000,
                            showConfirmButton: false
                        });
                    },
                    data: data
                });
                ajaxRequest.done(function (xhr, textStatus) {

                });

            });
        });
    </script>
    }

@using (Html.BeginForm())
{
    <div class="uploadContainer">
        <table>


            <tr>
                <td>Title :</td>
                <td colspan="2" class="editUploadTitle">
                    @Html.TextBoxFor(m => m.Title, new { @class = "uploadTitleInp" })
                    @Html.ValidationMessageFor(m => m.Title)
                </td>
            </tr>

            <tr>
                <td>Course :</td>
                <td>
                    @{
                        List<SelectListItem> listItems = new List<SelectListItem>();
                        foreach (var course in courses)
                        {
                            listItems.Add(new SelectListItem
                            {
                                Text = course .Courses.Name,
                                Value = course .Courses.Name
                            });
                        }
                    }

                    @Html.DropDownListFor(m => m.Course, listItems, "-- Select Course--")

                    @Html.ValidationMessageFor(m => m.Course)
                </td>
            </tr>

            <tr>
                <td>File :</td>
                <td>
                    <input type="file" name="FileUpload1" id="fileUpload" required />
                </td>
            </tr>

            <tr>
                <td></td>
                <td>
                    <input id="btnUploadFile" type="button" value="Upload File" />
                </td>
            </tr>

        </table>

    </div>
                        }




@Html.ActionLink("View Uploads", "Downloads")

When I try to create a custom file name using : string newfilename = Path.GetFileName((testing.Title + " - " + testing.Course) + "." + "pdf"); The course and the title for the upload that are entered in the view are represented as empty strings, I'm not quite sure why this is and any help would be greatly appreciated.

Plumbus
  • 31
  • 1
  • 1
  • 6
  • are you uploading single file or multiple files ? – Usman Apr 19 '17 at 17:20
  • @Usman single files, one file at a time to App_Data/uploads – Plumbus Apr 19 '17 at 17:23
  • i think your approach will cause problem when multiple files are selected and uploaded because even you try to upload single file it will get other files too and with Chris Pratt's answer is good if you want to upload single file not in table – Usman Apr 19 '17 at 17:54
  • Your making an ajax post but not sending any values for `Title` or `Course` in the request so they are `null`. Just use `var formdata = new FormData($('form').get(0));` to serialize all you form controls - refer [this answer](http://stackoverflow.com/questions/29293637/how-to-append-whole-set-of-model-to-formdata-and-obtain-it-in-mvc/29293681#29293681) for more detail –  Apr 19 '17 at 21:03

2 Answers2

1

Nothing is jumping out at me as an obvious cause for these two properties to be blank. However, there's a number of things wrong with your code here, so perhaps fixing those will fix this issue as well.

  1. You're using Html.BeginForm() with no parameters. In order to have file uploads your form must have enctype="multipart/form-data". That would require:

    @using (Html.BeginForm("Action", "Controller", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
    

    Or, you can simply use a form tag directly:

    <form action="" method="post" enctype="multipart/form-data">
    
  2. The whole point of using a view model is to give the view only what it needs to work with. As such, using Bind in conjunction with a view model makes no sense. Remove your Bind attribute from the action, and if Uploader shouldn't be available to be posted to, remove it from your view model. You're most likely setting this directly on the entity, anyways, via something like User.Identity.Name. If you want it available for display, but don't want people to be able to post to it, you can simply mark the property with [ReadOnly]. However, since you're responsible for creating the eventual entity this would be stored to, you simply would not map this value over.

  3. You're making you're life harder by not utilizing your view model for the actual file uploads. Add a property to your view model like:

    [DataType(DataType.Upload)]
    public HttpPostedFileBase FileUpload { get; set; }
    

    Then, you can work with this property on your model directly without delving into Request.Files.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Thanks for your input! The code I have is currently working fine for uploading the files with their original filenames, but I will take your advice on board! – Plumbus Apr 19 '17 at 16:58
  • Well, that's a neat trick since without the `enctype`, files are not uploaded at all. – Chris Pratt Apr 19 '17 at 16:59
  • ..anyway the files that were being 'uploaded' were appearing in the App_Data/uploads file and I was also able to download them, hence my belief that it was working, but obviously they aren't being uploaded correctly. I will begin a new implementation based on your feedback for the view model and the enctype, thanks for pointing it out. – Plumbus Apr 19 '17 at 17:16
0

you are adding file upload in data but not the values of Title and Course

var data = new FormData();
var files = $("#fileUpload").get(0).files;

if (files.length > 0) {
 data.append("UploadedFile", files[0]);
 }
data.append("Title", $('#Title').val());
data.append("Course", $('#Course').val());

you have to append values of your title and course along with file

Usman
  • 4,615
  • 2
  • 17
  • 33