#c# #file #asp.net-mvc-3
#c# #файл #asp.net-mvc-3
Вопрос:
У меня есть приложение MVC3, которое загружает файл с жесткого диска пользователя и манипулирует им. Одним из требований является то, что расширение файла должно быть .xls (или xlsx).
Я хотел бы проверить имя файла, но я хотел бы знать, какой вариант является наилучшим с точки зрения возможности повторного использования и производительности (и, конечно, наилучших методов кодирования).
У меня есть следующий вид индекса:
@using (Html.BeginForm("Index", "Home", FormMethod.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>
}
Вызывается методом действия контроллера Index:
public ActionResult Index()
{
return View("Index");
}
А пользовательский ответ обрабатывается методом действия с индексом (HttpPost):
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
FileServices lfileServices = new FileServices();
var lfilePath = lfileServices.UploadFile(file, "~/App_Data/uploads");
//Manipulation;
}
Теперь я могу использовать Path.GetExtension(filename)
в FileServices, чтобы получить расширение, а затем выполнить проверку, но это будет выполнено сразу после завершения загрузки.
Я хотел бы сделать это, как только пользователь попытается загрузить файл. Единственное, что пришло мне в голову, это создать модель (или, лучше, ViewModel) и использовать удаленную проверку из DataAnnotations.
Я видел демонстрацию от Скотта Хансельмана в прямом эфире, но, похоже, его это не очень устраивало, потому что приложение компилировалось, но не выполняло проверку.
Есть ли у кого-нибудь хороший подход для выполнения такого рода удаленной проверки или любого другого решения (например, jQuery)?
Спасибо
Франческо
Ответ №1:
Вы могли бы сделать это с помощью 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;
});
});
Конечно, это ни в коем случае не освобождает вас от обязанности выполнять ту же проверку на сервере, потому что, если у клиента не включен javascript, это будет единственный способ. И даже это не было бы надежным на 100%, поскольку ничто не мешает пользователям переименовывать любой мусорный файл в .xls
и загружать его. На сервере можно было бы использовать эвристику, чтобы попытаться угадать фактический тип файла, просмотрев некоторые известные последовательности байтов.
Обновить:
Пример с удаленной проверкой AJAX (из-за спроса в комментариях, я не рекомендую это делать). Вы могли бы использовать отличный плагин jquery.validate, который, кстати, поставляется в комплекте с 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>
и на сервере:
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);
}
Комментарии:
1. @Darin Dimitrov: спасибо за ваш ответ. Что вы думаете о вызове метода action вместо выполнения проверок в jQuery?
2. @Francesco, я не вижу необходимости. Если все, что это действие будет делать, это проверять расширение, это может быть сделано на клиенте. Зачем тратить впустую пропускную способность?
3. @Darin Dimitrov: например, если вы обобщаете случай и хотите повторно использовать функциональность в других приложениях с другими типами файлов.
4. @Francesco, пользовательский плагин jquery кажется хорошим способом повторного использования функциональности между различными приложениями.
5. @Darin Dimitrov: как насчет случая, когда типы файлов, подходящие для приложения, хранятся в базе данных?