412 000 произведений, 108 200 авторов.

Электронная библиотека книг » Гайдар Магдануров » Asp.net mvc framework » Текст книги (страница 6)
Asp.net mvc framework
  • Текст добавлен: 8 июля 2026, 17:38

Текст книги "Asp.net mvc framework"


Автор книги: Гайдар Магдануров



сообщить о нарушении

Текущая страница: 6 (всего у книги 17 страниц)

    return View () ;

  }

  [AcceptVerbs(HttpVerbs.Post)]

  [Authorize(Roles = "Administrators")]

  public ActionResult Select(Guid? userId)

  {

    if (!userId.HasValue)

      throw new HttpException(404, "Пользователь не найден");

    MembershipProvider mp = Membership.Provider;

    MembershipUser user = mp.GetUser(userId, false);

    ViewData.Model = user;

    return View () ;

  }

  [AcceptVerbs(HttpVerbs.Post)]

  [Authorize(Roles = "Administrators")]

  public ActionResult Update(Guid? userId, string email,

                        bool isApproved, bool isLockedOut)

  {

    if (!userId.HasValue)

      throw new HttpException(404, "Пользователь не найден");

    MembershipProvider mp = Membership.Provider;

    MembershipUser user = mp.GetUser(userId, false);

    user.Email = email; user.IsApproved = isApproved;

    if (user.IsLockedOut && !isLockedOut)

      user.UnlockUser();

    mp.UpdateUser(user);

    return RedirectToAction("Index");

  }

  [AcceptVerbs(HttpVerbs.Get)]

  [Authorize(Roles = "Administrators")]

  public ActionResult Delete(Guid? userId)

  {

    if (!userId.HasValue)

      throw new HttpException(404, "Пользователь не найден");

    MembershipProvider mp = Membership.Provider;

    MembershipUser user = mp.GetUser(userId, false);

    mp.DeleteUser(user.UserName, true);

    return RedirectToAction("Index");

  }

}

Как вы можете заметить, мы избавились от рутинной операции проверки права доступа к действию контроллера путем задания для каждого действия атрибута [Authorize(Roles = «Administrators»)]. Этот атрибут предписывает механизму MVC выполнить проверку права доступа пользователя при попытке вызвать действие нашего контроллера. Важным достоинством данного атрибута является его элегантность и унификация. Вместо того чтобы самим писать такой важный код, как код проверки прав доступа, мы оперируем механизмом метаданных в виде атрибута AuthorizeAttribute, помечая нужные нам участки кода. Так снижается возможность ошибки программиста, которая в случае работы с задачей безопасности может стоить очень дорого. Другим плюсом использования атрибута AuthorizeAttribute является заметное уменьшение кода, особенно в сложных вариантах, когда требуется предоставить доступ набору групп и пользователей.

Атрибут AutorizeAttibute принимает два параметра:

□ Roles – позволяет задавать перечисление ролей, которые имеют доступ к действию, через запятую;

□ Users – позволяет задавать перечисление пользователей, которые имеют доступ к действию, через запятую.

Так, например, следующий фрагмент кода определяет, что доступ к действию могут получить только члены группы Administrators и пользователи SuperUserl и SuperUser2:

[Authorize(Roles = «Administrators», Users = «SuperUserl, SuperUser2»)]

HandleErrorAttibute

Атрибут HandleErrorAttribute предназначен для того, чтобы однообразно сформировать механизм обработки необработанных в контроллерах исключений. Атрибут HandleErrorAttribute применим как к классу контроллера, так и к любому действию. Кроме того, допустимо указывать атрибут несколько раз. По умолчанию, без параметров, механизм MVC с помощью атрибута HandleErrorAttribute при возникновении исключения произведет переадресацию на представление Error, которое должно находиться в папке -/Views/Shared. Однако это действие можно изменить под свои потребности. Для манипулирования порядком действия атрибута HandleErrorAttribute у него есть ряд параметров:

□ ExceptionType – указывает тип исключения, на возникновение которого должен реагировать данный атрибут;

□ View – указывает представление, которое нужно показать пользователю при срабатывании атрибута;

□ Master – указывает наименование Master View, которое будет использоваться при демонстрации пользователю представления;

