MessageBox.Show(securePwd);
کامپوننتهای Nav در بوت استرپ 4
کامپوننتهای گروه Nav، در نگارش 4 آن به علت استفادهی از Flexbox، تغییرات بسیاری داشتهاند و در نتیجهی آن، انعطاف پذیرتر و سادهتر شدهاند.
در ابتدا لیست سادهی زیر را در نظر بگیرید. تنظیمات ابتدایی آن برای تبدیل به منوی راهبری بالای سایت به صورت زیر است:
<body> <div class="container"> <div class="row"> <section class="col-12"> <ul class="nav"> <li class="nav-item"><a class="nav-link active" href="#">Home</a></li> <li class="nav-item"><a class="nav-link" href="#">Mission</a></li> <li class="nav-item"><a class="nav-link" href="#">Services</a></li> <li class="nav-item"><a class="nav-link" href="#">Staff</a></li> <li class="nav-item"><a class="nav-link disabled" href="#">Testimonials</a></li> </ul> </div> </div> </body>
در اینجا دو کلاس active و disabled نیز به لینکهای منوی راهبری اضافه شدهاند. البته این کلاسها تا تکمیل نهایی nav، ظاهر آنچنان متفاوتی را ارائه نمیدهند.
اولین شیوهنامهای را که میتوان به nav اضافه کرد، nav-pills است:
<ul class="nav nav-pills">
Pills شبیه به دکمهها هستند و در این حالت لینک active، واضحتر به نظر میرسد.
و یا میتوان nav-tabs را به nav افزود:
<ul class="nav nav-tabs">
روش دیگر تعریف nav، استفاده از المان nav و سپس حذف ul و li و همچنین nav-item است:
<nav class="nav nav-pills justify-content-center"> <a class="nav-link active" href="#">Home</a> <a class="nav-link" href="#">Mission</a> <a class="nav-link" href="#">Services</a> <a class="nav-link" href="#">Staff</a> <a class="nav-link disabled" href="#">Testimonials</a> </nav>
کلاس دیگری را که در اینجا میتوان استفاده کرد، flex-column است تا آیتمهای nav، بجای نمایش در یک ردیف، در یک ستون ظاهر شوند:
و یا میتوان با استفاده از break-points، سبب شد تا اگر اندازهی صفحه بیش از sm بود، آیتمهای منوی راهبری، ردیفی و اگر کمتر از آن بود (حالت موبایل)، ستونی نمایش داده شوند:
<nav class="nav nav-pills justify-content-center flex-column flex-sm-row">
ایجاد navbars در بوت استرپ 4
Navbar بوت استرپ 4، بازنویسی کامل شده و کار کردن با آن نسبت به نگارش سوم آن بسیار سادهتر شدهاست.
<body> <nav class="navbar bg-dark navbar-dark navbar-expand-sm"> <div class="container"> <div class="navbar-nav"> <a class="nav-item nav-link active" href="#">Home</a> <a class="nav-item nav-link" href="#">Mission</a> <a class="nav-item nav-link" href="#">Services</a> <a class="nav-item nav-link" href="#">Staff</a> <a class="nav-item nav-link disabled" href="#">Testimonials</a> </div> </div> </nav> <div class="container">
در اینجا، کار با افزودن کلاس navbar به المان nav شروع میشود. سپس هر لینک داخل آن، کلاسهای nav-item nav-link را پیدا میکند. در اینجا اگر آیتمی قرار است به صفحهی جاری اشاره کند، با کلاس active مشخص خواهد شد.
سپس توسط کلاسهای bg-dark navbar-dark، رنگهای پس زمینه و رنگ متن مشخص شدهاند. برای مثال میتوان bg-light navbar-light را نیز آزمایش کرد:
<nav class="navbar bg-light navbar-light navbar-expand-sm">
و یا بجای این رنگهای پیشفرض، در بوت استرپ 4 میتوان به سادگی رنگ navbar را توسط یک background-color دلخواه، سفارشی سازی کرد:
<nav class="navbar navbar-dark navbar-expand-sm" style="background-color:red">
کاری که در نگارشهای پیشین بوت استرپ به سادگی میسر نبود.
همچنین اگر دقت کرده باشید از کلاس navbar-expand-sm نیز استفاده شدهاست. حالت پیشفرض نمایش آیتمهای navbar، ستونی است و برای حالت موبایل درنظر گرفته شدهاست. استفادهی از navbar-expand-sm سبب میشود تا پس از عرض sm، آیتمهای navbar همانند شکلهای فوق، در طی یک ردیف نمایش داده شوند و در عرض کمتر از sm، به صورت یک ستون:
به علاوه آیتمهای navbar را داخل یک container قرار دادهایم:
<div class="container"> <div class="navbar-nav">
تعریف متون و لوگو در navbar بوت استرپ 4
برای تعریف متن لوگوی سایت در navbar به صورت زیر عمل میشود:
<body> <nav class="navbar bg-dark navbar-dark navbar-expand-sm"> <div class="container"> <div class="navbar-brand"> Wisdom Pet Medicine </div> <div class="navbar-nav"> <a class="nav-item nav-link active" href="#">Home</a> <a class="nav-item nav-link" href="#">Mission</a> <a class="nav-item nav-link" href="#">Services</a> <a class="nav-item nav-link" href="#">Staff</a> <a class="nav-item nav-link disabled" href="#">Testimonials</a> </div> </div> </nav> <div class="container">
و یا میتوان بجای div، از المان anchor نیز استفاده کرد تا به صورت لینک نمایش داده شود:
<a class="navbar-brand" href="#"> Wisdom Pet Medicine </a>
برای تعریف متنی در navbar از کلاس navbar-text استفاده میشود:
<body> <nav class="navbar bg-dark navbar-dark navbar-expand-sm"> <div class="container"> <a class="navbar-brand d-none d-sm-inline-block" href="#"> Wisdom Pet Medicine </a> <div class="navbar-nav"> <a class="nav-item nav-link active" href="#">Home</a> <a class="nav-item nav-link" href="#">Mission</a> <a class="nav-item nav-link" href="#">Services</a> <a class="nav-item nav-link" href="#">Staff</a> <a class="nav-item nav-link disabled" href="#">Testimonials</a> </div> <span class="navbar-text d-none d-xl-inline-block">The best in traditional and alternate medicine</span> </div> </nav> <div class="container">
همین تنظیم را به navbar-brand، در اندازهی sm نیز اضافه کردهایم تا لوگوی سایت در اندازههای موبایل ظاهر نشود.
افزودن drop downs به navbar در بوت استرپ 4
برای تبدیل یکی از آیتمهای منوی راهبری، به منو، از dropdown استفاده میشود که نمونهای از آنرا در مثال زیر مشاهده میکنید:
<body> <nav class="navbar bg-dark navbar-dark navbar-expand-sm"> <div class="container"> <a class="navbar-brand d-none d-sm-inline-block" href="#"> <img src="images/wisdompetlogo.svg" style="width:40px;" alt=""> Wisdom Pet Medicine </a> <div class="navbar-nav ml-sm-auto"> <a class="nav-item nav-link active" href="#">Home</a> <a class="nav-item nav-link" href="#">Mission</a> <div class="dropdown"> <a class="nav-item nav-link dropdown-toggle" data-toggle="dropdown" id="servicesDropdown" aria-haspopup="true" aria-expanded="false" href="#">Services</a> <div class="dropdown-menu" aria-labelledby="servicesDropdown"> <a href="#" class="dropdown-item">Grooming</a> <a href="#" class="dropdown-item">General Health</a> <a href="#" class="dropdown-item">Nutrition</a> <a href="#" class="dropdown-item">Pest Control</a> <a href="#" class="dropdown-item">Vaccinations</a> </div> </div> <a class="nav-item nav-link" href="#">Staff</a> <a class="nav-item nav-link disabled" href="#">Testimonials</a> </div> <span class="navbar-text d-none d-xl-inline-block">The best in traditional and alternate medicine</span> </div> </nav> <div class="container">
- دراپداون نیاز به یک container دارد که آنرا با تعریف یک div با کلاس dropdown تعریف کردهایم.
- سپس به لینکی که قرار است آنرا نمایش دهد، کلاس dropdown-toggle را اضافه میکنیم تا آیکن مثلثی رو به پایینی را نمایان کند. وجود این مثلث، بیانگر وجود منویی به همراه آن است.
- اکنون با تنظیم data-toggle به dropdown، کدهای جاوا اسکریپتی بوت استرپ، این المان را به صورت یک dropdown پردازش میکنند و نیازی به افزودن اسکریپتی به صفحه برای فعالسازی آن نیست. ویژگیهای aria-expanded و aria-haspopup نیز به مقدار دهی پیشفرضهای کدهای جاوا اسکریپتی آن کمک میکنند.
- خود منو توسط دربرگیرندهای با کلاس dropdown-menu و آیتمهایی با کلاس dropdown-item تشکیل میشود.
- در ادامه برای متصل کردن این دربرگیرنده به لینک نمایش دهندهی منو، یک id را به لینک انتساب میدهیم (به نام servicesDropdown) و سپس aria-labelledby دربرگیرنده را به این id، مقدار دهی میکنیم.
- در این مثال با استفاده از کلاس navbar-nav ml-sm-auto، سبب شدهایم تا منوی سایت، از لبهی سمت راست صفحه پس از عرض sm، شروع شود.
افزودن المانهای فرمها به منوی راهبری سایت
برای اضافه کردن المانهای فرم به منوی راهبری سایت، ابتدا نیاز است کلاس form-inline را بر روی container این فرم قرار داد و سپس به ورودیهای این فرم، کلاس form-control را اضافه میکنیم. اگر نیاز بود، توسط کلاسهای margin و padding مخصوص بوت استرپ 4 مانند mr-2 نیز میتوان بین آنها فاصله ایجاد کرد:
<body> <nav class="navbar navbar-dark bg-dark navbar-expand-sm"> <div class="container"> <div class="navbar-nav"> <a class="nav-item nav-link active" href="#">Home</a> <a class="nav-item nav-link" href="#">Mission</a> <a class="nav-item nav-link" href="#">Services</a> <a class="nav-item nav-link" href="#">Staff</a> <a class="nav-item nav-link" href="#">Testimonials</a> </div> <form class="form-inline"> <input type="text" placeholder="Search..." class="form-control mr-2"> <button class="btn btn-outline-light" type="submit">Go</button> </form> </div> </nav> <div class="container">
بوت استرپ در اندازهی بزرگتر صفحه، فرم را به سمت راست و آیتمهای منو را در سمت چپ نمایش میدهد.
کنترل محل قرارگیری المانها در منوی راهبری سایت
توسط کلاسهایی مانند fixed-top (قرار گرفتن در بالای صفحه)، fixed-bottom (قرار گرفتن در پایین صفحه) و sticky-top، میتوان محل قرارگیری منوی راهبری را تغییر داد. این کلاسها را در مطلب «طرحبندی صفحات وب با بوت استرپ 4 - قسمت دوم» پیشتر بررسی کردیم.
برای توضیح حالت sticky-top، فرض کنید بالای منو، تصویر بزرگی از لوگوی سایت را دارید و این منو زیر آن قرار گرفتهاست. زمانیکه صفحه به سمت پایین اسکرول میشود، این منو نیز پایین خواهد آمد تا جائیکه در لبهی بالای صفحه قرار گیرد. پس از آن، این منو در همین ناحیه باقی مانده و شبیه به fixed-top عمل میکند.
یک نکته: اگر fixed-bottom را مورد استفاده قرار دادید:
<nav class="navbar navbar-dark bg-dark navbar-expand-sm fixed-bottom">
<div class="container mb-5">
اضافه کردن منوی همبرگری به منوی راهبری سایت
در مورد کلاس navbar-expand-sm در این مطلب توضیح دادیم. هرچند قابلیت عمودی و افقی شدن خودکار آیتمهای منوی راهبری بسیار جالب و کاربری است، اما در صفحات نمایشی کوچک، این نمایش عمودی میتواند ارتفاع قابل ملاحظهای را به خود اختصاص دهد. به همین جهت میخواهیم نمایش آیتمهای آنرا وابسته به تصمیم کاربر کنیم.
<body> <nav class="navbar navbar-dark bg-dark navbar-expand-sm"> <div class="container"> <a href="#" class="navbar-brand">Wisdom Pet Medicine</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#myToggle" aria-controls="myToggle" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="myToggle"> <div class="navbar-nav"> <a class="nav-item nav-link active" href="#">Home</a> <a class="nav-item nav-link" href="#">Mission</a> <a class="nav-item nav-link" href="#">Services</a> <a class="nav-item nav-link" href="#">Staff</a> <a class="nav-item nav-link" href="#">Testimonials</a> </div> </div> </div> </nav> <div class="container">
- ابتدا نیاز است دکمهی این منو اضافه شود که توسط کلاس navbar-toggler مشخص شدهاست. سپس با توجه به اینکه این کامپوننت توسط کدهای جاوا اسکریپتی بوت استرپ کار میکند، اطلاعات مورد نیاز آنرا توسط ویژگیهای data-toggle، data-target و aria مشخص میکنیم.
- این دکمه نیاز دارد تا به یک div با کلاس collapse navbar-collapse متصل شود. این اتصال نیز از طریق id آن صورت میگیرد که در ویژگی data-target مقدار دهی شدهاست.
- اگر این دکمه را پس از navbar-brand قرار دهیم، در سمت چپ صفحه و اگر پیش از آن قرار دهیم، در سمت راست صفحه ظاهر میشود.
در حالت نمایش sm، آیتمهای منو مخفی شده:
با کلیک بر روی دکمهی منوی همبرگری آن، گزینههای منو نمایش داده میشوند:
و در حالت اندازهی بزرگتر صفحه، محو میشود:
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: Bootstrap4_07.zip
Webgrid گرید توکار asp.net
mvc 3 است که در سری آموزشهای mvc جناب نصیری به خوبی بررسی شده است . WebGrid از طریق مجموعه ای از خواص امکان استایل دهی
به ستونها و ردیفها را به توسعه دهنده میدهد . اما در این بخش مشکلی وجود دارد که
در ادامه به آن خواهم پرداخت . کدهای زیر را در نظر بگیرید
مدلها :
public class Customer { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public string Website { get; set; } public string Phone { get; set; } } public class Customers { public IList<Customer> GetList() { return new List<Customer>() { new Customer() { Id=1, Name="mohsen.d", Email="email@domain.com", Website="domain.com", Phone="213214321" } }; } public IList<Customer> GetEmptyList() { return new List<Customer>(); } }
public class HomeController : Controller { public ActionResult List() { var model = new Customers().GetList(); return View(model); } public ActionResult EmptyList() { var model = new Customers().GetEmptyList(); return View("list", model); } }
تابع کمکی برای ایجاد گرید :
@helper GenerateList(IEnumerable<object> items, List<WebGridColumn> columns) { var grid = new WebGrid(items); <div> @grid.GetHtml( tableStyle: "list", headerStyle: "list-header", footerStyle: "list-footer", alternatingRowStyle: "list-alt", selectedRowStyle: "list-selected", rowStyle: "list-row", htmlAttributes: new { id = "listItems" }, mode: WebGridPagerModes.All, columns: columns ) </div> }
@model IEnumerable<WebGridHeaderStyle.Models.Customer> @{ ViewBag.Title = "List"; } <h2>List</h2> @_List.GenerateList( Model, new List<WebGridColumn>() { new WebGridColumn(){ ColumnName="Id", Header="Id", Style="list-small-field" }, new WebGridColumn(){ ColumnName="Name", Header="Name", Style="list-long-field" }, new WebGridColumn(){ ColumnName="Email", Header="Email", Style="list-mid-field" }, new WebGridColumn(){ ColumnName="Website", Header="Website", Style="list-mid-field" }, new WebGridColumn(){ ColumnName="Phone", Header="Phone", Style="list-mid-field" } } )
خوب چندان بد نیست . با استفاده از استایلهای تعریف شده برای فیلدها و ردیفها ، لیست ساختار مناسبی دارد . اما حالا به Home/EmptyList می رویم :
همانطور که میبینید استایل هایی که برای هر ستون تعریف کرده بودیم اعمال نشده اند. مشکل هم همین
جاست . WebGrid استایل تعریف شده را تنها به ستونهای درون tbody
اعمال میکند و thead از این تنظیمات بی نصیب میماند ( WebGrid از table برای ساختن لیست استفاده میکند ) و در زمانی که رکوردی وجود نداشته باشد فرمت طراحی شده اعمال نمیشود .
در وب ترفندهایی را برای این مشکل پیدا
کردم که اصلا جالب نبودند . در نهایت راه حل زیر به نظرم رسید :
در زمان ساختن
گرید ، استایلهای تعریف شده را در یک فیلد hidden ذخیره و سپس با
استفاده از jquery این استایلها را به ستونهای header اعمال میکنیم .
تابع ساختن فیلد hidden :
@helper SetHeaderColumnsStyle(IEnumerable<WebGridColumn> columns) { var styles = new List<string>(); foreach(var col in columns) { styles.Add(col.Style); } <input id="styles" type="hidden" value="@string.Join("#",styles)" /> }
@SetHeaderColumnsStyle(columns)
<script> $(document).ready(function () { var styles = $("#styles").attr("value").split('#'); var $cols = $("#listItems th"); $cols.each(function (i) { $(this).addClass(styles[i]); }); }); </script>
آشنایی با Gridify
[HttpGet("[action]")] public async Task<IActionResult> UsersList() { var users = await _dbContext.Users.AsNoTracking().ToListAsync(); return Ok(users); }
- عدم پشتیبانی از Pagination: چون API، تمامی کاربران را به سمت کلاینت ارسال میکند؛ به همین جهت، هم با مشکل کارآیی (performance) در آینده مواجه میشویم و هم امکان گذاشتن صفحه بندی (Pagination) وجود نخواهد داشت.
- عدم پشتیبانی از Sorting: اگر در گرید نمایش داده شده کاربر بخواهد اطلاعات را Sort کند، چون چنین امکانی هنوز برای API ما تعریف نشده، این عملیات سمت سرور امکان پذیر نیست.
- عدم پشتیبانی از Filtering: همیشه نمایش تمامی اطلاعات مفید نیست. در اکثر مواقع ما نیاز داریم تا قسمتی از اطلاعات را با شرطی خاص، برگردانیم. به طور مثال لیست کاربران فعال در سامانه یا لیست کاربران غیرفعال.
[HttpGet("[action]")] public async Task<IActionResult> UsersList(GridifyQuery filter) { var users = await _dbContext.Users.AsNoTracking().GridifyAsync(filter); return Ok(users); }
var result = Users.AsQueryable().ApplyFiltering("name==Ali");
var result = Users.AsQueryable().Where(q => q.Name == "Ali");
در چه برنامههایی استفاده از بانکهای اطلاعاتی NoSQL مناسبتر است؟
1) برنامههای مدیریت محتوا
2) کاتالوگهای محصولات (هر برنامهای با تعدادی شیء و خصوصا متادیتای متغیر)
3) شبکههای اجتماعی
4) Big Data
5) سایر
1) برنامههای مدیریت محتوا
بانکهای اطلاعاتی NoSQL سندگرا، جهت تهیه برنامههای مدیریت محتوا، بسیار مناسب هستند. در این نوع برنامهها، یک سری محتوا که دارای متادیتایی هستند، ذخیره خواهند شد. این متادیتاها مانند نوع، گروه و هر نوع خاصیت دیگری، میتواند باشند. برای ذخیره سازی این نوع اطلاعات، جفتهای key-value بسیار خوب عمل میکنند. همچنین در بانکهای اطلاعاتی سندگرای NoSQL، با استفاده از مفهوم برچسبها، امکان الصاق فایلهای متناظری به اسناد پیش بینی شدهاست. همانطور که در قسمت قبل نیز ذکر شد، در Document stores، نگارشهای قدیمی اسناد نیز حفظ میشوند. به این ترتیب، این خاصیت و توانمندی توکار، امکان دسترسی به نگارشهای مختلف یک محتوای خاص را به سادگی میسر میسازد. به علاوه اکثر Document stores امکان دسترسی به این مستندات را به کمک URLها و REST API، به صورت خودکار فراهم میسازند.
برای نمونه به CouchDB، عنوان Web database نیز داده شده است؛ از این جهت که یک برنامه وب را میتوان داخل بانک اطلاعاتی آن قرار داد. در اینجا منظور از برنامه وب، یک وب سایت قابل دسترسی از طریق URLها است و نه برنامههای سازمانی وب. برای نمونه ساختاری شبیه به برنامه معروف EverNote را میتوان داخل این نوع بانکهای اطلاعاتی به سادگی ایجاد کرد (خود بانک اطلاعاتی تشکیل شده است از یک وب سرور که REST API را پشتیبانی کرده و امکان دسترسی به اسناد را بدون نیاز به کدنویسی اضافهتری، از طریق URLها و HTTP Verbs استاندارد مهیا میکند).
2) کاتالوگهای محصولات
محصولات در یک کاتالوگ، ویژگیهای مشابه یکسان فراوانی دارند؛ اما تعدادی از این محصولات، دارای ویژگیهایی خاص و منحصربفردی نیز میباشند.
مثلا یک شیء محصول را درنظر بگیرید که دارای خواص مشترک و یکسان شماره، نام، توضیحات و قیمت است. اما بعضی از محصولات، بسته به ردهی خاصی که دارند، دارای ویژگیهای خاصی مانند قدرت تفکیک، رنگ، سرعت و غیره نیز هستند که از هر گروه، به گروه دیگری متغیر است.
برای مدیریت یک چنین نیازی، هر دو گروه key-value stores و wide column stores بانکهای اطلاعاتی NoSQL مناسب هستند؛ از این جهت که در یک key-value store نیازی به تعریف هیچ نوع ساختار خاصی، در ابتدای کار نیست و این ساختار میتواند از هر رکورد، به رکورد دیگری متفاوت باشد.
یا برای نمونه، یک برنامه فرم ساز را درنظر بگیرید که هر فرم آن، هر چند دارای یک سری خواص ثابت مانند نام، گروه و امثال آن است، اما هر کدام دارای فیلدهای تشکیل دهنده متفاوتی نیز میباشد. به این ترتیب با استفاده از key-value stores، دیگری نیازی به نگران بودن در مورد نحوه مدیریت اسکیمای متغیر مورد نیاز، نخواهد بود.
3) شبکههای اجتماعی
همانطور که در قسمت قبل نیز بحث شد، نوع خاص Graph databases برای کاربردهای برنامههای شبکههای اجتماعی و ردیابی تغییرات آنها بسیار مفید و کارآ هستند. برای مثال در یک شبکه افراد دارای تعدادی دنبال کننده هستند؛ عضو گروههای مختلف میباشند، در قسمتهای مختلفی نظر و مطلب ارسال میکنند. در اینجا، اشیاء نسبت به یکدیگر روابط مختلفی دارند. با استفاده از Graph databases، تشکیل روابط self-joins و تو در تو و بسیاری از روشهای خاص، مانند روابط many-to-many که در بانکهای اطلاعاتی رابطهای با تمهیدات ویژهای قابل تشکیل هستند، با سهولت بهتری مدیریت خواهند شد.
4) Big Data
الگوریتم MapReduce، برای کار با حجم دادههای عظیم، طراحی شده است و در این بین، بانکهای اطلاعاتی Wide column store (که در قسمت قبل بررسی شدند) و یا حتی Key-value store (مانند Amazon DynamoDB) بیشتر کاربرد دارند. در سناریوهای دادههای عظیم، واژههای Hadoop و Hbase دنیای NoSQL را زیاد خواهید شنید. Hadoop نسخه سورس باز MapReduce گوگل است و Hbase نیز نسخه سورس باز BigTable گوگل میباشد. مفاهیم پایهای Sharding و فایل سیستمهای Append-only (با سرعت بالای نوشتن) نیز به مدیریت BigData کمک میکنند.
در اینجا بحث مهم، خواندن اطلاعات و آنالیز آنها است و نه تهیه برنامههای معروف CRUD. بسیاری از اعمال آماری و ریاضی مورد نیاز بر روی دادههای عظیم، نیازی به اسکیمای از پیش مشخص شده بانکهای اطلاعاتی رابطهای را ندارند و یا در اینجا قابلیتهای نوشتن کوئریهای پیچیده نیز آنچنان مهم نیستند.
5) سایر کاربردها
- هر سیستمی که اطلاعات Log مانند را تولید میکند. منظور از Log، اطلاعاتی است که در حین رخداد خاصی تولید میشوند. عموما مرسوم است که این نوع اطلاعات را در فایلها، بجای بانک اطلاعاتی ذخیره کرد. بنابراین مدیریت این نوع فایلها توسط بانکهای اطلاعاتی NoSQL، قابلیت انجام امور آماری را بر روی آنها سادهتر خواهد ساخت.
- مدیریت اطلاعات برنامههایی مانند سیستمهای EMail.
و در چه برنامههایی استفاده از بانکهای اطلاعاتی رابطهای مناسبتر است؟
اگر تا اینجا به مزایای استفاده از بانکهای اطلاعاتی NoSQL اشاره شد، بدین معنا نیست که بانکهای اطلاعاتی رابطهای، منسوخ شدهاند یا دیگر قدر و قیمتی ندارند. واقعیت این است که هنوز بازه وسیعی از کاربردها را میتوان به کمک بانکهای اطلاعاتی رابطهای بهتر از بانکهای اطلاعاتی NoSQL مدیریت کرد. این کاربردها و مزیتها در 5 گروه عمده خلاصه میشوند:
1) نیاز به تراکنشها
2) اسکیمای پیش فرض
3) برنامههای LOB یا Line of business applications
4) زبانهای کوئری نویسی پیشرفته
5) نیاز به امکانات گزارشگیری پیشرفته
1) نیاز به تراکنشها
در سیستمهای تجاری عمومی، نیاز به پیاده سازی مفهوم ACID که در قسمتهای قبل به آن پرداخته شد، مانند Atomic transactions وجود دارد. Atomic transaction به زبان ساده به این معنا است که سیستم قادر است چندین دستور را در قالب یک گروه و در طی یک مرحله، به بانک اطلاعاتی اعمال کند و اگر یکی از این دستورات گروه در حال اعمال، با شکست مواجه شد، باید کل تراکنش برگشت خورده و امنیت کار تضمین گردد. در غیراینصورت با یک سیستم غیر هماهنگ مواجه خواهیم شد.
و همانطور که پیشتر نیز عنوان شد، سیستمهای NoSQL، مبنای کار را بر اساس «عاقبت یک دست شدن» اطلاعات قرار دادهاند؛ تا دسترسی پذیری به آنها افزایش یافته و سرعت عملیات به این نحو بهبود یابد. در این نوع سیستمها تضمینی در مورد ACID وجود ندارد.
2) اسکیمای پیش فرض
پروسههای متداول، دارای ساختاری مشخص و معمولی هستند. زیرا طراحی اولیه یک پروسه، بر مبنای مجموعهای از اطلاعات است که همیشه باید وجود داشته باشند و اگر همانند بحث کاتالوگهای محصولات، نیاز به متادیتای متغیر نباشد، ساختار و اسکیمای یک پروسه، از ابتدای طراحی آن مشخص میباشد.
و ... تمام اینها را به خوبی میتوان توسط بانکهای اطلاعاتی رابطهای، با تعریف یک اسکیمای مشخص، مدیریت کرد.
3) برنامههای LOB یا Line of business applications
در برنامههای تجاری متداول، طراحی طرحبندی فرمهای برنامه یا انقیاد دادهها، بر اساس یک اسکیما و ساختار مشخص صورت میگیرد. بدون داشتن یک اسکیمای مشخص، امکان تعاریف انقیاد دادهها به صورت strongly typed وجود نخواهد داشت. همچنین کل مفهوم Object relational mapping و ORMهای مختلف نیز بر اساس وجود یک اسکیمای مشخص و از پیش تعیین شده کار میکند. بنابراین بانکهای اطلاعاتی رابطهای، انتخاب بسیار مناسبی برای تهیه برنامههای تجاری روزمره هستند.
4) زبانهای کوئری نویسی پیشرفته
همانطور که عنوان شد برای تهیه کوئری بر روی اغلب بانکهای اطلاعاتی NoSQL، باید توسط یک برنامه ثانویه، کار پیاده سازی الگوریتم Map Reduce را انجام داد. هر چند تعدادی از این نوع بانکهای اطلاعاتی به صورت توکار دارای موتور MapReduce هستند، اما بسیاری از آنها خیر. به همین جهت برای تهیه کوئریهای متداول، کار پیاده سازی این برنامههای ثانویه مشکل خواهد بود. به این ترتیب نوشتن Ad Hoc queries و گزارشگیری بسیار مشکل میشوند.
علاوه بر امکانات خوب کوئری گرفتن در بانکهای اطلاعاتی رابطهای، این کوئریها در زمان اجرا نیز بر اساس اسکیمای موجود، بسیار بهینه و با سرعت بالا اجرا میشوند. قابلیتی که رسیدن به آن در بانکهای اطلاعاتی با اسکیمای متغیر، کار سادهای نیست و باید آنرا با کدنویسی شخصی بهینه کرد. البته اگر تعداد این نوع برنامههای ثانویه که به آنها imperative query در مقابل declarative query بانکهای رابطهای میگویند، کم باشد، شاید یکبار نوشتن و بارها استفاده کردن از آنها اهمیتی نداشته باشد؛ در غیراینصورت تبدیل به یک عذاب خواهد شد.
5) نیاز به امکانات گزارشگیری پیشرفته
گزارشگیرهای برنامههای تجاری نیز بر اساس یک ساختار و اسکیمای مشخص به کمک قابلیتهای پیشرفته کوئری نویسی بانکهای اطلاعاتی رابطهای به سادگی قابل تهیه هستند. برای تهیه گزارشاتی که قابلیت چاپ مناسبی را داشته باشند، محل قرارگیری فیلدهای مختلف در صفحه مهم هستند و با متغیر بودن آنها، قابلیت طراحی از پیش آنها را از دست خواهیم داد. در این حالت با اسکیمای متغیر، حداکثر بتوان یک dump از اطلاعات را به صورت ستونی نمایش داد.
بنابراین به صورت خلاصه، بانکهای اطلاعاتی رابطهای، جهت مدیریت کارهای روزمره تجاری اغلب شرکتها، بسیار ضروری و جزو مسایل پایهای بهشمار میروند و به این زودیها هم قرار نیست با نمونهی دیگری جایگزین شوند.
برای فعال سازی jqGrid در ASP.NET Core 3 به نحوی که بتونه اطلاعات جداول رو نمایش بده توسط متد POST چه تنظیمات دیگری نیازه؟
تنظیمات ارتقای از ASP.NET2.2 به ASP.NET3.0 رو از این لینک مطالعه کردم و همینطور همه بازخوردهای سایت که در زمینه ارتقای به ASP.NET Core3.0 بود رو مطالعه کردم ولی بازم اطلاعات رو نمایش نمیده؟!
همینطور بستهی نیوگت Microsoft.AspNetCore.Mvc.NewtonsoftJson را هم برای بخشی که اطلاعات به صورت json به صفحه ارسال میشه نصب کردم ولی اطلاعات رو در جداول نمایش نمیده.
روی ASP.NET Core 2.2 به خوبی کار میکرد ولی با ارتقا به ASP . NET Core 3.0 این مشکل پیش اومده.
کار خاص دیگرهم باید انجام بدیم؟
ممنون میشم راهنمایی بفرمایید.
پیشنیازهای کار با کش توزیع شدهی مبتنی بر SQL Server
برای کار با کش توزیع شدهی با قابلیت ذخیره سازی در یک بانک اطلاعاتی SQL Server، نیاز است دو بستهی ذیل را به فایل project.json برنامه اضافه کرد:
{ "dependencies": { "Microsoft.Extensions.Caching.SqlServer": "1.1.0" }, "tools": { "Microsoft.Extensions.Caching.SqlConfig.Tools": "1.1.0-preview4-final" } }
ایجاد جدول ذخیره سازی اطلاعات کش توزیع شده به کمک ابزار sql-cache
پس از افزودن و بازیابی ارجاعات فوق، با استفاده از خط فرمان، به پوشهی جاری برنامه وارد شده و دستور ذیل را صادر کنید:
dotnet sql-cache create "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=sql_cache;Integrated Security=True;" "dbo" "AppSqlCache"
- در اینجا میتوان هر نوع رشتهی اتصالی معتبری را به انواع و اقسام بانکهای SQL Server ذکر کرد. برای نمونه در مثال فوق این رشتهی اتصالی به یک بانک اطلاعاتی از پیش ایجاد شدهی LocalDB اشاره میکند. نام دلخواه این بانک اطلاعاتی در اینجا sql_cache ذکر گردیده و نام دلخواه جدولی که قرار است این اطلاعات را ثبت کند AppSqlCache تنظیم شدهاست و dbo، نام اسکیمای جدول است:
در اینجا تصویر ساختار جدولی را که توسط ابزار dotnet sql-cache ایجاد شدهاست، مشاهده میکنید. اگر خواستید این جدول را خودتان دستی ایجاد کنید، یک چنین کوئری را باید بر روی دیتابیس مدنظرتان اجرا نمائید:
CREATE TABLE AppSqlCache ( Id NVARCHAR (449) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL, Value VARBINARY (MAX) NOT NULL, ExpiresAtTime DATETIMEOFFSET NOT NULL, SlidingExpirationInSeconds BIGINT NULL, AbsoluteExpiration DATETIMEOFFSET NULL, CONSTRAINT pk_Id PRIMARY KEY (Id) ); CREATE NONCLUSTERED INDEX Index_ExpiresAtTime ON AppSqlCache(ExpiresAtTime);
ایجاد جدول ذخیره سازی اطلاعات کش توزیع شده به کمک ابزار Migrations در EF Core
زیر ساخت کش توزیع شدهی مبتنی بر SQL Server هیچگونه وابستگی به EF Core ندارد و تمام اجزای آن توسط Async ADO.NET نوشته شدهاند. اما اگر خواستید قسمت ایجاد جدول مورد نیاز آنرا به ابزار Migrations در EF Core واگذار کنید، روش کار به صورت زیر است:
- ابتدا یک کلاس دلخواه جدید را با محتوای ذیل ایجاد کنید:
public class AppSqlCache { public string Id { get; set; } public byte[] Value { get; set; } public DateTimeOffset ExpiresAtTime { get; set; } public long? SlidingExpirationInSeconds { get; set; } public DateTimeOffset? AbsoluteExpiration { get; set; } }
public class MyDBDataContext : DbContext { public virtual DbSet<AppSqlCache> AppSqlCache { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<AppSqlCache>(entity => { entity.ToTable(name: "AppSqlCache", schema: "dbo"); entity.HasIndex(e => e.ExpiresAtTime).HasName("Index_ExpiresAtTime"); entity.Property(e => e.Id).HasMaxLength(449); entity.Property(e => e.Value).IsRequired(); }); } }
البته این مورد به شرطی است که بخواهید از یک دیتابیس، هم برای برنامه و هم برای ذخیره سازی اطلاعات کش استفاده کنید.
معرفی تنظیمات رشتهی اتصالی و نام جدول ذخیره سازی اطلاعات کش به برنامه
پس از ایجاد جدول مورد نیاز جهت ذخیره سازی اطلاعات کش، اکنون نیاز است این اطلاعات را به برنامه معرفی کرد. برای این منظور به کلاس آغازین برنامه مراجعه کرده و متد الحاقی AddDistributedSqlServerCache را بر روی مجموعهی سرویسهای موجود فراخوانی کنید؛ تا سرویسهای این کش توزیع شده نیز به برنامه معرفی شوند:
public void ConfigureServices(IServiceCollection services) { services.AddDistributedSqlServerCache(options => { options.ConnectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=sql_cache;Integrated Security=True;"; options.SchemaName = "dbo"; options.TableName = "AppSqlCache"; });
آزمایش کش توزیع شدهی تنظیمی با فعال سازی سشنها
سشنها را همانند نکات ذکر شدهی در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 16 - کار با Sessions» فعال کنید و سپس مقداری را در آن بنویسید:
public IActionResult Index() { HttpContext.Session.SetString("User", "VahidN"); return Json(true); } public IActionResult About() { var userContent = HttpContext.Session.GetString("User"); return Json(userContent); }
همانطور که مشاهده میکنید، سیستم سشن اینبار بجای حافظه، به صورت خودکار از جدول بانک اطلاعاتی SQL Server تنظیم شده، برای ذخیره سازی اطلاعات خود استفاده کردهاست.
کار با کش توزیع شده از طریق برنامه نویسی
همانطور که در مقدمهی بحث نیز عنوان شد، استفادهی از زیر ساخت کش توزیع شده منحصر به استفادهی از آن جهت ذخیره سازی اطلاعات سشنها نیست و از آن میتوان جهت انواع و اقسام سناریوهای مختلف مورد نیاز استفاده کرد. در این حالت روش دسترسی به این زیر ساخت، از طریق اینترفیس IDistributedCache است. زمانیکه متد AddDistributedSqlServerCache را فراخوانی میکنیم، در حقیقت کار ثبت یک چنین سرویسی به صورت خودکار انجام خواهد شد:
services.Add(ServiceDescriptor.Singleton<IDistributedCache, SqlServerCache>());
در اینجا یک نمونه از این تزریق وابستگی و سپس استفادهی از متدهای Set و Get اینترفیس IDistributedCache را مشاهده میکنید:
using System; using System.Text; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; namespace Core1RtmEmptyTest.Controllers { public class CacheTestController : Controller { readonly IDistributedCache _cache; public CacheTestController(IDistributedCache cache) { _cache = cache; } public IActionResult SetCacheData() { var time = DateTime.Now.ToLocalTime().ToString(); var cacheOptions = new DistributedCacheEntryOptions { AbsoluteExpiration = DateTime.Now.AddYears(1) }; _cache.Set("Time", Encoding.UTF8.GetBytes(time), cacheOptions); return View(); } public IActionResult GetCacheData() { var time = Encoding.UTF8.GetString(_cache.Get("Time")); ViewBag.data = time; return View(); } public bool RemoveCacheData() { _cache.Remove("Time"); return true; } } }
Value VARBINARY (MAX) NOT NULL,
public byte[] Value { get; set; }
در این حالت اگر برنامه را اجرا و مسیر http://localhost:7742/CacheTest/SetCacheData را فراخوانی کنیم، اطلاعات ذخیره شدهی با کلید Test را میتوان در بانک اطلاعاتی مشاهده کرد:
Tag helper مخصوص کش توزیع شده
در ASP.NET Core، میتوان از یک Tag Helper جدید به نام distributed-cache برای کش سمت سرور توزیع شدهی محتوای قسمتی از یک View به نحو ذیل استفاده کرد:
<distributed-cache name="MyCacheItem2" expires-sliding="TimeSpan.FromMinutes(30)"> <p>From distributed-cache</p> @DateTime.Now.ToString() </distributed-cache>
در اینجا name به صورت هش شده به صورت کلید کش مورد استفاده قرار میگیرد. سپس محتوای تگ distributed-cache رندر شده، تبدیل به آرایهای از بایتها گردیده و در بانک اطلاعاتی ذخیره میگردد.
ذکر name در اینجا اجباری است و باید دقت داشت که چون به عنوان کلید بازیابی کش مورد استفاده قرار خواهد گرفت، نباید به اشتباه در قسمتهای دیگر برنامه با همین نام وارد شود. در غیر اینصورت دو قسمتی که name یکسانی داشته باشند، یک محتوا را نمایش خواهند داد.
RavenDB؛ تجربه متفاوت از پایگاه داده
npm install -g electron-packager-interactive
electron-packager-interactive
epi
? Overwrite output directory ? Yes ? Use asar source packaging ? Yes ? Select Electron app source directory: E:\Projects\electron\dbtest ? Select Electron app output directory: E:\Projects\electron\dbtest\releases ? Select Application name: myapp ? Select App Bundle Id (optional): 12 ? Select App Version(optional): 0.0.1 ? Select Electron icon file: ? Select Electron version release: 0.34.1 ? Select platforms: all ? Select architecture: all
پیکربندی از طریق packages.json
"scripts": { "start": "./node_modules/.bin/electron .", "test":"eslint .", "build":"electron-packager . myapp --platform=all --arch=all --overwrite --ignore=node_modules/dev-dependency --asar", "build:win32":"electron-packager . myapp --platform=win32 --arch=ia32 --overwrite --ignore=node_modules/dev-dependency --asar", "build:win64":"electron-packager . myapp --platform=win64 --arch=x64 --overwrite" },
npm run build npm run build:win32 npm run build:win64
افزودن فایلهای ایستا به بسته بندی
یکی از مشکلاتی که هنگام بسته بندی به آن برخوردم این بود که فایل sql.txt به بسته نهایی اضافه نشده بود و برنامه به همین علت terminate میشد. برای اینکه به این مشکل دچار نشوید، بهتر هست این موارد را داخل یک دایرکتوری قرار داده تا بعد از بسته بندی، دایرکتوری را به راحتی به بسته نهایی کپی کنید. با توجه به صحبتهایی که با یکی از تولیدکنندگان پکیج داشتم، ایشان متذکر شدند با اینکه این بسته حاوی یک لیست سیاه برای انتقال فایلهاست، ولی فایلی مثل sql.txt مشکلی ندارد. اما با این حال اگر به مشکل برخورد کردید، این مورد را خودتان دستی انجام دهید.
رمزنگاری و رمزگشایی اطلاعات توسط الگوریتم RSA
string secret = "My Secret"; string encoded = secret.Encrypt("mykey");
string secret = "My Secret"; string decoded = encoded.Decrypt("mykey");