25 июля 2011 г.

Использование HttpHandler-a для отображения картинок в ASP.Net MVC

Чем хорош HttpHandler? Да хотя бы тем, что с его помощью мы можем перехватывать запросы к определенным ресурсам приложения, совершать какие-то действия, и отдавать нужный результат.

Причем здесь изображения?
Давайте представим простую ситуацию - у нас есть некое подобие социальной сети на asp.net mvc. На личной странице пользователя отображается его аватар. Само изображение аватара (к слову, загруженное пользователем, хранится где-то далеко, в какой-то папке, имея название равное айдишнику пользователя). В ресурсе страницы тег картинки будет выглядеть как-то так:

<img src="/Uploads/Avatars/5e840171-3150-4014-a652-88945a9f7656.jpg" alt="my avatar" />

Это довольно плохой вариант т.к. не знаю как вы, а я не хотел бы, чтобы пользователь явно видел структуру моего сайта.

В таких ситуациях на помощь приходят httpHandler. С его помощью мы будем перехватывать запросы к картинкам по "спец." ссылке, и возвращать файл-результат для отображения.

Начнем с того, что добавим в Web.config параметр, в котором будет храниться путь к папке с аватарами:

<appSettings>
    <add key="AvatarsPath" value="~/Uploads/Avatars/" />
  </appSettings>

Теперь создадим сам handler. Для этого необходимо добавить в проект новый элемент - Generic Handler (Image.ashx), и написать в нем немного кода:

   1:  public void ProcessRequest(HttpContext context)
   2:  {
   3:      if (string.IsNullOrEmpty(context.Request["id"]))
   4:          return;
   5:   
   6:      context.Response.ContentType = "image/jpeg";
   7:   
   8:      string path = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["AvatarsPath"]) + context.Request["id"] + ".jpg";
   9:   
  10:      if (File.Exists(path))
  11:      {
  12:          context.Response.WriteFile(path);
  13:          context.Response.End();
  14:      }
  15:  }

Здесь мы получаем текущий контекст, изымаем из него параметр id, формируем строку-путь к файлу изображения, и, если такой файл существует, возвращаем его в качестве ответа. Для простого отображения картинки этого будет достаточно. Работа с HttpHandler-ом завершена.

Для отображение картинки в представлении, нам нужно знать ее название. В нашем случае это id пользователя (в виде гуида). Поэтому, сначала нам нужно получить id текущего юзера в контроллере, и передать его в представление:

   1:  [Authorize (Roles = "User")]
   2:  public ActionResult Index()
   3:  {
   4:      if ((Membership.GetUser() != null) && (Membership.GetUser().UserName != null))
   5:      {
   6:          ViewData["PersonId"] = Membership.GetUser().ProviderUserKey;
   7:      }
   8:   
   9:      return View();
  10:  }

Завершающий этап - формирование ссылки на изображение в представлении:

<img src="/image.ashx?id=<%= ViewData["PersonId"] %>" alt="my avatar" />

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

Вот и все.
Какую пользу помимо сокрытия оригинального пути может принести HttpHandler? Для изображений вариантов ооочень много.
Перед отображением картинки, мы можем обработать ее по необходимым требованиям. Например, нам не составит труда сделать ресайз картинки перед ее отображением, изменить цветовую гамму, перевернуть, и много много другого.

В следующем посте мы реализуем HttpHandler для автоматизации скачивания пользователем файла из хранилища сайта. А на этом все.
_____
Исходники