(MVC) MVC (2011 год)

Применение jQuery-UI-dialog в ASP.NET

Недавно мне попался проект, в котором заказчик возжелал применения jQuery-UI диалогов аж в трех различных ипостасях. Я решил поделиться с народом своими шаблонами решения этих проблем.

1.Диалог-намордник, запрашивающий логин/пароль.

В рамках технологии ASP.NET есть множество механизмов для решения проблемы всплывающего диалога, который должен закрыть некую страничку от посторонних. Эта задача может быть решена и на уровне IIS (с помощью базовой аутентификации и конструкции DENY в конфиге), это же можно решить на MS AJAX. Наиболее простой вариант - серверное решение с помощью MultiView, Panel и так далее. Но здесь попался большой любитель клиентского функционала - и jQuery так или иначе уже был задействован практически на каждой страничке проекта.

Для создания дополнительного клиенского диалога, запрашивающего логин-пароль, как таковая страничка ASP.NET с тегом Form и классом не нужна. Достаточно простой html-странички. Но в данном случае я сделал ASPX - это не имеет значения, ибо такая страничка-намордник серверного функционала не имеет.

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

Код странички ProtectedPageLogin (требующей логин-пароль для входа на страничку ProtectedPage выглядит совершенно бесхитростно:


   1:  <%@ Page Language="VB" AutoEventWireup="false" CodeFile="ProtectedPageLogin.aspx.vb" %>
   2:   
   3:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   4:   
   5:  <html xmlns="http://www.w3.org/1999/xhtml">
   6:  <head runat="server">
   7:      <title>FlySeason.RU - бронирование чартерного авиабилета</title>
   8:      <link rel="stylesheet" type="text/css" href="css/excite-bike/jquery-ui-1.8.14.custom.css" />
   9:      <script type="text/javascript" language="javascript" src="jquery-1.6.1.min.js"></script>
  10:      <script src="jquery-ui-1.8.14.custom.min.js" type="text/javascript"></script>
  11:      <script type="text/javascript" language="javascript">
  12:   
  13:              $(document).ready(function () {
  14:                  var $dialog1 = $('#login-dialog')
  15:                  .dialog({
  16:                  modal: true,
  17:                  autoOpen: true,
  18:                  resizable: false,
  19:                  draggable: true,
  20:                  buttons: {
  21:                      Ok: function () {
  22:                          $(this).dialog("close");
  23:                          $.ajax({
  24:                              'url': 'ProtectedPage.aspx',
  25:                              'data': { 'l': $('#txLogin')[0].value, 'p': $("#txPass")[0].value },
  26:                              'dataType': 'json',
  27:                              'type': 'POST',
  28:                              'success': window.location.href = 'ProtectedPage.aspx'
  29:                          });
  30:   
  31:                      },
  32:                      Close: function () {
  33:                          $(this).dialog("close");
  34:                          window.location.href = 'Default.aspx';
  35:                      }
  36:                  }
  37:   
  38:              });
  39:              });
  40:   
  41:   
  42:      </script>
  43:  </head>
  44:  <body>
  45:      <form id="form1" runat="server">
  46:   
  47:      <div style="visibility: hidden;">
  48:          <div id="login-dialog">
  49:              <p>
  50:                  <span class="ui-icon ui-icon-circle-check" style="float: left; margin: 0 7px 50px 0;">
  51:                  </span><b>Пожалуйста войдите:</b>
  52:              </p>
  53:              <table cellspacing="2px">
  54:                  <tr>
  55:                      <td>
  56:                          Логин:
  57:                      </td>
  58:                      <td>
  59:                          <asp:TextBox ID="txLogin" runat="server"></asp:TextBox>
  60:                      </td>
  61:                  </tr>
  62:                  <tr>
  63:                      <td>
  64:                          Пароль:
  65:                      </td>
  66:                      <td>
  67:                          <asp:TextBox ID="txPass" runat="server" TextMode="Password"></asp:TextBox>
  68:                      </td>
  69:                  </tr>
  70:              </table>
  71:              <br /><br />
  72:           </div>
  73:      </div>
  74:      </form>
  75:  </body>
  76:  </html>

На защищаемой от посторонних страничке я сделал вот такую проверочку.


   1:  Partial Class ProtectedPage
   2:      Inherits System.Web.UI.Page
   3:   
   4:      Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   5:          If Not IsPostBack Then
   6:              If Request.Form("l") IsNot Nothing And Request.Form("p") IsNot Nothing Then
   7:                  If Request.Form("l").Trim <> "" And Request.Form("p").Trim <> "" Then
   8:                      If CheckUser(Request.Form("l"), Request.Form("p")) Then
   9:                          Session("ProtectedPageLogin") = Request.Form("l")
  10:                          Session("ProtectedPagePass") = Request.Form("p")
  11:                          FormsAuthentication.SetAuthCookie(Request.Form("l"), True)
  12:                      End If
  13:                  Else
  14:                      Response.Redirect("ProtectedPageLogin.aspx")
  15:                  End If
  16:              Else
  17:                  If Request.IsAuthenticated Then
  18:                      CheckUser(Session("ProtectedPageLogin"), Session("ProtectedPagePass"))
  19:                  End If
  20:              End If
  21:          Else
  22:              If Request.IsAuthenticated Then
  23:                  CheckUser(Session("ProtectedPageLogin"), Session("ProtectedPagePass"))
  24:              End If
  25:          End If
  26:      End Sub
  27:   
  28:      Function CheckUser(ByVal Login As String, ByVal Pass As String) As Boolean
  29:          Dim db1 As New FlySeasonDataContext
  30:          Dim User = (From X In db1.ProtectedPage Where X.Login = Login And X.Password = Pass Select X).ToList
  31:          If User.Count > 0 Then
  32:              Return True
  33:          Else
  34:              Response.Redirect("ProtectedPageLogin.aspx")
  35:          End If
  36:      End Function
  37:  End Class

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

2.Всплывающее окно-предупреждение.

Теперь рассмотрим другой вариант всплывающей формы - когда надо одноразово сообщить что-то юзеру - например "Вам пришло новое сообщение", "Вам оформлен заказ номер XXX", "Вы уверены?. Для этого серверный код странички выполняет какую-то свою проверку и выставляет какое-то значение в поле HyddenFields : ZakazNum.Value = ZakazNumber(0).Zakaz_ID. Задача клиентского кода - отследить что значение этого триггера непустое и выдать всплывающую форму:


   1:  <%@ Page Language="VB" AutoEventWireup="false" CodeFile="Ticket.aspx.vb" Inherits="Ticket" EnableEventValidation="false" %>
   2:   
   3:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   4:  <html xmlns="http://www.w3.org/1999/xhtml">
   5:  <head>
   6:      <title>FlySeason.RU - бронирование чартерного авиабилета</title>
   7:      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   8:      <link rel="stylesheet" type="text/css" href="S.css" />
   9:      <link rel="stylesheet" href="css/excite-bike/jquery-ui-1.8.14.custom.css" type="text/css" media="screen" charset="utf-8" />
  10:      <script type="text/javascript" language="javascript" src="jquery-1.6.1.min.js"></script>
  11:      <script src="jquery-ui-1.8.14.custom.min.js" type="text/javascript"></script>
  12:      <script type="text/javascript" language="javascript">
  13:          $(document).ready(function () {
  14:              var $dialog2 = $('#dialog-message-2')
  15:              .dialog({
  16:                  modal: true,
  17:                  autoOpen: false,
  18:                  resizable: false,
  19:                  draggable: true,
  20:                  buttons: {
  21:                      OK: function () {
  22:                          $(this).dialog("close");
  23:                          $("#ZakazNum")[0].value="";
  24:                      }
  25:                  }
  26:              });
  27:   
  28:              if ($("#ZakazNum")[0].value != ""){
  29:                  $("#ZakazN")[0].innerHTML = $("#ZakazNum")[0].value;
  30:                  $dialog2.dialog('open');
  31:              }
  32:          });
  33:    
  34:      </script>
  35:  </head>
  36:  <body style="background-color: #FFFFFF; margin: 0px;">
  37:      <form id="form1" runat="server">
  38:      <asp:HiddenField ID="ZakazNum" ClientIDMode="Static" runat="server" />
  39:  ...
  40:          <div id="dialog-message-2">
  41:              <p style="margin:10px;">
  42:                  <span class="ui-icon ui-icon-circle-check" style="float: left; margin: 0 7px 50px 0;">
  43:                  </span><b>Спасибо, Ваш заказ принят </b>
  44:              </p>
  45:              <p style="margin:10px;">
  46:                  <span class="ui-icon ui-icon-circle-check" style="float: left; margin: 0 7px 50px 0;">
  47:                  </span> Ваш номер заказа: <b><span id="ZakazN"></span></b>
  48:              </p>
  49:              <p style="margin:10px;">
  50:                  Для ускорения обработки подтвердите пожалуйста Ваш заказ по телефону
  51:                  <br />
  52:                  <center><b>8(495)-648-80-88</b></center>
  53:              </p>
  54:          </div>
  55:  ...
  56:      </form>
  57:  </body>
  58:  </html>

Как видите, тут все тоже элментарно - клиентский код увидел взведенный триггер (в строке 38) и выдал форму предупреждения. Потом почистил триггер за собой.

3.Всплывающая jQuery форма при нажатии на кнопку.

И наконец, расмотрим третий (более интересный) вариант. На форме много кнопок (например "заказать этот товар") - при клике на кнопке надо выдать jQuery UI диалог принимающий заказ на товар. Это наиболее интересный вариант - потому что тут уже надо понимать пару моментов:


   1:  Partial Class Ticket
   2:      Inherits System.Web.UI.Page
   3:   
   4:      Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   5:          If Not IsPostBack Then
   6:  ...
   7:          Else
   8:              '__EVENTTARGET = undefined (этот jQuery постбек обрабатывается прямо тут
   9:              '__EVENTTARGET = Ticket ('этот постбек обрабатывается в нормальном конвеере ASP.NET)
  10:              Try
  11:                  If Request.Form("__EVENTTARGET") = "undefined" Then
  12:                      Dim db1 As New FlySeasonDataContext
  13:                      Dim ZakazNumber = (db1.AddZakaz(Request.Form("hName"), Request.Form("hTel"), Request.Form("hMail"), Request.Form("hKol"), Request.Form("hPrice"), Request.Form("hID"), Request.Form("hPromo"))).ToList
  14:                      If ZakazNumber IsNot Nothing Then
  15:                          If ZakazNumber.Count > 0 Then
  16:                              ZakazNum.Value = ZakazNumber(0).Zakaz_ID
  17:                          End If
  18:                      End If
  19:                  End If
  20:              Catch ex As Exception
  21:                  '
  22:              End Try
  23:          End If
  24:      End Sub

