۱۳۸۷/۱۱/۲۹

بررسي وجود نام كاربر با استفاده از jQuery Ajax در ASP.Net


شايد بعضي از سايت‌ها را ديده باشيد كه در حين ثبت نام، پس از وارد كردن يك نام كاربري و سپس مشغول شدن به پر كردن فيلد كلمه‌ي عبور، در قسمت نام كاربري شروع به جستجو در مورد آزاد بودن نام كاربري درخواستي مي‌كنند يا نمونه‌اي ديگر، فرم پرداخت الكترونيكي بانك سامان. پس از اينكه شماره قبض را وارد كرديد، بلافاصله بدون ريفرش صفحه به شما پيغام مي‌دهد كه اين شماره معتبر است يا خير. امروز قصد داريم اين قابليت را با استفاده از كتابخانه‌ي Ajax مجموعه jQuery در ASP.Net پياده سازي كنيم (بدون استفاده از ASP.Net Ajax مايكروسافت).
ابتدا سورس كامل را ملاحظه نمائيد:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AjaxTest.aspx.cs" Inherits="testWebForms87.AjaxTest" %>
<!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>jQuery Ajax Text</title>

<script src="jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#<%= TextBox1.ClientID %>").blur(function(event) {
$.ajax({
type: "POST",
url: "AjaxTest.aspx/IsUserAvailable",
data: "{'username': '" + $('#<%= TextBox1.ClientID %>').val() + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
$('#valid').html("<img src='ajaxImages/waiting.gif' alt='لطفا كمي تامل كنيد'>");
var delay = function() {
AjaxSucceeded(msg);
};

setTimeout(delay, 2000); //remove this
},
error: AjaxFailed
});
});
});
function AjaxSucceeded(result) {
if (result.d == true)
$('#msg').html("<img src='ajaxImages/available.gif' alt='نام كاربري درخواستي موجود است'>");
else
$('#msg').html("<img src='ajaxImages/taken.gif' alt='متاسفانه نام كاربري مورد نظر پيشتر دريافت شده‌است'>");
}
function AjaxFailed(result) {
alert(result.status + ' ' + result.statusText);
}
</script>

</head>
<body>
<form id="form1" runat="server">
<div>
user name:
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<span id="msg"></span>
<br />
pass:
<asp:TextBox ID="TextBox2" TextMode="Password" runat="server"></asp:TextBox>
</div>
<!-- preload -->
<div style="display: none">
<img src="ajaxImages/available.gif" alt="available" />
<img src="ajaxImages/taken.gif" alt="taken" />
<img src="ajaxImages/waiting.gif" alt="waiting" />
</div>
</form>
</body>
</html>


using System;
using System.Web.Services;

namespace testWebForms87
{
public partial class AjaxTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}

[WebMethod]
public static bool IsUserAvailable(string username)
{
// اين مورد را با خواندن اطلاعات از ديتابيس مي‌شود تعويض كرد
return username != "test";
}
}
}

توضيحات:
همانطور كه ملاحظه مي‌كنيد صفحه‌ي ASP.Net ما بسيار ساده است و از دو تكست باكس استاندارد تشكيل مي‌شود، به همراه تصاوير مربوط به Ajax كه يك سري تصاوير ساده چرخان معروف منتظر بمانيد ، يافت شد يا موجود نيست مي‌باشند. اين تصاوير در يك div مخفي (display: none) در صفحه قرار گرفته‌اند و در هنگام بارگذاري صفحه، اين‌ها نيز بارگذاري شده و حاضر و آماده خواهند بود. بنابراين هنگام استفاده از آن‌ها، كاربر تاخيري را مشاهده نخواهد كرد. همچنين يك span با id مساوي msg‌ را هم پس از تكست باكس اضافه كرده‌ايم تا تصاوير مربوط به رخدادهاي Ajax را با استفاده از توانايي‌هاي jQuery به آن اضافه كنيم.

اسكريپت Ajax ما با دراختيار گرفتن روال رخداد گردان blur شيء textBox1 شروع مي‌شود. همانطور كه در مقالات پيشين سايت نيز ذكر شد، روش صحيح دريافت ID يك كنترل ASP.Net در كدهاي سمت كلاينت جاوا اسكريپتي، بر اساس خاصيت ClientID آن است كه در اولين سطر كدهاي ما مشخص است (زيرا در ASP.Net نام و ID يك كنترل در هنگام رندر شدن به همراه ID كنترل‌هاي دربرگيرنده آن نيز خواهد بود، بنابراين بهتر است اين مورد را دايناميك كرد).

