پروتکل (Hyper Text Transfer Protocol (HTTP (انتقال فوق متن) پروتکلی است که وظیفه انتقال (ارسال و دریافت) دادهها بین کلاینت و سرور را بر عهده دارد. منظور از کلاینت مرورگر وب و منظور از سرور یک وب سایت اینترنتی است. در واقع پروتکل انتقال ابر متن زبان مشترک بین سرویس دهندگان و سرویس گیرندگان وب است و شامل مجموعه ای از قوانین است که برای انتقال انواع فایلها مثل صدا، متن، عکس و... برای انتقال در شبکه وب استفاده میشود.
مستند لینک بالا مزیتها و بهینه سازی هایی که در پروتکل HTTP2 نسبت به نسخه قبل از آن انجام شده است را مورد بررسی قرار میدهد.
لینکهای هفته دوم دی
وبلاگها ، سایتها و مقالات ایرانی (داخل و خارج از ایران)
- شیوهنامه فارسیپسند گوگلخوان، نسخه ۰.۱.۱ (کار جالبی است. آشنایی با افزونه استایلیش)
ASP. Net
طراحی و توسعه وب
PHP
اسکیوال سرور
سی شارپ
SharePoint
عمومی دات نت
ویندوز
مسایل اجتماعی و انسانی برنامه نویسی
متفرقه
- آشنایی با لولههای یاهو و همچنین نمونهای دیگر
استفاده از StructureMap به عنوان یک IoC Container
دریافت StructureMap
برای دریافت آن نیاز است دستور پاورشل ذیل را در کنسول نیوگت ویژوال استودیو فراخوانی کنید:
PM> Install-Package structuremap
آشنایی با ساختار برنامه
ابتدا یک برنامه کنسول را آغاز کرده و سپس یک Class library جدید را به نام Services نیز به آن اضافه کنید. در ادامه کلاسها و اینترفیسهای زیر را به Class library ایجاد شده، اضافه کنید. سپس از طریق نیوگت به روشی که گفته شد، StructureMap را به پروژه اصلی (ونه پروژه Class library) اضافه نمائید و Target framework آنرا نیز در حالت Full قرار دهید بجای حالت Client profile.
namespace DI03.Services { public interface IUsersService { string GetUserEmail(int userId); } } namespace DI03.Services { public interface IEmailsService { void SendEmailToUser(int userId, string subject, string body); } } using System; namespace DI03.Services { public class UsersService : IUsersService { public UsersService() { //هدف صرفا نمایش وهله سازی خودکار این وابستگی است Console.WriteLine("UsersService ctor."); } public string GetUserEmail(int userId) { //برای مثال دریافت از بانک اطلاعاتی و بازگشت یک نمونه جهت آزمایش برنامه return "name@site.com"; } } } using System; namespace DI03.Services { public class EmailsService: IEmailsService { private readonly IUsersService _usersService; public EmailsService(IUsersService usersService) { Console.WriteLine("EmailsService ctor."); _usersService = usersService; } public void SendEmailToUser(int userId, string subject, string body) { var email = _usersService.GetUserEmail(userId); Console.WriteLine("SendEmailTo({0})", email); } } }
سرویس کاربران بر اساس آی دی یک کاربر، برای مثال از بانک اطلاعاتی ایمیل او را بازگشت میدهد. سرویس ارسال ایمیل، نیاز به ایمیل کاربری برای ارسال ایمیلی به او دارد. بنابراین وابستگی مورد نیاز خود را از طریق تزریق وابستگیها در سازنده کلاس و وهله سازی شده در خارج از آن (معکوس سازی کنترل)، دریافت میکند.
در سازندههای هر دو کلاس سرویس نیز از Console.WriteLine استفاده شدهاست تا زمان وهله سازی خودکار آنها را بتوان بهتر مشاهده کرد.
نکته مهمی که در اینجا وجود دارد، بیخبری لایه سرویس از وجود IoC Container مورد استفاده است.
استفاده از لایه سرویس و تزریق وابستگیها به کمک StructureMap
using DI03.Services; using StructureMap; namespace DI03 { class Program { static void Main(string[] args) { // تنظیمات اولیه برنامه که فقط یکبار باید در طول عمر برنامه انجام شود ObjectFactory.Initialize(x => { x.For<IEmailsService>().Use<EmailsService>(); x.For<IUsersService>().Use<UsersService>(); }); //نمونهای از نحوه استفاده از تزریق وابستگیهای خودکار var emailsService = ObjectFactory.GetInstance<IEmailsService>(); emailsService.SendEmailToUser(userId: 1, subject: "Test", body: "Hello!"); } } }
به این ترتیب IoC Container ما زمانیکه قرار است object graph مربوط به IEmailsService درخواستی را تشکیل دهد، خواهد دانست ابتدا به سازندهی کلاس EmailsService میرسد. در اینجا برای وهله سازی این کلاس به صورت خودکار، باید وابستگیهای آنرا نیز وهله سازی کند. بنابراین بر اساس تنظیمات آغازین برنامه میداند که باید از کلاس UsersService برای تزریق خودکار وابستگیها در سازنده کلاس ارسال ایمیل استفاده نماید.
در این حالت اگر برنامه را اجرا کنیم، به خروجی زیر خواهیم رسید:
UsersService ctor. EmailsService ctor. SendEmailTo(name@site.com)
ابتداییترین مزیت استفاده از تزریق وابستگیها امکان تعویض آنها است؛ خصوصا در حین Unit testing. اگر کلاسی برای مثال قرار است با شبکه کار کند، میتوان پیاده سازی آنرا با یک نمونه اصطلاحا Fake جایگزین کرد و در این نمونه تنها نتیجهی کار را بازگشت داد. کلاسهای لایه سرویس ما تنها با اینترفیسها کار میکنند. این تنظیمات قابل تغییر اولیه IoC container مورد استفاده هستند که مشخص میکنند چه کلاسهایی باید در سازندههای کلاسها تزریق شوند.
تعیین طول عمر اشیاء در StructureMap
برای اینکه بتوان طول عمر اشیاء را بهتر توضیح داد، کلاس سرویس کاربران را به نحو زیر تغییر دهید:
using System; namespace DI03.Services { public class UsersService : IUsersService { private int _i; public UsersService() { //هدف صرفا نمایش وهله سازی خودکار این وابستگی است Console.WriteLine("UsersService ctor."); } public string GetUserEmail(int userId) { _i++; Console.WriteLine("i:{0}", _i); //برای مثال دریافت از بانک اطلاعاتی و بازگشت یک نمونه جهت آزمایش برنامه return "name@site.com"; } } }
//نمونهای از نحوه استفاده از تزریق وابستگیهای خودکار var emailsService1 = ObjectFactory.GetInstance<IEmailsService>(); emailsService1.SendEmailToUser(userId: 1, subject: "Test1", body: "Hello!"); var emailsService2 = ObjectFactory.GetInstance<IEmailsService>(); emailsService2.SendEmailToUser(userId: 1, subject: "Test2", body: "Hello!");
UsersService ctor. EmailsService ctor. i:1 SendEmailTo(name@site.com) UsersService ctor. EmailsService ctor. i:1 SendEmailTo(name@site.com)
اگر به هر دلیلی نیاز بود تا این رویه تغییر کند، میتوان بر روی طول عمر اشیاء تشکیل شده نیز تاثیر گذار بود. برای مثال تنظیمات آغازین برنامه را به نحو ذیل تغییر دهید:
// تنظیمات اولیه برنامه که فقط یکبار باید در طول عمر برنامه انجام شود ObjectFactory.Initialize(x => { x.For<IEmailsService>().Use<EmailsService>(); x.For<IUsersService>().Singleton().Use<UsersService>(); });
UsersService ctor. EmailsService ctor. i:1 SendEmailTo(name@site.com) EmailsService ctor. i:2 SendEmailTo(name@site.com)
حالتهای دیگر تعیین طول عمر مطابق متدهای زیر هستند:
Singleton() HttpContextScoped() HybridHttpOrThreadLocalScoped()
در حالت ThreadLocal، به ازای هر Thread، وهلهای متفاوت در اختیار مصرف کننده قرار میگیرد.
حالت Hybrid ترکیبی است از حالتهای HttpContext و ThreadLocal. اگر برنامه وب بود، از HttpContext استفاده خواهد کرد در غیراینصورت به ThreadLocal سوئیچ میکند.
شاید بپرسید که کاربرد مثلا HttpContextScoped در کجا است؟
در یک برنامه وب نیاز است تا یک وهله از DbContext (مثلا Entity framework) را در اختیار کلاسهای مختلف لایه سرویس قرار داد. به این ترتیب چون هربار new Context صورت نمیگیرد، هربار هم اتصال جداگانهای به بانک اطلاعاتی باز نخواهد شد. نتیجه آن رسیدن به یک برنامه سریع، با سربار کم و همچنین کار کردن در یک تراکنش واحد است. چون هربار فراخوانی new Context به معنای ایجاد یک تراکنش جدید است.
همچنین در این برنامه وب قصد نداریم از حالت طول عمر Singleton استفاده کنیم، چون در این حالت یک وهله از Context در اختیار تمام کاربران سایت قرار خواهد گرفت (و DbContext به صورت Thread safe طراحی نشده است). نیاز است به ازای هر کاربر و به ازای طول عمر هر درخواست، تنها یکبار این وهله سازی صورت گیرد. بنابراین در این حالت استفاده از HttpContextScoped توصیه میشود. به این ترتیب در طول عمر کوتاه Object graphهای تشکیل شده، فقط یک وهله از DbContext ایجاد و استفاده خواهد شد که بسیار مقرون به صرفه است.
مزیت دیگر مشخص سازی طول عمر به نحو HttpContextScoped، امکان Dispose خودکار آن به صورت زیر است:
protected void Application_EndRequest(object sender, EventArgs e) { ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects(); }
تنظیمات خودکار اولیه در StructureMap
اگر نام اینترفیسهای شما فقط یک I در ابتدا بیشتر از نام کلاسهای متناظر با آنها دارد، مثلا مانند ITest و کلاس Test هستند؛ فقط کافی است از قراردادهای پیش فرض StructureMap برای اسکن یک یا چند اسمبلی استفاده کنیم:
// تنظیمات اولیه برنامه که فقط یکبار باید در طول عمر برنامه انجام شود ObjectFactory.Initialize(x => { //x.For<IEmailsService>().Use<EmailsService>(); //x.For<IUsersService>().Singleton().Use<UsersService>(); x.Scan(scan => { scan.AssemblyContainingType<IEmailsService>(); scan.WithDefaultConventions(); }); });
دریافت مثال قسمت جاری
DI03.zip
به روز شدهی این مثالها را بر اساس آخرین تغییرات وابستگیهای آنها از مخزن کد ذیل میتوانید دریافت کنید:
Dependency-Injection-Samples
معرفی DNTProfiler
کد برنامه را دریافت کردم و به روز رسانیهای لازم را انجام دادم. این خطا برطرف شده است. خیلی ممنون.
آیا این پروفایلر امکان دریافت درخواست هایی که از طریق سرویسهای wcf به پایگاه داده ارسال میشوند را هم دارد؟ یا میتواند داشته باشد؟ (البته این سوال صرفاً جنبهی تئوریک دارد.)
- آدرسهای مجازی به صورت پیوسته و پشت سر هم هستند و آدرس دهی بسیار راحت است ولی دادهها بر روی یک حافظه به صورت متصل به هم یا پیوسته ذخیره یا خوانده نمیشوند و کار آدرس دهی مشکل است. پس یکی از مزایای داشتن آدرس دهی مجازی پشت سر هم قرار گرفتن آدرس هاست.
- برنامه از آدرسهای مجازی برای دسترسی به بافر حافظه استفاده میکند که بزرگتر از حافظه فیزیکی موجود هست. موقعی که نیاز به حافظه بیشتر باشد و حافظه سیستم کوچکتر یا کمتر از تقاضا باشد، مدیر حافظه، صفحات حافظه فیزیکی را به صورت یک فایل (عموما 4 کیلیویی) بر روی دیسک سخت ذخیره میکند و صفحات دادهها در موقع نیاز بین حافظه فیزیکی و دیسک سخت جابجا میشود.
- هر پردازشی که بر روی آدرسهای مجازی کار میکند ایزوله شده است. یعنی یک پروسه هیچ گاه نمیتواند به آدرسهای یک پروسه دیگر دسترسی داشته باشد و باعث تخریب دادههای آن شود.
در شکل بالا دو پروسه 64 بیتی به نامهای notepad.exe و myapp.exe قرار دارند که هر کدام فضای آدرسهای مجازی خودشان را دارند و از آدرس 0x000'0000000 شروع و تا آدرس 0x7FF'FFFFFFFF ادامه میابند. هر قسمت شامل یک صفحه 4 کیلویی از حافظه مجازی یا فیزیکی است. به برنامه نوتپد دقت کنید که از سه صفحه پشت سر هم یا پیوسته تشکیل شده که آدرس شروع آن 0x7F7'93950000 می باشد ولی در حافظه فیزیکی خبری از پیوسته بودن دیده نمیشود و حتما این نکته را متوجه شدید که هر دو پروسه از یک آدرس شروع استفاده کردهاند، ولی به آدرسی متفاوت از حافظه فیزیکی نگاشت شده اند.
فضای کاربری و فضای سیستمی User space and system space
گفتیم بسیاری از پروسهها در حالت user mode و پروسههای هسته سیستم عامل و درایورها در حالت kernel mode اجرا میشوند. هر پروسه مد کاربر از فضای آدرس دهی مجازی خودش استفاده میکند ولی در حالت کرنل همه از یک فضای آدرس دهی استفاده میکنند که به آن فضای سیستمی میگویند و برای مد کاربری میگویند فضای کاربری.
در سیستمهای 32 بیتی نهایتا تا 4 گیگ حافظه میتوان به اینها تخصیص داد؛ 2 گیگ ابتدایی به user space و دو گیگ بعدی به system space :
در ویندوزهای 32 بیتی شما امکان تغییر این مقدار حافظه را در میان بوت دارید و میتوانید حافظه کاربری را تا 3 گیگ مشخص کنید و یک گیگ را برای فضای سیستمی. برای اینکار میتوانید از برنامه bcedit استفاده کنید.
در سیستمهای 64 بیتی میزان حافظههای مجازی به صورت تئوری تا 16 اگزابایت مشخص شده است؛ ولی در عمل تنها بخش کوچکی از آن یعنی 8 ترابایت استفاده میشود.
- برنامه جهت اجرا در مد کاربر یک درخواست را برای خواندن دادههای یک device را آماده میکند. سپس برنامه آدرس شروع یک بافر را برای دریافت داده، مشخص میکند.
- وظیفه این درایور یک قطعه در مد کرنل این است که عملیات خواندن را شروع کرده و کنترل را به درخواست کننده ارسال میکند.
- بعد device یک وقفه را به هر تردی thread که در حال اجراست ارسال میکند تا بگوید، عملیات خواندن پایان یافته است. این وقفه توسط ترد درایور مربوطه دریافت میشود.
- حالا دیگر درایور نباید دادهها را در همان جایی که گام اول برنامه مشخص کرده است ذخیره کند. چون این آدرس که برنامه در مد کاربری مشخص کرده است، با نمونهای که این فرآیند محاسبه میکند متفاوت است.
درس خوندن، ارزشش رو داره؟
تعریف Interaction Design در زبان طراحی، تعامل انسان و کامپیوتر و توسعه نرمافزار اینگونه بیان میشود:
« عمل طراحی تعاملی محصولات دیجیتالی، محیطها، سیستمها و سرویسها. مانند سایر رشتههای طراحی، Interaction Design دارای شاخهها و توجهاتی است، اما به طور ساده میتوان گفت که تمرکز اصلی این رشته برروی رفتارها است.»
طراحی تعاملی یا Interaction Design که به اختصار به آن IxD نیز گفته میشود، بر روی ایجاد واسطهای کاربری جذاب با رفتارهای خوب تمرکز دارد. فهم این نکته که کاربران و تکنولوژی چگونه با یکدیگر ارتباط دارند، در این شاخه بسیار مهم و ضروری است. با این درک، شما میتوانید موارد زیر را پیشبینی نماید: اینکه چگونه یک فرد با سیستم تعامل دارد؟ چگونه مشکلات را با داشتن آن سیستم رفع میکند؟ و در نهایت با استفاده از این موارد راههای جدیدی برای توسعه سیستم، برای انجام کارها پیشنهاد دهید. در ادامه به بررسی Best Practice های Interaction Design خواهیم پرداخت.
بهترین روشهای طراحی تعاملی ( Interaction Design )
در هنگام طراحی و توسعه یک محصول نرمافزاری با المانهای تعاملی، ویژگیها و سوالات مطرح شدهی زیر را در نظر بگیرید:
سوالات مهم در هنگام لحاظ کردن طراحی تعاملگرا
کاربران به چه صورتهایی میتوانند با واسط کاربری در ارتباط باشند | - کاربر چه تعاملاتی را میتواند به طور مستقیم با ماوس، انگشت یا stylus با واسط کاربری داشته باشد؟ - چه دستوراتی را کاربر میتواند صادر کند و با آنها تعامل داشته باشد که به طور مستقیم جزء محصول نیست؟ به عنوان مثال Ctrl+C که درون مرورگرها فعال است و جزئی از خود محصول نیست. |
دادن اطلاعاتی به کاربران، در مورد رفتارهای سیستم، پیش از انجام یک عمل | - ظاهر المانهای صفحه (رنگ، شکل، اندازه و ...) چه سرنخهایی را در مورد عملکرد آنها به کاربر خواهد داد؟ این المانها به کاربر میفهماند که چگونه باید از آنها استفاده کند. - شما چه اطلاعاتی را میتوانید در المانها بگنجانید که کاربر پیش از انجام یک عملیات از عملکرد آن المان مطلع شود؟ این مفاهیم میتوانند با گنجاندن label های با معنا در دکمهها، یا دستورالعملهای بسیار کوتاه برای تاییدیههای نهایی کامل شود. |
پیشبینی و کاهش خطاها | - آیا پیامهای خطا، راه روشنی را برای کاربر باز میکند تا بتواند مشکل کار خود را پیدا کند و منشا خطا را کشف نماید؟ - آیا در برخی موارد فشار و اجبار ( Constraint ) برای تحمیل عملیاتی خاص به کاربر جهت جلوگیری از خطا وجود دارد؟ اصل Poka-Yoka میگوید برای جلوگیری از سردرگمی کاربر و همچنین جلوگیری از خطاهای ممکن، در برخی موارد لازم است که کاربر را در محدودهای خاص و در یک مسیر مشخص (مانند مراحل تکمیل یک فرم) نگه داریم. این ایجاد فشار هم به کاربر کمک میکند و هم به تیم توسعه. |
در نظر گرفتن فیدبک و زمان پاسخ سیستم | - چگونه قرار است که به کاربر بازخورد بدهیم که پروسهای در حال اجرا است؟ هنگامیکه کاربر درگیر انجام عملیاتی است، سیستم باید متعاقبا یک پاسخ را برای کاربر نمایش دهد و چه بهتر که کاربر را در حین انجام پروسه (اگر پروسه طولانی باشد، مثلا بیش از 30 ثانیه) از آنچه که در سمت سرور صورت میگیرد آگاه سازد. این فرآیندها را میتوان با یک progress bar ساده مدل کرد. - بین یک عمل و پاسخ آن چه مدت زمانی طول خواهد کشید؟ واکنش پاسخ را میتوان در چهار سطح مشخص نمود: فوری یا immediate (کمتر از 0.1 ثانیه)، کند یا stammer (بین 0.1 تا 1 ثانیه)، وقفه یا interruption (بین 1 تا 10 ثانیه) و اختلال یا disruption (بیش از 10 ثانیه). |
نگاه استراتژیک دربارهی هر یک از عناصر درون صفحه | - آیا عناصر واسط کاربری اندازهی معقولی برای تعامل با کاربر دارند؟ عناصری مانند دکمهها، باید به اندازه کافی بزرگ باشند تا کاربر بتواند بر روی آنها کلیک کند. اما یک طراح نباید این نگاه را تنها به یک مرورگر منتهی کند. عمدهی مشکل در دستگاههای قابل حمل، مثل موبایلها و تبلتها رخ میدهد. - آیا لبهها و گوشهها (فضاهای خالی) به خوبی برای گنجاندن عناصر تعاملی مانند منوها استفاده شدهاند؟ یک قانون مهم در این زمینه میگوید که لبهها و گوشهها و نواحی مرزی، نواحی خوبی برای قرارگیری عناصر هستند. زیرا این نواحی معمولا نواحی مرزی هستند و کاربر به راحتی میتواند بر روی آنها کلیک و یا آنها را لمس نماید. - آیا شما از استانداردها پیروی میکنید؟ بالاخره کاربران آنقدرها هم بیاطلاع نیستند. آنها کمی هم دربارهی اینکه یک رابط کاربری چگونه است و عناصر آنها چگونه رفتار میکنند، اطلاعات دارد. پس، از این رو نیازی به خلق و بدعتگذاری نیست. تنها کافیاست اندکی از آنچه که در UX متداول شده، بهتر باشید. اگر روش شما بتواند خلاقانه و در عین حال ساده باشد، شما نیز میتوانید صاحب سبک شوید. |
سادهسازی برای افزایش سرعت یادگیری | - آیا اطلاعات مورد نیاز کاربر درون نرمافزار به هفت (به علاوه منهای دو) تکه تقسیم شدهاند؟ George Miller طی آزمایشاتی کشف کرد که افراد تنها قادرند پنج تا نه مورد را در حافظهی کوتاه مدت خود قرار دهند. - آیا واسط User End تا حد ممکن ساده شده است؟ قانون Tesler بیان میکند که شما باید سعی کنید که تمامی پیچیدگیها را تا آنجا که ممکن است از واسط User End حذف کنید. |
منابع:
نگاهی به گزینههای مختلف مهیای جهت میزبانی SignalR
1) OWIN
2) ASP.NET Hosting
3) Self Hosting
4) Cloud و ویندوز Azure
1) OWIN
اگر به اسمبلیهای همراه با SignalR دقت کنید، یکی از آنها Microsoft.AspNet.SignalR.Owin.dll نام دارد. OWIN مخفف Open web server interface for .NET است و کار آن ایجاد لایهای بین وب سرورها و برنامههای وب میباشد. یکی از اهداف مهم آن ترغیب دنیای سورس باز به تهیه ماژولهای مختلف قابل استفاده در وب سرورهای دات نتی است. نکتهی مهمی که در SignalR و کلیه میزبانهای آن وجود دارد، بنا شدن تمامی آنها برفراز OWIN میباشد.
2) ASP.NET Hosting
بدون شک، میزبانی ASP.NET از هابهای SignalR، مرسومترین روش استفاده از این فناوری میباشد. این نوع میزبانی نیز برفراز OWIN بنا شده است. نصب آن توسط اجرای دستور پاور شل ذیل در یک پروژه وب صورت میگیرد:
PM> Install-Package Microsoft.AspNet.SignalR
3) خود میزبانی یا Self hosting
خود میزبانی نیز برفراز OWIN تهیه شده است و برای پیاده سازی آن نیاز است وابستگیهای مرتبط با آن، از طریق NuGet به کمک فرامین پاور شل ذیل دریافت شوند:
PM> Install-Package Microsoft.AspNet.SignalR.Owin PM> Install-Package Microsoft.Owin.Hosting -Pre PM> Install-Package Microsoft.Owin.Host.HttpListener -Pre
مراحل تهیه یک برنامه ثالث (برای مثال خارج از IIS یا یک وب سرور آزمایشی) به عنوان میزبان Hubs مورد نیاز به این شرح هستند:
الف) کلاس آغازین میزبان باید با پیاده سازی اینترفیسی به نام IAppBuilder تهیه شود.
ب) مسیریابیهای مورد نیاز تعریف گردند.
ج) وب سرور HTTP یا HTTPS توکار برای سرویس دهی آغاز گردد.
باید توجه داشت که در این حالت برخلاف روش ASP.NET Hosting، سایر اسمبلیهای برنامه جهت یافتن Hubهای تعریف شده، اسکن نمیشوند. همچنین هنگام کار با jQuery مباحث عنوان شده در مورد تنظیم دسترسیهای Cross domain نیز باید در اینجا اعمال گردند. به علاوه اجرای وب سرور توکار آن به دلایل امنیتی، نیاز به دسترسی مدیریتی دارد.
برای پیاده سازی یک نمونه، به برنامهای که تاکنون تهیه کردهایم، یک پروژه کنسول دیگر را به نام ConsoleHost اضافه کنید. البته باید درنظر داشت در دنیای واقعی این نوع برنامهها را عموما از نوع سرویسهای ویندوز NT تهیه میکنند.
در ادامه سه فرمان پاور شل یاد شده را برای افزودن وابستگیهای مورد نیاز فراخوانی نمائید. همچنین باید دقت داشت که این دستور بر روی پروژه جدید اضافه شده باید اجرا گردد.
using System; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; using Microsoft.Owin.Hosting; using Owin; namespace SignalR02.ConsoleHost { public class Startup { public void Configuration(IAppBuilder app) { app.MapHubs(new HubConfiguration { EnableCrossDomain = true }); } } [HubName("chat")] public class ChatHub : Hub { public void SendMessage(string message) { var msg = string.Format("{0}:{1}", Context.ConnectionId, message); Clients.All.hello(msg); } } class Program { static void Main(string[] args) { using (WebApplication.Start<Startup>("http://localhost:1073/")) { Console.WriteLine("Press a key to terminate the server..."); Console.Read(); } } } }
سمت کلاینت استفاده از آن هیچ تفاوتی نمیکند و با جزئیات آن پیشتر آشنا شدهاید؛ برای مثال در کلاینت جیکوئری خاصیت connection.hub.url باید به مسیر جدید سرور هاب تنظیم گردد تا اتصالات به درستی برقرار شوند.
دریافت پروژه کامل مرتبط با این 4 قسمت (البته بدون فایلهای باینری آن، جهت کاهش حجم 32 مگابایتی)
SignalRSamples.zip
در این مقاله قصد دارم نحوه ساخت یک بات تلگرامی را با استفاده از 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 ساعت بر روی دامین خود تنظیم کنید.
توضیحات بیشتر در این مورد را مثلا دکمههای پویا و گرفتن عکس پروفایل و ....، در مقالهی بعدی قرار خواهم داد.
شما میتوانید از این لینک پروژه بالا را دریافت و اجرا کنید .