□ Order – указывает на последовательный номер, в порядке которого атрибут будет исполняться.

Для демонстрации работы атрибута HandleErrorAttribute создадим представление AdminError, которое будет использоваться только тогда, когда произойдет ошибка при работе с контроллером AdminController. В листинге 4.3 представлен код представления.

<%@ Page Title="« Language=»C#"

  MasterPageFile="~/Views/Shared/Site.Master"

  Inherits="System.Web.Mvc.ViewPage" %>

  runat="server">

  Ошибка! Произошло необработанное исключение.

  runat="server">

  <% var model = (HandleErrorlnfo)ViewData.Model; %>

 

Внимание

  <р>При работе сайта произошла исключительная

    ситуация в действии <%= model.ActionName %>

    контроллера <%= model.ControllerName %>.

    Ниже представлена дополнительная информация об исключении:

 

 

<%= model.Exception.Message %>

 

<%= model.Exception.StackTrace %>

Обратите внимание, для получения доступа к расширенной информации об исключении мы используем свойство Model объекта ViewData, предварительно приведя его к типу HandleErrorInfo. Механизм атрибута HandleErrorAttribute создает для представления элемент типа HandleErrorInfo, объект которого содержит следующие данные:

□ ActionName – имя действия, в котором произошло исключение;

□ ControllerName – имя контроллера, в котором произошло исключение;

□ Exception – объект типа Exception, в котором содержится вся информация об исключении, в том числе строка сообщения и трассировка стека.

Для того чтобы проверить наше представление, создадим для тестирования новое действие TestException в контроллере AdminController:

public ActionResult TestException()

{

  throw new Exception("Проверка исключения");

}

Пометим наш контроллер AdminController атрибутом HandleErrorAttribute в следующем виде, как это показано во фрагменте:

[HandleError(View = «AdminError»)]

public class AdminController : Controller

Теперь, чтобы механизм атрибута HandleErrorAttribute заработал, необходимо включить механизм Custom Errors в файле web.config так, как показано во фрагменте:

После запуска приложения и попытки доступа к действию TestException мы получим сообщение об ошибке (рис. 4.8).

Кроме перечисленного, атрибут HandleErrorAttribute имеет ряд важных особенностей:

□ если механизм Custom Errors запрещен, или исключение уже было обработано другим атрибутом, то исполнение атрибута прекращается;

□ если исключение является HTTP-исключением с кодом, отличным от 500, исполнение атрибута прекращается. Другими словами, этот атрибут не обрабатывает HTTP-исключения с любыми кодами ошибок, кроме 500;

□ атрибут устанавливает Response.TrySkipIisCustomErrors = true для того, чтобы попытаться переопределить страницы веб-сервера, настроенные для отображения ошибок;

□ атрибут устанавливает код HTTP-ответа в значение 500, которое сообщает клиенту о возникшей при запросе ошибке.

Использование атрибута HandleErrorAttribte позволяет гибко настраивать реакцию вашего приложения на возникновение исключительных ситуаций.

Вы можете определять для каждого контроллера, действия или типа исключения свои представления вывода информации об ошибке.

ValidateAntiForgeryTokenAttribute

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

Вместе с возможностями защиты от несанкционированного доступа изменяются и способы проникновения и взлома защиты. Одним из таких способов проникнуть через защиту сайта является атака под названием Cross-site Request Forgery Attack (CSRF). Суть этой атаки заключается в следующем:

□ сайт должен иметь авторизацию по cookies, а пользователь, через которого планируется атака, должен иметь возможность автоматической авторизации;

□ на некой специальной странице в Интернете создается элемент формы со скрытыми параметрами и автоматическим отправлением этих данных по адресу сайта, на котором зарегистрирован пользователь;

□ при посещении страницы, подготовленной злоумышленником, пользователь, сам того не предполагая, авторизуется на своем сайте и выполняет некий запрос, который может делать все, что угодно, от простого принудительного "выхода" пользователя из системы до отправки неких данных на сервер в контексте авторизованного пользователя.