كار بررسي موجود بودن نام كاربري (يا مثلا يك شماره قبض و امثال آن) توسط WebMethod ايي به نام IsUserAvailable در code behind صفحه انجام مي‌شود كه پياده سازي آن‌را ملاحظه مي‌كنيد. بديهي است در اين مثال ساده، تنها نام كاربري از پيش رزرو شده، كلمه‌ي test است و در يك كد واقعي اين مورد با مقايسه‌ي نام كاربري با اطلاعات موجود در ديتابيس بايد صورت گيرد (و حملات تزريق اس كيوال را هم فراموش نكنيد. براي رهايي از آن‌ها "حتما" بايد از پارامترهاي ADO.Net استفاده كرد و گرنه كد شما مستعد به اين نوع حملات خواهد بود).

سؤال: چرا از web method استفاده شد و همچنين چرا اين متد static است؟
زمانيكه يك متد با كلمه كليدي static‌ مشخص مي‌شود حالت state less پيدا مي‌كند يعني مستقل از وهله‌ي كلاس عمل مي‌كند. در اين حالت نيازي به ارسال ViewState نبوده (بنابراين در كوئري مورد نظر ما بسيار بهينه و سبك عمل مي‌كنند) و همچنين نيازي به ايجاد يك وهله‌اي از كلاس صفحه‌ي ما نيز نخواهد بود. براي توضيحات بيشتر به اين مقاله مراجعه نمائيد. (به صورت خلاصه، دليل اصلي، كارآيي بالا و بهينه بودن اين روش در اين مساله ويژه است و در ASP.Net Ajax مايكروسافت به صورت گسترده‌اي در پشت صحنه مورد استفاده قرار مي‌گيرد)
استفاده از ويژگي WebMethod عملكرد صفحه‌ي ما را شبيه به يك وب سرويس خواهد كرد و امكان دسترسي به آن در متدهاي استاندارد POST به صورت ارسال ديتا به آدرس WebService.asmx/WebMethodName‌ خواهد بود. يك مثال ساده و عملي

بررسي تابع Ajax بكار رفته:
اين تابع هنگام فراخواني رخداد blur تكست‌باكس ما (مطابق كد فوق) فراخواني مي‌شود. ساختار ساده‌اي دارد كه به شرح زير است:
type: "POST"
نحوه‌ي ارسال داده را به متد وب سرويس ما مشخص مي‌كند.

url: "AjaxTest.aspx/IsUserAvailable"
اطلاعات پست شده، به صفحه‌ي AjaxTest.aspx و وب متد IsUserAvailable ارسال خواهد شد

data: "{'username': '" + $('#<%= TextBox1.ClientID %>').val() + "'}",
داده‌اي كه به آرگومان username ما ارسال مي‌شود، همان مقدار تايپ شده در TextBox1 است (كه باز هم دريافت ID آن به صورت دايناميك صورت گرفته تا مشكل زا نشود)

contentType: "application/json; charset=utf-8",
dataType: "json",
در اين دو سطر از نوع داده‌ي json استفاده شده است كه فرمت بسيار سبك و بهينه‌اي براي تبادل اطلاعات در وب به‌شمار مي‌آيد و توسط كتابخانه‌هاي جاوا اسكريپتي به سادگي پردازش شده و تبديل به اشياء مورد نظر خواهند شد. براي مثال اگر خروجي يك وب سرويس در حالت xml به صورت زير باشد:

<xx yy="nn"></xx>
معادل json آن به شرح زير است:
{ "xx": {"yy":"nn"} }
success: function(msg)
Success ، پس از موفقيت آميز بودن عمليات ajax در jQuery فراخواني مي‌شود
error: AjaxFailed
و اگر در اين بين خطايي رخ داده باشد، قسمت error فراخواني مي‌شود.

در اين مثال براي نمايش بهتر عمليات، يك وقفه‌ي 2 ثانيه‌اي توسط setTimeout ايجاد شده و بديهي است در يك مثال واقعي بايد آن‌را حذف نمود.

نكته: با استفاده از افزونه‌ي فايرباگ فايرفاكس، مي‌توان جزئيات اين عمليات را بهتر مشاهده نمود: