воскресенье, января 17, 2010

CallbackHandlerControl - серверный контрол для выполнения callback-запроса своими руками :)


исходные коды

По мотивам темы Как выполнить callback со стороны клиента на сервер в ASP.NET

Итак, чтобы каждый раз не писать/дублировать код - создаем контрол, обязанностями которого будет выполнение Callback-запроса на сервер и возврат ответа со стороны сервера и возврат его на клиента ...

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

Итак, все сказанное может выглядеть в разметке страницы или вашего user-control следующим образом:



<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CallbackHandlerControl._Default" %>

<%@ Register assembly="CallbackHandlerControl" namespace="CallbackHandlerControl.Controls" tagprefix="cc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>This is a Callback Handle Control Test Page</title>

<script language="javascript" type="text/javascript">
function btnCallServer_clientHandler() {
callServerHandler("argument");
}

function onSuccessfullHandler(result) {
alert(result);
}

function onErrorClientHandler(result) {
}
</script>

</head>
<body>
<form id="form1" runat="server">
<div>

<h1>This is a Callback Handle Control Test Page</h1><br />
<asp:button ID="btnCallServer"
runat="server" text="Script service method invocation"
OnClientClick="btnCallServer_clientHandler();return false;">
</asp:button>

<cc1:CallbackEventHandler ID="callbackHandler" runat="server"
OnClientDataReceived="callbackHandler_ClientDataReceived"
OnSuccessfullClientHandler="onSuccessfullHandler"
OnErrorClientHandler="onErrorClientHandler"
ServerCallFunctionName="callServerHandler"/>

</div>
</form>
</body>
</html>





Обращаем внимание на серверный обработчик серверного события ClientDataReceived - OnClientDataReceived -
данный обработчик будет использован на стороне сервера при получении данных со стороны клиента,
а также для формирования данных, которые будут отправлены на клиента в качестве ответа.



Сам code-behind класс страницы:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CallbackHandlerControl
{
/// <summary>
/// This is a Callback Handle Control Test Page
/// </summary>
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}

#region event handlers
protected void callbackHandler_ClientDataReceived(object sender, CallbackHandlerControl.Controls.ClientDataReceivedEventArgs e)
{
string clientData = e.ClientData;
e.Cancel = false;
e.ServerResponse = DateTime.Now.ToString();
}
#endregion
}
}




Итак, сам текст нашего контрола:


