نظرات مطالب
استفاده از قابلیت Speech Recognition ویندوز 7 برای تولید زیرنویس انگلیسی
بله، ممکن است. ولی به دو دلیل من ترجیح می‌دم به این سمت نروم:
- این مقدار پهنای باند آپلود در اختیار ندارم. (اینترنت حجمی ...)
- خیلی از این مباحث کپی رایت دارند و نمی‌شود به همین سادگی این‌ها را عمومی کرد، تست کرد و غیره.
پاسخ به بازخورد‌های پروژه‌ها
استفاده از pdfreport برای اولین بار
سورس پروژه را دریافت کنید؛ از اینجا
داخل آن یک پوشه‌ی Samples هست که از برنامه‌های وب تا EF و دسکتاپ و غیره را پوشش می‌دهد.
مستندات آن در گروه PdfReport سایت ارائه شده و همچنین در راهنمای آن در سایت.
پاسخ به بازخورد‌های پروژه‌ها
نشان دادن گزارش قبل از ذخیره یا چاپ
سورس پروژه رو دریافت کنید.
بعد مراجعه کنید به پوشه مثال‌های آن. در اینجا می‌تونید مثال‌های نحوه نمایش فایل گزارش تهیه شده را در برنامه‌های WinForms، WPF، سیلورلایت، وب ASP.NET و غیره ملاحظه کنید.
+ توضیحات بیشتر
پاسخ به بازخورد‌های پروژه‌ها
ساده سازی استفاده
بله مواردی که شما فرمودید از اون دسته پیاده سازی هایی هست که میتونه برای مثال استفاده از کوکی و غیره رو با این پروژه ادغام کرد. البته همین طور که از اسم این پروژه مشخص هست صرفا یک هندلر برای تولید یک تصویر امنیتی و البته با شباهتی نزدیک به تصویر امنیتی سایت میباشد.
مطالب
سیستم‌های توزیع شده در NET. - بخش هشتم- راه اندازی Apache Kafka
در این بخش نحوه راه اندازی Apache Kafka را در Ubuntu مورد بررسی قرار می‌دهیم و می‌بینیم که هر یک از تعاریف و اصطلاحاتی که در بخش قبل معرفی شد، چگونه پیاده سازی می‌شوند (در صورتی که امکان استفاده از Ubuntu را ندارید و می‌خواهید مراحل این بخش را در windows انجام دهید می‌توانید از راهنمای راه اندازی Kafka در windows استفاده کنید تا بتوانید بخشهای بعدی این سری مقالات را پیگیری و اجرا کنید).

بروز رسانی Ubuntu:
قبل از هرچیزی باید مطمئن شوید که Ubuntu بصورت کامل بروز رسانی شده است. برای این کار یک ترمینال جدید را باز و دستورهای زیر را در آن وارد کنید:
sudo apt-get update -y
sudo apt-get upgrade -y
نصب java:
نکته:درصورتی که قبلا java را نصب کرده‌اید نیازی به انجام این مرحله نیست و برای اطمینان از نصب java می‌توانید دستور زیر را در خط فرمان terminal ایجاد شده وارد کنید:
sudo java -version
قبل از دانلود و نصب Apache Kafka، باید ابتدا java را نصب کنید. برای این کار دستور زیر را اجرا کنید:
sudo add-apt-repository -y ppa:webupd8team/java
باید خروجی زیر به شما نمایش داده شود:
gpg: keyring `/tmp/tmpkjrm4mnm/secring.gpg' created
gpg: keyring `/tmp/tmpkjrm4mnm/pubring.gpg' created
gpg: requesting key EEA14886 from hkp server keyserver.ubuntu.com
gpg: /tmp/tmpkjrm4mnm/trustdb.gpg: trustdb created
gpg: key EEA14886: public key "Launchpad VLC" imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK
برای بروز رسانی metadata‌های repository جدید باید دستور زیر را وارد کنید:
sudo apt-get update
و در پایان دستور زیر را برای نصب java اجرا کنید:
sudo apt-get install oracle-java8-installer -y
برای اطمینان از نصب java دستور زیر را وارد کنید:
sudo java -version
در صورتیکه خروجی زیر به شما نمایش داده شود به این معنا است که عملیات نصب java با موفقیت انجام شده‌است:
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)

                                            
دانلود Apache Kafka :
آخرین نگارش پایدار از Apache Kafka، نگارش 1.0.0 می‌باشد که می‌توانید آن را از طریق صفحه دریافت Apache Kafka ، دریافت کنید.

دانلود Apache Kafka


پس از دریافت Apache Kafka، از طریق یک terminal جدید وارد پوشه Downloads شوید. سپس فایل مورد نظر را از حالت فشرده خارج کنید و وارد پوشه اصلی آن شوید. برای این کار از دستورات زیر استفاده کنید:

tar -xzf kafka_2.11-1.0.0.tgz
cd kafka_2.11-1.0.0

 سپس با استفاده از دستور "ls " لیست تمامی فایلها و فولدر‌های موجود در فولدر kafka_2.11-1.0.0  و   را نمایش دهید:

در لیست نمایش داده شده دو فولد اصلی bin و config وجود دارند که به ترتیب فایلهای اجرایی و کانفیگهای پیشفرض و مورد نیاز، در آنها قرار دارند.


اجرای Apache ZooKeeper:

همانطور که در بخش قبل توضیح داده شد، Apache Kafka هیچ Stateی را در خود ذخیره و مدیریت نمی‌کند و اصطلاحا Stateless می‌باشد و مدیریت تمامی این Stateها را بر عهده  Apache ZooKeeper قرار می‌دهد. بنابراین قبل از اینکه بخواهیم Kafka را اجرا کنیم، ابتدا باید Apache ZooKeeper را اجرا کنیم. برای اجرای Apache ZooKeeper در terminalی که قبلا باز کرده‌اید، دستور زیر را اجرا کنید:

bin/zookeeper-server-start.sh config/zookeeper.properties

با اجرای فایل zookeeper-server-start.sh و ارسال کانفیگ پیشفرضش در فولدر config با نام  zookeeper.properties، قسمت مدیریت کننده Stateهای Kafka  اجرا می‌شود.


اجرای Apache Kafka:

پس از اجرای Apache ZooKeeper، باید یک terminal جدید را باز کنید و با استفاده از دستور زیر kafka-server را با استفاده از کانفیگ پیشفرضش اجرا کنید:

 bin/kafka-server-start.sh config/server.properties


به همین راحتی Kafka Server اجرا شده و آماده‌ی استفاده است. برای ادامه و نمایش دادن سایر قابلیت‌های Kafka باید یک Topic جدید را ایجاد کنیم.


ایجاد Topic:

همانطور که می‌دانید تمامی پیامهای شما در Partition‌های Topic ذخیره می‌شوند؛ پس قبل از اینکه بخواهیم توسط یک Producer پیامی را ارسال کنیم یا اینکه بخواهیم توسط Consumer پیامی را دریافت کنیم، ابتدا باید Topic مربوطه را ایجاد کنیم. بهترین و عمومی‌ترین مثال برای نمایش قابلیت‌های Publish-Subscribe در Kafka، مثال چت بین کاربران است که در آن یک کاربر به عنوان Producer عمل می‌کند و پیامهایی را برای سایر کاربران که نقش Consumer را دارند ارسال می‌کند. kafka-topics .sh در Kafka ابزاریست برای مدیریت Topic ها  که با استفاده از آن می‌توانید Topic‌های مورد نیاز را تعریف، ویرایش و یا حذف کنید.

یک terminal جدید را آغاز و با استفاده از دستور زیر یک Topic را با نام userChat ایجاد کنید:

bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic userChat

با این دستور یک Topic در Kafka با نام userChat ایجاد می‌شود و مشخصات آن (منظور stateهای مرتبط با آن است)، در zookeeper نیز ثبت می‌شود.


توضیحات Optionها و  آرگومانهایی که در دستور ایجاد Topic استفاده شدند به شرح زیر است:

create-- :

مشخص کننده این است که شما می‌خواهید یک Topic جدید را ایجاد کنید.

zookeeper localhost:2181--:

مشخص کننده آدرس سرور zookeeper است (سرور zookeeper بصورت پیشفرض از پورت 2181 استفاده می‌کند).

replication-factor 1--:

مشخص کننده این است که تنها یک کپی از این Topic در سرور ایجاد شود. البته در این مثال به دلیل اینکه تنها یک سرور از Kafka را اجرا کرده‌ایم در صورتیکه این مقدار را بیش از عدد 1 در نظر بگیریم، با خطا مواجه می‌شویم. 

partitions 1--

تعداد Partition‌های این Topic را مشخص می‌کند. مقدار Partition در حالتیکه حتی یک سرور را نیز اجرا کرده‌ایم، می‌تواند بیش از 1 باشد؛ اما در این حالت Primary Broker برای تمام Partition‌های همین سرور در نظر گرفته می‌شود. 

topic userChat--

نام Topic را مشخص می‌کند.


پس از اینکه Topic مورد نظر ایجاد شد، با استفاده از دستور زیر می‌توانیم لیست Topic‌های ایجاد شده را مشاهده کنیم:

 bin/kafka-topics.sh --list --zookeeper localhost:2181


توضیحات Optionها و آرگومانهایی که در دستور نمایش لیست  Topicها استفاده شدند به شرح زیر است: 

list--:

شما می‌خواهید لیست topic‌ها را مشاهده کنید.

zookeeper localhost:2181--:

همانند دستور ایجاد، مشخص کننده سرور zookeeper می‌باشد.


تا اینجا برای ارسال و دریافت پیام در بین Application‌های مختلف همه چیز آماده‌است. البته همانطور که در بخش‌های بعدی این سری مقالات می‌بینیم، در عمل Producer‌ها و Consumer‌ها زیرسیستمهایی هستند که خود ما با استفاده از هر زبان برنامه نویسی پیاده سازی می‌کنیم. اما در این قسمت برای نمایش و تکمیل مثالمان، از ابزارهایی که خود Kafka در اختیار ما قرار داده استفاده می‌کنیم.


اجرای یک Producer و ارسال پیام به Kafka:

kafka-console-producer.sh ابزاریست که با استفاده از آن می‌توانید به راحتی یک Producer را ایجاد کنید. در terminalی که قبلا برای مدیریت Topicها باز کرده‌اید با استفاده از دستور زیر، Producer را اجرا می‌کنیم:

bin/kafka-console-producer.sh --broker-list localhost:9092 --topic userChat


توضیحات Optionها و آرگومانهایی که در دستور ایجاد Producer استفاده شدند به شرح زیر است:  

broker-list localhost:9092--:

نشان دهنده لیست Broker‌ها می‌باشد و در صورتیکه تعداد آنها بیش از یک باشد، می‌توان آنها را با "," از هم جدا کرد (پورت پیشفرض Kafka server برای دریافت دستورات، 9092 می‌باشد).

topic userChat--:

Topicی از Kafka server را مشخص می‌کند که این Producer می‌خواهد پیامهای خود را برایش ارسال کند.


پس از اجرای دستور فوق، با تایپ کردن و زدن کلید Enter، پیام مورد نظر به Broker موردنظر یعنی localhost:9092 ارسال و در تنها Partition تاپیک userChat ذخیره می‌شود.


اجرای یک Consumer و دریافت پیامهای موجود در Topic مورد نظر:

kafka-console-consumer.sh ابزاریست که خود Kafka در اختیار ما قرار داده است و با استفاده از آن می‌توانیم به راحتی یک Consumer برای  userChat ،Topic ایجاد کنیم.

