اشتراکها
نظرات مطالب
آپلود همزمان چندین فایل در Asp.Net Web Forms
ابتدا تگ input خود را در فرم قرار دهید :
و در پشت فرم میتوانید با استفاده از یک حلقه ، همه فایلهای انتخاب شده را آپلود کنید :
<input type="file" multiple="multiple" name="File1" id="File1" runat="server" />
for (int i = 1; i <= Request.Files.Count; i++) { var file = Request.Files[i]; }
اشتراکها
ایجاد Responsive Layered Slider
in this tutorial you will lean how to create
a responsive layered slider. The slider will have multiple slides, each
slide will have multiple layers which can have a different fade in
effect.
The entire slider works by using just a JavaScript document and you
don't have to attach any CSS style sheets to use it. Each layer will
have 18 possible effects which you can use to your liking. All
animations are created by inserting CSS code into the page using
JavaScript. Demo
الگوی Chain of Responsibility، یک زنجیر، از اشیاء متصل شدهی به هم را فراهم میکند که یکی از آنها میتواند درخواست رسیده را راضی کند؛ به عبارتی دیگر به محض دریافت درخواست، آن را پردازش میکند. این الگو اساسا یک جستجوی خطی ( linear search )، برای یک شیء میباشد که میتواند یک درخواست ویژه را handle کند.
مثال بالا، الگوی chain of responsibility را پیاده سازی میکند و بررسی میکند که آیا عدد وارد شده، مضربی از 2، 3 یا 5 است و یا نه.
الگوی chain-of-responsibility، ارتباط با الگوی Chaining دارد که به دفعات در جاوا اسکریپت استفاده شدهاست (jQuery استفادهی گستردهای از این الگو کردهاست).
این الگو اجازه میدهد که یک درخواست ارسال شدهی توسط کلاینت، توسط یک یا بیش از یک object، دریافت شود. یک مثال عمومی از این الگو، event bubbling در DOM میباشد. یک رویداد از طریق elementهای تودرتوی متفاوت انتشار پیدا میکند؛ تا زمانیکه یکی از آنها، آن را handle کند.
مثال زیر را در نظر بگیرید:
class HandlerChain
{
setNextObj(nextObjInChain){}
processMultiple(req){
console.log("No multiple for: " + req.getMultiple());
}
}
class Multiple
{
constructor(multiple){
this.multiple = multiple;
}
getMultiple(){
return this.multiple;
}
}
class MultipleofTwoHandler extends HandlerChain
{
constructor(){
super()
this.nextObjInChain = new HandlerChain()
}
setNextObj(nextObj){
this.nextObjInChain = nextObj;
}
processMultiple(req) {
if ((req.getMultiple() % 2) == 0) {
console.log("Multiple of 2: " + req.getMultiple());
}else{
this.nextObjInChain.processMultiple(req);
}
}
}
class MultipleofThreeHandler extends HandlerChain
{
constructor(){
super()
this.nextObjInChain = new HandlerChain()
}
setNextObj(nextObj){
this.nextObjInChain = nextObj;
}
processMultiple(req)
{
if ((req.getMultiple() % 3) == 0) {
console.log("Multiple of 3: " + req.getMultiple());
}else{
this.nextObjInChain.processMultiple(req);
}
}
}
class MultipleofFiveHandler extends HandlerChain
{
constructor(){
super()
this.nextObjInChain = new HandlerChain()
}
setNextObj(nextObj){
this.nextObjInChain = nextObj;
}
processMultiple(req) {
if ((req.getMultiple() % 5) == 0) {
console.log("Multiple of 5: " + req.getMultiple());
}else{
this.nextObjInChain.processMultiple(req);
}
}
}
//configuring the chain of handler objects
var c1 = new MultipleofTwoHandler();
var c2 = new MultipleofThreeHandler();
var c3 = new MultipleofFiveHandler();
c1.setNextObj(c2);
c2.setNextObj(c3);
//the chain handling different cases
c1.processMultiple(new Multiple(95)); // Multiple of 5: 95
c1.processMultiple(new Multiple(50)); // Multiple of 2: 50
c1.processMultiple(new Multiple(9)); // Multiple of 3: 9
c1.processMultiple(new Multiple(4)); // Multiple of 2: 4
c1.processMultiple(new Multiple(21)); // Multiple of 3: 21
c1.processMultiple(new Multiple(23)); // No multiple for: 23
چگونه میتوانیم این قابلیت را پیاده سازی کنیم؟ ما میخواهیم که یک عدد داشته باشیم و سپس به handlerها در زنجیره اجازه بدهیم که تصمیم گیری کنند که آیا آنها میخواهند عدد وارد شده را پردازش کنند، یا به handler بعدی پاس بدهند.
ما 3 نوع handler در این زنجیره داریم:
- MultipleofTwoHandler: بررسی میکند که آیا عدد وارد شده، مضربی از 2 است یا نه.
- MultipleofThreeHandler: بررسی میکند که آیا عدد وارد شده، مضربی از 3 است یا نه
- MultipleofFiveHandler: بررسی میکند که آیا عدد وارد شده، مضربی از 5 است یا نه.
اولین قدم، ایجاد یک زنجیره از handlerهای بالا میباشد. در اینجا یک کلاس را به نام HandlerChain، برای همین منظور داریم و این کلاس شامل دو تابع، به نامهای setNextObj و processMultiple میباشد.
class HandlerChain { setNextObj(nextObjInChain){} processMultiple(req){ console.log("No multiple for: " + req.getMultiple()); } }
پیاده سازی پیش فرض processMultiple، زمانی اجرا میشود که هیچ مضربی برای یک عدد، وجود نداشته باشد. به عبارت دیگر، عدد مورد نظر، مضربی از 2،3 و 5 نباشد ( از بین مضربهای تعین شده).
تمام handlerها در این زنجیره، از این کلاس ارث بری میکنند. هر handler میتواند دو عملیات را انجام دهد:
- تنظیم کردن handler بعدی در زنجیره
- پردازش عدد وارد شده به این منظور که آیا در مضرب مورد نظر قرار دارد یا نه.
class MultipleofTwoHandler extends HandlerChain { constructor(){/*code*/} setNextObj(nextObj){/*code*/} processMultiple(req){/*code*/} } class MultipleofThreeHandler extends HandlerChain { constructor(){/*code*/} setNextObj(nextObj){/*code*/} processMultiple(req){/*code*/} } class MultipleofFiveHandler extends HandlerChain { constructor(){/*code*/} setNextObj(nextObj){/*code*/} processMultiple(req){/*code*/} }
constructor برای هر handler، همانند زیر تعریف شدهاست:
constructor(){ super() this.nextObjInChain = new HandlerChain() }
در ابتدا توسط super ، مقدار دهی اولیهای برای متدهای setNextObj و processMultiple از کلاس پدر انجام میشود. همچنین در constructor، متغیر nextObjInChain
مقدار دهی اولیه میشود که تعیین کنندهی شیء بعدی در زنجیره میباشد.
مقدار دهی اولیه میشود که تعیین کنندهی شیء بعدی در زنجیره میباشد.
چگونه شیء جاری، شیء بعد را در زنجیره تعیین میکند؟ اجازه بدهید برای این منظور نگاهی به تابع setNextObj داشته باشیم. setNextObj در هر handler، همانند زیر تعیین شدهاست:
setNextObj(nextObj){ this.nextObjInChain = nextObj; }
اکنون میتوانیم زنجیرهای از handlerها را همانند زیر ایجاد کنیم:
var c1 = new MultipleofTwoHandler(); var c2 = new MultipleofThreeHandler(); var c3 = new MultipleofFiveHandler(); c1.setNextObj(c2); c2.setNextObj(c3);
در اینجا ما handlerهای c2, c1 و c3 را به منظور پردازش کردن مضربهای 2، 3 و 5 ایجاد کردهایم. آنها به یکدیگر به حالت زیر متصل شدهاند:
c2 به عنوان handler بعدی برای c1 و c3 به عنوان handler بعدی برای c2.
اکنون که زنجیره ایجاد شدهاست، زمان آن است که عدد وارد شده را پردازش کنیم. اجازه بدهید که کار را با ایجاد کردن شیء “multiple” با استفاده از کلاس Multiple، شروع کنیم.
class Multiple { constructor(multiple){ this.multiple = multiple } getMultiple(){ return this.multiple; } }
یک شیء Multiple، شامل یک خصوصیت به نام multiple و یک متد است به نام getMultiple که به منظور برگشت دادن multiple میباشد.
MultipleofTwoHandler به صورت زیر تعریف شدهاست:
processMultiple(req) { if ((req.getMultiple() % 2) == 0) { console.log("Multiple of 2: " + req.getMultiple()); }else{ this.nextObjInChain.processMultiple(req); } }
در اینجا، یک multiple دریافت شده و چک میشود که آیا مضربی از 2 میباشد یا نه؛ اگر چنین است، سپس عدد دریافت شده را به عنوان مضربی از 2 نمایش میدهد. در صورتیکه مضربی از 2 نباشد، handler آن را به شیء بعدی در زنجیره، پاس میدهد و سپس همین روال دوباره تکرار میشود و تا زمانیکه یکی از handler ها، جواب را برگشت دهد، این روال ادامه پیدا میکند.
تعریف تابع processMultiple برای هر 3 handler یکسان میباشد؛ با این تفاوت که MultipleofThreeHandler، برای بررسی مضربی از 3 بودن و MultipleofFiveHandler برای بررسی مضربی از 5 بودن است.
اجازه بدهید یک مثال بزنیم و ببینیم که چه اتفاقی میافتد:
c1.processMultiple(new Multiple(95)) // Multiple of 5: 95
اولین handler در زنجیره که c1 است، یک multiple (95) را دریافت میکند و چک میکند که آیا مضربی از 2 است یا نه. جواب خیر است؛ بنابراین multiple به دومین handler در زنجیره پاس داده میشود؛ یعنی به handler بررسی کنندهی مضربی از 3 . در اینجا دوباره بررسی میشود که آیا عدد مورد نظر، مضربی از 3 است یا نه؟ که جواب خیر است. در ادامه multiple به handler سوم در زنجیره که بررسی کنندهی مضربی از 5 است، پاس داده میشود. در اینجا، شرط درست است و عدد 95 به عنوان مضربی از 5 چاپ میشود.
چه زمانی از این الگو استفاده کنیم؟
به منظور مدیریت کردن انواع درخواستها، به روشهای متفاوت، بدون دانستن ترتیب و نوع درخواست از قبل، از این الگو استفاده میکنیم. این الگو به ما اجازه میدهد که زنجیرهای از چند handler را داشته باشیم. تمامی handlerها، یک شانس را جهت پردازش درخواست دارند.
اشتراکها
بازهها و الگوهای بازگشتی در C# 8
- C# 8 Adds Ranges and Recursive Patterns
- Ranges easily define a sequence of data, replacing the Enumberable.Range()
- Recursive Patterns brings an F#-like construct to C#
- Recursive Patterns is an awesome feature, it giving you the flexibility to testing the data against a sequence of conditions and performing further computations based on the condition met.
- Ranges is very useful to generate sequences of numbers in the form of a collection or a list.
برای یکی از پروژهها نیاز به یک آپلودر داشتم که قابلیت Drag&Drop را نیز
داشته باشد و در ضمن پیاده سازی آسانی هم داشته باشد. در این بین به
تعدادی از کتابخانههای جی کوئری میپردازیم.
FileDrop
اولین کتابخانهای که با آن آشنا شدم و از آن استفاده کردم، کتابخانهی FileDrop است که بسیار ساده و در عین حال قابلیتهای خوبی را میدهد و از فناوری Filereader (+) در Html5 برای اینکار استفاده میکند. مرورگرهای کروم، فایرفاکس 3.6 به بعد، IE10 به بعد و Opera 12 به بعد از آن پشتیبانی میکنند.
فایلهای مورد نیاز را از اینجا دانلود کنید . فایل اسکریت آن را ابتدا صدا بزنید:
<script src="~/scripts/jquery.filedrop.js" type="text/javascript"></script>
<div id="dropZone">فایل برنامه را به داخل این کادر بکشانید</div> <br> فایل یا فایلهای آپلود شده: <ul id="uploadResult"></ul>
تگ اول، محلی است که فایلها به سمت آن درگ و روی آن دراپ میشوند که از این
به بعد به آن محل آپلود میگوییم. المان بعدی جهت گزارش فایلهایی است که
آپلود شدهاند. با آپلود شدن هر تعداد فایل، اسم آن به لیست اضافه
میگردد.
کدهای css زیر را هم به صفحه اضافه کنید تا محل آپلود زیباتر شود:
.files { min-height: 42px; background: #CCC none repeat scroll 0% 0%; border-top: 1px solid #FFF; margin: 11px 0px; padding: 11px 13px; border-radius: 6px; } #dropZone.mouse-over { background-color: #1d4257; }
کد جی کوئری زیر را به صفحه اضافه کنید:
$('#dropZone').filedrop({ url: uploadAddress, paramname: 'files', maxFiles: 1, dragOver: function() { $('#dropZone').addClass('mouse-over'); }, dragLeave: function() { $('#dropZone').removeClass('mouse-over'); }, drop: function() { $('#dropZone').removeClass('mouse-over'); }, afterAll: function() { $('#dropZone').html('آپلود با موفقیت انجام شد'); }, uploadFinished: function(i, file, response, time) { $('#uploadResult').append('<li>' + file.name + '</li>'); } });
Url | آدرسی که قرار است فایلها به آن سمت ارسال شوند. |
Paramname | در سمت سرور باید فایلها را با استفاده از این نام پارامتر دریافت کنید. |
maxFiles | تعداد فایلهایی که میتوان با درگ و دراپ کردن روی آن به دست آورد. در بالا به یک فایل محدود شده است. |
dragOver | این رویداد زمانی اجرا خواهد شد که اشاره گر با حالت درگ کرده فایلها را به محل آپلود آورده است. |
dragLeave | موقعی که ماوس از محل آپلود خارج میشود |
drop | موقعی که شما فایلها را روی محل آپلود رها میکنید. |
afterAll | بعد از اینکه همه کارها تمام شد اجرا میشود.(آخرین رویداد) |
uploadFinished | کار آپلود به پایان رسیده است. در مثال بالا پس از پایان آپلود، نام فایل آپلود شده را به کاربر نشان دادهایم. |
نحوهی دریافت آن در سمت سرور, در یک اکشن متد به صورت زیر است:
[HttpPost] public virtual ActionResult UpdateApp(IEnumerable<HttpPostedFileBase>files) { foreach (HttpPostedFileBase file in files) { string filePath = Path.Combine(TempPath, file.FileName); file.SaveAs(filePath); } return Json(new {state = "success", message = "با موفقیت عملیات ارسال فایل انجام شد"}, JsonRequestBehavior.AllowGet); }
در اکشن متد بالا ما فایلها را از طریق نام پارامتر files که مشخص کرده بودیم، به عنوان یک لیست شمارشی دریافت میکنیم. کدها بالا برای سادهترین راه اندازی ممکن کفایت میکنند.
این موارد از اصلیترینها هستند که به کار میآیند. به غیر اینها یک سری خصوصیات اضافهتری هم برای آن وجود دارد.
fallback_id | اگر دوست دارید این آپلودر را نیر به یک آپلودر معمولی اتصال دهید از این شناسه استفاده کنید. |
withCredentials | با استفاده از کوکیها یک درخواست cross-origin ایجاد میکند. |
data | اگر دوست دارید به همراه فایلها اطلاعات دیگری هم به همراه آن
ارسال و پست شوند از این طریق اقدام نمایید. میتواند در قالب یک متغیر
باشد یا خروجی یک تابع.data: { param1: 'value1', param2: function(){ return calculated_data; } |
headers | برای ارسال مقدار اضافهتر در هدر درخواست به کار میرود و صدا زدن آن همانند کد data میباشد. |
error | در صورتیکه در فرایند آپلود خطایی رخ دهد، اجرا میگردد. نحوهی کدنویسی آن و بررسی خطاهای آن به شرح زیر است:error: function(err, file) { switch(err) { case 'BrowserNotSupported': alert('مرورگر از این فناوری پشتیبانی نمیکند') break; case 'TooManyFiles': // قصد آپلود همزمان فایلهای بیشتری از حد مجاز تعیین شده دارید break; case 'FileTooLarge': //حداقل حجم یکی از فایلها از حجم مجاز تعیین شده بیشتر است //برای دسترسی به نام آن فایل از کد زیر استفاده کنید //file.name break; case 'FileTypeNotAllowed': // نوع حداقل یکی از فایلها با نوعها مشخص شده ما یکی نیست break; case 'FileExtensionNotAllowed': // پسوند حداقل یکی از فایلها مورد تایید نیست break; default: break; } } |
allowedfiletypes | نوع فایلهای مجاز را تعیین میکند:allowedfiletypes: |
allowedfileextensions | پسوند فایل هایی که برای آپلود مجاز هستند را معرفی میکند.allowedfileextensions: |
maxfilesize | حداکثر حجم مجاز برای هر فایل که به مگابایت بیان میشود. |
docOver | این رویداد زمانی اجرا میشود که فایلهای درگ شده شما وارد محیط یا پنجره مرورگر میشود. |
uploadStarted | این رویداد زمانی اجرا میگردد که فرایند آپلود هر فایل به طور جداگانه در حال آغاز شدن است: متغیر i در کد زیر شامل اندیس فایلی است که آپلودش آغاز شده است و این اندیس از صفر آغاز میشود. متغیر file دسترسی شما را به اطلاعات یک فایل باز میکند مانند نام فایل. متغیر len تعداد فایل هایی را که کاربر در محل آپلود رها کرده است، باز میگرداند. function(i, file, len){ }, |
uploadFinished | با اتمام آپلود هر فایل، این رویداد فراخوانی میگردد. دو
پارامتر اول آن، همانند سابق هستند. پارامتر response خروجی json ایی را که در سمت
سرور برگرداندیم، به ما باز میگرداند. پارامتر بعدی، زمانی را که برای
آپلود طول کشیده است، بر میگرداند. function(i, file, response, time) { } |
progressUpdated | این رویداد برای نمایش پیشرفت یک آپلود مناسب است که آخرین پارامتر آن یک عدد صحیح از پیشرفت فایل را بر میگرداند.function(i, file, progress) { }, |
globalProgressUpdated | این رویداد میزان پیشرفت کلیه فایلها را به درصد باز میگرداند:function(progress) { $('#progress div') |
speedUpdated | سرعت آپلود هر فایل را با کیلوبیت بر ثانیه مشخص میکند.function(i, file, speed) { } |
rename | در صورتی که قصد تغییر نام فایل ارسالی را دارید میتوانید از این رویداد استفاده کنید. پارامتر name، نام اصلی فایل را بر میگرداند که میتوانید آن را دستکاری کنید و نام جدیدی را به عنوان خروجی برگردانید. نمونه کاربردی از این رویداد rename: function(name) { } |
beforeEach | این رویداد قبل از آپلود هر فایل آغاز میگردد و برگرداندن مقدار false در آن باعث جلوگیری و کنسل شدن آپلود آن فایل میگردد.function(file) { } |
beforeSend | پارامترهای اولی تکراری هستند ولی آخرین پارامتر یک
تابع done را میتوان به آن پاس کرد که قبل از اجرای کل عملیات آپلود صدا
زده میشود.function(file, i, done) { } |
رویدادی به اسم queuefiles هم هست تعداد فایلهایی را که میتوانند به طور موازی و همزمان آپلود گردند، مشخص میکند. ولی دراین حالت maxfiles مورد استفاده قرار نمیگیرد. جهت بررسی یک مثال عملی و همچنین کدهای سمت سرور در PHP میتوانید از این آموزش استفاده کنید.
با تستی که به صورت لوکال رو آن انجام دادم به نظر نمیرسد برای فایلهای با حجم متوسط به بالا مناسب باشد و برای فایلهای با حجم کم مناسب میباشد. یک فایل 8 مگابایتی در حالت لوکال 9 ثانیه آپلود آن زمان برد و برای فایلهای بزرگتر، فایرفاکس دیالوگ Stop Script را نشان داد.
PlUpload
این کتابخانه متن باز هم بسیار کارآمد و ساده و قابل انعطاف است و مثالهای آماده زیادی دارد. سایت سابسن هم در بخش آپلود زیرنویسها از این کتابخانه استفاده میکند. از آنجا که آموزش این کتابخانه در سایت جاری آمده است از ذکر نکات بیشتر در مورد آن خودداری مینماییم.
Bootstrap FileStyle
اگر از قالب بوت استراپ استفاده میکنید و دوست دارید روی المان input file قدیمی، ولی به شکلی مدرن کار کنید این کتابخانه هم فراموش نشود.
DropZoneJS
این کتابخانه به نسبت DropFile امکانات بیشتری را دارد و در سایت اختصاصی آن مثالها و مستندات خوبی قرار گرفته است. در سادهترین حالت آن ابتدا فایل کتابخانه را صدا زده و سپس تگ فرم را به آن نسبت دهید:
<script src="https://rawgit.com/enyo/dropzone/master/dist/dropzone.js"></script> <form action="/upload-target" class="dropzone"></form>
ولی اگر بخواهید آن را به سمت سرور ارسال کنید و از آنجا آن را کنترل کنید، کد فرم را به شکل زیر تغییر دهید:
ابتدا بستهی نیوگت آن را صدا بزنید:
Install-Package dropzone
با نصب این کتابخانه یک سری فایل CSS هم به سیستم اضافه میشود که میتوانید برای استایل دهی هر چه بیشتر از آن بهره ببرید. کد فرم را به شکل زیر تغییر دهید:
<form action="~/Home/SaveUploadedFile" method="post" enctype="multipart/form-data" class="dropzone" id="dropzoneForm" style="width: 50px; background: none; border: none;"> <div class="fallback"> <input name="file" type="file" multiple /> <input type="submit" value="Upload" /> </div> </form>
با استفاده از کدنویسی هم میتوان یک المان را به یک آپلودر تبدیل کرد:
var myDropzone = new Dropzone("div#myId", { url: "/file/post"}); //============ OR ==================== $("div#myId").dropzone({ url: "/file/post" });
برای کانفیگ آپلودرهایی که از طریف المانهای Html ایجاد میشوند، میتوان از کد زیر استفاده کرد و یک تنظیم عمومی برای تمامی آپلودرهای html آن صفحه ایجاد کرد.
Dropzone.options.myId= { paramName: "file", //نام پارامتری که فایل از طریق آن انتقال میبابد maxFilesize: 2, // MB accept: function(file, done) { if (file.name == "justinbieber.jpg") { done("Naha, you don't."); } else { done(); } } };
ازآنجا که این کتابخانه از تنظیمات وسیعی استفاده میکند و از حوصلهی این مقاله خارج است، بهتر هست که صفحهی مستندات آن را که کامل هم هست، مطالعه بفرمایید. از سری قابلیتهایی که پشتیبانی میکند: موارد پوشش داده شده در FileDrop، ساخت layout، ایجاد صف، متد حذف و اضافه و از این قبیل، ایجاد تصویر تمبر مانند و ...
یک نکته تکمیلی در مورد آپلود: در ASP.net به طور پیش فرض نهایت حجم فایل آپلودی 4 مگابایتی تعیین شده است که میتوانید آن را از طریق web.config تغییر دهید:
<configuration> <system.web> <httpRuntime maxRequestLength="1048576" /> </system.web> </configuration>
<system.webServer> <security> <requestFiltering> <requestLimits maxAllowedContentLength="1073741824" /> </requestFiltering> </security> </system.webServer>
در هر دو کد بالا نهایت حجم بر روی یک گیگابایت تعیین شده است که maxRequestLength به صورت کیلوبایت و maxAllowContentLength به صورت بایت تعیین شده است. توصیه میشود هر دو شکل آن را وارد کنید. به خصوص که IIS Express از کد ابتدایی استفاده میکند و بخواهید نتیجهی آن را در تستها ببینید.
اشتراکها
EF5 منتشر شد
فرض کنید تعیین اعتبار یکی از فیلدهای فرم نیاز به انجام محاسباتی در سمت سرور دارد و اینکار را میخواهیم با استفاده از jQuery Ajax انجام دهیم. مشکلی که در اینجا وجود دارد، این است که A در Ajax به معنای asynchronous است. یعنی زمانیکه کاربر دکمه submit را فشرد، دیگر برنامه منتظر این نخواهد شد که پاسخ کامل دریافت شود ، سایر پردازشها صورت گیرد و سپس فرم را به سرور ارسال نماید (شبیه به ایجاد یک ترد جدید در برنامههای ویندوزی). مثال زیر را در نظر بگیرید:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestCustomValidation.aspx.cs"
Inherits="TestJQueryAjax.TestCustomValodation" %>
<!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></title>
<script src="js/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
function validate() {
var number1 = $("#<%=txtNumber1.ClientID %>").val();
var number2 = $("#<%=txtNumber2.ClientID %>").val();
var result = false;
$.ajax({
type: "POST",
url: 'AjaxSrv.asmx/ValidateIt',
data: '{"number1":' + number1 + ',"number2":' + number2 + '}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success:
function(msg) {
if (msg.d) {
result = true;
alert('بسیار خوب');
}
else {
result = false;
alert('دوباره سعی کنید');
}
},
error:
function(XMLHttpRequest, textStatus, errorThrown) {
result = false;
alert("خطایی رخ داده است");
}
});
//debugger;
return result;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
number 1 :
<asp:TextBox runat="server" ID="txtNumber1" />
<br />
number 2 :
<asp:TextBox runat="server" ID="txtNumber2" />
<br />
<asp:Button ID="btnSubmit" Text="Submit" UseSubmitBehavior="false" runat="server"
OnClientClick="if(!validate()){ return false;}" OnClick="btnSubmitClick" />
</div>
</form>
</body>
</html>
این مثال یک نوع اعتبار سنجی سفارشی را در حین submit با استفاده از وب سرویس زیر انجام میدهد (حاصلضرب دو عدد دریافتی را بررسی میکند که باید مساوی 10 باشند. البته هدف از این مثال ساده، آشنایی با نحوهی انجام این نوع عملیات است که میتواند شامل کار با دیتابیس و غیره هم باشد. و گرنه بدیهی است این بررسی را با دو سطر کد جاوا اسکریپتی نیز میشد انجام داد):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Script.Services;
namespace TestJQueryAjax
{
/// <summary>
/// Summary description for AjaxSrv
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[ScriptService]
public class AjaxSrv : System.Web.Services.WebService
{
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public bool ValidateIt(int number1, int number2)
{
return number1 * number2 == 10;
}
}
}
راه حل چیست؟
راه حلهای فضایی بسیاری را در وب در این مورد میتوان پیدا کرد؛ اما راه حل استاندارد آن در این حالت ویژه، استفاده از Ajax در حالت غیرهمزمان است. یعنی این فریم ورک Ajax را وادار کنیم که تا پایان عملیات مورد نظر، منتظر بماند و سپس فرم را ارسال کند. برای این منظور تنها کافی است یک سطر زیر را پیش از فراخوانی تابع Ajax ، اضافه و فراخوانی نمائیم:
$.ajaxSetup({async: false}) ;
UseSubmitBehavior دکمه ما را به شکل زیر رندر میکند (دکمه به یک button معمولی (بجای حالت submit) تبدیل شده و سپس یک doPostBack را اضافه خواهد کرد):
<input id="btnSubmit" type="button" onclick="if(!validate()){ return false;};__doPostBack('btnSubmit','')" value="Submit" name="btnSubmit"/>
این کتابخانه که توسط آقای مهدی صادقی ایجاد شده است قابلیت نمایش فرمولهای ریاضی را به صورت یک کامپوننت ساده و عدم درگیری مستقیم با کتابخانه MathJax و life cycleها ایجاد کرده است:
<MathJax sanitizeOptions={ {USE_PROFILES: {html: true,mathMl: true}}} style={{'display':'inline-block'}} math={this.props.question.title} />
همچنین به دلیل بکارگیری کتابخانه DOMPurify امکان مدیریت تگها و جلوگیری از حملات xss و .. نیز فراهم میباشد.