using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CallbackHandlerControl.Controls
{

/// <summary>
/// Кконтрол выполняет callback обращение на серверную сторону со стороны клиента
/// </summary>
[ToolboxData("<{0}:CallbackEventHandler ID=\"callbackHandler\" runat=\"server\"> </{0}:CallbackEventHandler>")]
public partial class CallbackEventHandler : System.Web.UI.WebControls.WebControl, ICallbackEventHandler
{
#region events
/// <summary>
/// Данное событие будет подниматься в случае получения данных со стороны клиента
/// на сервеной стороне в контроле <see cref="WebSite.WebModules.Common.Callbacks.CallbackEventHandler"/>
/// </summary>
[Browsable(true)]
[Category("Callback Handlers")]
[Description("Данное событие будет подниматься в случае получения данных со стороны клиента на сервеной стороне в контроле WebSite.WebModules.Common.Callbacks.CallbackEventHandler")]
public event EventHandler<ClientDataReceivedEventArgs> ClientDataReceived;

/// <summary>
/// Данные, полученные со стороны клиента, а также отправляемые со стороны сервера клиенту
/// </summary>
private ClientDataReceivedEventArgs Arguments = null;
#endregion

#region fields & properties

/// <summary>
/// ViewState ключи
/// </summary>
private string SuccessfullClientHandlerViewStateID
{
get
{
return this.ID + "_SuccessfullClientHandler";
}
}

/// <summary>
/// ViewState ключи
/// </summary>
private string ErrorClientHandlerViewStateID
{
get
{
return this.ID + "_ErrorClientHandler";
}
}

/// <summary>
/// ViewState ключи
/// </summary>
private string ServerCallFunctionNameViewStateID
{
get
{
return this.ID + "_ServerCallFunctionName";
}
}

/// <summary>
/// Имя сценария, который будет вызван в случае успешного обращения на сервер
/// </summary>
[Browsable(true)]
[Category("Callback Handlers")]
[DefaultValue("onSuccessfullClientHandler")]
[Description("Имя сценария, который будет вызван в случае успешного обращения на сервер")]
public string OnSuccessfullClientHandler
{
get
{
if (ViewState[SuccessfullClientHandlerViewStateID] != null)
return (String)ViewState[SuccessfullClientHandlerViewStateID];
else
return "";
}
set
{
ViewState[SuccessfullClientHandlerViewStateID] = value;
}
}

/// <summary>
/// Имя сценария, который будет вызван в случае неудачного обращения на сервер
/// </summary>
[Browsable(true)]
[Category("Callback Handlers")]
[DefaultValue("onErrorClientHandler")]
[Description("Имя сценария, который будет вызван в случае неудачного обращения на сервер")]
public string OnErrorClientHandler
{
get
{
if (ViewState[ErrorClientHandlerViewStateID] != null)
return (String)ViewState[ErrorClientHandlerViewStateID];
else
return "";
}
set
{
ViewState[ErrorClientHandlerViewStateID] = value;
}
}

/// <summary>
/// Имя функции, которая будет использоваться для вызова серверного сценария со стороны клиента, принимает один аргумент ARG в виде строки
/// </summary>
[Browsable(true)]
[Category("Callback Handlers")]
[DefaultValue("serverCall")]
[Description("Имя функции, которая будет использоваться для вызова серверного сценария со стороны клиента, принимает один аргумент ARG в виде строки ")]
public string ServerCallFunctionName
{
get
{
if (ViewState[ServerCallFunctionNameViewStateID] != null)
return (String)ViewState[ServerCallFunctionNameViewStateID];
else
return "";
}
set
{
ViewState[ServerCallFunctionNameViewStateID] = value;
}
}
#endregion

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
string webFormDoCallbackScript = this.Page.ClientScript.GetCallbackEventReference(this, "arg", this.OnSuccessfullClientHandler, null, true);
string serverCallScript = "function " + this.ServerCallFunctionName + "(arg){" + webFormDoCallbackScript + ";\n}\n";

if (!this.Page.ClientScript.IsClientScriptBlockRegistered(this.ServerCallFunctionName))
{
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), this.ServerCallFunctionName, serverCallScript, true);
}
}

protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);

}

#region ICallbackEventHandler Members

public string GetCallbackResult()
{
// прошла обработка данных в Argumets на стороне сервера, отправляем результат на клиента
if (this.Arguments != null)
{
return this.Arguments.ServerResponse;
}
else
return "";
}

public void RaiseCallbackEvent(string eventArgument)
{
this.OnClientArgumentReceived(eventArgument);
}

#endregion

#region event handlers

public virtual void OnClientArgumentReceived(string eventArgument)
{
if (this.ClientDataReceived != null)
{
this.Arguments = new ClientDataReceivedEventArgs
{
ClientData = eventArgument
};

this.ClientDataReceived(this, this.Arguments);
}

}
#endregion

}
}


Обратите внимание на реализацию интерфейса ICallbackEventHandler, смысл которого был описан ранее в статье Как выполнить callback со стороны клиента на сервер в ASP.NET


Обращаем также внимание на код обработчика callbackHandler_ClientDataReceived в коде нашего code-behind класса страницы,
который был декларативно указан в разметке страницы в обработке контрола в строке
OnClientDataReceived="callbackHandler_ClientDataReceived".


protected void callbackHandler_ClientDataReceived(object sender, CallbackHandlerControl.Controls.ClientDataReceivedEventArgs e)
{
string clientData = e.ClientData;
e.Cancel = false;
e.ServerResponse = DateTime.Now.ToString();
}


Именно в нем мы получаем данные со стороны клиента, и подготавлиаем данные, отправляемые на клиента со стороны сервера



Данный обработчик принимает аргумент класса-наследника EventArgs - ClientDataReceivedEventArgs, которое содержит как данные, полученные со стороны клиента, так и данные, которые
будут отправлены клиентской стороне в качестве ответа от сервера. Нужно помнить также о том, что мы всегда можем отправить как со стороны сервера, так и со стороны клиента сложные объекты, использую сериализацию в строку -
потому вполне достаточно ограничиться строковоыми типами данных.





Само событие в коде нашего контрола выглядит следущим образом:

