کتابخانه wheelnav
پرسش و پاسخهای متداول ایجاد یک وبلاگ بلاگری
The feed address you entered is password protected. You can specify a username and password in the URL like http://user:password@www.website.com/index.xml.
قصد داریم تا مانند مثال قسمت قبل، مجموعه ای از اطلاعات مربوط به مرورگرهای مختلف را در یک جدول نشان دهیم، اما این بار منبع داده ما فرق میکند. منبع داده از طرف سرور فراهم میشود. هر مرورگر - همان طور که در قسمت قبل مشاهده نمودید - شامل اطلاعات زیر خواهد بود:
- موتور رندرگیری (Engine)
- نام مرورگر (Name)
- پلتفرم (Platform)
- نسخه موتور (Version)
- نمره سی اس اس (Grade)
به همین دلیل در سمت سرور، کلاسی خواهیم ساخت که نمایانگر یک مرورگر باشد. بدین صورت:
public class Browser { public int Id { get; set; } public string Engine { get; set; } public string Name { get; set; } public string Platform { get; set; } public float Version { get; set; } public string Grade { get; set; } }
این روش، یکی از امکانات jQuery DataTables است که با استفاده از آن، کلاینت تنها یک مصرف کننده صرف خواهد بود و وظیفه پردازش اطلاعات - یعنی تعداد رکوردهایی که برگشت داده میشود، صفحه بندی، مرتب سازی، جستجو، و غیره - به عهده سرور خواهد بود.
برای به کار گیری این روش، اولین کار این است که ویژگی bServerSide را true کنیم، مثلا بدین صورت:
var $table = $('#browsers-grid'); $table.dataTable({ "bServerSide": true, "sAjaxSource": "/Home/GetBrowsers" });
همچنین ویژگی sAjaxSource را به Url ی که باید دادهها از آن دریافت شوند مقداردهی میکنیم.
به صورت پیش فرض مقدار ویژگی bServerSide مقدار false است؛ که یعنی منبع داده این پلاگین از سمت سرور خوانده نشود. اگر true باشد منبع داده و خیلی اطلاعات دیگر مربوط به دادههای درون جدول باید از سرور به مرورگر کاربر پس فرستاده شوند. با true کردن مقدار bServerSide، آنگاه DataTables اطلاعاتی را راجع به شماره صفحه جاری، اندازه هر صفحه، شروط فیلتر کردن داده ها، مرتب سازی ستون ها، و غیره را به سرور میفرستد. همجنین انتظار میرود تا سرور در پاسخ به این درخواست، دادههای مناسبی را به فرمت JSON به مرورگر پس بفرستد. در حالتی که bServerSide مقدار true به خود بگیرد، پلاگین فقط رابطه متقابل بین کاربر و سرور را مدیریت میکند و هیچ پردازشی را انجام نمیدهد.
در این درخواست XHR یا Ajax ی پارامترهایی که به سرور ارسال میشوند اینها هستند:
iDisplayStart عدد صحیح
نقظه شروع مجموعه داده جاری
iDisplayLength عدد صحیح
تعداد رکوردهایی که جدول میتواند نمایش دهد. تعداد رکوردهایی که از طرف سرور برگشت داده میشود باید با این عدد یکسان باشند.
iColumns عدد صحیح
تعداد ستونهایی که باید نمایش داده شوند.
sSearch رشته
فیلد جستجوی عمومی
bRegex بولین
اگر true باشد معنی آن این است که میتوان از عبارات باقاعده برای جستجوی عبارتی خاص در کل ستونهای جدول استفاده کرد. مثلا در کادر جستجو نوشت :
^[1-5]$
sSearch_(int) رشته
فیلتر مخصوص هر ستون. اگر از ویژگی multi column filtering پلاگین استفاده شود به صورت sSearch0 ، sSearch1 ، sSeach2 و ... به طرف سرور ارسال میشوند. شماره انتهای هر کدام از پارامترها بیانگر شماره ستون جدول است.
bRegex_(int) بولین
اگر true باشد، بیان میکند که میتوان از عبارت با قاعده در ستون شماره int جهت جستجو استفاده کرد.
bSortable_(int) بولین
مشخص میکند که آیا یک ستون در سمت کلاینت، قابلیت مرتب شدن بر اساس آن وجود دارد یا نه. (در اینجا int اندیس ستون را مشخص میکند)
iSortingCols عدد صحیح
تعداد ستون هایی که باید مرتب سازی بر اساس آنها صورت پذیرد. در صورتی که از امکان multi column sorting استفاده کنید این مقدار میتواند بیش از یکی باشد.
iSortCol_(int) عدد صحیح
شماره ستونی که باید بر اساس آن عملیات مرتب سازی صورت پذیرد.
sSortDir_(int) رشته
نحوه مرتب سازی ؛ شامل صعودی (asc) یا نزولی (desc)
mDataProp_(int) رشته
اسم ستونهای درون جدول را مشخص میکند.
sEcho رشته
اطلاعاتی که datatables از آن برای رندر کردن جدول استفاده میکند.
شکل زیر نشان میدهد که چه پارامترهایی به سرور ارسال میشوند.
بعضی از این پارامترها بسته به تعداد ستونها قابل تغییر هستند. (آن پارامترهایی که آخرشان یک عدد هست که نشان دهنده شماره ستون مورد نظر میباشد)
در پاسخ به هر درخواست XHR که datatables به سرور میفرستد، انتظار دارد تا سرور نیز یک شیء json را با فرمت مخصوص که شامل پارامترهای زیر میشود به او پس بفرستد:
iTotalRecords عدد صحیح
تعداد کل رکوردها (قبل از عملیات جستجو) یا به عبارت دیگر تعداد کل رکوردهای درون آن جدول از دیتابیس که دادهها باید از آن دریافت شوند. تعداد کل رکوردهایی که در طرف سرور وجود دارند. این مقدار فقط برای نمایش به کاربر برگشت داده میشود و نیز از آن برای صفحه بندی هم استفاده میشود.
iTotalDisplayRecords عدد صحیح
تعداد کل رکوردها (بعد از عملیات جستجو) یا به عبارت دیگر تعداد کل رکوردهایی که بعد از عملیات جستجو پیدا میشوند نه فقط آن تعداد رکوردی که به کاربر پس فرستاده میشوند. تعداد کل رکوردهایی که با شرط جستجو مطابقت دارند. اگر کاربر چیزی را جستجو نکرده باشد مقدار این پارامتر با پارامتر iTotalRecords یکسان خواهد بود.
sEcho عدد صحیح
یک عدد صحیح است که در قالب رشته در تعامل بین سرور و کلاینت جا به جا میشود. این مقدار به ازاء هر درخواست تغییر میکند. همان مقداری که مرورگر به سرور میدهد را سرور هم باید به مرورگر تحویل بدهد. برای جلوگیری از حملات XSS باید آن را تبدیل به عدد صحیح کرد. پلاگین DataTables مقدار این پارامتر را برای هماهنگ کردن و منطبق کردن درخواست ارسال شده و جواب این درخواست استفاده میکند. همان مقداری که مروگر به سرور میدهد را باید سرور تحویل به مرورگر بدهد.
sColumns رشته
اسم ستونها که با استفاده از کاما از هم جدا شده اند. استفاده از آن اختیاری است و البته منسوخ هم شده است و در نسخههای جدید jQuery DataTables از آن پشتیبانی نمیشود.
aaData آرایه
همان طور که قبلا هم گفتیم، مقادیر سلول هایی را که باید در جدول نشان داده شوند را در خود نگهداری میکند. یعنی در واقع دادههای جدول در آن ریخته میشوند. هر وقت که DataTables دادههای مورد نیازش را دریافت میکند، سلولهای جدول html مربوطه اش را از روی آرایه aaData ایجاد میکند. تعداد ستونها در این آرایه دو بعدی، باید با تعداد ستونهای جدول html مربوطه به آن یکسان باشد
شکل زیر پارامترها دریافتی از سرور را نشان میدهند:
همان طور که گفتیم، کلاینت به سرور یک سری پارامترها را ارسال میکند و آن پارامترها را هم شرح دادیم. برای دریافت این پارامترها طرف سرور، احتیاج به یک مدل هست. این مدل به صورت زیر پیاده سازی خواهد شد:
/// <summary> /// Class that encapsulates most common parameters sent by DataTables plugin /// </summary> public class jQueryDataTableParamModel { /// <summary> /// Request sequence number sent by DataTable, /// same value must be returned in response /// </summary> public string sEcho { get; set; } /// <summary> /// Text used for filtering /// </summary> public string sSearch { get; set; } /// <summary> /// Number of records that should be shown in table /// </summary> public int iDisplayLength { get; set; } /// <summary> /// First record that should be shown(used for paging) /// </summary> public int iDisplayStart { get; set; } /// <summary> /// Number of columns in table /// </summary> public int iColumns { get; set; } /// <summary> /// Number of columns that are used in sorting /// /// </summary> public int iSortingCols { get; set; } /// <summary> /// Comma separated list of column names /// </summary> public string sColumns { get; set; } }
مدل بایندر mvc وظیفه مقداردهی به خصوصیات درون این کلاس را بر عهده دارد، بقیه پارامترهایی که به سرور ارسال میشوند و در این کلاس نیامده اند، از طریق شیء Request در دسترس خواهند بود.
اکشن متدی که مدل بالا را دریافت میکند، میتواند به صورت زیر پیاده سازی شود. این اکشن متد وظیفه پاسخ دادن به درخواست DataTables بر اساس پارامترهای ارسال شده در مدل DataTablesParam را دارد. خروجی این اکشن متد شامل پارارمترهای مورد نیاز پلاگین DataTables برای تشکیل جدول است که آنها را هم شرح دادیم.
public JsonResult GetBrowsers(jQueryDataTableParamModel param) { IQueryable<Browser> allBrowsers = new Browsers().CreateInMemoryDataSource().AsQueryable(); IEnumerable<Browser> filteredBrowsers; // Apply Filtering if (!string.IsNullOrEmpty(param.sSearch)) { filteredBrowsers = new Browsers().CreateInMemoryDataSource() .Where(x => x.Engine.Contains(param.sSearch) || x.Grade.Contains(param.sSearch) || x.Name.Contains(param.sSearch) || x.Platform.Contains(param.sSearch) ).ToList(); float f; if (float.TryParse(param.sSearch, out f)) { filteredBrowsers = filteredBrowsers.Where(x => x.Version.Equals(f)); } } else { filteredBrowsers = allBrowsers; } // Apply Sorting var sortColumnIndex = Convert.ToInt32(Request["iSortCol_0"]); Func<Browser, string> orderingFunction = (x => sortColumnIndex == 0 ? x.Engine : sortColumnIndex == 1 ? x.Name : sortColumnIndex == 2 ? x.Platform : sortColumnIndex == 3 ? x.Version.ToString() : sortColumnIndex == 4 ? x.Grade : x.Name); var sortDirection = Request["sSortDir_0"]; // asc or desc filteredBrowsers = sortDirection == "asc" ? filteredBrowsers.OrderBy(orderingFunction) : filteredBrowsers.OrderByDescending(orderingFunction); // Apply Paging var enumerable = filteredBrowsers.ToArray(); IEnumerable<Browser> displayedBrowsers = enumerable.Skip(param.iDisplayStart). Take(param.iDisplayLength).ToList(); return Json(new { sEcho = param.sEcho, iTotalRecords = allBrowsers.Count(), iTotalDisplayRecords = enumerable.Count(), aaData = displayedBrowsers }, JsonRequestBehavior.AllowGet); }
تشریح اکشن متد GetBrowsers :
این اکشن متد از مدل jQueryDataTableParamModel به عنوان پارامتر ورودی خود استفاده میکند. این مدل همان طور هم که گفتیم، شامل یک سری خصوصیت است که توسط پلاگین jQuery DataTables مقداردهی میشوند و همچنین مدل بایندر mvc وظیفه بایند کردن این مقادیر به خصوصیات درون این کلاس را بر عهده خواهد داشت. درون بدنه اکشن متد GetBrowsers دادهها بعد از اعمال عملیات فیلترینگ، مرتب سازی، و صفحه بندی به فرمت مناسبی درآمده و به طرف مرورگر فرستاده خواهند شد.
برای پیاده سازی کدهای طرف کلاینت نیز، درون یک View کدهای زیر قرار خواهند گرفت:
$(function () { var $table = $('#browsers-grid'); $table.dataTable({ "bProcessing": true, "bStateSave": true, "bServerSide": true, "bFilter": true, "sDom": 'T<"clear">lftipr', "aLengthMenu": [[5, 10, 25, 50, -1], [5, 10, 25, 50, "All"]], "bAutoWidth": false, "sAjaxSource": "/Home/GetBrowsers", "fnServerData": function (sSource, aoData, fnCallback) { $.ajax({ "dataType": 'json', "type": "POST", "url": sSource, "data": aoData, "success": fnCallback }); }, "aoColumns": [ { "mDataProp": "Engine" }, { "mDataProp": "Name" }, { "mDataProp": "Platform" }, { "mDataProp": "Version" }, { "mDataProp": "Grade" } ], "oLanguage": { "sUrl": "/Content/dataTables.persian.txt" } }); });
تشریح کدها:
fnServerData :
این متد، در واقع نحوه تعامل سرور و کلاینت را با استفاده از درخواستهای XHR مشخص خواهد کرد.
oLanguage :
برای فعال سازی زبان فارسی، فیلدهای مورد نیاز ترجمه شده و در یک فایل متنی قرار داده شده اند. کافی است آدرس این فایل متنی به ویژگی oLanguage اختصاص داده شوند.
مثال این قسمت را از لینک زیر دریافت کنید:
DataTablesTutorial04.zip
لازم به ذکر است پوشه bin، obj، و packages جهت کاهش حجم این مثال از solution حذف شده اند. برای اجرای این مثال از اینجا کمک بگیرید.
مطالعه بیشتر
برای مطالعه بیشتر در مورد این پلاگین و نیز پیاده سازی آن در MVC میتوانید به لینک زیر نیز مراجعه بفرمائید که بعضی از قسمتهای این مطلب هم از مقاله زیر استفاده کرده است:
jQuery DataTables and ASP.NET MVC Integration - Part I
(The God Class Problem (Behavioral Form
یکی از مخاطراتی که ممکن است موجب عدم بروز مزایای شیء گرایی در طرح شما شود، بحث God Class میباشد. شکل رفتاری آن (Behavioral Form) بیشتر در اثر یک خطای مشترک بین توسعه دهندگان پارادایم action-oriented و در جریان مهاجرت به سمت پارادایم شیء گرا، رخ میدهد.
این توسعه دهندگان بیشتر سعی در تسخیر و دستیابی به یک مکانیزم کنترل مرکزی شبیه به آنچه در پارادایم action-oriented داشتهاند، در طراحی شیء گرای خود دارند. حاصل این کار تشکیل کلاسی خواهد بود که همه کارها را انجام میدهد، درحالیکه جزئیات ناچیزی هم به عهده مجموعهای از کلاسها سپرده شده است.
قاعده شهودی 3.1
تا حد ممکن هوشمندی سیستم را به صورت افقی و به طور یکنواخت توزیع کنید. به این معنی که کلاسهای سطح بالای موجود در طراحی، باید کار را به طور یکسان مابین خود به اشتراک بگذارند. (Distribute system intelligence horizontally as uniformly as possible, that is, the top-level classes in a design should share the work uniformly)منظور اینکه Businessای را که سیستم قرار است پیاده سازی کند، بین کلاسهای سطح بالا تقسیم کنید. در حالت vertical یا عمودی میتوان در نظر گرفت که کلاسی این Business را توسط یکسری متد در دل خود پیاده سازی کند و این متدها یکدیگر را فراخوانی خواهند کرد.
قاعده شهودی 3.2
در سیستم خود God Class ایجاد نکنید. به کلاس هایی که نام آنها شامل Driver، Manager و یا Subsystem میباشد، مشکوک باشید. (Do not create god classes/objects in your system. Be very suspicious of a class whose name contains Driver, Manager, System, or Subsystem)
مانند: BlahBlahSystem یا BlahManager
قاعده شهودی 3.3مراقب کلاس هایی باشید که در واسط عمومی آنها تعداد زیادی Accessor Method تعریف شده است؛ وجود آنها نشان از این دارد که داده و رفتار، در یکجا نگه داشته نشده اند. (Beware of classes that have many accessor methods defined in their public interface. Having many implies that related data and behavior are not being kept in one place)ازدیاد عملیات get و set در واسط عمومی کلاسها که Accessor Method نامیده میشوند، نشان دهنده ایجاد شکل رفتاری God Class میباشند. منظور این است که یک کلاس، رفتارهایی برای کار کردن با دادههای خود در نظر نگرفته است و این دادهها را از طریق accessor methodها در اختیار کلاس دیگری قرار میدهد تا عملیات روی دادهها را انجام دهد. در اینجا هم مقصود God Class شدن کلاسی است که از این accessor methodها استفاده میکند و نشان از این دارد که تعداد رفتارهای آن زیاد خواهد شد.
مراقب کلاس هایی باشید که تعداد خیلی زیادی رفتار نامرتبط دارند؛ یعنی رفتارهایی که فقط برروی زیر مجموعه ای از دادههای کلاس کار میکنند. God Classها اغلب دارای اینگونه رفتارهای نامرتبط به هم هستند. (Beware of classes that have too much noncommunicating behavior, that is, methods that operate on a proper subset of the data members of a class. God classes often exhibit much noncommunicating behavior)منظور اینکه کلاس مورد نظر را میتوان شکست و تبدیل به دو کلاس مختلف کرد. به عنوان اولین مثال، دامنه مربوط به سیستم برنامه ریزی دورههای آموزشی را در نظر بگیرید. در این دامنه، ما با وهله هایی از «Student» ،«Course» و «CourseOffering» سروکار خواهیم داشت.
قصد داریم با فراخوانی متد ()add_student مربوط به CourseOffering، یک دانشجو را به لیست شرکت کنندگان یک دوره اضافه کنیم. همچنین در این زمان لازم است مطمئن شویم که دانشجوی مورد نظر تمام پیش نیازهای دوره انتخاب شده را گذرانده باشد. به نظر شما کدام کلاس میبایست عملیات چک کردن پیش نیازها را انجام دهد؟
کلاس دانشجو از دورههایی که گذرانده است آگاه است و کلاس دوره هم از پیش نیازهای خود. در بهترین حالت شاید یکی از طراحیهای زیر را ارائه دهید. به شکلی که یا کلاس دوره با استفاده از متد get_courses مربوط به کلاس دانشجو، داده مورد نیاز را بدست آورده و عملیات چک کردن را در دل خود بگنجاند یا برعکس.
در هر دو طراحی بالا، بخشی از اطلاعات مربوط به policy (سیاست) در کلاس هایی قرار دارد که موضوع تصمیمات سیاستها هستند. این کار از آن جهت که کلاسهای مورد نظر ما را به دامنه خاصی که این policy در آن دامنه معنا دارد وابسته میکند و امکان استفاده مجدد از آن کلاسها را از دست خواهید داد.
راه حلهای پیشنهادی برای مشکل مطرح شده به شکل زیر میباشند:
با توجه به طراحی شکل بالا، یا خود کلاس CourseOffering با استفاده از لیست دورههای گذرانده شده توسط دانشجو و لیست دورههای پیش نیاز دوره انتخابی، چک کردن را انجام دهد و یا کلاسی با عنوان PrereqChecker که یک Controller Class (کلاسی که فقط رفتار دارد و داده مورد نظر خود را توسط سایر کلاسها و از طریق accessor methodهای آنها تأمین میکند) میباشد، وظیفه چک کردن را برعهده بگیرد.
علاوه بر اینکهaccessor method ها، داده را برای کلاسهای کنترلر مهیا میکنند (مانند مثال بالا)، وظیفهی مهیا کردن داده برای UI (رابط کاربری) را نیاز بر عهده خواهند داشت. به این صورت که رابط کاربری، با استفاده از این متدها، مشخصات درونی مدل را نمایش دهد و یا این امکان را به کاربر میدهد که این مشخصات درونی مدل را ویرایش کرده و به سمت مدل ارسال نماید.
قاعده شهودی 3.5
در برنامههایی که شامل یک مدل شی گرایی میباشند که با رابط کاربری تعامل دارند، مدل نباید به رابط کاربری وابسته باشد. رابط کاربری میبایست وابسته به مدل باشد. (In applications that consist of an object-oriented model interacting with a user interface, the model should never be dependent on the interface. The interface should be dependent on the model)
برای عدم نقض این قاعده شهودی، لازم است در مدل یکسری accessor method در نظر گرفته شود تا رابط کاربری از آن استفاده کند؛ ولی باید مراقب بود که این accessor methodها صرفا توسط رابط کاربری استفاده شود و عدم توجه به این قضیه، احتمالا شما را به سمت نقض قاعده 3.3 متمایل خواهد کرد.
تا پیش از نگارش 2.1، تمام درخواستهای رسیدهی به IIS توسط یک پروکسی معکوس به نام ASP.NET Core Module به Kestrel ارسال میشدند:
در نگارش 2.1، میتوان کل برنامه را داخل IIS worker process یا همان w3wp.exe هاست کرد تا تاثیر منفی این پروکسی معکوس حذف شود. با بررسیهای انجام شده، این روش بهبود کارآیی بیش از 4 برابری را به همراه دارد؛ نسبت به حالت out-of-process فعلی (تصویر فوق).
برای فعالسازی آن یا فایل web.config را به صورت ذیل جهت تعیین hostingModel ویرایش کنید:
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" hostingModel="inprocess" />
<PropertyGroup> <AspNetCoreModuleHostingModel>inprocess</AspNetCoreModuleHostingModel> </PropertyGroup>
Top Issues Fixed in Visual Studio 2019 version 16.2.5
- Visual Studio stops respsonding on creating a new SSIS project
- Fixed UI freezes occurring after extended usage of the editor.
Security Advisory Notices
CVE-2019-1232 Diagnostics Hub Standard Collector Service Elevation of Privilege Vulnerability
An elevation of privilege vulnerability exists when the Diagnostics Hub Standard Collector Service improperly impersonates certain file operations. An attacker who successfully exploited this vulnerability could gain elevated privileges. An attacker with unprivileged access to a vulnerable system could exploit this vulnerability. The security update addresses the vulnerability by ensuring the Diagnostics Hub Standard Collector Service properly impersonates file operations.
CVE-2019-1301: Denial of Service Vulnerability in .NET Core
A denial of service vulnerability exists when .NET Core improperly handles web requests. An attacker who successfully exploited this vulnerability could cause a denial of service against a .NET Core web application. The vulnerability can be exploited remotely, without authentication.
The update addresses the vulnerability by correcting how the .NET Core web application handles web requests.