مطالب
بررسی ساختار ویجت‌های وب Kendo UI
ویجت‌های وب Kendo UI کدامند؟

ویجت‌های وب Kendo UI مجموعه‌ای از کنترل‌های سفارشی HTML 5 هستند که برفراز jQuery تهیه شده‌اند. این کنترل‌ها برای برنامه‌های وب و همچنین برنامه‌های دسکتاپ لمسی طراحی شده‌اند.
بهترین روش برای مشاهده‌ی این مجموعه، مراجعه به فایل examples\index.html پوشه‌ی اصلی Kendo UI است که لیست کاملی از این ویجت‌ها را به همراه مثال‌های مرتبط ارائه می‌دهد. تعدادی از اعضای این مجموعه شامل کنترل‌های ذیل هستند:
Window, TreeView, Tooltip, ToolBar, TimePicker, TabStrip, Splitter, Sortable, Slider, Gantt, Scheduler, ProgressBar, PanelBar, NumericTextBox, Notification, MultiSelect, Menu, MaskedTextBox, ListView, PivotGrid, Grid, Editor, DropDownList, DateTimePicker, DatePicker, ComboBox, ColorPicker, Calendar, Button, AutoComplete


نحوه‌ی استفاده کلی از ویجت‌های وب Kendo UI

با توجه به اینکه کنترل‌های Kendo UI مبتنی بر jQuery هستند، نحوه‌ی استفاده از آن‌ها، مشابه سایر افزونه‌های جی‌کوئری است. ابتدا المانی به صفحه اضافه می‌شود:
 <input id="pickDate" type="text"/>
سپس این المان را در رویداد document ready، به یکی از کنترل‌های Kendo UI مزین خواهیم کرد. برای مثال تزئین یک TextBox معمولی با یک Date Picker:
 <script type="text/javascript">
  $(function() {
        $("#pickDate").kendoDatePicker();
  });
</script>
روش دیگری به نام declarative initialization نیز برای اعمال ویجت‌های وب Kendo UI قابل استفاده است که از ویژگی‌های *-data مرتبط با HTML 5 کمک می‌گیرد. برای نمونه، کدهای جاوا اسکریپتی فوق را می‌توان با ویژگی data-role ذیل جایگزین کرد:
 <input id="dateOfBirth" type="text" data-role="datepicker" />
اگر در این حالت برنامه را اجرا کنید، تفاوتی را مشاهده نخواهید کرد.
برای فعال سازی حالت declarative initialization باید به دو نکته‌ی مهم دقت داشت:
الف) در مطلب معرفی Kendo UI اسکریپت‌های ذیل برای آماده سازی Kendo Ui معرفی شدند:
 <!--KendoUI: Web-->
<link href="styles/kendo.common.min.css" rel="stylesheet" type="text/css" />
<link href="styles/kendo.default.min.css" rel="stylesheet" type="text/css" />
<script src="js/jquery.min.js" type="text/javascript"></script>
<script src="js/kendo.web.min.js" type="text/javascript"></script>

<!--KendoUI: DataViz-->
<link href="styles/kendo.dataviz.min.css" rel="stylesheet" type="text/css" />
<script src="js/kendo.dataviz.min.js" type="text/javascript"></script>

<!--KendoUI: Mobile-->
<link href="styles/kendo.mobile.all.min.css" rel="stylesheet" type="text/css" />
<script src="js/kendo.mobile.min.js" type="text/javascript"></script>
باید دقت داشت که در آن واحد نمی‌توان تمام این بسته‌ها را با هم بکار برد؛ چون برای مثال فایل‌های جداگانه ویجت‌های وب و موبایل با هم تداخل ایجاد می‌کنند. بجای اینکار بهتر است از فایل‌های kendo.all.min.js (که حاوی تمام اسکریپت‌های لازم است) و css‌های عنوان شده استفاده کرد:
 <link href="styles/kendo.common.min.css" rel="stylesheet" type="text/css" />
<link href="styles/kendo.default.min.css" rel="stylesheet" type="text/css" />
<script src="js/jquery.min.js" type="text/javascript"></script>
<script src="js/kendo.all.min.js" type="text/javascript"></script>
ب) data-roleها توسط متد kendo.init فعال می‌شوند.
یک مثال کامل:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>

    <link href="styles/kendo.common.min.css" rel="stylesheet" type="text/css" />
    <link href="styles/kendo.default.min.css" rel="stylesheet" type="text/css" />
    <script src="js/jquery.min.js" type="text/javascript"></script>
    <script src="js/kendo.all.min.js" type="text/javascript"></script>

    <script type="text/javascript">
        $(function () {
            $("#pickDate").kendoDatePicker();
        });

        $(function () {
            // initialize any widgets in the #container div
            kendo.init($("#container"));
        });
    </script>