در یک terminal جدید با استفاده از دستور زیر یک Consumer را ایجاد کنید که userChat  ،Topic را Subscribe می‌کند:

 bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic userChat --from-beginning


توضیحات Optionها و آرگومانهایی که در دستور ایجاد یک Consumer استفاده شدند به شرح زیر است:  

bootstrap-server localhost:9092-- :

مشخص کننده Kafka serverی است که می‌خواهیم از طریق آن به تمامی اعضای Cluster دسترسی داشته باشیم. در صورتیکه بیش از یک سرور را بخواهیم وارد کنیم، باید آنها را با  "," از هم جدا کنیم.

topic userChat --:

مشخص کننده Topicی است که این Consumer میخواهد روی آن Subscribe کند.

from-beginning--:

 مشخص کننده این است که Consumer ایجاد شده می‌خواهد تمامی پیامهای موجود در userChat ، Topic را از اولین offset تا آخرین offset دریافت کند.

پس از اجرای کد فوق مشاهده می‌کنید که پیامهایی که قبلا Producer در تاپیک userChat ثبت کرده‌است، برای این Consumer ارسال می‌شوند.


از اینجا به بعد هر لحظه که در terminal ارسال کننده یا Producer پیامی تایپ کنید و کلید Enter را بزنید، بلافاصله پیام مورد نظر برای Consumer ارسال می‌شود و در terminal آن نمایش داده می‌شود. حتی می‌توانیم چندین Consumer را در terminal ‌های مختلفی اجرا کنیم. در این صورت با ارسال هر پیام از طرف Producer، تمامی Consumer‌ها آن را نمایش می‌دهند.


با استفاده از سادگی راه اندازی و قابلیتهای بسیار زیادی که Apache Kafka در مدیریت  جریان داده‌ای بین سیستم‌هایمان به ما می‌دهد، می‌توانیم به سادگی در سیستم‌هایمان   قابلیتهای مقیاس پذیری افقی، تحمل در برابر خطا، در دسترس بودن، کارآیی بالا و سادگی مدیریت ارتباطات بخشهای مختلف را اضافه کنیم. در بخشهای بعدی به نحوه ایجاد یک Cluster و اینکه چگونه می‌توان از این بستر در Net. استفاده کرد، می‌پردازیم.

مطالب
محدود سازی نرخ دسترسی به منابع در برنامه‌های ASP.NET Core - قسمت اول - بررسی مفاهیم
به ASP.NET Core 7، یک میان‌افزار جدید به نام Rate limiter اضافه شده‌است که امکان محدود سازی دسترسی به منابع برنامه‌ی ما را میسر می‌کند. این میان‌افزار، طراحی جامع و مفصلی را دارد. به همین جهت نیاز است در ابتدا با مفاهیم مرتبط با آن آشنا شد و سپس به سراغ پیاده سازی و استفاده‌ی از آن رفت.


چرا باید میزان دسترسی به منابع یک برنامه‌ی وب را محدود کرد؟

فرض کنید در حال ساخت یک web API هستید که کارش ذخیره سازی لیست وظایف اشخاص است و برای مثال از یک GET /api/todos برای دریافت لیست ظایف، یک POST /api/todos برای ثبت و یک PUT /api/todos/{id} برای تغییر موارد ثبت شده، تشکیل می‌شود.
سؤال: چه مشکلی ممکن است به همراه این سه endpoint بروز کند؟
پاسخ: به حداقل چهار مورد زیر می‌توان اشاره کرد:
- یک مهاجم سعی می‌کند با برنامه‌ای که تدارک دیده، هزاران وظیفه‌ی جدید را در چند ثانیه به سمت برنامه ارسال کند تا سبب خاتمه‌ی سرویس آن شود.
- برنامه‌ی ما در حین سرویس دهی، به یک سرویس ثالث نیز وابسته‌است و آن سرویس ثالث، اجازه‌ی استفاده‌ی بیش از اندازه‌ی از منابع خود را نمی‌دهد. با رسیدن تعداد زیادی درخواست به برنامه‌ی ما تنها از طرف یک کاربر، به سقف مجاز استفاده‌ی از آن سرویس ثالث رسیده‌ایم و اکنون برنامه، برای تمام کاربران آن قابل استفاده نیست.
- شخصی در حال دریافت اطلاعات تک تک کاربران است. از شماره یک شروع کرده و به همین نحو جلو می‌رود. برای دریافت اطلاعات کاربران، نیاز است شخص به سیستم وارد شده و اعتبارسنجی شود؛ یعنی به ازای هر درخواست، یک کوئری نیز به سمت بانک اطلاعاتی جهت بررسی وضعیت فعلی و آنی کاربر ارسال می‌شود. به همین جهت عدم کنترل میزان دسترسی به لیست اطلاعات کاربران، بار سنگینی را به بانک اطلاعاتی و CPU سیستم وارد می‌کند.
- هم اکنون چندین موتور جستجو و بات‌هایی نظر آن‌ها در حال پیمایش سایت و برنامه‌ی شما هستند که هر کدام از آن‌ها می‌توانند در حد یک مهاجم رفتار کنند.

به صورت خلاصه، همیشه استفاده‌ی از برنامه، به آن نحوی که ما پیش‌بینی کرده‌ایم، به پیش نمی‌رود و در آن لحظه، برنامه، در حال استفاده از CPU، حافظه و بانک اطلاعاتی به اشتراک گذاشته شده‌ی با تمام کاربران برنامه‌است. در این حالت فقط یک کاربر مهاجم می‌تواند سبب از کار افتادن و یا به شدت کند شدن این برنامه شود و دسترسی سایر کاربران همزمان را مختل کند.


محدود کردن نرخ دسترسی به برنامه چیست؟

Rate limiting و یا نام دیگر آن request throttling، روشی است که توسط آن بتوان از الگوهای پیش بینی نشده‌ی استفاده‌ی از برنامه جلوگیری کرد. عموما برنامه‌های وب، محدود کردن نرخ دسترسی را بر اساس تعداد بار درخواست انجام شده‌ی در یک بازه‌ی زمانی مشخص، انجام می‌دهند و یا اگر کار برنامه‌ی شما ارائه‌ی فیلم‌های ویدیویی است، شاید بخواهید میزان حجم استفاده شده‌ی توسط یک کاربر را کنترل کنید. در کل هدف نهایی از آن، کاهش و به حداقل رساندن روش‌های آسیب زننده‌ی به برنامه و سیستم است؛ صرفنظر از اینکه این نحوه‌ی استفاده‌ی خاص، سهوی و یا عمدی باشد.


محدود کردن نرخ دسترسی را باید به چه منابعی اعمال کرد؟

پاسخ دقیق به این سؤال: «همه چیز» است! بله! همه چیز را کنترل کنید! در اینجا منظور از همه چیز، همان endpointهایی هستند که استفاده‌ی نابجای از آن‌ها می‌توانند سبب کند شدن برنامه یا از دسترس خارج شدن آن شوند. برای مثال هر endpoint‌ای که از CPU، حافظه، دسترسی به دیسک سخت، بانک اطلاعاتی، APIهای ثالث و خارجی و امثال آن استفاده می‌کند، باید کنترل و محدود شود تا استفاده‌ی ناصحیح یک کاربر از آن‌ها، استفاده‌ی از برنامه را برای سایر کاربران غیرممکن نکند. البته باید دقت داشت که هدف از اینکار، عصبی کردن کاربران عادی و معمولی برنامه نیست. هدف اصلی در اینجا، تشویق به استفاده‌ی منصفانه از منابع سیستم است.


الگوریتم‌های محدود کردن نرخ دسترسی

پیاده سازی ابتدایی محدود کردن نرخ دسترسی به منابع یک برنامه کار مشکلی است و در صورت استفاده از الگوریتم‌های متداولی مانند تعریف یک جدول که شامل user-id، action-id و timestamp، به همراه یکبار ثبت اطلاعات به ازای هر درخواست و همچنین خواندن اطلاعات موجود است که جدول آن نیز به سرعت افزایش حجم می‌دهد. به همین جهت تعدادی الگوریتم بهینه برای اینکار طراحی شده‌اند:

الگوریتم‌های بازه‌ی زمانی مشخص

در این روش، یک شمارشگر در یک بازه‌ی زمانی مشخص فعال می‌شود و بر این مبنا است که محدودیت‌ها اعمال خواهند شد. یک مثال آن، مجاز دانستن فقط «100 درخواست در یک دقیقه» است که نام دیگر آن «Quantized buckets / Fixed window limit» نیز هست.
برای مثال «نام هر اکشن + یک بازه‌ی زمانی»، یک کلید دیکشنری نگهدارنده‌ی اطلاعات محدود کردن نرخ دسترسی خواهد بود که به آن کلید، «bucket name» هم می‌گویند؛ مانند مقدار someaction_106062120. سپس به ازای هر درخواست رسیده، شمارشگر مرتبط با این کلید، یک واحد افزایش پیدا می‌کند و محدود کردن دسترسی‌ها بر اساس مقدار این کلید صورت می‌گیرد. در ادامه با شروع هر بازه‌ی زمانی جدید که در اینجا window نام دارد، یک کلید یا همان «bucket name» جدید تولید شده و مقدار متناظر با این کلید، به صفر تنظیم می‌شود.
اگر بجای دیکشنری‌های #C از بانک اطلاعاتی Redis برای نگهداری این key/valueها استفاده شود، می‌توان برای هر کدام از مقادیر آن، طول عمری را نیز مشخص کرد تا خود Redis، کار حذف خودکار اطلاعات غیرضروری را انجام دهد.

یک مشکل الگوریتم‌های بازه‌ی زمانی مشخص، غیر دقیق بودن آن‌ها است. برای مثال فرض کنید که به ازای هر 10 ثانیه می‌خواهید تنها اجازه‌ی پردازش 4 درخواست رسیده را بدهید. مشکل اینجا است که در این حالت یک کاربر می‌تواند 5 درخواست متوالی را بدون مشکل ارسال کند؛ 3 درخواست را در انتهای بازه‌ی اول و دو درخواست را در ابتدای بازه‌ی دوم:


به یک بازه‌ی زمانی مشخص، fixed window و به انتها و ابتدای دو بازه‌ی زمانی مشخص متوالی، sliding window می‌گویند. همانطور که در تصویر فوق هم مشاهده می‌کنید، در این اگوریتم، امکان محدود سازی دقیقی تنها در یک fixed window میسر است و نه در یک sliding window.

سؤال: آیا این مساله عدم دقت الگوریتم‌های بازه‌ی زمانی مشخص مهم است؟
پاسخ: بستگی دارد! اگر هدف شما، جلوگیری از استفاده‌ی سهوی یا عمدی بیش از حد از منابع سیستم است، این مساله مشکل مهمی را ایجاد نمی‌کند. اما اگر دقت بالایی را انتظار دارید، بله، مهم است! در این حالت از الگوریتم‌های «sliding window limit » بیشتر استفاده می‌شود که در پشت صحنه از همان روش استفاده‌ی از چندین fixed window کوچک، کمک می‌گیرند.


الگوریتم‌های سطل توکن‌ها (Token buckets)

