Удаленная проверка расширения файла в ASP.NET MVC3 с помощью C #?

#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: как насчет случая, когда типы файлов, подходящие для приложения, хранятся в базе данных?