Reputation: 31
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.
Upvotes: 0
Views: 100
Reputation: 4703
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
Upvotes: 0
Reputation: 239290
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.
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">
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.
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
.
Upvotes: 1