… отчет формировался долго. Песочные часы и синяя полоска клонили в сон. Вначале он хотел обезьянку, которая лезет по лестнице, потом градусник, но в итоге остался таймер и счетчик. Глупая улыбка и добрый, сочувствующий, взгляд делают чудеса.
В процессе разработки форм для отчетности, пользователь захотел видеть процесс загрузки данных из базы. Он хотел, чтобы после нажатия кнопки включался секундомер, а по мере получения строк, их количество отображалось на форме.Реализовать это надо было в рамках существующего проекта на ASP.NET.
Решая эту задачу, я столкнулся с проблемой выбора способа обмена данными с сервером, так как ему надо было передать данные и получить какой-то ответ, не перегружая страницу. Помимо кардинального метода – переписать всё на MVC, есть и другие способы. Большинство из них было описано в статье Как выполнить callback со стороны клиента на сервер в ASP.NET. Так же можно пользоваться Callback контролами от DevExpress или ему подобных коммерческих продуктах.
В описываемом случае я воспользовался методом, о котором узнал, читая Дино Эспозито. Речь идёт об HTTPHandler. Его преимущество – это минимум кода, который выполняет сервер по сравнению с другими способами, отсюда высокое быстродействие, чего очень не хватает ASP.NET приложениям. На стороне клиента я использовал JQuery и функцию setTimeout.
Код на стороне сервера выглядит так:
Файл TestForm.aspx.cs:
using System; namespace HTTPHandler_Test { public partial class TestForm : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } } }
HTTPHandler для теста — HTTPHandlerTest.ashx.cs :
using System.Web; using System.Web.SessionState; namespace HTTPHandler_Test.HTTPHandler { /// <summary> /// Сводное описание для HTTPHandlerTest /// </summary> public class HTTPHandlerTest : IHttpHandler, IRequiresSessionState { public void ProcessRequest(HttpContext context) { var counter = context.Request.QueryString["counter"]; int iCount; if (int.TryParse(counter, out iCount)) { counter = (++iCount).ToString(); } context.Response.Write(counter); } public bool IsReusable { get { return true; } } } }
На стороне клинета так же надо добавить пару строк:
Файл TestForm.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestForm.aspx.cs" Inherits="HTTPHandler_Test.TestForm" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script src="Script/jquery-1.10.2.min.js"></script> <script src="Script/askHTTPHandler.js"></script> </head> <body> <form id="form1" runat="server"> <div> <label id="lblStatus" style="display:block">Таймер: </label> <label id="lblCounter" style="display:block">Счетчик: </label> <input type="button" id="btnStartStop" value="Старт" onclick="AskHttpHandler()"/> </div> </form> </body> </html>
Файл askHTTPHandler.js:
var start = false; function AskHttpHandler() { var dateStart = new Date(); var counter = 0; start = !start; if (start) { $('#btnStartStop').val("Стоп"); Ask(); } else $('#btnStartStop').val("Старт"); function Ask() { var difInSeconds = Math.floor(((new Date()).getTime() - dateStart.getTime()) / 1000); var hours = Math.floor(difInSeconds / 3600); var minutes = Math.floor((difInSeconds - (hours * 3600)) / 60); var seconds = difInSeconds - (hours * 3600) - (minutes * 60); if (hours < 10) hours = "0" + hours; if (minutes < 10) minutes = "0" + minutes; if (seconds < 10) seconds = "0" + seconds; $('#lblStatus').text("Таймер: " + hours + ":" + minutes + ":" + seconds); var $ajaxQ = $.ajax({ type: "GET", async: false, url: "/HTTPHandler/HTTPHandlerTest.ashx", data: "counter=" + counter, success: onSuccessAsk, error: onErrorAsk }); var noop = function () { }; if ($ajaxQ != null) { $ajaxQ.onreadystatechange = $ajaxQ.abort = noop; $ajaxQ = null; } function onSuccessAsk(result) { counter = parseInt(result); $('#lblCounter').text("Счетчик: " + result); if (start) setTimeout(Ask, 1000); } function onErrorAsk(result) { alert("error " + result.responseText); } }; }
В процессе разработки обнаружилась досадная утечка памяти на стороне клиента. Решил её с помощью кода ниже:
var noop = function () { }; if ($ajaxQ != null) { $ajaxQ.onreadystatechange = $ajaxQ.abort = noop; $ajaxQ = null; }
Предварительно полазив по интернету и наткнувшись на это ссылку: Memory Growing to Heaven
Заключение
В процессе работы с ASP.NET все больше и больше приходиться смешаться в сторону толстого клиента и использовать сервер как источник данных. HTTPHandler неплохо справляется с этой задачей, позволяя сохранить специфический для ASP.NET функционал и обойти его недостатки.
P.S.
Данное решение, помимо информирования пользователя, так же помогло отловить баги связанные с провайдером к БД Oracle. Время от времени, при получении данных от сервера, скорость чтения строк начинала очень быстро падать. Исправить это получилось установкой Min Pool Size и Max Pool Size в значение 23.
ссылка на оригинал статьи http://habrahabr.ru/post/253875/
Добавить комментарий