</head>
<body>
    <span>
        Pick a date: <input id="pickDate" type="text" />
    </span>

    <div id="container">
        <input id="dateOfBirth" type="text" data-role="datepicker" />
        <div id="colors"
             data-role="colorpalette"
             data-columns="4"
             data-tile-size="{ width: 34, height: 19 }"></div>
    </div>
</body>
</html>
- در این مثال نحوه‌ی پیوست تمام فایل‌های لازم Kendo UI را به صورت یکجا ملاحظه می‌کنید که در ابتدای head صفحه ذکر شده‌اند.
- در اینجا pickDate به صورت معمولی فعال شد‌ه‌است.
- اما در قسمت kendo.init نام یک ناحیه یا نام یک کنترل را می‌توان ذکر کرد. برای مثال در اینجا کل ناحیه‌ی مشخص شده توسط یک div با id مساوی container به صورت یکجا با تمام کنترل‌های داخل آن فعال گردیده‌است.

بنابراین برای اعمال declarative initialization، یک ناحیه را توسط kendo.init مشخص کرده و سپس توسط data-roleها، نام ویجت وب مورد نظر را به صورت lower case مشخص می‌کنیم. همچنین فایل‌های اسکریپت مورد استفاده نیز نباید تداخلی داشته باشند.


تنظیمات ویجت‌های وب Kendo UI

تاکنون نمونه‌ی ساده‌ای از بکارگیری ویجت‌های وب Kendo UI را بررسی کردیم؛ اما این ویجت‌ها توسط تنظیمات پیش بینی شده برای آن‌ها بسیار قابل تنظیم و تغییر هستند. تنظیمات آن‌ها نیز بستگی به روش استفاده و آغاز آن‌ها دارد. برای مثال اگر این ویجت‌ها را توسط کدهای جاوا اسکریپتی آغاز کرده‌اید، در همانجا توسط پارامترهای افزونه‌ی جی‌کوئری می‌توان تنظیمات مرتبط را اعمال کرد:
 <script type="text/javascript">
  $(function () {
      $("#pickDate").kendoDatePicker({
              format: "yyyy/MM/dd"
        });
  });
</script>
که در اینجا توسط پارامتر format، نحوه‌ی دریافت تاریخ نهایی مشخص می‌شود.
در حالت declarative initialization، پارامتر format تبدیل به ویژگی data-format خواهد شد:
<input id="dateOfBirth" type="text"
          data-role="datepicker"
          data-format="yyyy/MM/dd" />


تنظیمات DataSource ویجت‌های وب

بسیاری از ویجت‌های وب Kendo UI با داده‌ها سر و کار دارند مانند Grid، Auto Complete، Combo box و غیره. این کنترل‌ها داده‌های خود را از طریق خاصیت DataSource دریافت می‌کنند. برای نمونه در اینجا یک combo box را در نظر بگیرید. در مثال اول، خاصیت dataSource کنترل ComboBox در همان افزونه‌ی جی‌کوئری تنظیم شده‌است:
    <input id="colorPicker1" />
    <script type="text/javascript">
        $(document).ready(function () {
            $("#colorPicker1").kendoComboBox({
                dataSource: ["Blue", "Green", "Red", "Yellow"]
            });
        });
    </script>
و در مثال دوم، نحوه‌ی مقدار دهی ویژگی data-source را در حالت declarative initialization مشاهده می‌کنید. همانطور که عنوان شد، در این حالت ذکر متد kendo.init بر روی یک ناحیه و یا یک کنترل ویژه، جهت آغاز فعالیت آن ضروری است:
    <input id="colorPicker2" data-role="combobox" data-source='["Blue", "Green", "Red", "Yellow"]' />
    <script type="text/javascript">
        $(document).ready(function () {
            kendo.init($("#colorPicker2"));
        });
    </script>


کار با رویدادهای ویجت‌های وب

