لینکهای هفته سوم دی
وبلاگها ، سایتها و مقالات ایرانی (داخل و خارج از ایران)
ASP. Net
- ویدیویی دربارهی ASP.Net 4 (بهبودهای حاصل شده در web forms از جهت کار با اسکریپتها خصوصا با تاکید بر jQuery و همچنین ذکر اینکه با آمدن ASP.Net MVC ، وب فرمها کهنه نشده و همچنان توسعه و بهبود داده خواهند شد)، یا مقالهای در این مورد
طراحی و توسعه وب
PHP
اسکیوال سرور
سی شارپ
عمومی دات نت
مسایل اجتماعی و انسانی برنامه نویسی
متفرقه
در یک برنامه کنسول، متد Main یعنی کدهایی که در ترد اصلی برنامه اجرا میشوند. زمان اجرای تمام taskهای تعریف شده، با زمان اجرای ترد اصلی برنامه بسیار بسیار نزدیک است اما ممکن است یک تاخیر چند میلی ثانیهای اینجا وجود داشته باشد و آن هم وهله سازی و در صف قرار دادن taskها و اجرای آنها است.
Task در دات نت 4 از thread pool مخصوص CLR استفاده میکند که همان thread pool ایی است که توسط متد ThreadPool.QueueUserWorkItem موجود در نگارشهای قبلی دات نت، مورد استفاده قرار میگیرد؛ با این تفاوت که جهت کارکرد با Tasks بهینه سازی شده است (جهت استفاده بهتر از CPUهای چند هستهای).
همچنین باید توجه داشت که استفاده از یک استخر تردها به معنای درصف قرار دادن کارها نیز هست. بنابراین یک زمان بسیار کوتاه جهت در صف قرار دادن کارها و سپس ایجاد تردهای جدید برای اجرای آنها در اینجا باید درنظر گرفت.
یک منبع بسیار عالی برای مباحث پردازش موازی به همراه توضیحات لازم:
http://www.albahari.com/threading/part5.aspx#_Task_Parallelism
- آموزش MVC - قسمت هشتم - نمایش Autocomplete DropDownList در MVC | www.30sharp.com
- دانلود رایگان کتاب ۳۷۰ص وبلاگ نویسی شیرین با وردپرس | کسب و کار اینترنتی | www.ebusinessfa.com
- مقدمه ای بر RavenDB – قسمت اول | www.dotnetdev.info
- مقدمه ای بر RavenDB – قسمت دوم | www.dotnetdev.info
- Droid Arabic Kufi & Naskh for Google™ | 29letters.wordpress.com
- Microsoft Download Manager | www.microsoft.com
- Modern C++(0x) Programming with Visual Studio | www.microsoft.com
- System.Net.WebSockets در دات نت 4.5 | www.paulbatum.com
- Updated Release: Windows Phone Toolkit | silverlight.codeplex.com
- WebSockets در ویندوز 8 | www.paulbatum.com
- ابزارهای مدیریت پروژه رایگان | 3.7designs.co
- ایجاد چارت در ASP.NET MVC3 | mojtabasahraei.blogfa.com
- پایان توسعه Flash Player جهت دستگاههای موبایل | blogs.adobe.com
- پیاده سازی یک بافر حلقوی Generic در دات نت | www.blackwasp.co.uk
- زبان معاصر فارسی از دیدگاه یک غیرایرانی | 29letters.wordpress.com
در مورد معرفی WPF Extended toolkit چندی قبل مطلبی منتشر شد. در ادامه این بی مهریها (!) میتوان به عدم به روز رسانی قالبهای ارائه شده برای WPF اشاره کرد. در WPF4 ، کنترل DataGrid از WPF toolkit به مجموعهی کنترلهای اصلی WPF منتقل شده است، اما قالبهای منتشر شدهی آن جهت لحاظ کردن این مورد به روز نشدهاند. یعنی اگر برای مثال یکی از قالبهای موجود را به برنامه خود اعمال کنید و سپس DataGrid را بر روی فرم قرار دهید، وصلهی ناهماهنگی را مشاهده خواهید نمود. این مشکلات در Silverlight وجود ندارند و قالبهای ارائه شدهی برای آن به روز بوده و همچنین روز به روز هم تعدادشان بیشتر میشوند.
اما باز هم نمیتوان ایراد گرفت چون کار ارائه شده سورس باز است. به عبارتی اگر مایکروسافت این قالبها را به روز نکرده، خوب، لطفا خود شما وقت بگذارید و این کار را انجام داده و سپس یک patch ارائه دهید. ایرادی دارد؟!
برای این منظور پروژهای در سایت CodePlex ایجاد شده است و تنها به پوشش دات نت سه و نیم و دیتاگرید متعلق به WPF Toolkit پرداخته است :
اگر علاقمند باشید که از دیتاگرید بومی دات نت 4 استفاده کنید میتوانید از این patch استفاده کنید.
<?xml version="1.0"?> <Configuration xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <AllowAnonymousPush>false</AllowAnonymousPush> <Repositories>D:\GitRepo</Repositories> <AllowUserRepositoryCreation>true</AllowUserRepositoryCreation> <AllowAnonymousRegistration>false</AllowAnonymousRegistration> <DefaultLanguage>en-US</DefaultLanguage> <IsCommitAuthorAvatarVisible>true</IsCommitAuthorAvatarVisible> </Configuration>
قابلیت جالبی که در اینجا به نظر من خیلی مهم بود، استخراج تاریخچهی کامل ساب ورژن توسط گیت و انتقال همه آنها به مخزن گیت است که تنها با یک خط فرمان انجام پذیر است. برای اینکار مخرنی را در گیت ساخته و آدرس .git آن را برای اجرای فرمان نگه میداریم:
البته نصب گیت برای ویندوز برای صدور فرمان انتقال به گیت الزامی است که میتوانید از این آدرس آنرا دانلود و نصب کنید.
پس از آن در 2 مرحله مخرن ساب ورژن را به گیت انتقال میدهیم:
1- استخراج آن در یک مخزن لوکال
2- افزودن به سرور گیت (که راه اندازی شده)
برای استخراج مخزنی از ساب ورژن به یک مخزن لوکال گیت، یک فولدر خالی را ایجاد میکنیم. سپس با خط فرمان به آن وارد میشویم و بعد فرمان زیر را اجرا میکنیم:
در ادامه نام کاربری و کلمهی عبور را وارد میکنیم. البته به صورت پیش فرض، نام کاربری جاری ویندوز را در نظر میگیرد و بعد نام کاربری و کلمهی عبور سرویس ساب ورژن را میپرسد و حالا گیت کارش را شروع میکند:
پس از اتمام کار با توجه به مقالهی «مراحل ارسال یک پروژهی Visual Studio به GitHub» برای کار با گیت در ویژوال استودیو، میتوان به کار با گیت بصورت ریموت ادامه دهید.
و اما نکتهی آخر: من برای استفاده از این سرور مجبور بودم که نام localhost را با نام mehdi-pc جابجا کنم تا بتوانم از طریق یک کامپیوتر دیگر با سورس کنترل کار کنم و طی جستجوهایی که در اینترنت کردم، این کار بصورت کامند و فرمانهای شبه لینوکسی انجام پذیر بود. ولی راهی را همچون این مقاله «مشکل در جابجایی پروژههای svn» پیدا کردم که بنظرم آنرا مرتبط با موضوع میدانم و گفتن آن را خالی از لطف نمیبینم.
فایل config در واقع فایل کانفیگ داخل مخزن لوکال است؛ یعنی داخل فولدر .git و بصورت متنی ذخیره شده است:
طبق انتظار قسمتی از فایل که در زیر آمده، مربوط به مشخصات اتصال به سرور ریموت میباشد:
[remote "origin"] url = http://mehdi-pc:8551/NewsService.git fetch = +refs/heads/*:refs/remotes/origin/*
البته باید بسیار با دقت این تغییر را ایجاد کنید و مطمئن باشید که آدرس را بطور صحیح و به یک مخزن درست گیت تغییر میدهید.
کلاس ArrayList
using System; using System.Collections; class ProgrArrayListExample { static void Main() { ArrayList list = new ArrayList(); list.Add("Hello"); list.Add(5); list.Add(3.14159); list.Add(DateTime.Now); for (int i = 0; i < list.Count; i++) { object value = list[i]; Console.WriteLine("Index={0}; Value={1}", i, value); } } }
Index=0; Value=Hello Index=1; Value=5 Index=2; Value=3.14159 Index=3; Value=29.02.2015 23:17:01
ArrayList list = new ArrayList(); list.Add(2); list.Add(3.5f); list.Add(25u); list.Add(" ریال"); dynamic sum = 0; for (int i = 0; i < list.Count; i++) { dynamic value = list[i]; sum = sum + value; } Console.WriteLine("Sum = " + sum); // Output: Sum = 30.5ریال
مجموعههای جنریک Generic Collections
GenericType<T> instance = new GenericType<T>();
List<int> intList = new List<int>(); List<bool> boolList = new List<bool>(); List<double> realNumbersList = new List<double>();
List<int> intList = new List<int>();
- استفاده از index برای دسترسی به یک مقدار، صرف نظر از اینکه چه میزان دادهای در آن وجود دارد، بسیار سریع انجام میگیرد.
- جست و جوی یک عنصر بر اساس مقدار: جست و جو خطی است در نتیجه اگر مقدار مورد نظر در آخرین خانهها باشد بدترین وضعیت ممکن رخ میدهد و بسیار کند عمل میکند. داده هر چی کمتر بهتر و هر چه بیشتر بدتر. البته اگر بخواهید مجموعهای از مقدارهای برابر را برگردانید هم در بدترین وضعیت ممکن خواهد بود.
- حذف و درج (منظور insert) المانها به خصوص موقعی که انتهای آرایه نباشید، شیفت پیدا کردن در آرایه عملی کاملا کند و زمانبر است.
- موقعی که عنصری را بخواهید اضافه کنید اگر ظرفیت آرایه تکمیل شده باشد، نیاز به عمل زمانبر افزایش ظرفیت خواهد بود که البته این عمل به ندرت رخ میدهد و عملیات افزودن Add هم هیچ وابستگی به تعداد المانها ندارد و عملی سریع است.
- افزودن به انتهای لیست به خاطر این که همیشه گره آخر در tail وجود دارد بسیار سریع است.
- عملیات درج insert در هر موقعیتی که باشد اگر یک اشاره گر به آن محل باشد یک عملیات سریع است یا اینکه درج در ابتدا یاانتهای لیست باشد.
- جست و جوی یک مقدار چه بر اساس اندیس باشد و چه مقدار، کار جست و جو کند خواهد بود. چرا که باید تمامی المانها از اول به آخر اسکن بشن.
- عملیات حذف هم به خاطر اینکه یک عمل جست و جو در ابتدای خود دارد، یک عمل کند است.
استفاده از لیست پیوندی برای پیاده سازی پشته:
Stack<string> stack = new Stack<string>(); stack.Push("A"); stack.Push("B"); stack.Push("C"); while (stack.Count > 0) { string letter= stack.Pop(); Console.WriteLine(letter); } //خروجی //C //B //A
ابتدای آرایه مکانی است که عنصر از آنجا برداشته میشود و Head به آن اشاره میکند و tail هم به انتهای آرایه که جهت درج عنصر جدید مفید است. با برداشتن هر خانهای که head به آن اشاره میکند، head یک خانه به سمت جلو حرکت میکند و زمانی که Head از tail بیشتر شود، یعنی اینکه دیگر عنصری یا المانی در صف وجود ندارد و head و Tail به ابتدای صف حرکت میکنند. در این حالت موقعی که المان جدیدی قصد اضافه شدن داشته باشد، افزودن، مجددا از اول صف آغاز میشود و به این صفها، صف حلقوی میگویند.
عملیات اصلی صف دو مورد هستند enqueue که المان جدید را در انتهای صف قرار میدهد و dequeue اولین المان صف را بیرون میکشد.
پیاده سازی صف به صورت پویا با لیستهای پیوندی
برای پیاده سازی صف، لیستهای پیوندی یک طرفه کافی هستند:
در این حالت عنصر جدید مثل سابق به انتهای لیست اضافه میشود و برای حذف هم که از اول لیست کمک میگیریم و با حذف عنصر اول، متغیر Head به عنصر یا المان دوم اشاره خواهد کرد.
کلاس از پیش آمده صف در دات نت <Queue<T است و نحوهی استفاده آن بدین شکل است:
static void Main() { Queue<string> queue = new Queue<string>(); queue.Enqueue("Message One"); queue.Enqueue("Message Two"); queue.Enqueue("Message Three"); queue.Enqueue("Message Four"); while (queue.Count > 0) { string msg = queue.Dequeue(); Console.WriteLine(msg); } } //خروجی //Message One //Message Two //Message Thre //Message Four
برای بررسی ویژگیهای جاوا اسکریپت مدرن، یک پروژهی جدید React را ایجاد میکنیم.
> create-react-app sample-02 > cd sample-02 > npm start
به علاوه چون در این قسمت خروجی UI نخواهیم داشت، تمام خروجی را در کنسول developer tools مرورگر خود میتوانید مشاهده کنید (فشردن دکمهی F12).
var، let و const
در اکثر زبانهای برنامه نویسی، متغیرها در محدودهی دید قطعه کدی که تعریف شدهاند (scope)، قابل دسترسی هستند. برای نمونه محتوای فایل index.js پروژه را به صورت زیر تغییر داده و با فرض اجرای دستور npm start، خروجی آنرا میتوان در کنسول مرورگر مشاهده کرد.
function sayHello() { for (var i = 0; i < 5; i++) { console.log(i); } console.log(i); } sayHello();
در آخرین پیمایش حلقه، i مساوی 5 شده و از حلقه خارج میشود. اما چون در اینجا برای تعریف متغیر از واژهی کلیدی var استفاده شدهاست، محدودهی دید آن به کل تابعی که در آن تعریف شدهاست، بسط پیدا میکند. به همین جهت در این خروجی، عدد 5 را نیز مشاهده میکند که حاصل دسترسی به i، خارج از حلقهاست.
برای یک دست سازی این رفتار با سایر زبانهای برنامه نویسی، در ES6، واژهی کلیدی جدیدی به نام let تعریف شدهاست که میدان دید متغیر را به قطعه کدی که در آن تعریف شدهاست، محدود میکند. اکنون اگر در حلقهی فوق بجای var از let استفاده شود، یک چنین خطایی در مرورگر ظاهر خواهد شد که عنوان میکند، i استفاده شدهی در خارج از حلقه، تعریف نشدهاست.
./src/index.js Line 14:15: 'i' is not defined no-undef Search for the keywords to learn more about each error.
علاوه بر let، واژهی کلیدی جدید const نیز به ES6 اضافه شدهاست که از آن برای تعریف ثوابت استفاده میشود. constها نیز همانند let، میدان دید محدود شدهای به قطعه کد تعریف شدهی در آن دارند؛ اما قابلیت انتساب مجدد را ندارند:
const x = 1; x = 2; // Attempting to override 'x' which is a constant.
به صورت خلاصه از این پس واژهی کلیدی var را فراموش کنید. همیشه با const جهت تعریف متغیرها شروع کنید. اگر به خطا برخوردید و نیاز به انتساب مجدد وجود داشت، آنرا به let تغییر دهید. بنابراین استفاده از const همیشه نسبت به let ارجحیت دارد.
اشیاء در جاوا اسکریپت
اشیاء در جاوا اسکریپت به صورت مجموعهای از key/valueها تعریف میشوند:
const person = { name: "User 1", walk: function() {}, // method talk() {} // concise method };
const person = { name: "User 1", walk() {}, talk() {} };
person.talk(); person.name = "User 3"; person["name"] = "User 2";
مورد آخر همان روش استفاده از key/valueها است که اساس اشیاء جاوا اسکریپتی را تشکیل میدهد. البته از این روش فقط زمانی استفاده کنید که قرار است یکسری کار پویا صورت گیرند (مقدار key به صورت متغیر دریافت شود) و از ابتدا مشخص نیست که کدام خاصیت یا متد قرار است تعریف و استفاده شود:
const targetMember = "name"; person[targetMember] = "User 2";
واژهی کلیدی this در جاوا اسکریپت
از واژهی کلیدی this، در قسمتهای بعدی زیاد استفاده خواهیم کرد. به همین جهت نیاز است تفاوتهای اساسی آنرا با سایر زبانهای برنامه نویسی بررسی کنیم.
همان شیء person را که پیشتر تعریف کردیم درنظر بگیرید. در متد walk آن، مقدار this را لاگ میکنیم:
const person = { name: "User 1", walk() { console.log(this); }, talk() {} }; person.walk();
شیء this در جاوا اسکریپت، همانند سایر زبانهای برنامه نویسی مانند سیشارپ و یا جاوا رفتار نمیکند. در سایر زبانهای نامبرده شده، this همواره ارجاعی را به وهلهای از شیء جاری، باز میگرداند؛ دقیقا همانند تصویری که در بالا مشاهده میکنید. در اینجا نیز this جاوا اسکریپتی لاگ شده، ارجاعی را به وهلهی جاری شیء person، بازگشت دادهاست. اما مشکل اینجا است که this در جاوا اسکریپت، همیشه به این صورت رفتار نمیکند!
برای نمونه در ادامه یک ثابت را به نام walk تعریف کرده و آنرا به person.walk مقدار دهی میکنیم:
const walk = person.walk; console.log(walk);
سؤال: اکنون اگر این function را با فراخوانی ()walk اجرا کنیم، چه خروجی را میتوان مشاهده کرد؟
اینبار this لاگ شده، به شیء person اشاره نمیکند و شیء استاندارد window مرورگر را بازگشت دادهاست!
اگر یک function به صورت متدی از یک شیء فراخوانی شود، مقدار this همواره اشارهگری به وهلهای از آن شیء خواهد بود. اما اگر این تابع به صورت متکی به خود و به صورت یک function و نه متد یک شیء، فراخوانی شود، اینبار this، شیء سراسری جاوا اسکریپت یا همان شیء window را بازگشت میدهد.
یک نکته: اگر strict mode جاوا اسکریپت را در پروژهی جاری فعال کنیم، بجای شیء window، مقدار undefined را در خروجی فوق شاهد خواهیم بود.
اتصال مجدد this به شیء اصلی در جاوا اسکریپت
تا اینجا دریافتیم که اگر یک function را به صورت متکی به خود و نه جزئی از یک شیء فراخوانی کنیم، شیء this در این حالت به شیء window سراسری مرورگر اشاره میکند و اگر strict mode فعال باشد، فقط undefined را بازگشت میهد. اکنون میخواهیم بررسی کنیم که چگونه میتوان این مشکل را برطرف کرد؛ یعنی صرفنظر از نحوهی فراخوانی متدها یا تابعها، this همواره ارجاعی را به شیء person بازگشت دهد.
در جاوا اسکریپت، تابعها نیز شیء هستند. برای مثال person.walk نوشته شده نیز یک شیء است. برای اثبات سادهی آن فقط یک دات را پس از person.walk قرار دهید:
همانطور که مشاهده میکنید، شیء person.walk مانند تمام اشیاء دیگر جاوا اسکریپت، به همراه متد bind نیز هست. کار آن، انقیاد یک تابع، به یک شیء است. یعنی هرچیزی را که به عنوان آرگومان آن، به آن ارسال کنیم، به عنوان مقدار شیء this درنظر میگیرد:
const walk2 = person.walk.bind(person); console.log(walk2); walk2();
Arrow functions
تابع زیر را درنظر بگیرید که به یک ثابت انتساب داده شدهاست:
const square = function(number) { return number * number; };
const square2 = (number) => { return number * number; };
const square2 = number => { return number * number; };
در ادامه اگر بدنهی این تابع، فقط حاوی یک return بود، میتوان آنرا به صورت زیر نیز خلاصه کرد (در اینجا {} به همراه واژهی کلیدی return حذف میشوند):
const square3 = number => number * number; console.log(square3(5));
اکنون مثال مفید دیگری را در مورد Arrow functions بررسی میکنیم که بیشتر شبیه به عبارات LINQ در #C است:
const jobs = [ { id: 1, isActive: true }, { id: 2, isActive: true }, { id: 3, isActive: true }, { id: 4, isActive: true }, { id: 5, isActive: false } ];
var activeJobs = jobs.filter(function(job) { return job.isActive; });
در ادامه میتوان این تابع را توسط arrow functions به صورت سادهتر زیر نیز نوشت:
var activeJobs2 = jobs.filter(job => job.isActive);
ارتباط بین arrow functions و شیء this
نکتهی مهمی را که باید در مورد arrow functions دانست این است که شیء this را rebind نمیکنند (rebind: مقدار دهی مجدد؛ ریست کردن).
در مثال زیر، ابتدا شیء user با متد talk که در آن شیء this، لاگ شده، ایجاد شده و سپس این متد فراخوانی گردیدهاست:
const user = { name: "User 1", talk() { console.log(this); } }; user.talk();
اکنون اگر متد لاگ کردن را داخل یک تایمر قرار دهیم چه اتفاقی رخ میدهد؟
const user = { name: "User 1", talk() { setTimeout(function() { console.log(this); }, 1000); } }; user.talk();
در این حالت خروجی console.log، مجددا همان شیء سراسری window مرورگر است و دیگر به وهلهی جاری شیء user اشاره نمیکند. علت اینجا است که پارامتر اول متد setTimeout که یک callback function نام دارد، جزئی از هیچ شیءای نیست. بنابراین دیگر مانند فراخوانی متد ()user.talk در مثال قبلی کار نمیکند؛ چون متکی به خود است. هر زمان که یک متد متکی به خود غیر وابستهی به یک شیء را اجرا کنیم، به صورت پیشفرض this آن، به شیء window مرورگر اشاره میکند.
سؤال: چگونه میتوان درون یک callback function متکی به خود، به this همان شیء user جاری دسترسی یافت؟
یک روش حل این مساله، ذخیره this شیء user در یک متغیر و سپس ارسال آن به متد متکی به خود setTimeout است:
const user2 = { name: "User 2", talk() { var self = this; setTimeout(function() { console.log(self); }, 1000); } }; user2.talk();
const user3 = { name: "User 3", talk() { setTimeout(() => console.log(this), 1000); } }; user3.talk();
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: sample-02.zip
در قسمت بعد نیز بررسی پیشنیازهای جاوا اسکریپتی شروع به کار با React را ادامه خواهیم داد.
از متدهای همزمان متداول برای انجام امور ذیل استفاده نمائید:
- جهت پردازش اعمالی ساده و سریع
- اعمال مدنظر بیشتر قرار است بر روی CPU اجرا شوند و از مرزهای IO سیستم عبور نمیکنند.
و از متدهای غیرهمزمان برای پردازش موارد زیر کمک بگیرید:
- از وب سرویسهایی استفاده میکنید که متدهای نگارش async را نیز ارائه دادهاند.
- عمل مدنظر network-bound و یا I/O-bound است بجای CPU-bound. یعنی از مرزهای IO سیستم عبور میکند.
- نیاز است چندین عملیات را به موازات هم اجرا کرد.
- نیاز است مکانیزمی را جهت لغو یک عملیات طولانی ارائه دهید.
مزایای استفاده از متدهای async در ASP.NET
استفاده از await در ASP.NET، ساختار ذاتی پروتکل HTTP را که اساسا یک synchronous protocol، تغییر نمیدهد. کلاینت، درخواستی را ارسال میکند و باید تا زمان آماده شدن نتیجه و بازگشت آن از طرف سرور، صبر کند. نحوهی تهیهی این نتیجه، خواه async باشد و یا حتی همزمان، از دید مصرف کننده کاملا مخفی است. اکنون سؤال اینجا است که چرا باید از متدهای async استفاده کرد؟
- پردازش موازی: میتوان چند Task را مثلا توسط Task.WhenAll به صورت موازی با هم پردازش کرده و در نهایت نتیجه را سریعتر به مصرف کننده بازگشت داد. اما باید دقت داشت که این Taskها اگر I/O bound باشند، ارزش پردازش موازی را دارند و اگر compute bound باشند (اعمال محاسباتی)، صرفا یک سری ترد را ایجاد و مصرف کردهاید که میتوانستهاند به سایر درخواستهای رسیده پاسخ دهند.
- خالی کردن تردهای در حال انتظار: در اعمالی که disk I/O و یا network I/O دارند، پردازش موازی و اعمال async به شدت مقیاس پذیری سیستم را بالا میبرند. به این ترتیب worker thread جاری (که تعداد آنها محدود است)، سریعتر آزاد شده و به worker pool بازگشت داده میشود تا بتواند به یک درخواست دیگر رسیده سرویس دهد. در این حالت میتوان با منابع کمتری، درخواستهای بیشتری را پردازش کرد.
ایجاد Asynchronous HTTP Handlers در ASP.Net 4.5
در نگارشهای پیش از دات نت 4.5، برای نوشتن فایلهای ashx غیرهمزمان میبایستی اینترفیس IHttpAsynchHandler پیاده سازی میشد که نحوهی کار با آن از مدل APM پیروی میکرد؛ نیاز به استفاده از یک سری callback داشت و این عملیات باید طی دو متد پردازش میشد. اما در دات نت 4.5 و با معرفی امکانات async و await، نگارش سازگاری با پیاده سازی کلاس پایه HttpTaskAsyncHandler فراهم شده است.
برای آزمایش آن، یک برنامهی جدید ASP.NET Web forms نگارش 4.5 یا بالاتر را ایجاد کنید. سپس از منوی پروژه، گزینهی Add new item یک Generic handler به نام LogRequestHandler.ashx را به پروژه اضافه نمائید.
زمانیکه این فایل به پروژه اضافه میشود، یک چنین امضایی را دارد:
public class LogRequestHandler : IHttpHandler
using System; using System.Net; using System.Text; using System.Threading.Tasks; using System.Web; namespace Async14 { public class LogRequestHandler : HttpTaskAsyncHandler { public override async Task ProcessRequestAsync(HttpContext context) { string url = context.Request.QueryString["rssfeedURL"]; if (string.IsNullOrWhiteSpace(url)) { context.Response.Write("Rss feed URL is not provided"); } using (var webClient = new WebClient {Encoding = Encoding.UTF8}) { webClient.Headers.Add("User-Agent", "LogRequestHandler 1.0"); var rssfeed = await webClient.DownloadStringTaskAsync(url); context.Response.Write(rssfeed); } } public override bool IsReusable { get { return true; } } public override void ProcessRequest(HttpContext context) { throw new Exception("The ProcessRequest method has no implementation."); } } }
در این مثال آدرس یک فید RSS از طریق کوئری استرینگ rssfeedURL دریافت شده و سپس محتوای آن به کمک متد DownloadStringTaskAsync دریافت و بازگشت داده میشود.
برای آزمایش آن، مسیر ذیل را درخواست دهید:
http://localhost:4207/LogRequestHandler.ashx?rssfeedURL=https://www.dntips.ir/feed/latestchanges
صفحات async در ASP.NET 4.5
در قسمتهای قبل مشاهده کردیم که در برنامههای دسکتاپ، به سادگی میتوان امضای روالهای رخداد گردان را به async تغییر داد و ... برنامه کار میکند. به علاوه از مزیت استفاده از واژه کلیدی await نیز در آنها برخوردار خواهیم شد. اما ... هرچند این روش در وب فرمها نیز صادق است (مثلا public void Page_Load را به public async void Page_Load میتوان تبدیل کرد) اما اعضای تیم ASP.NET آنرا در مورد برنامههای وب فرم توصیه نمیکنند:
Async void event handlers تنها در مورد تعداد کمی از روالهای رخدادگردان ASP.NET Web forms کار میکنند و از آنها تنها برای تدارک پردازشهای ساده میتوان استفاده کرد. اگر کار در حال انجام اندکی پیچیدگی دارد، «باید» از PageAsyncTask استفاده نمائید. علت اینجا است که Async void یعنی fire and forget (کاری را شروع کرده و فراموشش کنید). این روش در برنامههای دسکتاپ کار میکند، زیرا این برنامهها مدل طول عمر متفاوتی داشته و تا زمانیکه برنامه از طرف OS خاتمه نیابد، مشکلی نخواهند داشت. اما برنامههای بدون حالت وب متفاوتند. اگر عملیات async پس از خاتمهی طول عمر صفحه پایان یابد، دیگر نمیتوان اطلاعات صحیحی را به کاربر ارائه داد. بنابراین تا حد ممکن از تعاریف async void در برنامههای وب خودداری کنید.
تبدیل روالهای رخدادگردان متداول وب فرمها به نسخهی async شامل دو مرحله است:
الف) از متد جدید RegisterAsyncTask که در کلاس پایه Page قرار دارد برای تعریف یک PageAsyncTask استفاده کنید:
using System; using System.Net; using System.Text; using System.Threading.Tasks; using System.Web.UI; namespace Async14 { public partial class _default : Page { protected void Page_Load(object sender, EventArgs e) { RegisterAsyncTask(new PageAsyncTask(LoadSomeData)); } public async Task LoadSomeData() { using (var webClient = new WebClient { Encoding = Encoding.UTF8 }) { webClient.Headers.Add("User-Agent", "LogRequest 1.0"); var rssfeed = await webClient.DownloadStringTaskAsync("url"); //listcontacts.DataSource = rssfeed; } } } }
ب) سپس در کدهای فایل aspx، نیاز است خاصیت async را نیز true نمائید:
<%@ Page Language="C#" AutoEventWireup="true" Async="true" CodeBehind="default.aspx.cs" Inherits="Async14._default" %>
تغییر تنظیمات IIS برای بهره بردن از پردازشهای Async
اگر از ویندوزهای 7، ویستا و یا 8 استفاده میکنید، IIS آنها به صورت پیش فرض به 10 درخواست همزمان محدود است.
بنابراین تنظیمات ذیل مرتبط است به یک ویندوز سرور و نه یک work station :
به IIS manager مراجعه کنید. سپس برگهی Application Pools آنرا باز کرده و بر روی Application pool برنامه خود کلیک راست نمائید. در اینجا گزینهی Advanced Settings را انتخاب کنید. در آن Queue Length را به مثلا عدد 5000 تغییر دهید. همچنین در دات نت 4.5 عدد 5000 برای MaxConcurrentRequestsPerCPU نیز مناسب است. به علاوه عدد connectionManagement/maxconnection را نیز به 12 برابر تعداد هستههای موجود تغییر دهید.
LocalDB چیست؟
LocalDB نسخهای جدید از Sql server express است که به توسعه دهندگان این اجازه را میدهد تا با نصب آن، از نصب کامل دیگر نسخههای Sql server جلوگیری نمایند. LocalDB برای برنامههایی که به صورت Local و بر روی یک سیستم اجرا میشوند مورد استفاده قرار میگیرد.
مزایای استفاده از این نسخه
- فایل نصب با حجم بسیار کم. (28.2MB برای نسخه 32 بیتی و 33.7MB برای نسخه 64بیتی)
- سادگی ( بدون نیاز به انجام تنظیمات خاص بر روی سیستم)
- اجرا در محیطهایی که کاربر جاری دسترسی مدیریتی ندارد.(برای اجرای آن نیاز به Permissionهای مدیریتی نیست و یک کاربر سطح پایین هم میتواند آن را اجرا کند)
- سادگی نصب
- همانند Sql server Express سازگاری کاملی با T-Sql دارد. همچنین از Stored Procedureها ، دادههای جغرافیایی و مکانی ( geometry and geography ها) ، Triggers و Viewها پشتیبانی میکند.
- سازگاری با Provider معمولی Sql server
- عدم اجرای سرویس خاصی در حافظه برای مدیریت دیتابیس. پروسسهای LocalDb هر زمان که نیاز باشد اجرا میشوند و هر زمان که به آنها نیاز نداشته باشیم به صورت اتوماتیک متوقف میشوند.
- پشتیبانی از خصوصیت AttachDbFileName در کانکشن استرینگ جهت استفاده از فایل بانک اطلاعات به صورت مستقیم
- سرویس پکهای جدید جهت LocalDB به راحتی برروی نسخه موجود نصب میشوند و نسخه قبلی را به روز رسانی میکنند.
- نصب یک LocalDB برای همه کاربران یک کامپیوتر
- پشتیبانی کامل از Silent Installation
- امکان استفاده از آن توسط Asp.net
- پشتیبانی از XML (XQuery و XPath) و BLOB
- پشتیبانی از Ado.net sync framework
- پشتیبانی از LINQ
- پشتیبانی از Distributed transactions
- کانکشنهای نامحدود (البته به صورت Local)
- نیاز به نصب Sql server 2012 native client . این مورد به همراه LocalDB روی سیستم نصب نمیشود
- نیاز به دسترسی مدیریتی جهت نصب
- 140MB فضای خالی دیسک سخت
- به روز رسانی دات نت فریم ورک 4 به 4.0.2 و یا نسخههای بالاتر
- عدم پشتیبانی از Windows xp ، Window server 2003 و Windows 2000
- عدم امکان نصب نسخه 32 بیتی بر روی ویندوز 64 بیتی (حتما باید نسخه 64 بیتی آن را نصب کنید)
- فقط میتوان به صورت Local از آن استفاده کرد. امکان استفاده تحت شبکه وجود ندارد و فقط به کانکشنهای Local پاسخ میدهد.
- فقط توسط Sql server 2012 management studio در دسترس میباشد. LocalDB را نمیتوان از طریق Management studioهای قدیمی مدیریت کرد.
- عدم پشتیبانی Visual Studio 2010 از LocalDB
- عدم اجرا بر روی موبایلهای هوشمند
- محدودیت سایز بانک اطلاعات : 10GB
- عدم پشتیبانی از قابلیت FileStream
- محدودیت استفاده از فقط یک CPU
- عدم امکان Debuging دستورات Sql در هنگام اتصال به LocalDB
نحوه اتصال به LocalDB توسط Sql Server Management Studio
اگر net framework. خود را از نسخه 4 به 4.0.2 و یا نسخههای بعد از آن به روز رسانی کرده باشید میتوان توسط Sql Server 2012 Management Studio به Sql server LocalDB وصل شد. عبارت local)\v11.0) را به عنوان نام سرور وارد نمایید.
مجددا لازم به ذکر است که امکان اتصال توسط Management Studioهای قبلی به بانک LocalDB امکان پذیر نمیباشد.