Avatar ·

Загрузка файлов в ASP.NET MVC 3: как правильно реализовать?

Всем привет! Я новичок в ASP.NET MVC 3 и пытаюсь реализовать загрузку файлов на сервер. Перечитал кучу статей, но всё равно путаюсь. У меня есть форма в представлении (View), где пользователь должен выбрать файл (например, изображение или документ) и отправить его. Я сделал так: ```csharp // Модель public class UploadModel { public string FileName { get; set; } public HttpPostedFileBase File { get; set; } } // Контроллер [HttpPost] public ActionResult Upload(UploadModel model) { if (model.File != null && model.File.ContentLength > 0) { var fileName = Path.GetFileName(model.File.FileName); var path = Path.Combine(Server.MapPath("~/uploads"), fileName); model.File.SaveAs(path); ViewBag.Message = "Файл загружен!"; } else { ViewBag.Message = "Ошибка: файл не выбран."; } return View(); } ``` И в представлении: ```html @using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) { @Html.TextBoxFor(m => m.FileName) } ``` Проблема в том, что `model.File` всегда приходит `null`, даже если я выбираю файл. Я пробовал разные варианты атрибутов в `BeginForm`, но ничего не помогает. Также не понимаю, как обрабатывать несколько файлов сразу и как проверять расширения/размер. Может, я что-то упускаю в настройках? Буду благодарен за подробное объяснение с рабочим кодом. <<>>

Основная причина: несоответствие имени поля и модели

Ваша главная ошибка — в представлении вы используете name="File", а в модели свойство называется File. Это правильно, но важно: в Html.BeginForm вы забыли указать enctype = "multipart/form-data" в правильном месте. У вас он есть, но давайте проверим весь код.

На самом деле, если model.File приходит null, скорее всего проблема в том, что вы используете @Html.TextBoxFor(m => m.FileName) без enctype на форме, либо форма не отправляется как multipart. Убедитесь, что ваш BeginForm выглядит так:

@using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.TextBoxFor(m => m.FileName)
    <input type="file" name="File" id="File" />
    <input type="submit" value="Загрузить" />
}

Полный рабочий пример

Вот проверенный код для ASP.NET MVC 3:

// Модель
public class UploadViewModel
{
    public string FileName { get; set; }
    public HttpPostedFileBase UploadedFile { get; set; } // Переименуйте, чтобы избежать путаницы
}

// Контроллер
[HttpPost]
public ActionResult Upload(UploadViewModel model)
{
    if (model.UploadedFile != null && model.UploadedFile.ContentLength > 0)
    {
        // Проверка расширения
        var allowedExtensions = new[] { ".jpg", ".png", ".pdf", ".docx" };
        var fileExtension = Path.GetExtension(model.UploadedFile.FileName).ToLower();
        if (!allowedExtensions.Contains(fileExtension))
        {
            ViewBag.Error = "Недопустимый формат файла.";
            return View();
        }

        // Проверка размера (например, не более 5 МБ)
        if (model.UploadedFile.ContentLength > 5 * 1024 * 1024)
        {
            ViewBag.Error = "Файл слишком большой (макс. 5 МБ).";
            return View();
        }

        // Генерация уникального имени, чтобы избежать конфликтов
        var uniqueFileName = Guid.NewGuid().ToString() + fileExtension;
        var savePath = Path.Combine(Server.MapPath("~/uploads"), uniqueFileName);
        model.UploadedFile.SaveAs(savePath);

        ViewBag.Message = $"Файл '{model.UploadedFile.FileName}' успешно загружен как '{uniqueFileName}'.";
    }
    else
    {
        ViewBag.Error = "Файл не выбран или пуст.";
    }
    return View();
}

Как загрузить несколько файлов

Для множественной загрузки используйте IEnumerable<HttpPostedFileBase>:

// В модели
public IEnumerable<HttpPostedFileBase> Files { get; set; }

// В представлении
<input type="file" name="Files" multiple />

// В контроллере
[HttpPost]
public ActionResult UploadMultiple(IEnumerable<HttpPostedFileBase> files)
{
    foreach (var file in files)
    {
        if (file != null && file.ContentLength > 0)
        {
            // обработка каждого файла
        }
    }
}

Важные моменты

  • enctype — обязателен для загрузки файлов. Без него файлы не передаются.
  • Размер файла — по умолчанию в ASP.NET MVC 3 лимит 4 МБ. Чтобы увеличить, добавьте в web.config:
    <system.web>
        <httpRuntime maxRequestLength="10240" /> <!-- 10 МБ -->
    </system.web>
  • Безопасность — всегда проверяйте расширение и размер на сервере, не полагайтесь только на клиентскую проверку.
  • Путь сохранения — используйте Server.MapPath для преобразования виртуального пути в физический.
<<>>

Альтернативный подход: использование Ajax для асинхронной загрузки

Если вы хотите загружать файлы без перезагрузки страницы, можно использовать jQuery и Ajax. Это улучшает пользовательский опыт.

// Представление с формой и скриптом
@using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data", id = "uploadForm" }))
{
    <input type="file" name="File" id="fileInput" />
    <input type="submit" value="Загрузить" />
}

<div id="result"></div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script>
    $('#uploadForm').submit(function (e) {
        e.preventDefault();
        var formData = new FormData(this);
        $.ajax({
            url: '@Url.Action("Upload", "Home")',
            type: 'POST',
            data: formData,
            contentType: false,
            processData: false,
            success: function (data) {
                $('#result').html(data.Message);
            },
            error: function () {
                $('#result').html('Ошибка загрузки.');
            }
        });
    });
</script>

В контроллере оставьте тот же метод Upload, но верните JSON вместо View:

[HttpPost]
public ActionResult Upload(UploadViewModel model)
{
    // ... проверки, как в первом ответе ...
    if (success)
        return Json(new { Message = "Файл загружен." });
    else
        return Json(new { Message = "Ошибка." });
}

Этот подход позволяет показывать сообщения без перезагрузки страницы и легко обрабатывать множественные файлы.