Опасность такой атаки очень велика, для того чтобы защититься, существует один простой, но действенный метод. К любой форме на странице добавляется скрытое поле с неким генерируемым значением, это же значение записывается в пользовательское cookie. После отправки запроса значение поля сравнивается на сервере со значением cookie, и если значения не совпадают, считается, что производится нелегальный запрос. Злоумышленник не сможет сгенерировать те же самые коды, и поэтому его попытки провести такого рода атаку будут бесполезными.

Механизм ASP.NET MVC имеет поддержку такого рода защиты в виде атрибута ValidateAntiForgeryTokenAttribute и helper-метода Html.AntiForgeryToken. В нашем примере с контроллером AdminController есть слабое и уязвимое место – это действие Delete, которое выполняется с помощью GET-запросов и может быть использовано злоумышленником для того, чтобы преднамеренно удалять данные о пользователях. Правильно сформированные формы не должны разрешать любые модификации данных по GET-запросам. Иными словами, GET-запросы должны выполнять действия "только для чтения", а все остальные действия должны происходить через POST-запросы. Перепишем наш механизм действия Delete и добавим к нему и действию Update поддержку атрибута ValidateAntiForgeryTokenAttribute, для этого изменим разметку представления так, как показано в следующем фрагменте:

<% using (Html.BeginForm(«Update», «Admin»)) { %>

<%= Html.Hidden("userId", (Guid)user.ProviderUserKey) %>

<%= Html.AntiForgeryToken() %>

  Данные

 

   

    <%=Html.TextBox("email", user.Email)%>

 

 

   

             user.IsApproved)%>подтвержден

   

 

 

   

               user.IsLockeCOut)%>заблокирован

   

 

<% } %>

<% using(Html.BeginForm("Delete", "Admin")) { %>

<%= Html.Hidden("userId", (Guid)user.ProviderUserKey) %>

<%= Html.AntiForgeryToken() %>

<% } %>

Как вы можете заметить, к основной форме мы добавили поле Html.AntiForgeryToken(), а вместо ссылки для удаления создали еще одну форму, которая также защищена полем Html.AntiForgeryToken().

Теперь добавим поддержку защиты в наш контроллер AdminController для действий Update и Delete, как показано во фрагменте:

[AcceptVerbs(HttpVerbs.Post)]

[Authorize(Users = "Admin")]

[ValidateAntiForgeryToken]

public ActionResult Update(Guid? userId,

   string email, bool isApproved, bool isLockedOut)

[AcceptVerbs(HttpVerbs.Post)]

[Authorize(Users = "Admin")]

[ValidateAntiForgeryToken]

public ActionResult Delete(Guid? userId)

Обратите внимание, что мы ограничили доступ к нашему обновленному действию Delete только для POST-запросов. Для защиты от CSRF-атак мы добавили атрибут ValidateAntiForgeryTokenAttribute. Это все, что нам нужно сделать, чтобы защитить данные формы от несанкционированного доступа.

Для более высокого уровня безопасности атрибуту ValidateAntiForgeryTokenAttribute можно передать параметр Salt ("соль"), который представляет собой числовое значение. Параметр Salt – это дополнительный секретный ключ, который используется при формировании итогового проверяемого значения, для повышения уровня защиты.

Для более гибкой настройки helper-метод Html.AntiForgeryToken имеет ряд параметров:

□ salt – задает значение Salt, которое используется в атрибуте ValidateAntiForgeryTokenAttribute;

□ domain – задает значение параметра Domain для объекта HttpCookie, указывающее конкретный домен, с которым ассоциирован cookie;

□ path – задает значение параметра Path для объекта HttpCookie, указывающее виртуальный путь, с которым ассоциирован cookie.

После наших исправлений в контроллере AdminController не осталось действий, которые манипулируют с данными по GET-запросам, а действия с POST-запросами защищены механизмом атрибута ValidateAntiForgeryTokenAttribute.

ValidateInputAttribute

Одной из самых уязвимых частей любого веб-сайта является пользовательский ввод. Представьте ситуацию, когда после ввода пользовательских данных, они сразу же становятся видны другим пользователям. Тогда, если не существует никакой фильтрации таких данных, злоумышленник может ввести вместо данных опасный код на JavaScript, который повредит любому, кто попытается получить доступ к вашему сайту. Для предотвращения ввода таких данных в механизм ASP.NET MVC встроена защита, которая проверяет любой запрос на наличие потенциально опасных значений параметров запроса.

