برای توسعه پذیری سیستم خود از چه روشهایی استفاده کرده اید؟
ولی در حالت کلی مطمئنا روش مقیاس پذیر کردن به صورت افقی بهتر است به خصوص اگر دیتابیسهای nosql در آن مدنظر باشد و یا میزان سرویس به صورت realtime و بدون وقفه و در لحظه در آن بالا باشد. در غر اینصورت مسلما مقایس پذیرکردن به روش عمودی انتخاب بهتر و کم هزینهتری خواهد بود
Entity Framework 6.0.2 RTM منتشر شد
برای توسعه پذیری سیستم خود از چه روشهایی استفاده کرده اید؟
چون پروژههای ما با این روش نیازشان مرتفع میشد. هزینه کمتری برای ارتقا وجود داره و جوابگوی نیاز ما بود ولی در حال حاضر به امید خدا داریم پروژه ای رو استارت میزنیم که در آینده نیاز به توسعه پذیری افقی خواهد داشت به خصوص که بانک آن قرار است از طریق ravendb تامین شود
آموزش Prism #1
- MVVM Light
- Prism
- Caliburn
- Cinch
- WAF
- Catel
- Onyx
- MVVM helpers
- و...
هر کدوم از فریم ورکهای بالا مزایا، معایب و طرفداران خاص خودشون رو دارند(^) ولی به جرات میتونیم Prism رو به عنوان قویترین فریم ورک برای پیاده سازی پروژهای بزرگ و قوی و ماژولار با تکنولوژی WPF یا Silverlight بنامیم. در این پست به معرفی و بررسی مفاهیم اولیه Prism خواهیم پرداخت و در پستهای دیگر به پیاده سازی عملی همراه با مثال میپردازیم.
*اگر به هر دلیلی مایل به یادگیری و استفاده از Prism نیستید، بهتون پیشنهاد میکنم از WAF استفاده کنید.
پیش نیازها:
برای یادگیری PRISM ابتدا باید با مفاهیم زیر در WPF یا Silverlight آشنایی داشته باشید.(فرض بر این است که به UserControl و Xaml و Dependency Properties، تسلط کامل دارید)
- Data binding
- Resources
- Commands
- Behaviors
چرا Prism ؟
- Prism به صورت کامل از Modular Programming برای پروژههای WPF و Silverlight پشتیانی میکند*
- از Prism هم میتوانیم در پروژههای WPF استفاده کنیم و هم Silverlight.
- Prism به صورت کامل از الگوی MVVM برای پیاده سازی پروژهها پشتیبانی میکند.
- پیاده سازی مفاهیمی نظیر Composite Command و Command Behavior و Asynchronous Interacion به راحتی در Prism امکان پذیر است.
- مفاهیم تزریق وابستگی به صورت توکار در Prism فراهم است که برای پیاده سازی این مفاهیم به طور پیش فرض امکان استفاده از UnityContainer و MEF در Prism تدارک دیده شده است.
- پیاده سازی Region navigation در Prism به راحتی امکان پذیر است.
- به وسیله امکان Event Aggregation به راحتی میتوانیم بین ماژولهای مختلف ارتباط برقرار کنیم.
*توضیح درباره برنامههای ماژولار
در تولید پروژهای نرم افزاری بزرگ هر چه قدر هم اگر در تهیه فایلهای اسمبلی، کلاس ها، اینترفیسها و کلا طراحی پروژه به صورت شی گرا دقت به خرج دهیم باز هم ممکن است پروژه به صورت یک پارچه طراحی نشود. یعنی بعد از اتمام پروژه، توسعه، تست پذیری و نگهداری آن سخت و در بعضی مواقع غیر ممکن خواهد شد. برنامه نویسی ماژولار این امکان را فراهم میکنه که یک پروزه با مقیاس برزگ به چند پروژه کوچک تقسیم شده و همه مراحل طراحی و توسعه و تست برای هر کدام از این ماژولها به صورت جدا انجام شود.
Prism امکاناتی رو برای طراحی و توسعه این گونه پروژهها به صورت ماژولار فراهم کرده است:
- ابتدا باید نام و مکان هر ماژول رو به Prism معرفی کنیم که میتونیم اونها رو در کد یا Xaml یا Configuration File تعریف کنیم.
- با استفاده از Metadata باید وابستگیها و مقادیر اولیه برای هر ماژول مشخص شود.
- با کمک تزریق وابستگیها ارتباطات بین ماژولها میسر میشود.
- ماژول مورد نظر به دو صورت OnDemand و Available لود خواهد شد.
در شکل زیر مراحل بالا قابل مشاهده است:
Bootstrapper چیست؟
در هر پروژه ماژولار (مختص Prism نیست) برای اینکه ماژولهای مختلف یک پروژه، قابلیت استفاده به صورت یک پارچه رو در یک Application داشته باشند باید مفهومی به نام Bootstapper رو پیاده سازی کنیم که وظیفه اون شناسایی و پیکربندی و لود ماژول هاست. در Prism دو نوع Bootstrapper پیش فرض وجود دارد.
- MefBootstrapper : کلاس پایه Bootstrapper که مبنای آن MEF است. اگر قصد استفاده از MEF رو در پروژههای خود دارید(^) Bootstrapper شما باید از این کلاس ارث ببرد.
- UnityBootstrapper : کلاس پایه Bootstrapper که مبنای آن UnityContainer است. اگر قصد استفاده از UnityContainer یا Service Locator (^) رو در پروژههای خود دارید Bootstrapper شما باید از این کلاس ارث ببرد.
تصویری از ارتباط Bootstrapper با ماژولهای سیستم
مفهوم Shell
در پروژههای WPF، در فایل App.xaml توسط یک Uri نقطه شروع پروژه را تعیین میکنیم. در پروژههای Silverlight به وسیله خاصیت RootVisual نقطه شروع سیستم تعیین میشود. در Prism نقطه شروع پروژه توسط bootsrapper تعیین میشود. دلیل این امر این است که Shell در پروژههای مبتنی بر Prism متکی بر Region Manager است. از Region برای لود و نمایش ماژولها استفاده خواهیم کرد.
ادامه دارد...
<uses-permission android:name="android.permission.RECORD_AUDIO" />
سیستمعامل مجاز به اجرای برنامهای بدون امضاء نخواهد بود.
سیستم ASP.NET Membership بهمراه ASP.NET 2.0 در سال 2005 معرفی شد، و از آن زمان تا بحال تغییرات زیادی در چگونگی مدیریت احزار هویت و اختیارات کاربران توسط اپلیکیشنهای وب بوجود آمده است. ASP.NET Identity نگاهی تازه است به آنچه که سیستم Membership هنگام تولید اپلیکیشنهای مدرن برای وب، موبایل و تبلت باید باشد.
پیش زمینه: سیستم عضویت در ASP.NET
- الگوی پایگاه داده آن برای SQL Server طراحی شده است، و قادر به تغییرش هم نیستید. میتوانید اطلاعات پروفایل را اضافه کنید، اما تمام دادهها در یک جدول دیگر ذخیره میشوند، که دسترسی به آنها نیز مشکلتر است، تنها راه دسترسی Profile Provider API خواهد بود.
- سیستم تامین کننده (Provider System) امکان تغییر منبع دادهها را به شما میدهد، مثلا میتوانید از بانکهای اطلاعاتی MySQL یا Oracle استفاده کنید. اما تمام سیستم بر اساس پیش فرض هایی طراحی شده است که تنها برای بانکهای اطلاعاتی relational درست هستند. میتوانید تامین کننده (Provider) ای بنویسید که دادههای سیستم عضویت را در منبعی به غیر از دیتابیسهای relational ذخیره میکند؛ مثلا Windows Azure Storage Tables. اما در این صورت باید مقادیر زیادی کد بنویسید. مقادیر زیادی هم System.NotImplementedException باید بنویسید، برای متد هایی که به دیتابیسهای NoSQL مربوط نیستند.
- از آنجایی که سیستم ورود/خروج سایت بر اساس مدل Forms Authentication کار میکند، سیستم عضویت نمیتواند از OWIN استفاده کند. OWIN شامل کامپوننت هایی برای احراز هویت است که شامل سرویسهای خارجی هم میشود (مانند Microsoft Accounts, Facebook, Google, Twitter). همچنین امکان ورود به سیستم توسط حسابهای کاربری سازمانی (Organizational Accounts) نیز وجود دارد مانند Active Directory و Windows Azure Active Directory. این کتابخانه از OAuth 2.0، JWT و CORS نیز پشتیبانی میکند.
- ذخیره دادههای سیستم عضویت در بانکهای اطلاعاتی non-relational مشکل است.
- نمی توانید از آن در کنار OWIN استفاده کنید.
- با فراهم کنندههای موجود ASP.NET Membership بخوبی کار نمیکند. توسعه پذیر هم نیست.
ASP.NET Universal Providers
ASP.NET Universal Providers برای ذخیره سازی اطلاعات سیستم عضویت در Windows Azure SQL Database توسعه پیدا کردند. با SQL Server Compact هم بخوبی کار میکنند. این تامین کنندهها بر اساس Entity Framework Code First ساخته شده بودند و بدین معنا بود که دادههای سیستم عضویت را میتوان در هر منبع داده ای که توسط EF پشتیبانی میشود ذخیره کرد. با انتشار این تامین کنندهها الگوی دیتابیس سیستم عضویت نیز بسیار سبکتر و بهتر شد. اما این سیستم بر پایه زیر ساخت ASP.NET Membership نوشته شده است، بنابراین محدودیتهای پیشین مانند محدودیتهای SqlMembershipProvider هنوز وجود دارند. به بیان دیگر، این سیستمها همچنان برای بانکهای اطلاعاتی relational طراحی شده اند، پس سفارشی سازی اطلاعات کاربران و پروفایلها هنوز مشکل است. در آخر آنکه این تامین کنندهها هنوز از مدل احراز هویت فرم استفاده میکنند.
ASP.NET Identity
- یک سیستم هویت واحد (One ASP.NET Identity system)
- سیستم ASP.NET Identity میتواند در تمام فریم ورکهای مشتق از ASP.NET استفاده شود. مانند ASP.NET MVC, Web Forms, Web Pages, Web API و SignalR
- از این سیستم میتوانید در تولید اپلیکیشنهای وب، موبایل، استور (Store) و یا اپلیکیشنهای ترکیبی استفاده کنید.
- سادگی تزریق دادههای پروفایل درباره کاربران
- روی الگوی دیتابیس برای اطلاعات کاربران و پروفایلها کنترل کامل دارید. مثلا میتوانید به سادگی یک فیلد، برای تاریخ تولد در نظر بگیرید که کاربران هنگام ثبت نام در سایت باید آن را وارد کنند.
- کنترل ذخیره سازی/واکشی اطلاعات
- بصورت پیش فرض ASP.NET Identity تمام اطلاعات کاربران را در یک دیتابیس ذخیره میکند. تمام مکانیزمهای دسترسی به دادهها توسط EF Code First کار میکنند.
- از آنجا که روی الگوی دیتابیس، کنترل کامل دارید، تغییر نام جداول و یا نوع داده فیلدهای کلیدی و غیره ساده است.
- استفاده از مکانیزمهای دیگر برای مدیریت دادههای آن ساده است، مانند SharePoint, Windows Azure Storage Table و دیتابیسهای NoSQL.
- تست پذیری
- ASP.NET Identity تست پذیری اپلیکیشن وب شما را بیشتر میکند. میتوانید برای تمام قسمت هایی که از ASP.NET Identity استفاده میکنند تست بنویسید.
- تامین کننده نقش (Role Provider)
- تامین کننده ای وجود دارد که به شما امکان محدود کردن سطوح دسترسی بر اساس نقوش را میدهد. بسادگی میتوانید نقشهای جدید مانند "Admin" بسازید و بخشهای مختلف اپلیکیشن خود را محدود کنید.
- Claims Based
- ASP.NET Identity از امکان احراز هویت بر اساس Claims نیز پشتیبانی میکند. در این مدل، هویت کاربر بر اساس دسته ای از اختیارات او شناسایی میشود. با استفاده از این روش توسعه دهندگان برای تعریف هویت کاربران، آزادی عمل بیشتری نسبت به مدل Roles دارند. مدل نقشها تنها یک مقدار منطقی (bool) است؛ یا عضو یک نقش هستید یا خیر، در حالیکه با استفاده از روش Claims میتوانید اطلاعات بسیار ریز و دقیقی از هویت کاربر در دست داشته باشید.
- تامین کنندگان اجتماعی
- به راحتی میتوانید از تامین کنندگان دیگری مانند Microsoft, Facebook, Twitter, Google و غیره استفاده کنید و اطلاعات مربوط به کاربران را در اپلیکیشن خود ذخیره کنید.
- Windows Azure Active Directory
- برای اطلاعات بیشتر به این لینک مراجعه کنید.
- یکپارچگی با OWIN
- ASP.NET Identity بر اساس OWIN توسعه پیدا کرده است، بنابراین از هر میزبانی که از OWIN پشتیبانی میکند میتوانید استفاده کنید. همچنین هیچ وابستگی ای به System.Web وجود ندارد. ASP.NET Identity یک فریم ورک کامل و مستقل برای OWIN است و میتواند در هر اپلیکیشنی که روی OWIN میزبانی شده استفاده شود.
- ASP.NET Identity از OWIN برای ورود/خروج کاربران در سایت استفاده میکند. این بدین معنا است که بجای استفاده از Forms Authentication برای تولید یک کوکی، از OWIN CookieAuthentication استفاده میشود.
- پکیج NuGet
- ASP.NET Identity در قالب یک بسته NuGet توزیع میشود. این بسته در قالب پروژههای ASP.NET MVC, Web Forms و Web API که با Visual Studio 2013 منتشر شدند گنجانده شده است.
- توزیع این فریم ورک در قالب یک بسته NuGet این امکان را به تیم ASP.NET میدهد تا امکانات جدیدی توسعه دهند، باگها را برطرف کنند و نتیجه را بصورت چابک به توسعه دهندگان عرضه کنند.
ASP.NET Identity در قالب پروژههای ASP.NET MVC, Web Forms, Web API و SPA که بهمراه Visual Studio 2013 منتشر شده اند استفاده میشود. در ادامه به اختصار خواهیم دید که چگونه ASP.NET Identity کار میکند.
- یک پروژه جدید ASP.NET MVC با تنظیمات Individual User Accounts بسازید.
-
پروژه ایجاد شده شامل سه بسته میشود که مربوط به ASP.NET Identity هستند:
- Microsoft.AspNet.Identity.EntityFramework این بسته شامل پیاده سازی ASP.NET Identity با Entity Framework میشود، که تمام دادههای مربوطه را در یک دیتابیس SQL Server ذخیره میکند.
- Microsoft.AspNet.Identity.Core این بسته محتوی تمام interfaceهای ASP.NET Identity است. با استفاده از این بسته میتوانید پیاده سازی دیگری از ASP.NET Identity بسازید که منبع داده متفاوتی را هدف قرار میدهد. مثلا Windows Azure Storage Table و دیتابیسهای NoSQL.
- Microsoft.AspNet.Identity.OWIN این بسته امکان استفاده از احراز هویت OWIN را در اپلیکیشنهای ASP.NET فراهم میکند. هنگام تولید کوکیها از OWIN Cookie Authentication استفاده خواهد شد.
هنگامیکه بر روی دکمهی Register کلیک شود، کنترلر Account، اکشن متد Register را فراخوانی میکند تا حساب کاربری جدیدی با استفاده از ASP.NET Identity API ساخته شود.
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser() { UserName = model.UserName }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { await SignInAsync(user, isPersistent: false); return RedirectToAction("Index", "Home"); } else { AddErrors(result); } } // If we got this far, something failed, redisplay form return View(model); }
اگر حساب کاربری با موفقیت ایجاد شود، کاربر توسط فراخوانی متد SignInAsync به سایت وارد میشود.
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser() { UserName = model.UserName }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { await SignInAsync(user, isPersistent: false); return RedirectToAction("Index", "Home"); } else { AddErrors(result); } } // If we got this far, something failed, redisplay form return View(model); }
private async Task SignInAsync(ApplicationUser user, bool isPersistent) { AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); var identity = await UserManager.CreateIdentityAsync( user, DefaultAuthenticationTypes.ApplicationCookie); AuthenticationManager.SignIn( new AuthenticationProperties() { IsPersistent = isPersistent }, identity); }
از آنجا که ASP.NET Identity و OWIN Cookie Authentication هر دو Claims-based هستند، فریم ورک، انتظار آبجکتی از نوع ClaimsIdentity را خواهد داشت. این آبجکت تمامی اطلاعات لازم برای تشخیص هویت کاربر را در بر دارد. مثلا اینکه کاربر مورد نظر به چه نقش هایی تعلق دارد؟ و اطلاعاتی از این قبیل. در این مرحله میتوانید Claimهای بیشتری را به کاربر بیافزایید.
کلیک کردن روی لینک Log off در سایت، اکشن متد LogOff در کنترلر Account را اجرا میکند.
// POST: /Account/LogOff [HttpPost] [ValidateAntiForgeryToken] public ActionResult LogOff() { AuthenticationManager.SignOut(); return RedirectToAction("Index", "Home"); }
همانطور که مشاهده میکنید برای ورود/خروج کاربران از AuthenticationManager استفاده میشود که متعلق به OWIN است. متد SignOut همتای متد FormsAuthentication.SignOut است.
کامپوننتهای ASP.NET Identity
تصویر زیر اجزای تشکیل دهنده ASP.NET Identity را نمایش میدهد. بسته هایی که با رنگ سبز نشان داده شده اند سیستم کلی ASP.NET Identity را میسازند. مابقی بستهها وابستگی هایی هستند که برای استفاده از ASP.NET Identity در اپلیکیشنهای ASP.NET لازم اند.
دو پکیج دیگر نیز وجود دارند که به آنها اشاره نشد:
- Microsoft.Security.Owin.Cookies این بسته امکان استفاده از مدل احراز هویت مبتنی بر کوکی (Cookie-based Authentication) را فراهم میکند. مدلی مانند سیستم ASP.NET Forms Authentication.
- EntityFramework که نیازی به معرفی ندارد.
مهاجرت از Membership به ASP.NET Identity
قدمهای بعدی
ترکیب کامپوننتها
در ادامه، همان برنامهی تا قسمت 5 را که کار نمایش یک counter را انجام میدهد، تکمیل میکنیم. در این برنامه اگر به فایل index.js دقت کنید، کار رندر تک کامپوننت Counter را انجام میدهیم:
ReactDOM.render(<Counter />, document.getElementById("root"));
برای نمایش این مفهوم، کامپوننت جدید src\components\counters.jsx را ایجاد میکنیم. قصد داریم در این کامپوننت، لیستی از کامپوننتهای Counter را رندر کنیم. سپس در index.js، بجای رندر کامپوننت Counter، کامپوننت جدید Counters را رندر میکنیم. به این ترتیب درخت کامپوننتهای برنامه، در سطح بالایی خودش از کامپوننت Counters شروع میشود و سپس فرزندان آنرا کامپوننتهای Counter تشکیل میدهند. به همین جهت فایل index.js را به صورت زیر ویرایش میکنیم تا به کامپوننت Counters اشاره کند:
import Counters from "./components/counters"; ReactDOM.render(<Counters />, document.getElementById("root"));
import React, { Component } from "react"; import Counter from "./counter"; class Counters extends Component { state = {}; render() { return ( <div> <Counter /> <Counter /> <Counter /> <Counter /> </div> ); } } export default Counters;
در مرحلهی بعد، بجای رندر و درج دستی این کامپوننتها، آرایهای از اشیاء counter را ایجاد کرده و سپس آنها را توسط متد Array.map رندر میکنیم:
import React, { Component } from "react"; import Counter from "./counter"; class Counters extends Component { state = { counters: [ { id: 1, value: 0 }, { id: 2, value: 0 }, { id: 3, value: 0 }, { id: 4, value: 0 } ] }; render() { return ( <div> {this.state.counters.map(counter => ( <Counter key={counter.id} /> ))} </div> ); } } export default Counters;
ارسال دادهها به کامپوننتها
مشکل! مقدار value هر شیء شمارشگر تعریف شده، به کامپوننتهای مرتبط رندر شده اعمال نشدهاست. برای مثال اگر value اولین شیء را به 4 تغییر دهیم، هنوز هم این کامپوننت با همان مقدار صفر شروع به کار میکند. برای رفع این مشکل، به همان روشی که ویژگی key کامپوننت Counter را مقدار دهی کردیم، میتوان ویژگیهای سفارشی دیگری را تعریف و مقدار دهی کرد:
render() { return ( <div> {this.state.counters.map(counter => ( <Counter key={counter.id} value={counter.value} selected={true} /> ))} </div> );
class Counter extends Component { state = { count: 0 }; render() { console.log("props", this.props); //...
خاصیت this.props، یک شیء سادهی جاوا اسکریپتی است و شامل تمام ویژگیهایی میباشد که ما در کامپوننت Counters برای هر کدام از کامپوننتهای Counter رندر شدهی توسط آن، تعریف کردیم. برای نمونه دو ویژگی جدید value و selected را که به تعاریف المانهای Counter در کامپوننت Counters اضافه کردیم، در اینجا به همراه مقادیر منتسب به آنها، قابل مشاهده هستند. البته در این خروجی، key را ملاحظه نمیکنید؛ چون هدف اصلی آن، معرفی یکتای المانها در DOM مجازی React است.
بنابراین اکنون میتوان به value تنظیم شدهی در کامپوننت Counters به صورت this.props.value در کامپوننت Counter دسترسی یافت و سپس از آن جهت مقدار دهی اولیهی counter استفاده کرد.
class Counter extends Component { state = { count: this.props.value };
یک نکته: در اینجا selected={true} را داریم. اگر مقدار آنرا حذف کنیم، یعنی selected تنها درج شود، مقدار آن، همان true دریافت خواهد شد.
تعریف فرزند برای المانهای کامپوننتها
ویژگیهای اضافه شدهی به تعاریف المانهای کامپوننتها، توسط خاصیت this.props، به هر کدام از آن کامپوننتها منتقل میشوند. این خاصیت props، یک خاصیت ویژه را به نام children، نیز دارا است و از آن برای دسترسی به المانهای تعریف شدهی بین تگهای یک المان اصلی استفاده میشود:
render() { return ( <div> {this.state.counters.map(counter => ( <Counter key={counter.id} value={counter.value} selected={true}> <h4>Counter #{counter.id}</h4> </Counter> ))} </div> ); }
یک نمونه مثال واقعی این قابلیت، امکان تعریف محتوای دیالوگ باکسها، توسط استفاده کنندهی از آن است.
روش دیباگ برنامههای React
افزونهی مفید React developer tools را میتوانید برای مرورگرهای کروم و فایرفاکس، دریافت و نصب کنید. برای نمونه پس از نصب آن در مرورگر کروم، یک برگهی جدید به لیست برگههای کنسول توسعه دهندگان آن اضافه میشود:
همانطور که مشاهده کنید، درخت کامپوننتهای برنامه را در برگهی جدید Components، میتوان مشاهده کرد. در اینجا با انتخاب هر کدام از فرزندان این درخت، مشخصات آن نیز مانند props و state، در کنار صفحه ظاهر میشوند. همچنین در بالای همین قسمت، 4 آیکن مشاهدهی سورس، مشاهدهی DOM و یا لاگ کردن جزئیات شیء کامپوننت انتخابی در کنسول هم درج شدهاند:
که برای نمونه چنین خروجی را لاگ میکند:
بررسی تفاوتهای خواص props و state
در کامپوننت Counter، از props برای مقدار دهی اولیهی state استفاده میکنیم:
class Counter extends Component { state = { count: this.props.value };
- props حاوی اطلاعاتی است که به یک کامپوننت ارسال میکنیم؛ اما state حاوی اطلاعاتی است که مختص به آن کامپوننت بوده و private است. یعنی سایر کامپوننتها نمیتوانند به state کامپوننت دیگری دسترسی پیدا کنند. برای مثال در کامپوننت Counters، تمام attributes سفارشی تنظیم شدهی بر روی تعاریف المانهای کامپوننت Counter، جزئی از اطلاعات props خواهند بود. در اینجا نمیتوان به state کامپوننت مدنظری دسترسی یافت و آنرا مقدار دهی کرد. به همین ترتیب state کامپوننت Counters نیز در سایر کامپوننتها قابل دسترسی نیست.
- همچنین باید درنظر داشت که props، در مقایسه با state، فقط خواندنی است. به عبارتی مقدار ورودی به یک کامپوننت را داخل آن کامپوننت نمیتوان تغییر داد. برای مثال سعی کنید در داخل متد رویدادگردان کلیک موجود در کامپوننت Counter، مقدار this.props.value را به صفر تنظیم کنید. در این حالت با کلیک بر روی دکمهی Increment، بلافاصله خطای readonly بودن خواص شیء منتسب به props را دریافت میکنیم. در اینجا اگر نیاز است این مقدار را داخل کامپوننت تغییر دهیم، باید ابتدا این مقدار را دریافت کرده و سپس آنرا داخل state قرار دهیم. پس از آن امکان ویرایش اطلاعات منتسب به state، داخل یک کامپوننت وجود خواهد داشت.
صدور و مدیریت رخدادها
در ادامه میخواهیم در کنار هر دکمهی Increment کامپوننت شمارشگر، یک دکمهی Delete هم قرار دهیم:
مشکل! اگر کد مدیریتی handleDelete را در کامپوننت Counter قرار دهیم، چگونه باید به لیست آرایهی اشیاء counters والد آن، یعنی کامپوننت Counters که سبب رندر شدن کامپوننتهای شمارشگر شده (state = { counters: [ ] })، دسترسی یافت و شیءای را از آن حذف کرد؟ در React، کامپوننتی که state ای را تعریف میکند، باید کامپوننتی باشد که قرار است آنرا تغییر دهد و اطلاعات state هر کامپوننت، صرفا متعلق به آن کامپوننت بوده و جزو اطلاعات خصوصی آن است. بنابراین مدیریت حذف و یا افزودن کامپوننتها در لیست نمایش داده شده، باید جزو وظایف کامپوننت Counters باشد و نه Counter.
برای حل این مشکل، کامپوننت Counter تعریف شده (کامپوننت فرزند) باید سبب بروز رخداد onDelete شود تا کامپوننت Counters (کامپوننت والد)، آنرا توسط متد handleDelete مدیریت کند. بنابراین ابتدا به کامپوننت Counters (کامپوننت والد) مراجعه کرده و متد رویدادگردان handleDelete را به آن اضافه میکنیم:
handleDelete = () => { console.log("handleDelete called."); };
<Counter key={counter.id} value={counter.value} selected={true} onDelete={this.handleDelete} />
<button onClick={this.props.onDelete} className="btn btn-danger btn-sm m-2" > Delete </button>
اکنون اگر برنامه را ذخیره کرده و پس از بارگذاری مجدد برنامه در مرورگر بر روی دکمهی Delete کلیک کنیم، پیام «handleDelete called» در کنسول توسعه دهندگان مرورگر لاگ میشود. به این ترتیب کامپوننت فرزند سبب بروز رخدادی شده و والد آن، این رخداد را مدیریت میکند.
به روز رسانی state
تا اینجا دکمهی Delete فرزند، به متد handleDelete والد متصل شدهاست. مرحلهی بعد، پیاده سازی واقعی حذف یک المان از DOM مجازی و به روز رسانی state است. برای اینکار ابتدا به رخدادگردان onClick، در کامپوننت شمارشگر، مراجعه کرده و id دریافتی را به سمت والد ارسال میکنیم:
onClick={() => this.props.onDelete(this.props.id)}
<Counter key={counter.id} value={counter.value} selected={true} onDelete={this.handleDelete} id={counter.id} />
handleDelete = counterId => { console.log("handleDelete called.", counterId); const counters = this.state.counters.filter( counter => counter.id !== counterId ); this.setState({ counters }); // = this.setState({ counters: counters }); };
البته پیاده سازی ما تا به اینجا بدون مشکل کار میکند، اما به ازای هر خاصیت counter، یک ویژگی جدید را به تعریف المان مرتبط اضافه کردهایم که در طول زمان بیش از اندازه طولانی خواهد شد. برای رفع این مشکل، خود شیء counter را به صورت یک ویژگی جدید به کامپوننت مرتبط با آن ارسال میکنیم. به این ترتیب اگر در آینده خاصیتی را به این شیء اضافه کردیم، دیگر نیازی نیست تا آنرا به صورت دستی و مجزا تعریف کنیم. به همین جهت ابتدا تعریف المان Counter را به صورت زیر خلاصه میکنیم که در آن ویژگی جدید counter، حاوی کل شیء counter است:
<Counter key={counter.id} counter={counter} onDelete={this.handleDelete} />
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: sample-07.zip
معرفی سرویسهای ارائه شده توسط شرکتهای گوگل، آمازون و مایکروسافت در قالب رایانش ابری - قسمت دوم
سرویسها و اجزای وب سرویس آمازون:
وب سرویسهای آمازون دارای اجزای زیادی میباشند. تعدادی از این سرویسها برای ارائه خدمات پردازشی و تعداد دیگری برای ارائه فضای ذخیرهسازی، عرضه شدهاند. در ادامه گروهی از این سرویسها معرفی میگردد:
- ابر محاسباتی توسعه پذیر آمازون (EC2)
- سرویس صف ساده آمازون(Simple Queue Service): یک صف پیام یا سیستم تراکنش برای برنامههای مبتنی بر اینترنت توزیع شده میباشد. این سرویس تضمین میکند که پیامها حتی در زمانی که مؤلفهای موجود نیست، گم نشود و برای انتقال پیام میان مؤلفههای مختلف که هرکدام کار جداگانهای را انجام میدهند، بسیار مناسب است.
- سرویس
آگاه سازی ساده آمازون(Simple Notification Service): ): وب سرویسی است که میتواند پیام
یک برنامه را منتشر کند و آنها را به برنامهها یا مشترکین دیگر منتقل کند. SNS متدی
را برای راهاندازی فعالیتها ارائه مینماید که برنامهها را قادر میسازد تا در
مورد اطلاعات جدید یا تغییر یافته از آنها نظرسنجی شود یا به روز رسانیها را
انجام دهند.
- سرویس
نظارت ابر آمازون(Amazon Cloud Watch): کنسولی
را فراهم میکند که در آن مصرف منابع، شاخصهای کلیدی عملکرد سایت و نشانگرهای
عملیاتی برای عواملی همچون تقاضای پردازشگر، مصرف دیسک و ورودی و خروجی شبکه را
ارائه میدهد. نتایج
معیارهایی که توسط آن کسب میشود برای فعالسازی قابلیتی به نام Auto Scaling مورد
استفاده قرار میگیرد که به صورت خودکار میتواند یک سایت EC2 را بر مبنای مجموعهای از قوانین
که توسعه دهنده ایجاد میکند، توسعه دهد.
- توازن بار منعطف(Elastic Load Balancing): نمونههای ماشین آمازون(Amazon Machine Image) با استفاده از این قابلیت، دارای امکان توازن بار ترافیکی میشوند. این قابلیت هنگامی که نمونهای دچار شکست میشود آن را کشف کرده و ترافیک را به یک نمونه سالم حتی نمونهای در محیطهای دیگر AWS مسیریابی مجدد میکند.
قیمت گذاری انواع مختلف نمونه ماشین آمازون به سه پارامتر وابسته است. اولین مورد سیستم عامل مورد استفاده است. دومین عامل مرکز دادهای است که در آن قرار گرفته و سومین عامل مدت زمانی است که اجرا میشود. نرخها بر مبنای ساعت محاسبه میشوند. علاوه بر آن مبالغ اضافی نیز بابت موارد زیر اخذ میشود:
- میزان داده
منتقل شده
- آدرسهای IP اختصاصی
- استفاده
سرور اختصاصی مجازی از فضای ذخیرهسازی بلوکی توسعه پذیر آمازون
- استفاده از توازن بار توسعه پذیر برای دو یا چند سرور
- سایر
ویژگیهای مورد نیاز
- نمونه
مبتنی بر تقاضا: نرخ
ساعتی بدون التزام طولانی مدت
-
نمونه رزرو شده: خرید قراردادی هر نمونه با هزینه به مراتب پایینتر به ازای هر ساعت بعد از رزرو اولیه
-
نمونه نقطهای: این متد برای قیمت گذاری بر روی ظرفیت استفاده نشده EC2 بر مبنای قیمت نقطه فعلی است. این قابلیت، قیمتهای بسیار پایین را به همراه خواهد داشت اما در زمانهای مختلف فرق میکند یا در زمانی که ظرفیت مازادی نباشد، در دسترس نخواهد بود.
نوع | موتور محاسبه | حافظه اصلی(GB) | ذخیره سازی(GB) | سکو |
ریز نمونه | تا دو واحد محاسباتی در انفجار بار | 0.613 | EBS | 32 یا 64 بیتی |
نمونه کوچک | یک واحد محاسباتی | 1.7 | 160 | 32 بیتی |
نمونه بزرگ | چهار واحد محاسباتی | 7.5 | 850 | 64 بیتی |
نمونه بسیار بزرگ | هشت واحد محاسباتی | 15 | 1690 | 64 بیتی |