I have an MVC3 application that uploads a file from the users' hard drive and manipulates it. One requirement is that the file extension should be .xls(or xlsx).
I would like to validate the file name but I would like to know what is the best option in terms of reusability and performance (and of course best coding practices).
I have the following Index view:
@using (Html.BeginForm("Index", "Home", Form开发者_运维技巧Method.Post, new { enctype = "multipart/form-data" }))
{
<br />
<p><input type="file" id="file" name="file" size="23"/></p><br />
<p><input type="submit" value="Upload file" /></p>
}
Called by the controller action method Index:
public ActionResult Index()
{
return View("Index");
}
And the user response is handled by the Index action method (HttpPost):
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
FileServices lfileServices = new FileServices();
var lfilePath = lfileServices.UploadFile(file, "~/App_Data/uploads");
//Manipulation;
}
Now I can use the Path.GetExtension(filename)
in the FileServices to get the extension and then perform the check but it will be performed just after the upload completes.
I would like to do it once the user attempts to upload the file. The only thing that came up to my mind is create a Model(or better a ViewModel) and use the remote validation from DataAnnotations.
I saw a demonstration from Scott Hanselman live but it seemed like he was not really confortable with that because the application was compiling but was not performing the check.
Has anybody a good approach in order to perform such kind of remote validation or any other solution (jQuery for instance)?
Thanks
Francesco
You could do this using javascript:
$(function () {
$('form').submit(function () {
var selectedFile = $('#file').val();
var matches = selectedFile.match(/\.(xlsx?)$/i);
if (matches == null) {
alert('please select an Excel file');
return false;
}
return true;
});
});
Of course this doesn't in any case free you from the obligation of performing the same check on the server because if the client has no javascript enabled that will be the only way. And even this wouldn't be 100% reliable as there is nothing preventing users from renaming any garbage file to .xls
and upload it. Heuristics could be used on the server to try to guess the actual file type by looking at some known byte sequences.
UPDATE:
Example with remote AJAX validation (due to demand in the comments, I don't recommend it though). You could use the excellent jquery.validate plugin which by the way comes bundled with ASP.NET MVC 3:
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" id="file" name="file" size="23" data-remote-val-url="@Url.Action("CheckExtension")"/>
<br />
<input type="submit" value="Upload file" />
}
<script type="text/javascript">
$('form').validate({
rules: {
file: {
remote: $('#file').data('remote-val-url')
}
},
messages: {
file: {
remote: 'Please select an Excel file'
}
}
});
</script>
and on the server:
public ActionResult CheckExtension(string file)
{
var extension = Path.GetExtension(file ?? string.Empty);
var validExtensions = new[] { ".xls", ".xlsx" };
var isValid = validExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
return Json(isValid, JsonRequestBehavior.AllowGet);
}
精彩评论