Загрузка файлов в БД

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 1.11.2015

Большинство веб-приложений так или иначе используют файлы: аудио, видео, изображения, текстовые и другие типы файлов. В этой статье рассмотрим, как сохранять файлы (на примере файлов изображений) в базе данных.

Но сразу надо сказать, что есть два способа сохранения файлов - в бд и в файловой системе, и хранение файлов в базе данных - не всегда является идеальным способом. Microsoft рекомендует сохранять в базе данных файлы, размер которых не более 1 мб. Все остальное - в файловой системе. Подробное исследование на эту тему: To BLOB or Not To BLOB

Так или иначе у обоих способов есть свои плюсы. Например, при хранении в бд соблюдается целостность данных. В то же время работа с базой данных - это одно из узких мест веб-приложения. И чем больше запросы к бд будут оптимизированы, и чем их будет меньше, тем больше будет производительность. А доступ к файловой системе, как правило, будет происходить быстрее, чем доступ к бд. И если у вас веб-приложение активно работает с большими файлами, как например, социальная сеть вконтакте, то лучше их сохранять в файловой системе, а в базе данных хранить ссылки.

Итак, создадим новый проект приложения ASP.NET MVC и добавим в него следующую модель Picture, которая будет описывать загружаемое изображение:

public class Picture
{
    public int Id { get; set; }
    public string Name { get; set; } // название картинки
    public byte[] Image { get; set; }
}

Для простоты примера тут всего три свойства: id, название изображения и массив байтов файла, который будет храниться в бд. И контекст данных тоже будет выглядеть просто:

public class PictureContext : DbContext
{
    public PictureContext()
        : base("DefaultConnection")
    { }

    public DbSet<Picture> Pictures { get; set; }
}

В данном случае будем использовать строку по умолчанию DefaultConnection, которая уже определена в файле web.config. Для взаимодействия с БД мы будем использовать подход Code First. Но в случае если у наc есть уже бд, то нам нужна соответствующая таблица Pictures с тремя полями, где поле Image будет иметь тип varbinary(max).

Теперь перейдем к контроллеру. В нем определим всего два действия - для добавления картинок и для их просмотра в виде списка:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ImageDbApp.Models;
using System.IO;

namespace ImageDbApp.Controllers
{
    public class HomeController : Controller
    {
        PictureContext db = new PictureContext();

        public ActionResult Index()
        {
            return View(db.Pictures);
        }

        public ActionResult Create()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Create(Picture pic, HttpPostedFileBase uploadImage)
        {
            if (ModelState.IsValid && uploadImage!=null)
            {
                byte[] imageData = null;
				// считываем переданный файл в массив байтов
                using (var binaryReader = new BinaryReader(uploadImage.InputStream))
                {
                    imageData = binaryReader.ReadBytes(uploadImage.ContentLength);
                }
				// установка массива байтов
                pic.Image = imageData;

                db.Pictures.Add(pic);
                db.SaveChanges();

                return RedirectToAction("Index");
            }
            return View(pic);
        }

    }
}

Представление Index для вывода изображений из бд:

@model IEnumerable<ImageDbApp.Models.Picture>

@{
    ViewBag.Title = "Index";
}

<h2>Мои изображения</h2>

<p>
    @Html.ActionLink("Добавить изображение", "Create")
</p>
<table>
    <tr>
        <th>Название</th>
        <th>Картинка</th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.Raw("<img style='width:80px; height:60px;' src=\"data:image/jpeg;base64," 
                                + Convert.ToBase64String(item.Image) + "\" />")
        </td>
    </tr>
}

</table>

Так как свойство item.Image у нас представляет массив байтов, то мы можем переконвертировать его в строку base64 и таким образом вывести в представлении. Если же у нас в бд храняться какие-либо другие файлы, не обязательно файлы изображений, то мы можем просто повесить ссылку на них. Например, <a href="Home/GetFile/@item.Id">Загрузить</a>, где GetFile - это название действия, которое по id будет извлекать файл из бд и возвращать объект FileContentResult.

В итоге это могло бы выглядеть примерно так:

Загрузка файлов в базу данных

И представляение Create для создания объекта данной модели:

@model ImageDbApp.Models.Picture

@{
    ViewBag.Title = "Create";
}

@using (Html.BeginForm("Create", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Добавить изображение</legend>

        <div class="editor-label">Название</div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        <div class="editor-label">Файл изображения</div>
        <div class="editor-field">
           <input type="file" name="uploadImage" />
        </div>

        <p>
            <input type="submit" value="Добавить" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Вернуться к списку", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850