نحوه‌ی کار با رویدادهای ویجت‌های وب نیز بر اساس نحوه‌ی آغاز آن‌ها متفاوت است. در مثال‌های ذیل، دو حالت متفاوت تنظیم رویداد change را توسط خواص افزونه‌ی جی‌کوئری:
    <input id="colorPicker3" />
    <script type="text/javascript">
        function onColorChange(e) {
             alert('Color Change!');
        }

        $(document).ready(function () {
            $("#colorPicker3").kendoComboBox({
                dataSource: ["Blue", "Green", "Red", "Yellow"],
                change: onColorChange
            });
        });
    </script>
و همچنین توسط ویژگی data-change مشاهده می‌کنید:
    <input id="colorPicker4" data-role="combobox"
           data-source='["Blue", "Green", "Red", "Yellow"]'
           data-change="onColorChange" />

    <script type="text/javascript">
        function onColorChange(e) {
            alert('Color Change!');
        }

        $(document).ready(function () {
            kendo.init($("#colorPicker4"));
        });
    </script>
در هر دو حالت، انتخاب یک گزینه‌ی جدید combo box، سبب فراخوانی متد callback ایی به نام onColorChange می‌شود.


تغییر قالب ویجت‌های وب

Kendo UI همیشه یک جفت CSS را جهت تعیین قالب‌های ویجت‌های خود، مورد استفاده قرار می‌دهد. برای نمونه در مثال‌های فوق، kendo.common.min.css حاوی اطلاعات محل قرارگیری و اندازه‌ی ویجت‌ها است. شیوه نامه‌ی دوم همیشه به شکل kendo.[skin].min.css تعریف می‌شود که دارای اطلاعات رنگ و پس زمینه‌ی ویجت‌ها خواهد بود؛ مانند kendo.black.min.css، kendo.blueopal.min.css و امثال آن که در پوشه‌ی styles قابل مشاهده هستند.
همچنین باید دقت داشت که همیشه common باید پیش از skin ذکر شود؛ زیرا در تعدادی از حالات، شیوه نامه‌ی skin، اطلاعات common را بازنویسی می‌کند.
علاوه بر skinهای پیش فرض موجود در پوشه‌ی styles، امکان استفاده از یک theme builder آنلاین نیز وجود دارد: kendo-ui-themebuilder
مطالب
محدود سازی نرخ دسترسی به منابع در برنامه‌های 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 استفاده کرد تا بتواند اطلاعات تمام نمونه‌های در حال اجرای برنامه را پوشش دهد. اما اگر هدف از این محدود سازی تنها میسر ساختن دسترسی منصفانه‌ی به منابع آن است، ذخیره سازی آن‌ها در حافظه‌ی همان نمونه‌ی در حال اجرای برنامه هم کافی است.
مطالب
پیاده سازی ویژگی مشابه asp-append-version در برنامه‌های Blazor SSR

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

<link rel="stylesheet" href="/css/site.css"  />    
<script src="/js/site.js"></script>    

مشکلی که به همراه این روش وجود دارد، مطلع سازی کاربران و مرورگر، از تغییرات آن‌هاست؛ چون این فایل‌های ثابت، توسط مرورگرها کش شده و با فشردن دکمه‌هایی مانند Ctrl+F5 و به‌روز شدن کش مرورگر، به نگارش جدید،‌ ارتقاء پیدا می‌کنند. برای رفع این مشکل حداقل دو روش وجود دارد:

الف) هربار نام این فایل‌ها را تغییر دهیم. برای مثال بجای نام قدیمی site.css، از نام جدید site.v.1.1.css استفاده کنیم.

ب) یک کوئری استرینگ متغیر را به نام ثابت این فایل‌ها، اضافه کنیم.

که در این بین، روش دوم متداول‌تر و معقول‌تر است. برای این منظور، ASP.NET Core به همراه ویژگی توکاری است به نام asp-append-version که اگر آن‌‌را به تگ‌های اسکریپت و link اضافه کنیم:

<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />    
<script src="~/js/site.js" asp-append-version="true"></script>    

این کوئری استرینگ را به صورت خودکار محاسبه کرده و به آدرس فایل درج شده اضافه می‌کند؛ با خروجی‌هایی شبیه به مثال زیر:

<link rel="stylesheet" href="/css/site.css?v=AAs5qCYR2ja7e8QIduN1jQ8eMcls-cPxNYUozN3TJE0" />    
<script src="/js/site.js?v=NO2z9yI9csNxHrDHIeTBBfyARw3PX_xnFa0bz3RgnE4"></script>  

ASP.NET Core در اینجا هش فایل‌های یافت شده را با استفاده از الگوریتم SHA256 محاسبه و url encode کرده و به صورت یک کوئری استرینگ، به انتهای آدرس فایل‌ها اضافه می‌کند. به این ترتیب با تغییر محتوای این فایل‌ها، این هش نیز تغییر می‌کند و مرورگر بر این اساس، همواره آخرین نگارش ارائه شده را از سرور دریافت خواهد کرد. نتیجه‌ی این محاسبات نیز به صورت خودکار کش می‌شود و همچنین با استفاده از یک File Watcher در پشت صحنه، تغییرات این فایل‌ها هم بررسی می‌شوند. یعنی اگر فایلی تغییر کرد، نیازی به ‌ری‌استارت برنامه نیست و محاسبات جدید و کش شدن مجدد آن‌ها، به صورت خودکار انجام می‌شود.

البته این ویژگی هنوز به Blazor اضافه نشده‌است؛ اما امکان استفاده‌ی از زیر ساخت ویژگی asp-append-version با کدنویسی مهیا است که در ادامه با استفاده از آن، کامپوننتی را مخصوص Blazor SSR، تهیه می‌کنیم.

دسترسی به زیر ساخت محاسباتی ویژگی asp-append-version با کدنویسی

زیرساخت محاسباتی ویژگی asp-append-version، با استفاده از سرویس توکار IFileVersionProvider به صورت زیر قابل دسترسی است:

public static class FileVersionHashProvider
{
    private static readonly string ProcessExecutableModuleVersionId =
        Assembly.GetEntryAssembly()!.ManifestModule.ModuleVersionId.ToString("N");

    public static string GetFileVersionedPath(this HttpContext httpContext, string filePath, string? defaultHash = null)
    {
        ArgumentNullException.ThrowIfNull(httpContext);

        var fileVersionedPath = httpContext.RequestServices.GetRequiredService<IFileVersionProvider>()
            .AddFileVersionToPath(httpContext.Request.PathBase, filePath);

        return IsEmbeddedOrNotFound(fileVersionedPath, filePath)
            ? QueryHelpers.AddQueryString(filePath, new Dictionary<string, string?>(StringComparer.Ordinal)
            {
                {
                    "v", defaultHash ?? ProcessExecutableModuleVersionId
                }
            })
            : fileVersionedPath;
    }

    private static bool IsEmbeddedOrNotFound(string fileVersionedPath, string filePath)
        => string.Equals(fileVersionedPath, filePath, StringComparison.Ordinal);
} 

در برنامه‌های Blazor SSR، دسترسی کاملی به HttpContext‌ وجود دارد و همانطور که مشاهده می‌کنید، این سرویس نیز به اطلاعات آن جهت محاسبه‌ی هش فایل معرفی شده‌ی به آن، نیاز دارد. در اینجا اگر هش قابل محاسبه نبود، از هش فایل اسمبلی جاری استفاده خواهد شد.

ساخت کامپوننت‌هایی برای درج خودکار هش فایل‌های اسکریپت‌ها

یک نمونه روش استفاده‌ی از متد الحاقی GetFileVersionedPath فوق را در کامپوننت DntFileVersionedJavaScriptSource.razor زیر می‌توانید مشاهده کنید:

@if (!string.IsNullOrWhiteSpace(JsFilePath))
{
    <script src="@HttpContext.GetFileVersionedPath(JsFilePath)" type="text/javascript"></script>
}

@code{
    [CascadingParameter] public HttpContext HttpContext { set; get; } = null!;

    [Parameter]
    [EditorRequired]
    public required string JsFilePath { set; get; }
}

با استفاده از HttpContext مهیای در برنامه‌های Blazor SSR، متد الحاقی GetFileVersionedPath به همراه مسیر فایل js. مدنظر، در صفحه درج می‌شود.

برای مثال یک نمونه از استفاده‌ی آن، به صورت زیر است:

<DntFileVersionedJavaScriptSource JsFilePath="/lib/quill/dist/quill.js"/>

در نهایت با اینکار، یک چنین خروجی در صفحه درج خواهد شد که با تغییر محتوای فایل quill.js، هش متناظر با آن به صورت خودکار به‌روز خواهد شد:

