عنوان:

‫بررسی وجود نام کاربر با استفاده از jQuery Ajax در ASP.Net


نویسنده: وحید نصیری
تاریخ: ۱۳۸۷/۱۱/۲۹ ۱۳:۱۸:۰۱
آدرس: www.dntips.ir

شاید بعضی از سایت‌ها را دیده باشید که در حین ثبت نام، پس از وارد کردن یک نام کاربری و سپس مشغول شدن به پر کردن فیلد کلمه‌ی عبور، در قسمت نام کاربری شروع به جستجو در مورد آزاد بودن نام کاربری درخواستی می‌کنند یا نمونه‌ای دیگر، فرم پرداخت الکترونیکی بانک سامان. پس از اینکه شماره قبض را وارد کردید، بلافاصله بدون ریفرش صفحه به شما پیغام می‌دهد که این شماره معتبر است یا خیر. امروز قصد داریم این قابلیت را با استفاده از کتابخانه‌ی 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 ایجاد شده و بدیهی است در یک مثال واقعی باید آن‌را حذف نمود.

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





نظرات

  • مهمان در ۱۳۸۷/۱۱/۲۹ ۲۲:۳۸:۰۰
    سلام استاد.

    من برام یه سوال پیش اومده ،

    من چند وقته ذهنم درگیر این شده که آیا واقعا vb.net متد های Static رو داره یا نه!

    من سر این با خیلی ها بحث کردم.

    بعضی ها میگن Modual جایگزینش شده ، بعضی ها متد های Shared رو جایگزین می دونن.

    نظر شما چیه؟

    راستی شما روی jQuery Ajax کار میکنید؟
    من خیلی دوست دارم کار کردن باهاش رو.

    دارم یه فریم ورک کوچولو برای Jquery Ajax برای دات نت می سازم.البته پر از ارور :دی
  • وحید نصیری در ۱۳۸۷/۱۱/۳۰ ۰۱:۰۴:۰۰
    سلام
    بله. برنامه reflector معروف که مد نظر هست. اسمبلی برنامه فوق را با آن باز کردم و زبان انتخابی هم VB . حاصل به صورت زیر نمایش داده شد:
    Public Shared Function IsUserAvailable

    یک سری کار سورس باز دیدم در CodePlex در مورد jQuery Ajax که تلاش‌هایی برای ساده‌تر کردنش کردند. بد نیست برای تکمیل کار یک سری هم به آن‌ها هم بزنید. برای ایده گرفتن خوب است.
  • مهمان در ۱۳۸۸/۰۵/۰۱ ۱۰:۲۱:۱۳
    سلام
    اگه بخوایم دو پارامتر ارسال کنیم چی ؟!!
  • وحید نصیری در ۱۳۸۸/۰۵/۰۱ ۱۰:۳۰:۴۶
    محدودیتی ندارد. وب متد را اصلاح کنید تا دو پارامتر مورد نظر را قبول کند. همچنین قسمت data در اسکریپت را که با فرمت json باید ارسال شود را نیز اصلاح کنید. مثلا
    var json = '{"param1":"val1", "param2":"val2", "param3":number3}';
  • مهمان در ۱۳۸۸/۱۰/۰۹ ۱۱:۵۹:۵۷
    با سلام و تشکر
    من مثال فوق را استفاده کردم اما همیشه قسمت error به اجرا در میاد و error status 200 را بر می گرداند اما زمانی که datatype :"json" رااز کد حذف می کنم قسمت success اجرا می شه اما نتیجه درست نیست.
    من از framework 2.0 استفاده می کنم، ممنون می شم راهنمایم کنید.
  • وحید نصیری در ۱۳۸۸/۱۰/۰۹ ۱۴:۲۰:۴۴
    سلام
    در مورد دات نت 2 به آخرین کامنت بنده در این مقاله مراجعه بفرمائید (انتهای صفحه):
    https://www.dntips.ir/2009/07/blog-post_06.html
  • مهمان در ۱۳۸۹/۰۷/۲۰ ۱۲:۳۲:۵۳
    من این برنامه رو تست کردم همیشه قسمت error را اجرا می کند و این پیغام می دهد
    500 Internal Server Error
  • وحید نصیری در ۱۳۸۹/۰۷/۲۰ ۱۳:۱۷:۳۸
    کمکی نمی‌تونم بهتون بکنم و من عموما پیغام‌هایی مانند پیغام شما رو حذف می‌کنم به این دلایل:
    - نه کدی ارائه شده (کل Solution شما نیاز است برای بررسی)
    - نه توضیحات کافی که چه مراحلی رو طی کردید
    - نه توضیحاتی که از چه ابزاری و چه نگارشی از VS.NET دارید استفاده می‌کنید.

    و توقع دارید که من از راه دور کد شما رو در VS.NET ایی که معلوم نیست چه نگارشی است دیباگ کنم، پس از عیب یابی مشخص کنم مشکل چی بوده ...

    این‌ها رو هم نوشتم تا کسانی که پیغام‌هاشون حذف شده بدونند علت این امر چی بوده.
  • وحید نصیری در ۱۳۸۹/۰۷/۲۰ ۱۳:۲۰:۴۱
    یک مورد کلی را اضافه کنم برای دیباگ پیغام 500 Internal Server Error که عرض کردم از راه دور نمی‌شود آن‌را دیباگ کرد:
    افزونه‌ی فایرباگ مربوط به فایرفاکس را نصب کنید. سپس آن‌را روی صفحه جاری خودتون فعال کنید. صفحه رو ریفرش کنید و سپس یکبار مراحل رسیدن به خطا رو طی کنید. در قسمت network مربوط به firebug دقیقا اطلاعات رد و بدل شده و همچنین خطای نهایی که سیستم برگردونده لاگ می‌شود. این را بررسی کنید تا مشکل را بشود حل کرد.
  • مهمان در ۱۳۸۹/۱۱/۱۱ ۲۱:۴۱:۴۳
    سلام آقای نصیری.
    من عین کد شما را در Page تست کردم و صحیح کار کرد اما در User Control پیام Forbidden را بر می گرداند. آیا علت خاصی دارد؟
  • وحید نصیری در ۱۳۸۹/۱۱/۱۱ ۲۳:۲۸:۳۶
    بله. در یوزر کنترل‌ها این مورد ساپورت نمی‌شود. در تمام حالات روش صحیح و قابل نگهداری و قابل استفاده در قسمت‌‌های مختلف برنامه، استفاده از یک WCF Service است (یا یک درجه پایین‌تر یک وب سرویس معمولی asmx با سرعت کمتر از WCF سرویس).
    • ایمان اسلامی در ۱۳۹۱/۰۴/۲۱ ۱۴:۲۶
      با سلام و خسته نباشید خدمت استاد نصیری
      من برنامه ام رو با code first  و الگوی UnitOfWork که شما مطرح کردید نوشتم که واقعاٌ عالی و لذت بخش هست.
      مشکلی که هست اینه که اگه بخوام از این امکان jqueryAjax در برنامه خودم استفاده کنم می‌بایست userServiice تعریف شده رو در یک متد استاتیک(با توجه به مطلب بالا) استفاده کنم که اینکار انجام نمیشه.ممنون میشم کمکم کنید. 
      • وحید نصیری در ۱۳۹۱/۰۴/۲۱ ۱۶:۴
        - در MVC این مشکلات وجود ندارد و سازگاری کاملی با jQuery در آن درنظر گرفته شده. در آنجا لازم نیست چیزی رو استاتیک تعریف کنید. همچنین چون صفحات دارای ViewState هم نیستند، به سادگی می‌شود قسمتی از آن‌را با jQuery Ajax کلا تعویض کرد بدون اینکه پیغام خراب بودن ViewState را در post back به سرور، دریافت کنید. در آنجا مفهومی به نام PartialView تعریف شده که به صورت خودکار یک View را به شکل رشته برای شما رندر می‌کند و در اختیار jQuery Ajax قرار می‌دهد.
        - در اینجا اگر نمی‌تونید از وهله سازی خودکار توسط DI Container استفاده کنید، می‌شود آن‌را دستی هم انجام داد. اصطلاحا به آن Service locator گفته می‌شود. نمونه آن‌را در استفاده از ObjectFactory.GetInstance در قسمت 12 دیده‌اید (استفاده از الگوی واحد کار و کلاس‌های سرویس تهیه شده در یک برنامه کنسول ویندوزی ).

        • ایمان اسلامی در ۱۳۹۱/۰۴/۲۱ ۱۶:۳۰
          من فراموش کردم که اشاره کنم من از asp.net web form استفاده میکنم.
          راه حل برای asp.net web form  چیست؟
          • وحید نصیری در ۱۳۹۱/۰۴/۲۱ ۱۶:۳۳
            همان توضیحات بند دوم نظر قبلی بنده (الگوی service locator مخصوص به فناوری خاصی نیست و در صورت لزوم در همه جا می‌توان از آن استفاده کرد. یک ضد الگو است. تا حد امکان نباید از آن استفاده کرد؛ اما اگر امکان استفاده صحیح از تزریق وابستگی‌ها نبود، این روش هم کار می‌کنه).
             
            • ایمان اسلامی در ۱۳۹۱/۰۴/۲۱ ۱۶:۵۶
              مهندس فقط میتونم بگم " یه دونه ای! "
              واقعاٌ ممنون


              کار کرد.البته در تمامی page‌ها از base Page ارث بری میکنیم.این استفاده از Object Factory با توجه به استفاده از Object Factory در سازنده کلاس base page ، مشکلی ایجاد نمیکند؟ 
              • وحید نصیری در ۱۳۹۱/۰۴/۲۱ ۱۷:۱۱
                خیر. در پشت صحنه این کتابخانه، Object Factory به صورت خودکار عمل می‌کند. اگر امکان استفاده خودکار از آن نبود، روشی دستی آن (ObjectFactory.GetInstance) همان عملیات را انجام می‌دهد.
  • مهدی غفاری در ۱۳۹۱/۰۷/۰۸ ۱۵:۴۶
    من یک پوشه ایجاد کردم و صفحه AjaxTest.aspx رو تو اون قرار دادم
    بعد برای اینکه کسی نتونه با وارد کردن آدرس اون به صفحه دسترسی داشته باشه، توی اون پوشه یه web.config ایجاد کردم و تگ زیر رو به اون اضاف کردم
     <deny users="*"/> 
    چون میخواستم هیچ کس نتونه اون صفحه رو ببینه. ولی خوب کدهای نوشته شده توسط من باید بتونن به اون صفحه دسترسی داشته باشن (فقط برنامه)
    لطفا بفرمائید این رو چطور ادیت کنم تا این کار ممکن بشه؟
    ممنونم از شما
    • وحید نصیری در ۱۳۹۱/۰۷/۰۸ ۱۶:۳۱
      jQuery یا کلا JavaScript یعنی کدهای سمت کاربر. بنابراین این کدها باید دسترسی رسیدن به مدخل سمت سرور را داشته باشند و اگر عموم از آن منع شده باشند، یک اسکریپت معمولی هم بدیهی است که دسترسی خاصی نخواهد داشت چون سمت سرور اجرا نمی‌شود. فقط نتیجه عملیات آن به سمت سرور Post می‌شود.
      یکی از کارهای متداول سمت سرور جهت منع عموم و فقط دسترسی دادن به jQuery مورد زیر است:
      «بررسی امنیتی، حین استفاده از jQuery Ajax»

      • مهدی غفاری در ۱۳۹۱/۰۷/۰۸ ۲۲:۴۶
        ممنونم از توجه شما؛
        آیا نمیشه از هندلرها استفاده کرد تو همچین مواقعی؟
        • وحید نصیری در ۱۳۹۱/۰۷/۰۸ ۲۲:۵۲
          بله امکان پذیر است. مثل این مثال اسلایدشو می‌تونید JSON بازگشت دهید.