3.Сборка jQuery UI.

Jquery UI - весьма тяжеловесная игрушка (на мой взгляд совершенно непригодная для массовых и нагруженных сайтов). Мало того, что нужна сама jQuery - которая является адской и тормозной надстройкой над JavaScript - нужна еще и библиотека jQuery UI.

Для того, чтобы хоть как-то подсластить эту пилюлю - создан конфигуратор jQuery UI, которым вы можете создать для своего сайта не полный, а усеченный вариант jQuery UI. Разница весьма существенная скажем jQuery UI 1.8.16 - только Core - весит всего 4 КБ (и 89 КБ сама jQuery), а все 31 функции jQuery UI 1.8.16 весят 205 КБ!

То есть даже пустая страничка сайта будет весить треть мегабайта! А насколько странички такого сайта будут тормозными! Даже не в плане просто вытаскивания трети мегабайта из web-сервера, а в плане медленного-медленного просчета JavaScript в один поток браузером клиентского кампутера. Собстенно вся идея серверного программирования была придумана чтобы избавится от медленного-медленного просчета JavaScript на каком-нибудь тормозном НетБуке, подключенном по WiFi - где только сама эта библиотека будет вытаскиваться из инета по несколько секунд на каждом постбеке - потом зависание браузера на полминуты - и страничка готова! Помимо того, исполнение кода JavaScript вообще надо специально разрешит браузеру. Поэтому подобный активный функционал следует использовать весьма и весьма осторожно.



Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/jQuery-UI-Dialog/index.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>