<scriptsrc="/lib/quill/dist/quill.js?v=5q7uUOOlr88Io5YhQk3lgYcoB_P3-5Awq1lf0rRa7-Y" type="text/javascript"></script>

شبیه به همین کار را برای شیوه‌نامه‌ها هم می‌توان تکرار کرد و کدهای آن، تفاوت آنچنانی با کامپوننت فوق ندارند.

نظرات مطالب
ساخت منوهای چند سطحی در ASP.NET MVC
سلام؛ من مطالبی را که ابتدای مقاله فرمودید، مطالعه کرده‌ام. اگر امکان دارد مثال پروژه را قرار دهید تا بتوانیم از آن استفاده کنیم.
مطالب
WPF و قالب‌هایی جهت کنترل DataGrid

در مورد معرفی WPF Extended toolkit چندی قبل مطلبی منتشر شد. در ادامه این بی مهری‌ها (!) می‌توان به عدم به روز رسانی قالب‌های ارائه شده برای WPF اشاره کرد. در WPF4 ، کنترل DataGrid از WPF toolkit به مجموعه‌ی کنترل‌های اصلی WPF منتقل شده است، اما قالب‌های منتشر شده‌ی آن جهت لحاظ کردن این مورد به روز نشده‌اند. یعنی اگر برای مثال یکی از قالب‌های موجود را به برنامه خود اعمال کنید و سپس DataGrid را بر روی فرم قرار دهید، وصله‌ی ناهماهنگی را مشاهده خواهید نمود. این مشکلات در Silverlight وجود ندارند و قالب‌های ارائه شده‌ی برای آن به روز بوده و همچنین روز به روز هم تعدادشان بیشتر می‌شوند.
اما باز هم نمی‌توان ایراد گرفت چون کار ارائه شده سورس باز است. به عبارتی اگر مایکروسافت این قالب‌ها را به روز نکرده، خوب، لطفا خود شما وقت بگذارید و این کار را انجام داده و سپس یک patch ارائه دهید. ایرادی دارد؟!
برای این منظور پروژه‌ای در سایت CodePlex ایجاد شده است و تنها به پوشش دات نت سه و نیم و دیتاگرید متعلق به WPF Toolkit پرداخته است :


اگر علاقمند باشید که از دیتاگرید بومی دات نت 4 استفاده کنید می‌توانید از این patch استفاده کنید.

اشتراک‌ها
نسخه‌بندی معنایی 2.0.0

در دنیای مدیریت نرم‌افزار مکان مخوفی به نام «جهنم وابستگی» (dependency hell) وجود دارد. هر چه سیستم شما بزرگتر باشد و بسته‌های (package) بیشتری با نرم‌افزار شما یکپارچه شده باشند، احتمال بیشتری وجود دارد که روزی خود را دراین گودال ناامیدی بیابید. 

نسخه‌بندی معنایی 2.0.0
اشتراک‌ها
بزرگترین موسسه بررسی رنکینگ دیتابیس ها

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

بزرگترین موسسه بررسی رنکینگ دیتابیس ها
نظرات مطالب
تبدیل HTML به PDF با استفاده از کتابخانه‌ی iTextSharp
از خدا برای شما بهترین ها را آرزو میکنم.امشب مشکل من را حل کردید.امیدوارم که ثمره آن را در زندگی تان ببینی.اگر روزی بدانم میتوانم برایتان کاری انجام بدم و در توانم باشد دریغ نخواهم کرد.همیشه پیروز باشید.

2011/10/21 Disqus <>
نظرات نظرسنجی‌ها
با توجه به امکانات جدید Razor Components، آیا در آینده از SPA frameworks استفاده میکنید؟
بله درحال حاضر چیزی بهتر از spa وجود نداره به همین دلیل به کرات درحال استفاده هستیم ... من به نسبت شعارغیر مستقیم تیم تولید blazor  این رو در نظر سنجی گذاشتم هر چند خودم هم احتمال این رو میدم یک روزی نه چندان دور کسی از spa استفاده نکنه.
نظرات مطالب
یکی از مزایای استفاده از SVN در یک پروژه تک نفره
نوشته خیلی خوبی و سودمندی بود. من شخصا برای PHP از SVN آنلاین سایت http://xp-dev.com استفاده می‏کنم. بد نیست نگاهی بیاندازید. سایت خیلی خوبی است و خدماتش کلا رایگان است. سایت شما را در لیست دوستان لینک کردم.