در دنیای مخابرات، از الگوریتم‌های token buckets جهت کنترل میزان مصرف پهنای باند، زیاد استفاده می‌شود. از واژه‌ی سطل در اینجا استفاده شده، چون عموما به همراه آب بکارگرفته می‌شود:
فرض کنید سطل آبی را دارید که در کف آن نشتی دارد. اگر نرخ پر کردن این سطل، با آب، از نرخ نشتی کف آن بیشتر باشد، آب از سطل، سرریز خواهد شد. به این معنا که با سرریز توکن‌ها یا آب در این مثال، هیچ درخواست جدید دیگری پردازش نمی‌شود؛ تا زمانیکه مجددا سطل، به اندازه‌ای خالی شود که بتواند توکن یا آب بیشتری را بپذیرد.

یکی از مزیت‌های این روش، نداشتن مشکل عدم دقت به همراه بازه‌های زمانی مشخص است. در اینجا اگر تعداد درخواست زیادی به یکباره به سمت برنامه ارسال شوند، سطل پردازشی آن‌ها سرریز شده و دیگر پردازش نمی‌شوند.
مزیت دیگر آن‌ها، امکان بروز انفجاری یک ترافیک (bursts in traffic) نیز هست. برای مثال اگر قرار است سطلی با 60 توکن در دقیقه پر شود و این سطل نیز هر ثانیه یکبار تخلیه می‌شود، کلاینت‌ها هنوز می‌توانند 60 درخواست را در طی یک ثانیه ارسال کنند (ترافیک انفجاری) و پس از آن نرخ پردازشی، یک درخواست به ازای هر ثانیه خواهد شد.


آیا باید امکان بروز انفجار در ترافیک را داد؟

عموما در اکثر برنامه‌ها وجود یک محدود کننده‌ی نرخ دسترسی کافی است. برای مثال یک محدود کننده‌ی نرخ دسترسی سراسری 600 درخواست در هر دقیقه، برای هر endpoint ای شاید مناسب باشد. اما گاهی از اوقات نیاز است تا امکان بروز انفجار در ترافیک (bursts) را نیز درنظر گرفت. برای مثال زمانیکه یک برنامه‌ی موبایل شروع به کار می‌کند، در ابتدای راه اندازی آن تعداد زیادی درخواست، به سمت سرور ارسال می‌شوند و پس از آن، این سرعت کاهش پیدا می‌کند. در این حالت بهتر است چندین محدودیت را تعریف کرد: برای مثال امکان ارسال 10 درخواست در هر ثانیه و حداکثر 3600 درخواست در هر ساعت.


روش تشخیص کلاینت‌ها چگونه باشد؟

تا اینجا در مورد bucket name یا کلید دیکشنری اطلاعات محدود کردن دسترسی به منابع، از روش «نام هر اکشن + یک بازه‌ی زمانی» استفاده کردیم. به این کار «پارتیشن بندی درخواست‌ها» هم گفته می‌شود. روش‌های دیگری نیز برای انجام اینکار وجود دارند:
پارتیشن بندی به ازای هر
- endpoint
- آدرس IP. البته باید دقت داشت که کاربرانی که در پشت یک پروکسی قرار دارند، از یک IP آدرس اشتراکی استفاده می‌کنند.
- شماره کاربری. البته باید در اینجا بحث کاربران اعتبارسنجی نشده و anonymous را نیز مدنظر قرار داد.
- شمار سشن کاربر. در این حالت باید بحث ایجاد سشن‌های جدید به ازای دستگاه‌های مختلف مورد استفاده‌ی توسط کاربر را هم مدنظر قرار داد.
- نوع مروگر.
- هدر ویژه رسیده مانند X-Api-Token

بسته به نوع برنامه عموما از ترکیبی از موارد فوق برای پارتیشن بندی درخواست‌های رسیده استفاده می‌شود.


درنظر گرفتن حالت‌های استثنائی

هرچند همانطور که عنوان شد تمام قسمت‌های برنامه باید از لحاظ میزان دسترسی محدود شوند، اما استثناءهای زیر را نیز باید درنظر گرفت:
- عموما تیم مدیریتی یا فروش برنامه، بیش از سایر کاربران، با برنامه کار می‌کنند.
- بیش از اندازه محدود کردن Web crawlers می‌تواند سبب کاهش امتیاز SEO سایت شما شود.
- گروه‌های خاصی از کاربران برنامه نیز می‌توانند دسترسی‌های بیشتری را خریداری کنند.


نحوه‌ی خاتمه‌ی اتصال و درخواست

اگر کاربری به حد نهایی استفاده‌ی از منابع خود رسید، چه باید کرد؟ آیا باید صرفا درخواست او را برگشت زد یا اطلاعات بهتری را به او نمایش داد؟
برای مثال GitHub یک چنین خروجی را به همراه هدرهای ویژه‌ای جهت مشخص سازی وضعیت محدود سازی دسترسی به منابع و علت آن‌، ارائه می‌دهد:
> HTTP/2 403
> Date: Tue, 20 Aug 2013 14:50:41 GMT
> x-ratelimit-limit: 60
> x-ratelimit-remaining: 0
> x-ratelimit-used: 60
> x-ratelimit-reset: 1377013266
> {
> "message": "API rate limit exceeded for xxx.xxx.xxx.xxx. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)",
> "documentation_url": "https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting"
> }
بنابراین بسته به نوع خروجی برنامه که اگر خروجی آن یک API از نوع JSON است و یا یک صفحه‌ی HTML، می‌توان از ترکیبی از هدرها و اطلاعات متنی و HTML استفاده کرد.
حتی یکسری از APIها از status codeهای ویژه‌ای مانند 403 (دسترسی ممنوع)، 503 (سرویس در دسترس نیست) و یا 429 (تعداد درخواست‌های زیاد) برای پاسخ دهی استفاده می‌کنند.



محل ذخیره سازی اطلاعات محدود سازی دسترسی به منابع کجا باشد؟

اگر محدودسازی دسترسی به منابع، جزئی از مدل تجاری برنامه‌ی شما است، نیاز است حتما از یک بانک اطلاعاتی توزیع شده مانند Redis استفاده کرد تا بتواند اطلاعات تمام نمونه‌های در حال اجرای برنامه را پوشش دهد. اما اگر هدف از این محدود سازی تنها میسر ساختن دسترسی منصفانه‌ی به منابع آن است، ذخیره سازی آن‌ها در حافظه‌ی همان نمونه‌ی در حال اجرای برنامه هم کافی است.
نظرات مطالب
چه زمانی بهتر است از Silverlight استفاده شود؟
- بله. هدفگیری اصلی سیلورلایت 4 ، LOB‌ است یا به قولی line of business applications . اگر به کتاب‌های سال 2010 مراجعه کنید تعداد کتاب‌هایی که در مورد LOB و SL4 منتشر شده قابل توجه است:
Pro Business Applications with Silverlight 4 - APress
Silverlight 4 Data and Services Cookbook - Packt Publishing
Microsoft Silverlight 4 Business Application Development - Packt Publishing
و ...

با استفاده از WCF RIA Services یا حتی WCF Services و غیره دسترسی کامل برای مثال به entity framework خواهید داشت. همچنین کاربران شما مجددا به تجربه‌ی کار با برنامه‌های دسکتاپ باز خواهند گشت، هر چند برنامه تحت وب است. قابلیت نصب خارج از مرورگر را هم دارد (مثل یک برنامه دسکتاپ معمولی).

- برای خارج از سازمان هم مشکلی نیست. چون برنامه شما یکبار فقط باید دریافت شود. بعد کش می‌شود و افزونه‌ی سیلورلایت به صورت خودکار هربار چک می‌کند که آیا برنامه روی سرور تغییر کرده یا نه. اگر خیر از کش خوانده خواهد شد و کاربر راه دور معطل نخواهد شد. همچنین با استفاده از MEF (managed extensibility framework) می‌شود قسمت‌های مختلف برنامه را به صورت افزونه درآورد. یعنی کاربری که نیاز به تمام قسمت‌ها را ندارد خوب لزومی هم ندارد که همه‌ی آن‌ها را دریافت کند.
نظرات مطالب
نحوه‌ی مشاهده‌ی خروجی SQL تولید شده توسط WCF RIA Services
سلام،
من یک زمانی از طرفداران نوشتن stored procedure بودم اما الان به دلایل ذیل نیستم:
- امنیت: تمام کوئری‌های تولیدی entity framework از نوع پارامتری هستند. این مورد یعنی عقیم سازی حملات تزریق اس کیوال . (بنابراین اگر کسی عنوان کند که با SP ما امنیت بیشتری داریم، باید عنوان کرد که اینجا هم به همین صورت است)
- سرعت: در نگارش‌های جدید اس کیوال سرور، با کوئری‌های پارامتری دقیقا مانند SP رفتار می‌شود. همان کش شدن execution plan و غیره. بنابراین اینجا هم از همان مزایای SP برخوردار هستیم و سرعت سیستم مطلوب است.
- مشکلات نگهداری SP :
شما می‌تونید ساختار جداول رو تغییر بدید بدون اینکه اس کیوال سرور به شما پیغام خطایی در مورد غیر معتبر شدن یک SP بدهد. شما می‌تونید حتی یک SP غیر معتبر را تا زمانیکه syntax مربوط به آن صحیح است تولید کنید. هر دو مورد در زمان اجرا، سبب از کار افتادن برنامه می‌شوند. اما با EF این مشکلات را ندارید. ساختار را که عوض کنید برنامه دیگر کامپایل نمی‌شود. این مورد در برنامه‌های بزرگ خیلی خیلی خوب است!
مورد دیگر: یک برنامه بزرگ با چند صد SP رو در نظر بگیرید. جدا نگهداری این‌ها پیدا کردن کدها در یک برنامه‌ی بزرگ عذاب است. طبقه بندی آن‌ها یک طرف، اعمال تغییرات از طرف دیگر.
- مورد دیگر که من دیدم در یک سری از سایت‌ها در مورد آن بحث می‌کنند این است که نباید business logic برنامه را داخل دیتابیس طراحی کرد. این مورد باید با کد نویسی داخل برنامه باشد. در اینجا هم باز EF یا موارد مشابه بهتر هستند.
- مورد دیگری که در SP ها مشکل ساز می‌شود به اشتراک گذاری آن در بین برنامه‌های مختلف است. هم خوب است. بالاخره کد نویسی کمتر می‌شود. هم بد است، از این لحاظ که شاید این SP نیاز به تغییر داشت و اینجا است که برنامه‌های دیگر مشکل پیدا می‌کنند.
مطالب
معرفی WPF Extended toolkit

یکی از نکات جالبی که در مورد Silverlight وجود دارد این است که هر چند تنها قسمتی از WPF را به ارث برده (برای اینکه حجم افزونه‌ی آن قابل قبول باشد)، اما بیشتر از خود WPF مورد توجه مایکروسافت است! شاید یک دلیل آن استفاده از Silverlight در Windows phone 7 باشد. به عبارتی اگر برنامه نویس Silverlight هستید، هم اکنون برنامه نویس Windows phone 7 نیز می‌باشید.
این توجه بیشتر در Silverlight toolkit کاملا مشخص است. Silverlight toolkit از یک سری ابزار و کامپوننت برای توسعه‌ی ساده‌تر برنامه‌های Silverlight به صورت سورس باز و تهیه شده توسط مایکروسافت، تشکیل شده است. حجم WPF toolkit که آن هم توسط مایکروسافت به صورت سورس باز ارائه و به روز می‌شود حدود 2 مگابایت است؛ اما حجم Silverlight toolkit حدود 18 مگابایت می‌باشد! بسیاری از کنترل‌ها و امکانات Silverlight toolkit را در WPF نمی‌توانید پیدا کنید مانند BusyIndicator ، ChildWindow ، DataForm و غیره. نمونه‌ی دیگر این توجه WCF RIA Services است. هدفگیری اصلی این مورد نیز Silverlight است و نه WPF (که از آن در Visual studio LightSwitch هم استفاده کرده‌اند).
اخیرا یک گروه خیّر کار تبدیل و انتقال کنترل‌های Silverlight toolkit به WPF toolkit را شروع کرده است که حاصل آن از آدرس ذیل قابل دریافت است: (این هم یکی از مزیت‌های پروژه‌های سورس باز است)