По умолчанию этот механизм включен для всех запросов, и ничего дополнительного делать не нужно. Но существуют случаи, когда все же требуется получить введенные пользователем данные, даже если они могут быть опасными. Например, если вы разрабатываете редактор для записей блога, то вам, возможно, будет необходимо предоставить пользователю возможность вводить HTML-разметку вместе с содержимым записи блога. Если оставить механизм защиты ASP.NET MVC включенным, то любой запрос, параметр которого содержит теги, будет вызывать исключительную ситуацию.

ASP.NET MVC предлагает разработчику гибкий механизм управления проверкой параметров запроса. Для такого управления существует атрибут ValidateInputAttribute. Для демонстрации действия этого атрибута добавим в нашу форму редактирования параметров Select.aspx возможность редактирования поля Comment, которое будет содержать любой текст, в том числе и с HTML-разметкой. Данное поле будет выводиться вместе с отображаемым именем пользователя, играя роль сообщения для пользователя.

Изменим форму ввода, добавив следующий фрагмент кода:

 

  <%=Html.TextArea("comment", user.Comment) %>

Соответственно изменим определение действия Update контроллера AdminController:

[AcceptVerbs(HttpVerbs.Post)]

[Authorize(Users = "Admin")]

[ValidateAntiForgeryToken]

public ActionResult Update(Guid? userId, string email,

      string comment, bool isApproved, bool isLockedOut)

{

  if (!userId.HasValue)

    throw new HttpException(404, "Пользователь не найден");

  MembershipProvider mp = Membership.Provider;

  MembershipUser user = mp.GetUser(userId, false);

  user.Email = email;

  user.Comment = comment;

  user.IsApproved = isApproved;

  if (user.IsLockedOut && !isLockedOut) user.UnlockUser();

  mp.UpdateUser(user);

  return RedirectToAction("Index");

}

Для того чтобы пользователь видел сообщение, модифицируем частичное представление LogOnUserControl.ascx так, как показано в листинге 4.4.

Листинг 4.4. Представление LogOnUserControl.ascx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<%

  if (Request.IsAuthenticated) {

%>

    Welcome <%= Html.Encode(Page.User.Identity.Name) %>!

    [ <%= Html.ActionLink("Log Off", "LogOff", "Account") %> ]

   

<%= Membership.GetUser(Page.User.Identity.Name).Comment %>

  }

  else {

%>

    [ <%= Html.ActionLink("Log On", "LogOn", "Account") %> ]

<%

  }

%>

После запуска попробуем добавить в поле комментария для любого из пользователей значение добрый день! и сохранить изменения. Так как механизм проверки ввода включен по умолчанию, мы получим сообщение об ошибке (рис. 4.9).

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

[AcceptVerbs(HttpVerbs.Post)]

[Authorize(Users = "Admin")]

[ValidateAntiForgeryToken]

[ValidateInput(false)]

public ActionResult Update(Guid? userId, string email,

       string comment, bool isApproved, bool isLockedOut)

Атрибут ValidateInput с параметром false указывает механизму ASP.NET MVC на то, что проверка параметров запроса для данного действия не требуется. После указания этого значения атрибута мы сможем задавать для значения Comment данные с HTML-тегами. Сообщение будет выведено рядом с именем пользователя, как показано на рис. 4.10.

Механизм атрибута ValidateInputAttribute позволяет в ряде случаев предоставить пользователю больший функционал, но использовать его следует с большой осторожностью. Отключая встроенный механизм проверки параметров запроса на опасное содержимое, вы таким образом берете на себя все проверки, связанные с вопросами безопасности. ValidateInputAttribute с параметром false должен использоваться только в тех местах, где он действительно необходим, в общем случае его применение не рекомендуется и его следует избегать.

Атрибуты ActionFilterAttribute и OutputCacheAttribute