/// <summary>
/// Данное событие будет подниматься в случае получения данных со стороны клиента
/// на сервеной стороне в контроле <see cref="WebSite.WebModules.Common.Callbacks.CallbackEventHandler"/>
/// </summary>
[Browsable(true)]
[Category("Callback Handlers")]
[Description("Данное событие будет подниматься в случае получения данных со стороны клиента на сервеной стороне в контроле WebSite.WebModules.Common.Callbacks.CallbackEventHandler")]
public event EventHandler<ClientDataReceivedEventArgs> ClientDataReceived;




Как видите, обработчик события ClientDataReceived должен принимать аргумент класса ClientDataReceivedEventArgs, код которого представлен ниже:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace CallbackHandlerControl.Controls
{
/// <summary>
/// Параметры события ClientDataReceivedEvent, которое будет подниматься в случае получения данных со стороны клиента
/// на сервеной стороне в контроле <see cref="WebSite.WebModules.Common.Callbacks.CallbackEventHandler"/>
/// </summary>
public class ClientDataReceivedEventArgs : EventArgs
{

/// <summary>
/// Строка, отправленная со стороны клиента на сервер - это может быть как простой аргумент, так и
/// серилиазованное состояние объекта
/// </summary>
public string ClientData = "";

/// <summary>
/// Ответ от сервера, отправляемый на клиента - это может быть сериализованное состояние объекта или просто строка;
/// Логика по обработке данной строки лежит на стороне клиента
/// </summary>
public string ServerResponse = "";

/// <summary>
/// Данный флаг определяет, завершить цепочку выполнения Callback или нет
/// </summary>
public bool Cancel = false;
}
}




Ну и пара скриншотов:

результат выполнения callback по клику на кнопке на странице, разметка которого приведена в начале страницы:






Контрол в режиме редактирования на странице





Удачи в использовании.

ps: возможно, получилось сумбурно, но мне кажется, разобравшись с принципом проведения Callback-запроса третьим описанным способом из статьи Как выполнить callback со стороны клиента на сервер в ASP.NET
код (доступен по ссылке в начале статьи ) и принцип работы самого контрола становится понятным.

среда, января 13, 2010

У меня погиб сегодня кот...не думал что так будет тяжело осознавать, что его я больше не увижу, моего первого кота, того который приходил утром топтаться на мне, который постоянно просился на улицу погулять, который был мудр для своего прожитого года, который меня любил....Дуэша прости меня что не уберег, прости...



и это сообщение - дань твоей памяти

вторник, октября 20, 2009

РодственныЕ сайты

Скажи мне кто твой друг...




ps: и ведь не поспоришь


четверг, июля 30, 2009

Мне стыдно в этом признаться, но с недавних пор я пью безалкогольное пиво :(

понедельник, июня 29, 2009

Народ, скажите мне что ЭТО?

В картинках сорри за качество:







прилагаю также видео:






ps
: увидел в луже на грунтовой дороге по дороге на дачу, в размерах около 5 см, зарываются глубоко в грунт, постоянно плавают брюхом вверх к поверхности...впереди на панцире пара рядом посаженных глаз :) явно хищник :) от хвоста пара усиков, спереди по бокам по паре усиков




pps: сразу предупреждаю, деревня не рядом с припятью :-D



воскресенье, июня 07, 2009

джоли джампинг

Попробовал, хочу еще :))) :










Побегал, хотя наверно все таки походил :), буквально минут 15-20, но масса ощущений, ужасно устают ноги, но как сказали, просто с непривычки, люди, которые не первый раз уже встают на "прыгунки" бегают со скоростью до 30 км в час, заявленная :) максимальная высота прыжка порядка 2х метров...но это пока не для меня :)


а вообще, стал выбор между приобретением велосипеда и jollyjamper девайса, причем цена вопроса у обоих приблизительно одинаковая и выходит за рамки 10 тыс. рублей что за велосипед, что за взрослый комплект jolly jumper


пятница, июня 05, 2009

ЛабрадойЛЕР

Один из фильмов, которые обязательно стоит посмотреть и можно поставить в один ряд с фильмом "В погоне за щастьем" с Вилл Смитом - название фильма конечно не "лабрадойлер" - фильм "Марли и Я"

фильм конкретно меняет мировозрение, однозначно в видиотеку....

ps: как я смог проиграть спор своей девушке о том, как назвал один из героев фильма породу собаки лабрадойлером, а не лабрадойЗЕРом, понятия не имею :)

Само...

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