مطالب
آشنایی با نحوه‌ی وهله سازی کنترلرها در ASP.NET MVC با ساخت یک Controller Factory سفارشی
یکی از مزایای مهم فریم ورک ASP.NET MVC، توسعه پذیری کنترلرهای آن است. با مرور قسمت‌هایی از مسیر پردازش درخواست که منجر به اجرای یک اکشن متد می‌شود، شروع می‌کنیم و روش‌های مختلفی را که می‌توان بر روی این پردازش، کنترل داشت، بررسی می‌کنیم. شکل ذیل مسیر یک درخواست را مابین کامپوننت‌های مختلف فریم ورک نشان می‌دهد:
 
 

Controller Factory و Action Invoker وظیفه‌ای مطابق نامشان را عهده دار هستند. اولی برای وهله سازی کنترلرهای مرتبط با درخواست و دومی برای پیدا کردن و تریگر نمودن یک اکشن متد به کار گرفته می‌شوند. فریم ورک MVC پیاده سازی پیش فرضی را از این دو کامپوننت، به صورت توکار دارد. در طی مقالاتی نحوه‌ی کنترل کردن رفتار پیش فرض این Controller Factory و هم نحوه‌ی جایگزین کرن کامل این کامپوننت را بررسی می‌کنیم.

ابتدا پروژه‌ی جدیدی را از نوع MVC و با الگوی Empty به نام ControllerExtensibility ایجاد می‌کنیم. در پوشه‌ی Models یک فایل را به نام Result.cs ساخته و از آن برای معرفی کلاس Result مطابق کدهای ذیل استفاده می‌کنیم:
namespace ControllerExtensibility.Models
{
    public class Result
    {
        public string ControllerName { get; set; }
        public string ActionName { get; set; }
    }
}
در مسیر /Views/Shared ویویی را به نام Result.cshtml اضافه می‌کنیم. این ویویی است که در این مثال، همه‌ی اکشن متدهای کنترلرهایمان، آن را رندر خواهند کرد:
@model ControllerExtensibility.Models.Result
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Result</title>
</head>
<body>
<div>Controller: @Model.ControllerName</div>
<div>Action: @Model.ActionName</div>
</body>
</html>
در خط اول، مدل ویو را از نوع کلاس Result تعیین کرده‌ایم.
دو کنترلر را نیز حاوی کدهای زیر ایجاد می‌کنیم:

کنترلر product
using ControllerExtensibility.Models;
using System.Web.Mvc;
namespace ControllerExtensibility.Controllers
{
    public class ProductController : Controller
    {
        public ViewResult Index()
        {
            return View("Result", new Result
            {
                ControllerName = "Product",
                ActionName = "Index"
            });
        }
        public ViewResult List()
        {
            return View("Result", new Result
            {
                ControllerName = "Product",
                ActionName = "List"
            });
        }
    }
}

کنترلر customer

using System.Web.Mvc;
namespace ControllerExtensibility.Controllers
{
    public class CustomerController : Controller
    {
        public ViewResult Index()
        {
            return View("Result", new Result
            {
                ControllerName = "Customer",
                ActionName = "Index"
            });
        }
        public ViewResult List()
        {
            return View("Result", new Result
            {
                ControllerName = "Customer",
                ActionName = "List"
            });
        }
    }
}
اکشن‌های این دو کنترلر حاوی کد خاصی نبوده و صرفا ویوی Result.cshtml را صدا می‌زنند. ولی در این مرحله این همه‌ی آن چیزی است که برای نشان دادن نحوه‌ی سفارشی کردن کنترلرها بدان نیاز داریم.
ایجاد یک Controller Factory سفارشی بهترین راه برای درک نحوه‌ی وهله سازی کنترلر‌ها توسط MVC است. ولی این کار صرفا جنبه‌ی آموزشی داشته و در یک پروژه‌ی واقعی این نوع پیاده سازی‌ها پیشنهاد نمی‌شود؛ زیرا راه‌های مفیدتر و ساده‌تری با پیاده سازی توکار Controller Factory وجود دارند.
Controller Factory‌ها با پیاده سازی اینترفیس IControllerFactory معرفی می‌شوند. کدهای این اینترفیس را در ذیل می‌بینید:
using System.Web.Routing;
using System.Web.SessionState;
namespace System.Web.Mvc
{
    public interface IControllerFactory
    {
        IController CreateController(RequestContext requestContext,
        string controllerName);
        SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext,
        string controllerName);
        void ReleaseController(IController controller);
    }
}
پوشه‌ای را به نام Infrastructure ساخته و فایلی را به نام CustomControllerFactory.cs ، حاوی کدهای زیر اضافه کنید:
using System;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;
using ControllerExtensibility.Controllers;

namespace ControllerExtensibility.Infrastructure
{
    public class CustomControllerFactory : IControllerFactory
    {
        public IController CreateController(RequestContext requestContext,
            string controllerName)
        {
            Type targetType = null;
            switch (controllerName)
            {
                case "Product":
                    targetType = typeof (ProductController);
                    break;
                case "Customer":
                    targetType = typeof (CustomerController);
                    break;
                default:
                    requestContext.RouteData.Values["controller"] = "Product";
                    targetType = typeof (ProductController);
                    break;
            }
            return targetType == null
                ? null
                : (IController) DependencyResolver.Current.GetService(targetType);
        }