Существует еще один способ расширения механизма ASP.NET MVC. Через атрибут ActionFilterAttribute разработчик может задать выполнение кода по нескольким событиям, происходящим при работе механизма MVC. Вот следующие события, на которые можно реагировать с помощью определения атрибута ActionFilterAttribute: перед выполнением действия, после выполнения действия, перед исполнением результата и после исполнения результата.

Атрибут ActionFilterAttribute представляет собой абстрактный класс с четырьмя виртуальными методами: OnActionExecuting, OnActionExecuted, onResultExecuting, onResultExecuted. Реализация атрибута ложится на плечи разработчика. Обработка этих событий может быть полезна, например, для реализации механизма логов с целью вычисления времени исполнения действий. Другим вариантом использования может быть модификация HTTP-заголовков для ответа клиенту. Таким образом работает включенный в состав ASP.NET MVC атрибут OutputCacheAttribute.

OutputCacheAttribute предназначен для управления стандартными HTTP-заголовками, влияющими на кэширование веб-страниц браузером пользователя. Разработчикам классического ASP.NET этот механизм знаком по директиве @ OutputCache для ASPX-страниц и ASCX-компонентов. OutputCacheAttribute может быть определен как для класса контроллера, так и для отдельного действия. Для управления действием у OutputCacheAttribute есть ряд параметров:

□ Duration – значение времени в секундах, на которое производится кэширование;

□ Location – значение перечисления OutputCacheLocation, которое определяет местоположение для кэшированного содержимого: на стороне клиента или сервера. По умолчанию устанавливается значение OutputCacheLocation.Any, это означает, что содержимое может кэшироваться в любом месте;

□ Shared – булево значение, которое определяет, может ли использоваться один экземпляр кэшированного значения для многих страниц. Используется, когда действие возвращает результат в виде не целой страницы, а в виде частичного результата;

□ VaryByCustom – любой текст для управления кэшированием. Если этот текст равен browser, то кэширование будет производиться условно по имени браузера и его версии (major version). Если у VaryByCustom будет указана строка, то вы обязаны переопределить метод GetVaryByCustomString в файле Global.asax для осуществления условного кэширования;

□ varyByHeader – строка с разделенными через точку с запятой значениями HTTP-заголовков, по которым будет производиться условное кэширование;

□ varyByParam – задает условное кэширование, основанное на значениях строки запроса при GET или параметрах при POST;

□ varyByContentEncodings – указывает условие кэширования в зависимости от содержимого директивы HTTP-заголовка Accept-Encoding;

□ CacheProfile – используется для указания профиля кэширования заданного через web.config и секцию caching;

□ NoStore – принимает булево значение. Если значение равно true, то добавляет в директиву HTTP-заголовка Cache-Control параметр no-store;

□ SqlDependency – строковое значение, которое содержит набор пар строк "база данных" и "таблица", от которых зависит кэшируемое содержимое. Позволяет управлять кэшированием на основе изменений определенных таблиц в базе данных.

В качестве примера рассмотрим следующий фрагмент кода, в котором устанавливается кэширование 1800 секунд (30 минут) любого результата контроллера AdminController вне зависимости от параметров запроса:

[OutputCache(Duration = 1800, VaryByParam = ="none")]

public class AdminController : Controller

В другом фрагменте, наоборот, с помощью атрибута OutputCacheAttribute отключается любое кэширование результатов контроллера AdminController:

[OutputCache(Location = OutputCacheLocation.None)]

public class AdminController : Controller

В своей работе атрибут OutputCacheAttribute переопределяет метод OnResultExecuting, который вызывается перед исполнением результата действия, когда результат типа ActionResult преобразуется в ответ на запрос пользователя, например в HTML-страницу. Вы можете создать свои варианты реализации ActionFilterAttribute, реализовав атрибут, переопределяющий ActionFilterAttribute. Для демонстрации подобной реализации создадим атрибут, который реализует сжатие результирующих страниц с помощью GZip-сжатия, которое поддерживается всеми современными браузерами.

В листинге 4.5 представлен код атрибута GZipCompressAttribute, который реализует механизм сжатия результата действия через GZip.

Листинг 4.5

using System;

using System.IO.Compression;

using System.Web.Mvc;

namespace MVCBookProject {

