Чтение изображения из базы данных и отображение в представлении

#asp.net-mvc #c#-4.0 #gridview #partial-views

#asp.net-mvc #c #-4.0 #просмотр сетки #частичные представления

Вопрос:

Я пытаюсь преобразовать более старый ASP.NET приложение к MVC (я только изучаю MVC). и мне нужно отобразить изображение в виде сетки. Само изображение хранится в таблице SQL Server как изображение типа данных. Ниже приведен код, который использовался ранее. Может кто-нибудь предложить подход с использованием MVC? Я думал о создании частичной страницы, которую я мог бы встроить в стандартное представление, но не уверен, что это правильный дизайн для реализации.

Заранее спасибо!

    `  string sqlText = "SELECT * FROM Images WHERE img_pk = "   id;
        SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString);

        SqlCommand command = new SqlCommand(sqlText, connection);
        connection.Open();
        SqlDataReader dr = command.ExecuteReader();
        if (dr.Read())
        {
            //Response.Write("test");
           Response.BinaryWrite((byte[])dr["img_data"]);
        }
        connection.Close();
    }
  

Затем на него можно ссылаться с помощью этого тега изображения:

 <asp:Image Height="73" Width="80" ID="Image1" ImageAlign="Middle" ImageUrl='<%#"viewimage.aspx?id="   Eval("ImageId") %>' runat="server"/></a></td>
  

Комментарии:

1. Код — это метод действия, элемент управления изображением — тег изображения, а ImageUrl — URL-адрес действия для тега изображения. Вроде того.

Ответ №1:

Первое, что нужно забыть о GridView в ASP.NET Приложение MVC. Элементы управления на стороне сервера, обратные передачи, состояние просмотра, события, … все это понятия, которых больше не существует.

В ASP.NET MVC вы работаете с моделями, контроллерами и представлениями.

Таким образом, вы могли бы написать действие контроллера, которое будет извлекать изображение из базы данных и обслуживать его:

 public class ImagesController: Controller
{
    public ActionResult Index(int id)
    {
        string sqlText = "SELECT img_data FROM Images WHERE img_pk = @id";
        using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString))
        using (var command = conn.CreateCommand())
        {
            conn.Open();
            command.CommandText = sqlText;
            command.Parameters.AddWithValue("@id", id);
            using (var reader = command.ExecuteReader())
            {
                if (!reader.Read())
                {
                    return HttpNotFound();
                }

                var data = GetBytes(reader, reader.GetOrdinal("img_data"));
                return File(data, "image/jpg");
            }
        }
    }

    private byte[] GetBytes(IDataReader reader, int columnIndex)
    {
        const int CHUNK_SIZE = 2 * 1024;
        byte[] buffer = new byte[CHUNK_SIZE];
        long bytesRead;
        long fieldOffset = 0;
        using (var stream = new MemoryStream())
        {
            while ((bytesRead = reader.GetBytes(columnIndex, fieldOffset, buffer, 0, buffer.Length)) > 0)
            {
                byte[] actualRead = new byte[bytesRead];
                Buffer.BlockCopy(buffer, 0, actualRead, 0, (int)bytesRead);
                stream.Write(actualRead, 0, actualRead.Length);
                fieldOffset  = bytesRead;
            }
            return stream.ToArray();
        }
    }
}
  

а затем, по вашему мнению, просто:

 <img src="@Url.Action("Index", "Images", new { id = "123" })" alt="" />
  

Теперь, конечно, все эти действия контроллера хороши и удобны, но вы должны действительно абстрагировать весь доступ к данным в хранилище:

 public interface IImagesRepository
{
    byte[] GetImageData(int id);
}
  

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

 public class ImagesRepositorySql: IImagesRepository
{
    public byte[] GetImageData(int id)
    {
        // you already know what to do here.
        throw new NotImplementedException();
    }
}
  

Наконец, ваш контроллер станет независимым от базы данных. Слои в вашем приложении теперь слабо связаны между собой, что позволит вам повторно использовать и тестировать их изолированно:

 public class ImagesController: Controller
{
    private readonly IImagesRepository _repository; 
    public ImagesController(IImagesRepository repository)
    {
        _repository = repository;
    }

    public ActionResult Index(int id)
    {
        var data = _repository.GetImageData(id);
        return File(data, "image/jpg");
    }
}
  

и последней частью будет настройка вашей любимой платформы DI для внедрения правильной реализации репозитория в контроллер.

Комментарии:

1. 1 за обучение шаблонам IoC и репозитория в ответ на невинный вопрос об отображении изображения: D

2. Спасибо за ответ, Дарин! Я подключил ваш код, и он работал без особых изменений. Теперь мне нужно пройти через это больше, чтобы лучше понять. Мне не нравится просто использовать примеры кода, не зная, как это работает.