        public SessionStateBehavior GetControllerSessionBehavior(RequestContext
            requestContext, string controllerName)
        {
            return SessionStateBehavior.Default;
        }

        public void ReleaseController(IController controller)
        {
            IDisposable disposable = controller as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }
    }
}
مهمترین متد کدهای فوق، CreateController است که فریم ورک، بر حسب نیاز، جهت سرویس دهی به درخواست واصله آن را صدا خواهد زد. پارامتر ورودی این متد، شیء RequestContext است که جزئیاتی در خصوص درخواست واصله را در اختیار factory خواهد گذاشت. همچنین یک رشته که نام کنترلر را بر حسب URL واصله تعیین می‌کند:
 

نام

نوع

توضیحات

HttpContext

HttpContextBase

حاوی اطلاعاتی در خصوص درخواست است.

RouteData

RouteData

حاوی اطلاعاتی در خصوص Rout است که با درخواست رسیده همخوانی دارد.

 
یکی از دلایلی که عنوان شد Controller factory سفارشی بدین روش در یک پروژه‌ی عملی به کار گرفته نشود این است که یافتن کلاس‌هایی از نوع Controller در سراسر برنامه و وهله سازی آنها کار دشواری است. چرا که لازم خواهد بود بتوانید به صورت پویا کنترلر را مکان یابی کرده و بین کلاس‌های هم نام در دیگر فضاهای نام تمییز قائل شوید و خطاهای محتمل در حین وهله سازی را کنترل کنید.
در این مثال تنها دو کنترلر داریم و آنها را به صورت مستقیم در Controller Factory وهله سازی می‌کنیم که در یک پروژه‌ی واقعی مطلوب نیست. ولی آنچه را که این روش آشکار‌تر می‌سازد، انعطاف پذیری بالای فریم ورک MVC است که دست ما را برای نفوذ و دخل و تصرف در اعمال و رفتاریهای پیش فرض خود باز گذاشته است و برای مثال در مباحث تزریق وابستگی‌ها و تنظیمات ابتدایی IoC Containers کاربرد دارد.
متد CreateController لازم است وهله‌ای از کلاسی که اینترفیس IController را پیاده سازی کرده برگرداند؛ در غیر اینصورت کار با خطا متوقف خواهد شد. لذا برای زمانی که درخواست کاربر، هیچ کدام از کنترلر‌ها را مشمول عنایت قرار نمی‌دهد، باید چاره‌ای اندیشیده شود.
می‌توان آن را به کنترلر خاصی که پیغام خطایی را رندر می‌کند، هدایت کنیم. به عبارت بهتر باید درخواست را به کنترلری که مطمئن هستیم وجود دارد (اصطلاحا کنترلر جانشین) هدایت نماییم. همان طور که در کد فوق در قسمت default می‌بینید:
default:
requestContext.RouteData.Values["controller"] = "Product";
targetType = typeof(ProductController);
break;
در صورت عدم تطابق با هیچ کدام از حالات تعیین شده، درخواست را به کنترلر ProductController جهت رسیدگی هدایت کرده‌ایم.
در MVC انتخاب ویوی مناسب، بر حسب مقدار RouteData.Values صورت می‌گیرد؛ نه نام کلاس Controller و این سبب خواهد شد فریم ورک، ویوهای مرتبط با کنترلر جانشین شده‌ی توسط ما را جستجو کند و نه کنترلری که کاربر از طریق URL ورودی آن را درخواست کرده است.
لذا Controller Factory صرفا وظیفه مپ کردن درخواست‌های واصله به کنترلر‌ها را ندارد، بلکه توانایی دخل و تصرف در درخواست واصله بر حسب مورد را نیز خواهد داشت.
در نهایت هم نحوه‌ی استفاده از DependencyResolver را برای وهله سازی کلاس‌های کنترلر می‌بینید. متد استاتیک Current یک پیاده سازی از اینترفیس IDependencyResolver را که حاوی متد GetService است، برگشت داده و سپس یک شیء System.Type را به عنوان ورودی گرفته و یک وهله‌ی ساخته شده‌ی از آن را به عنوان خروجی برمی‌گرداند.
متد GetControllerSessionBehavior نیز توسط MVC جهت تعیین اینکه Session data برای کنترلر نیاز است یا خیر به کار گرفته می‌شود.
متد ReleaseController نیز هر گاه به شیء کنترلر ساخته شده در متد CreateController دیگر نیازی نبود، صدا زده خواهد شد. در کدهای ما ابتدا بررسی می‌شود آیا اینترفیس IDisposable توسط کلاس، پیاده سازی شده است یا خیر؟ اگر بلی متد Dispose آن جهت آزاد سازی منابعی که می‌توانند آزاد شوند، صدا زده می‌شود.
جهت ثبت Controller  Factory ساخته شده در متد Application_Start موجود در فایل global.asax.cs بوسیله کلاس ControllerBuilder و مطابق کدهای ذیل عمل می‌نماییم:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
using ControllerExtensibility.Infrastructure;
namespace ControllerExtensibility
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            ControllerBuilder.Current.SetControllerFactory(new
            CustomControllerFactory());
        }
    }
}
پس از ثبت به شیوه‌ی فوق، controller factory ساخته شده، مسئول هندل کردن تمامی درخواست‌های واصله‌ی به برنامه خواهد بود. پس از اولین اجرا، مرورگر ریشه‌ی سایت را هدف قرار خواهد داد که توسط سیستم مسیر یابی به کنترلر Home، نگاشت شده و بر اساس تعاریف و کدهای ما، چون با هیچ کدام از کنترلرهای Product و Customer تطابق نخواهد داشت، به کنترلر جایگزین تنظیم شده، یعنی Product هدایت خواهد شد.