  [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,

    Inherited = true, AllowMultiple = false)]

  public class GZipCompress : ActionFilterAttribute {

    public override void OnActionExecuting(

           ActionExecutingContext filterContext)

    {

      string acceptEncoding = filterContext.HttpContext.Request

          .Headers["Accept-Encoding"];

      if (string.IsNullOrEmpty(acceptEncoding)) return;

      var response = filterContext.HttpContext.Response;

      if (acceptEncoding.ToLower().Contains("gzip"))

      {

        response.AppendHeader("Content-encoding", "gzip");

        response.Filter = new GZipStream(

           response.Filter, CompressionMode.Compress);

      }

    }

  }

}

Обратите внимание, что атрибут GZipCompressAttribute наследует от ActionFilterAttribute и реализует метод OnActionExecuting, в котором С Помощью класса GZipStream производится сжатие. Использование нашего атрибута тривиально, например, применяем его для контроллера AdminController так, как показано во фрагменте кода:

[GZipCompress]

public class AdminController : Controller

Реализация своего варианта ActionFilterAttribute – это очень мощное средство для расширения механизма ASP.NET MVC. Благодаря ему, мы реализовали прозрачное и простое средство для GZip-сжатия ответов для клиента. Другим стандартным средством, которое использует ActionFilterAttribute, является атрибут outputcacheAttribute, который позволяет управлять кэшированием результатов действий контроллера.

Стандартные реализации класса ActionResult


ActionResult – это базовый класс, экземпляр которого возвращает любое действие контроллера в ASP.NET MVC. В MVC существует несколько стандартных реализаций класса ActionResult: ViewResult, JsonResult, FileResult, RedirectResult, RedirectToRouteResult, ContentResult, EmptyResult. Их назначение и тип возвращаемых данных перечислены в табл. 4.1.

Когда действие завершает свое выполнение, оно возвращает результат в виде базового класса ActionResult или его наследников. После этого механизм MVC вызывает у возвращенного результата стандартный метод ExecuteResult, который и формирует результат, получаемый клиентом.

ViewResult

ViewResult – это стандартный и самый используемый на практике результат, наследующий тип ActionResult, который возвращается действиями контроллеров. Назначение ViewResult – это определение представления, которое будет использовано механизмом MVC для представления состояния модели.

У ViewResult и базового класса ViewResultBase, от которого ViewResult унаследован, есть ряд параметров:

□ ViewData – хранилище данных модели, которые используются представлением для отображения результата работы действия;

□ TempData – аналогичное viewData хранилище данных модели, но с существенным отличием, которое позволяет данным храниться после перенаправления запроса на другое действие;

□ viewName – имя представления, которое должно отреагировать на изменение модели контроллером. Иными словами, этот параметр указывает механизму MVC, какое представление нужно использовать для отображения результата работы действия;

□ MasterName – имя master-представления, которое должно быть использовано для отображения результата работы действия;

□ view – экземпляр представления, которое должно быть использовано для отображения результата работы действия. Может быть использовано вместо параметра viewName для определения представления.

Обычно для возвращения результата типа viewResult из действия используется стандартный метод контроллера view, который принимает те же параметры, что и viewResult. Рассмотрим пример вызова метода view:

public ActionResult Select(Guid? userid)

{

  MembershipProvider mp = Membership.Provider;

  MembershipUser user = mp.GetUser(userId, false);

  return view("Select", "Site", user);

}

В приведенном фрагменте действие Select возвращает результат типа viewResult, который формируется стандартным методом контроллера view. В данном случае метод view принимает три параметра: имя представления Select, имя master-представления Site и модель данных user.

JsonResult

JsonResult – это стандартная возможность механизма MVC возвращать результат на запрос пользователя в виде JSON-данных. JSON – это формат данных, название которого расшифровывается как JavaScript Object Notation или объектная нотация JavaScript. Хотя в названии присутствует слово JavaScript, формат данных JSON языконезависимый и может быть использован при разработке на любом языке.

Примечание

JSON является альтернативой другому формату данных – XML, но по сравнению с XML JSON более короткий, поэтому JSON получил распространение при совместном использовании с механизмом Ajax, когда размер передаваемых данных может иметь большое значение.

*********************************

Класс JsonResult содержит несколько свойств, для более гибкой настройки возвращаемого результата:

□ ContentEncoding – устанавливает значение HTTP-параметра ContentEncoding, который определяет кодировку возвращаемого результата;

□ ContentType – устанавливает значение HTTP-параметра ContentType, если не указано, то по умолчанию устанавливается в application/json;

□ Data – любые данные, которые могут быть сериализованы в формат JSON с помощью класса JavaScriptSerializer.

Использовать JsonResult для возвращения результата в виде JSON-данных очень просто, для этого в контроллере существует стандартный метод Json, который принимает все параметры JsonResult и возвращает готовый результат. Рассмотрим пример действия для контроллера AdminController, которое возвращает JSON-данные по запросу с параметром имени пользователя:

public JsonResult SelectUserData(string userName)

{

  if (string.IsNullOrEmpty(userName))

    throw new HttpException(404, "Пользователь не найден");

  MembershipProvider mp = Membership.Provider;

  MembershipUser user = mp.GetUser(userName, false);

  UserData userData = new UserData()

  {

    Comment = user.Comment,

    Email = user.Email,

    IsApproved = user.IsApproved,

    IsLockedOut = user.IsLockedOut

  };

  return Json(userData, null, Encoding.UTF8);

}

В представленном фрагменте кода для передачи набора данных о пользователе в виде JSON-данных используется единственный метод Json, которому передается набор данных. Результатом, который получит пользователь в ответ, например, на такой запрос http://localhost:5434/Admin/SelectUserData?userName=admin будет текст в следующем формате:

{"UserId":null,"Email":"vyunev@live.ru","Comment":"","IsApproved":true, «IsLockedOut»:false,"CurrentMembershipUser":null}


FileResult

Очень часто в ответ на запрос пользователя требуется вернуть не HTML-страницу или данные в формате JSON, а какой-нибудь бинарный файл. FileResult – это механизм, который как раз и позволяет возвратить файл как результат работы действия контроллера.

У FileResult есть два важных свойства, которые требуется указывать при возвращении результата действия:

□ contentType – свойство, которое задается через конструктор класса FileResult и не может быть изменено напрямую. ContentType указывает MIME-тип содержимого передаваемого файла;

□ FileDownloadName – свойство, указывающее на файл, который требуется передать в ответ на запрос.

Рассмотрим использование FileResult на следующем примере. Пусть нам требуется на пользовательский запрос возвращать сопоставленный с пользователем рисунок. Реализуем эту возможность с помощью файловой системы. Для этого создадим в корне проекта папку Admin, в которой будем хранить рисунки пользователей в формате PNG с именем вида: GUID пользователя.рng. Действие GetUserImage контроллера AdminController, которое будет возвращать изображение с помощью FileResult, представлено в следующем фрагменте:

public ActionResult GetUserImage(string userName)

{

  if (string.IsNullOrEmpty(userName))

    throw new HttpException(404, "Пользователь не найден");

  MembershipProvider mp = Membership.Provider;

  MembershipUser user = mp.GetUser(userName, false);

  if (user == null)

    throw new HttpException(404, "Пользователь не найден");

  string userGuidString = ((Guid) user.ProviderUserKey).ToString();

  string fileName = userGuidString + ".png";

  return File(fileName, "image/png");

}

Обратите внимание, что для возвращения результата типа FileResult в примере используется стандартный метод контроллера File, который упрощает возврат результата в виде FileResult. Методу File передается два параметра: путь к возвращаемому файлу и его MIME-тип, который в данном случае для PNG-файла равен image/png.

В MVC Framework существует еще один класс для работы с файлами – класс FileContentResult, который наследует от FileResult и позволяет возвращать данные не на основании пути к файлу, а с помощью существующего потока данных, который может генерироваться в самом действии.

RedirectResult и RedirectToRouteResult

Важным свойством MVC Framework является возможность перенаправлять запрос на другие действия контроллеров либо другие URL-адреса. Для этого в MVC встроены механизмы RedirectResult и RedirectToRouteResult, которые наследуют от ActionResult и являются допустимыми результатами работы любого действия.


    Ваша оценка произведения:

Популярные книги за неделю