اشتراکها
نظرات مطالب
بازنویسی سطح دوم کش برای Entity framework 6
درود
وقت بخیر
من چندتا سوال داشتم
من از CacheManager.Core , CacheManager.StackExchange.Redis استفاده کردم
1- توی redis-cli دستور get keyName رو که میزنم عبارت nill رو میاره که یعنی خالیه ، چجوری میتونم تو cli مقدار کلید رو ببینم
2- ظاهرا هز cli تا 16 تا دیتابیس رو قبول میکنه ، این 16 تا دیتابیس رو فقط تو یه پروژه میشه استفاده کرد، نمیشه با یک cli چندتا پروژه رو دیتابیسهای مختلف پیاده کرد (مثلا db0 برای یک پروژه ، db1 برای یک پروژه و ... ) ؟
3-من الان دوتا پروژه دارم که تو جفتش سطح دوم کش رو پیاده کردم و جفتش رو یه سرور هست،پروژه ای که اول run میشه مشکل نداره ولی پروژه بعدی که run میکنم خطای زیر رو میده، حتی رو یک port دیگه هم redis رو run کردم و تو پروژه تنظیم کردم ولی بازم همین خطا رو میده
Only one usage of each socket address (protocol/network address/port) is normally permitted.
4-ظاهرا شما چندتا کتابخانه توسعه دادید برای سطح دوم کش، کدومش اخرین ورژنه
من از https://github.com/VahidN/EFCoreSecondLevelCacheInterceptor استفاده کردم
ببخشید سوالاتم زیاد شد
ممنونم
با تشکر؛ فقط این نکته رو اشاره کنم در تکمیل مقاله دوستمون و اونم اینه که حتما باید ابزار عبور از تحریم فعال باشه برای اجرای دستور
چون طبق تصویر زیر ممکنه با خطای زیر مواجه بشین
npm install -g @vue/cli
چون طبق تصویر زیر ممکنه با خطای زیر مواجه بشین
نظرات مطالب
مبانی TypeScript؛ ماژولها
- با هربار تغییر فایل tsconfig.json، کامپایل دوبارهی پروژه را فراموش نکنید (مهم). از منوی build گزینهی rebuild solution را انتخاب کنید. این rebuild، کار کامپایل مجدد فایلهای ts. را هم انجام میدهد.
- commonjs بیشتر برای برنامههای nodejs استفاده میشود. اگر علاقمند باشید که با سیستمی شبیه به AngularJS 2.0 کار کنید، از یک module loader ویژه، به نام SystemJS استفاده کنید (که قابلیت بارگذاری خودکار ES6 modules, AMD, CommonJS را دارد). بنابراین فایل tsconfig.json را به این صورت تغییر دهید:
بعد فایل index.html شما چنین شکلی را پیدا میکند:
در اینجا System.JS کار بارگذاری اولین ماژول برنامه یا همان app.js را به صورت خودکار انجام میدهد (و همچنین تمام ماژولهای مرتبط با آنرا). بنابراین دیگر نیازی به ذکر اسکریپتهای برنامه در اینجا نیست (هیچکدام از آنها، منهای موارد عمومی مثل خود system.js).
بعد فایل app.ts را هم به این صورت تغییر دهید، چون این کدها پس از onload اجرا میشوند:
- commonjs بیشتر برای برنامههای nodejs استفاده میشود. اگر علاقمند باشید که با سیستمی شبیه به AngularJS 2.0 کار کنید، از یک module loader ویژه، به نام SystemJS استفاده کنید (که قابلیت بارگذاری خودکار ES6 modules, AMD, CommonJS را دارد). بنابراین فایل tsconfig.json را به این صورت تغییر دهید:
{ "compileOnSave": true, "compilerOptions": { "target": "es5", "module": "system", "sourceMap": true } }
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>TypeScript HTML App</title> <link rel="stylesheet" href="app.css" type="text/css"/> <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.22/system.js"></script> <script type="text/javascript"> System.defaultJSExtensions = true; System.import('app'); </script> </head> <body> <h1>TypeScript HTML App</h1> <div id="content"></div> </body> </html>
بعد فایل app.ts را هم به این صورت تغییر دهید، چون این کدها پس از onload اجرا میشوند:
import {Book} from "./testmd"; let book: Book = new Book(); console.log(book.bookName); document.getElementById("content").innerText = book.GetbookNmae;
یک نکتهی تکمیلی: روش دیگری برای بهبود کنترل نمایش و مخفی سازی قسمتهای مختلف صفحه
کدهای یک دایرکتیو سفارشی نمایش و یا مخفی سازی قسمتهای مختلف صفحه را بر اساس سطوح دسترسی کاربر جاری، در IsVisibleForAuthUserDirective مشاهده کردید. روش دیگر انجام اینکار، نوشتن یک دایرکتیو ساختاری شبیه به ngIf توکار خود Angular است. کاری که ngIf انجام میدهد، مخفی کردن یک المان در صفحه نیست؛ بلکه کل آنرا از DOM حذف میکند.
نکتهی اصلی پیاده سازی یک دایرکتیو ساختاری
اگر به سازندهی IsVisibleForAuthUserDirective دقت کنید، تزریق وابستگی ElementRef را داریم:
به این ترتیب Angular به صورت خودکار امکان دسترسی به المان جاری را با تزریق آن در سازندهی کلاس، میسر میکند.
برای ایجاد یک دایرکتیور ساختاری، نیاز است از تزریق TemplateRef و ViewContainerRef استفاده کرد:
در این حالت Angular تنها زمانی این وابستگیها را به سازندهی کلاس تزریق میکند که پیش از نام این دایرکتیو، یک * قرار دهید (مانند ngIf توکار آن):
پس از آن میتوان از viewContainer، برای نمایش المان و یا قالب مدنظر:
و یا حذف کامل آن المان از DOM کمک گرفت:
اگر این نکات را کنار هم قرار دهیم و کدهای IsVisibleForAuthUserDirective فوق را بر این اساس اصلاح کنیم، به قطعه کد زیر میرسیم:
سپس تعریف آنرا به قسمتهای declarations و exports مربوط به SharedModule اضافه میکنیم:
اکنون ماژول Dashboard برای استفادهی از این امکانات تنها کافی است SharedModule را دریافت کند (یا هر ماژول دیگری نیز به همین ترتیب است):
پس از آن برای مخفی سازی یک المان از دید کاربران وارد نشدهی به سیستم، فقط کافی است دایرکتیو ساختاری hasAuthUserViewPermission را به المان اعمال کنیم:
و یا اگر نیاز به اعمال نقشها نیز وجود داشت میتوان به صورت زیر عمل کرد:
خلاصهی این تغییرات به کدهای نهایی این سری اعمال شدهاند.
کدهای یک دایرکتیو سفارشی نمایش و یا مخفی سازی قسمتهای مختلف صفحه را بر اساس سطوح دسترسی کاربر جاری، در IsVisibleForAuthUserDirective مشاهده کردید. روش دیگر انجام اینکار، نوشتن یک دایرکتیو ساختاری شبیه به ngIf توکار خود Angular است. کاری که ngIf انجام میدهد، مخفی کردن یک المان در صفحه نیست؛ بلکه کل آنرا از DOM حذف میکند.
نکتهی اصلی پیاده سازی یک دایرکتیو ساختاری
اگر به سازندهی IsVisibleForAuthUserDirective دقت کنید، تزریق وابستگی ElementRef را داریم:
@Directive({ selector: "[isVisibleForAuthUser]" }) export class IsVisibleForAuthUserDirective implements OnInit, OnDestroy { constructor(private elem: ElementRef, private authService: AuthService) { }
برای ایجاد یک دایرکتیور ساختاری، نیاز است از تزریق TemplateRef و ViewContainerRef استفاده کرد:
@Directive({ selector: "[hasAuthUserViewPermission]" }) export class HasAuthUserViewPermissionDirective implements OnInit, OnDestroy { constructor( private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef, private authService: AuthService ) { }
<div *hasAuthUserViewPermission="['Admin','User']"> *hasAuthUserViewPermission="['Admin','User']" </div>
this.viewContainer.createEmbeddedView(this.templateRef);
this.viewContainer.clear();
اگر این نکات را کنار هم قرار دهیم و کدهای IsVisibleForAuthUserDirective فوق را بر این اساس اصلاح کنیم، به قطعه کد زیر میرسیم:
import { Directive, Input, OnDestroy, OnInit, TemplateRef, ViewContainerRef } from "@angular/core"; import { Subscription } from "rxjs/Subscription"; import { AuthService } from "./../../core/services/auth.service"; @Directive({ selector: "[hasAuthUserViewPermission]" }) export class HasAuthUserViewPermissionDirective implements OnInit, OnDestroy { private isVisible = false; private requiredRoles: string[] | null = null; private subscription: Subscription | null = null; @Input() set hasAuthUserViewPermission(roles: string[] | null) { this.requiredRoles = roles; } // Note, if you don't place the * in front, you won't be able to inject the TemplateRef<any> or ViewContainerRef into your directive. constructor( private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef, private authService: AuthService ) { } ngOnInit() { this.subscription = this.authService.authStatus$.subscribe(status => this.changeVisibility(status)); this.changeVisibility(this.authService.isAuthUserLoggedIn()); } ngOnDestroy(): void { if (this.subscription) { this.subscription.unsubscribe(); } } private changeVisibility(status: boolean) { const isInRoles = !this.requiredRoles ? true : this.authService.isAuthUserInRoles(this.requiredRoles); if (isInRoles && status) { if (!this.isVisible) { this.viewContainer.createEmbeddedView(this.templateRef); this.isVisible = true; } } else { this.isVisible = false; this.viewContainer.clear(); } } }
سپس تعریف آنرا به قسمتهای declarations و exports مربوط به SharedModule اضافه میکنیم:
import { HasAuthUserViewPermissionDirective } from "./directives/has-auth-user-view-permission.directive"; @NgModule({ declarations: [ HasAuthUserViewPermissionDirective ], exports: [ HasAuthUserViewPermissionDirective ] }) export class SharedModule {}
اکنون ماژول Dashboard برای استفادهی از این امکانات تنها کافی است SharedModule را دریافت کند (یا هر ماژول دیگری نیز به همین ترتیب است):
import { SharedModule } from "../shared/shared.module"; @NgModule({ imports: [ SharedModule ] }) export class DashboardModule { }
پس از آن برای مخفی سازی یک المان از دید کاربران وارد نشدهی به سیستم، فقط کافی است دایرکتیو ساختاری hasAuthUserViewPermission را به المان اعمال کنیم:
<div *hasAuthUserViewPermission=""> *hasAuthUserViewPermission="" </div>
<div *hasAuthUserViewPermission="['Admin','User']"> *hasAuthUserViewPermission="['Admin','User']" </div>
خلاصهی این تغییرات به کدهای نهایی این سری اعمال شدهاند.
در قسمت قبل، Docker for Windows را بر روی ویندوز 10 نصب کردیم تا بتوانیم از هر دوی Linux Containers و Windows Containers استفاده کنیم. در این قسمت، نحوهی نصب Docker را بر روی ویندوز سرور، صرفا جهت اجرای Windows Containers، بررسی میکنیم؛ از این جهت که در دنیای واقعی، عموما Linux Containers را بر روی سرورهای لینوکسی و Windows Containers را بر روی سرورهای ویندوزی اجرا میکنند.
Docker for Windows چگونه از هر دوی کانتینرهای ویندوزی و لینوکسی پشتیبانی میکند؟
زمانیکه docker for windows را اجرا میکنیم، سرویسی را ایجاد میکند که سبب اجرای پروسهی ویژهای به نام com.docker.proxy.exe میشود:
هنگامیکه برای مثال فرمان docker run nginx را توسط Docker CLI اجرا میکنیم، Docker CLI از طریق واسط یاد شده، دستورات را به MobyLinuxVM منتقل میکند. به این صورت است که امکان اجرای Linux Containers، بر روی ویندوز میسر میشوند:
اکنون اگر به Windows Containers سوئیچ کنیم (از طریق کلیک راست بر روی آیکن Docker در قسمت Tray Icons ویندوز)، پروسهی dockerd.exe یا docker daemon شروع به کار خواهد کرد:
اینبار اگر مجددا از Docker CLI برای اجرای مثلا IIS Container استفاده کنیم، دستور ما از طریق واسطهای com.docker.proxy و dockerd، به کانتینر ویندوزی منتقل و اجرا میشود:
نگاهی به معماری Docker بر روی ویندوز سرور
داکر بر روی ویندوز سرور، تنها به همراه موتور مدیریت کنندهی Windows Containers است:
در اینجا با صدور فرمانهای Docker CLI، پیامها مستقیما به dockerd یا موتور داکر بر روی ویندوز سرور ارسال شده و سپس کار اجرا و مدیریت یک Windows Container انجام میشود.
نصب Docker بر روی ویندوز سرور
جزئیات مفصل و به روز Windows Containers را همواره میتوانید در این آدرس در سایت مستندات مجازی سازی مایکروسافت مطالعه کنید (قسمت Container Host Deployment - Windows Server آن). پیشنیاز کار با آن نیز نصب حداقل ویندوز سرور 2016 میباشد و بهتر است تمام به روز رسانیهای آنرا نیز نصب کرده باشید؛ چون تعدادی از بهبودهای کار با کانتینرهای آن، به همراه به روز رسانیها آن ارائه شدهاند.
برای شروع به نصب، نیاز است کنسول PowerShell ویندوز را با دسترسی Admin اجرا کنید.
سپس اولین دستوراتی را که نیاز است اجرا کنید، کار نصب موتور Docker و CLI آنرا به صورت خودکار بر روی ویندوز سرور انجام میدهند:
- که پس از نصب و ریاستارت سیستم، نتیجهی آنرا در پوشهی c:\Program Files\Docker میتوانید ملاحظه کنید.
- به علاوه اگر دستور *get-service *docker را در کنسول PowerShell صادر کنید، مشاهده خواهید کرد که سرویس جدیدی را به نام Docker نیز نصب و راه اندازی کردهاست که به dockerd.exe اشاره میکند.
- و یا اگر در کنسول PowerShell دستور docker را صادر کنید، ملاحظه خواهید کرد که CLI آن، فعال و قابل استفادهاست. برای مثال، دستور docker version را صادر کنید تا بتوانید نگارش docker نصب شده را ملاحظه نمائید.
اجرای Image مخصوص NET Core. بر روی ویندوز سرور
تگهای مختلف Image مخصوص NET Core. را در اینجا ملاحظه میکنید. در ادامه قصد داریم tag مرتبط با nanoserver آنرا نصب کنیم (با حجم 802MB):
زمانیکه این دستور را اجرا میکنیم، پس از اجرای آن، ابتدا یک \:C را نمایش میدهد و بعد خاتمه یافته و به command prompt بازگشت داده میشویم. برای مشاهدهی علت آن، اگر دستور docker ps -a را اجرا کنیم، در ستون command آن، قسمتی از دستوری را که اجرا کردهاست، میتوان مشاهده کرد. برای مشاهدهی کامل این دستور، نیاز است دستور docker ps -a --no-trunc را اجرا کنیم. در اینجا سوئیچ no-trunc به معنای no truncate است یا عدم حذف قسمت انتهایی یک دستور طولانی. در این حالت مشاهده خواهیم کرد که این دستور، کار اجرای cmd.exe واقع در پوشهی ویندوز را انجام میدهد (یا همان command prompt معمولی ویندوز). چون دستور docker run فوق به آن متصل نشدهاست، این پروسه ابتدا \:c را نمایش میدهد و سپس خاتمه پیدا میکند. برای رفع این مشکل، از interactive command که در قسمت قبل توضیح دادیم، استفاده خواهیم کرد:
اینبار اگر این دستور را اجرا کنیم، به command prompt آغاز شدهی توسط آن، متصل خواهیم شد. اکنون اگر در همینجا (داخل container در حال اجرا) دستور dotnet --info را صادر کنید، میتوان مشخصات NET Core SDK. نصب شده را مشاهده کرد. برای خروج از آن نیز دستور exit را صادر کنید.
چرا حجم Image مخصوص NET Core. نگارش nanoserver آن حدود 800 مگابایت است؟
در مثال قبلی، دسترسی به command prompt مجزایی نسبت به command prompt اصلی سیستم، در داخل یک container، شاید اندکی غیر منتظره بود و اکنون این سؤال مطرح میشود که یک image، شامل چه چیزهایی است؟
یک image شاید در ابتدای کار صرفا شامل فایلهای اجرایی یک برنامهی خاص به نظر برسد؛ اما زمانیکه قرار است تبدیل به یک container قابل اجرا شود، شامل بسیاری از فایلهای دیگر نیز خواهد شد. برای درک این موضوع نیاز است لایههای نرم افزاری که یک سیستم را تشکیل میدهند، بررسی کنیم:
در این تصویر از پایینترین لایهای را که با سخت افزار ارتباط برقرار میکند تا بالاترین لایهی موجود نرم افزاری را مشاهده میکنید. دراینجا هر چیزی را که در ناحیهی کرنل قرار نمیگیرد، User Space مینامند. برنامههای قرار گرفتهی در User Space برای کار با سخت افزار نیاز است با کرنل ارتباط برقرار کنند و برای این منظور از System Calls استفاده میکنند که عموما کتابخانههایی هستند که جزئی از سیستم عامل میباشند؛ مانند API ویندوز. برای مثال MongoDB توسط Win32 API و System Calls، فرامینی را به کرنل منتقل میکند.
در روش متداول توزیع و نصب نرم افزار، ما عموما همان بالاترین سطح را توزیع و نصب میکنیم؛ برای مثال خود MongoDB را. در اینجا نصاب MongoDB فرض میکند که در سیستم جاری، تمام لایههای دیگر، موجود و آمادهی استفاده هستند و اگر اینگونه نباشد، به مشکل برخواهد خورد و اجرا نمیشود. برای اجتناب از یک چنین مشکلاتی مانند عدم حضور وابستگیهایی که یک برنامه برای اجرا نیاز دارد، imageهای docker، نحوهی توزیع نرم افزارها را تغییر دادهاند. اینبار یک image بجای توزیع فقط MongoDB، شامل تمام قسمتهای مورد نیاز User Space نیز هست:
به این ترتیب دیگر مشکلاتی مانند عدم وجود یک وابستگی یا حتی وجود یک وابستگی غیرسازگار با نرم افزار مدنظر، وجود نخواهند داشت. حتی میتوان تصویر فوق را به صورت زیر نیز خلاصه کرد:
به همین جهت بود که برای مثال در قسمت قبل موفق شدیم IIS مخصوص ویندوز سرور با تگ nanoserver را بر روی ویندوز 10 که بسیاری از وابستگیهای مرتبط را به همراه ندارد، با موفقیت اجرا کنیم.
به علاوه چون یک container صرفا به معنای یک running process از یک image است، هر فایل اجرایی داخل آن image را نیز میتوان به صورت یک container اجرا کرد؛ مانند cmd.exe داخل image مرتبط با NET Core. که آنرا بررسی کردیم.
کارآیی Docker Containers نسبت به ماشینهای مجازی بسیار بیشتر است
مزیت دیگر یک چنین توزیعی این است که اگر چندین container در حال اجرا را داشته باشیم:
در نهایت تمام آنها فقط با یک لایهی کرنل کار میکنند و آن هم کرنل اصلی سیستم جاری است. به همین جهت کارآیی docker containers نسبت به ماشینهای مجازی بیشتر است؛ چون هر ماشین مجازی، کرنل مجازی خاص خودش را نسبت به یک ماشین مجازی در حال اجرای دیگر دارد. در اینجا برای ایجاد یک لایه ایزولهی اجرای برنامهها، تنها کافی است یک container جدید را اجرا کنیم و در این حالت وارد فاز بوت شدن یک سیستم عامل کامل، مانند ماشینهای مجازی نمیشویم.
شاید مطابق تصویر فوق اینطور به نظر برسد که هرچند تمام این containers از یک کرنل استفاده میکنند، اما اگر قرار باشد هر کدام OS Apps & Libs خاص خودشان را در حافظه بارگذاری کنند، با کمبود شدید منابع روبرو شویم. دقیقا مانند حالتیکه چند ماشین مجازی را اجرا کردهایم و دیگر سیستم اصلی قادر به پاسخگویی به درخواستهای رسیده به علت کمبود منابع نیست. اما در واقعیت، یک image داکر، از لایههای مختلفی تشکیل میشود که فقط خواندنی هستند و غیرقابل تغییر و زمانیکه docker یک لایهی فقط خواندنی را در حافظه بارگذاری کرد، اگر container دیگری، از همان لایهی تعریف شده، در image خود نیز استفاده میکند، لایهی بارگذاری شدهی فقط خواندنی در حال اجرای موجود را با آن به اشتراک میگذارد (مانند تصویر زیر). به این ترتیب میزان مصرف منابع docker containers نسبت به ماشینهای مجازی بسیار کمتر است:
روش کنترل پروسهای که درون یک کانتینر اجرا میشود
با اجرای دستور docker run -it microsoft/dotnet:nanoserver ابتدا به command prompt داخلی و مخصوص این container منتقل میشویم و سپس میتوان برای مثال با NET Core CLI. کار کرد. اما امکان اجرای این CLI به صورت زیر نیز وجود دارد:
این دستور، مشخصات SDK نصب شده را نمایش میدهد و سپس مجددا به command prompt سیستم اصلی (که به آن میزبان، host و یا container host نیز گفته میشود) بازگشت داده خواهیم شد؛ چون کار NET Core CLI. خاتمه یافتهاست، پروسهی متعلق به آن نیز خاتمه مییابد.
بدیهی است در این حالت تمام فایلهای اجرایی داخل این container را نیز میتوان اجرا کرد. برای مثال میتوان کنسول پاورشل داخل این container را اجرا کرد:
زمانیکه به این کنسول دسترسی پیدا کردید، برای مثال دستور get-process را اجرا کنید. به این ترتیب میتوانید لیست تمام پروسههایی ر که هم اکنون داخل این container در حال اجرا هستند، مشاهده کنید.
هر کانتینر دارای یک File System ایزولهی خاص خود است
تا اینجا دریافتیم که هر image، به همراه فایلهای user space مورد نیاز خود نیز میباشد. به عبارتی هر image یک file system را نیز ارائه میدهد که تنها درون همان container قابل دسترسی میباشد و از مابقی سیستم جاری ایزوله شدهاست.
برای آزمایش آن، کنسول پاورشل را در سیستم میزبان (سیستم عامل اصلی که docker را اجرا میکند)، باز کرده و دستور \:ls c را صادر کنید. به این ترتیب میتوانید لیست پوشهها و فایلهای موجود در درایو C میزبان را مشاهده نمائید. سپس دستور docker run -it microsoft/dotnet:nanoserver powershell را اجرا کنید تا به powershell داخل کانتینر NET Core. دسترسی پیدا کنیم. اکنون دستور \:ls c را مجددا اجرا کنید. خروجی آن کاملا متفاوت است نسبت به گزارشی که پیشتر بر روی سیستم میزبان تهیه کردیم؛ دقیقا مانند اینکه هارد درایو یک container متفاوت است با هارد درایو سیستم میزبان.
این تصویر زمانی تهیه شدهاست که دستور docker run یاد شده را صادر کردهایم و درون powershell آن قرار داریم. همانطور که مشاهده میکنید یک Disk جدید، به ازای این Container در حال اجرا، به سیستم میزبان اضافه شدهاست. این Disk زمانیکه در powershell داخل container، دستور exit را صادر کنیم، بلافاصله محو میشود. چون پروسهی container، به این ترتیب خاتمه یافتهاست.
اگر دستور docker run یاد شده را دو بار اجرا کنیم، دو Disk جدید ظاهر خواهند شد:
یک نکته: اگر بر روی این درایوهای مجازی کلیک راست کرده، گزینهی change drive letter or path را انتخاب نموده و یک drive letter را به آنها نسبت دهید، میتوانید محتویات داخل آنها را توسط Windows Explorer ویندوز میزبان نیز به صورت یک درایو جدید، مشاهده کنید.
خلاصهای از ایزوله سازیهای کانتینرها تا به اینجا
تا اینجا یک چنین ایزوله سازیهایی را بررسی کردیم:
- ایزوله سازی File System و وجود یک disk مجازی مجزا به ازای هر کانتینر در حال اجرا.
- پروسههای کانتینرها از پروسههای میزبان ایزوله هستند. برای مثال اگر دستور get-process را داخل یک container اجرا کنید، خروجی آن با خروجی اجرای این دستور بر روی سیستم میزبان یکی نیست. یعنی نمیتوان از داخل کانتینرها، به پروسههای میزبان دسترسی داشت و دخل و تصرفی را در آنها انجام داد که از لحاظ امنیتی بسیار مفید است. هر چند اگر به task manager ویندوز میزبان مراجعه کنید، میتوان پروسههای داخل یک container را توسط Job Object ID یکسان آنها تشخیص دهید (مثال آخر قسمت قبل)، اما یک container، قابلیت شمارش پروسههای خارج از مرز خود را ندارد.
- ایزوله سازی شبکه مانند کارت شبکهی مجازی کانتینر IIS که در قسمت قبل بررسی کردیم. برای آزمایش آن دستور ipconfig را در داخل container و سپس در سیستم میزبان اجرا کنید. نتیجهای را که مشاهده خواهید کرد، کاملا متفاوت است. یعنی network stack این دو کاملا از هم مجزا است. شبیه به اینکه به یک سیستم، چندین کارت شبکه را متصل کرده باشید. اینکار در اینجا با تعریف virtual network adaptors انجام میشود و لیست آنها را در قسمت «All Control Panel Items\Network Connections» سیستم میزبان میتوانید مشاهده کنید. یکی از مهمترین مزایای آن این است که اگر در یک container، وب سروری را بر روی پورت 80 آن اجرا کنید، مهم نیست که در سیستم میزبان، یک IIS در حال سرویس دهی بر روی پورت 80 هم اکنون موجود است. این دو پورت با هم تداخل نمیکنند.
- در حالت کار با Windows Containers، رجیستری کانتینر نیز از میزبان آن مجزا است و یا متغیرهای محیطی اینها یکی نیست. برای مثال دستور \:ls env را در کانتینر و سیستم میزبان اجرا کنید تا environment variables را گزارش گیری کنید. خروجی این دو کاملا متفاوت است. برای مثال حداقل computer name، user nameهای قابل مشاهدهی در این گزارشها، متفاوت است و یا دستور \:ls hkcu را در هر دو اجرا کنید تا خروجی رجیستری متعلق به کاربر جاری هر کدام را مشاهده کنید که در هر دو متفاوت است.
- در حالت کار با Linux Containers هر چیزی که ذیل عنوان namespace مطرح میشود مانند شبکه، PID، User، UTS، Mount و غیره شامل ایزوله سازی میشوند.
دو نوع Windows Containers وجود دارند
در ویندوز، Windows Server Containers و Hyper-V Containers وجود دارند. در این قسمت تمام کارهایی را که بر روی ویندوز سرور انجام دادیم، در حقیقت بر روی Windows Server Containers انجام شدند و تمام Containerهای ویندوزی را که در قسمت قبل بر روی ویندوز 10 ایجاد کردیم، از نوع Hyper-V Containers بودند.
تفاوت مهم اینها در مورد نحوهی پیاده سازی ایزوله سازی آنها است. در حالت Windows Server Containers، کار ایزوله سازی پروسهها توسط کرنل اشتراکی بین کانتینرها صورت میگیرد اما در Hyper-V Containers، این ایزوله سازی توسط hypervisor آن انجام میشود؛ هرچند نسبت به ماشینهای مجازی متداول بسیار سریعتر است، اما بحث به اشتراک گذاری کرنل هاست را که پیشتر در این قسمت بررسی کردیم، در این حالت شاهد نخواهیم بود. ویندوز سرور 2016 میتواند هر دوی این ایزوله سازیها را پشتیبانی کند، اما ویندوز 10، فقط نوع Hyper-V را پشتیبانی میکند.
روش اجرای Hyper-V Containers بر روی ویندوز سرور
در صورت نیاز برای کار با Hyper-V Containers، نیاز است مانند قسمت قبل، ابتدا Hyper-V را بر روی ویندوز سرور، فعالسازی کرد:
اکنون برای اجرای دستور docker run ای که توسط Hyper-V مدیریت میشود، میتوان به صورت زیر، از سوئیچ isolation استفاده کرد:
در این حالت اگر به disk management سیستم میزبان مراجعه کنید، دیگر حالت اضافه شدن disk مجازی را مشاهده نمیکنید. همچنین اگر به task manager ویندوز میزبان مراجعه کنید، دیگر لیست پروسههای داخل container را نیز در اینجا نمیبینید. علت آن روش ایزوله سازی متفاوت آن با Windows Server Containers است و بیشتر شبیه به ماشینهای مجازی عمل میکند. در کل اگر نیاز به حداکثر و شدیدترین حالت ایزوله سازی را دارید، از این روش استفاده کنید.
Docker for Windows چگونه از هر دوی کانتینرهای ویندوزی و لینوکسی پشتیبانی میکند؟
زمانیکه docker for windows را اجرا میکنیم، سرویسی را ایجاد میکند که سبب اجرای پروسهی ویژهای به نام com.docker.proxy.exe میشود:
هنگامیکه برای مثال فرمان docker run nginx را توسط Docker CLI اجرا میکنیم، Docker CLI از طریق واسط یاد شده، دستورات را به MobyLinuxVM منتقل میکند. به این صورت است که امکان اجرای Linux Containers، بر روی ویندوز میسر میشوند:
اکنون اگر به Windows Containers سوئیچ کنیم (از طریق کلیک راست بر روی آیکن Docker در قسمت Tray Icons ویندوز)، پروسهی dockerd.exe یا docker daemon شروع به کار خواهد کرد:
اینبار اگر مجددا از Docker CLI برای اجرای مثلا IIS Container استفاده کنیم، دستور ما از طریق واسطهای com.docker.proxy و dockerd، به کانتینر ویندوزی منتقل و اجرا میشود:
نگاهی به معماری Docker بر روی ویندوز سرور
داکر بر روی ویندوز سرور، تنها به همراه موتور مدیریت کنندهی Windows Containers است:
در اینجا با صدور فرمانهای Docker CLI، پیامها مستقیما به dockerd یا موتور داکر بر روی ویندوز سرور ارسال شده و سپس کار اجرا و مدیریت یک Windows Container انجام میشود.
نصب Docker بر روی ویندوز سرور
جزئیات مفصل و به روز Windows Containers را همواره میتوانید در این آدرس در سایت مستندات مجازی سازی مایکروسافت مطالعه کنید (قسمت Container Host Deployment - Windows Server آن). پیشنیاز کار با آن نیز نصب حداقل ویندوز سرور 2016 میباشد و بهتر است تمام به روز رسانیهای آنرا نیز نصب کرده باشید؛ چون تعدادی از بهبودهای کار با کانتینرهای آن، به همراه به روز رسانیها آن ارائه شدهاند.
برای شروع به نصب، نیاز است کنسول PowerShell ویندوز را با دسترسی Admin اجرا کنید.
سپس اولین دستوراتی را که نیاز است اجرا کنید، کار نصب موتور Docker و CLI آنرا به صورت خودکار بر روی ویندوز سرور انجام میدهند:
Install-Module -Name DockerMsftProvider -Repository PSGallery -Force Install-Package -Name docker -ProviderName DockerMsftProvider Restart-Computer -Force
- به علاوه اگر دستور *get-service *docker را در کنسول PowerShell صادر کنید، مشاهده خواهید کرد که سرویس جدیدی را به نام Docker نیز نصب و راه اندازی کردهاست که به dockerd.exe اشاره میکند.
- و یا اگر در کنسول PowerShell دستور docker را صادر کنید، ملاحظه خواهید کرد که CLI آن، فعال و قابل استفادهاست. برای مثال، دستور docker version را صادر کنید تا بتوانید نگارش docker نصب شده را ملاحظه نمائید.
اجرای Image مخصوص NET Core. بر روی ویندوز سرور
تگهای مختلف Image مخصوص NET Core. را در اینجا ملاحظه میکنید. در ادامه قصد داریم tag مرتبط با nanoserver آنرا نصب کنیم (با حجم 802MB):
docker run microsoft/dotnet:nanoserver
docker run -it microsoft/dotnet:nanoserver
چرا حجم Image مخصوص NET Core. نگارش nanoserver آن حدود 800 مگابایت است؟
در مثال قبلی، دسترسی به command prompt مجزایی نسبت به command prompt اصلی سیستم، در داخل یک container، شاید اندکی غیر منتظره بود و اکنون این سؤال مطرح میشود که یک image، شامل چه چیزهایی است؟
یک image شاید در ابتدای کار صرفا شامل فایلهای اجرایی یک برنامهی خاص به نظر برسد؛ اما زمانیکه قرار است تبدیل به یک container قابل اجرا شود، شامل بسیاری از فایلهای دیگر نیز خواهد شد. برای درک این موضوع نیاز است لایههای نرم افزاری که یک سیستم را تشکیل میدهند، بررسی کنیم:
در این تصویر از پایینترین لایهای را که با سخت افزار ارتباط برقرار میکند تا بالاترین لایهی موجود نرم افزاری را مشاهده میکنید. دراینجا هر چیزی را که در ناحیهی کرنل قرار نمیگیرد، User Space مینامند. برنامههای قرار گرفتهی در User Space برای کار با سخت افزار نیاز است با کرنل ارتباط برقرار کنند و برای این منظور از System Calls استفاده میکنند که عموما کتابخانههایی هستند که جزئی از سیستم عامل میباشند؛ مانند API ویندوز. برای مثال MongoDB توسط Win32 API و System Calls، فرامینی را به کرنل منتقل میکند.
در روش متداول توزیع و نصب نرم افزار، ما عموما همان بالاترین سطح را توزیع و نصب میکنیم؛ برای مثال خود MongoDB را. در اینجا نصاب MongoDB فرض میکند که در سیستم جاری، تمام لایههای دیگر، موجود و آمادهی استفاده هستند و اگر اینگونه نباشد، به مشکل برخواهد خورد و اجرا نمیشود. برای اجتناب از یک چنین مشکلاتی مانند عدم حضور وابستگیهایی که یک برنامه برای اجرا نیاز دارد، imageهای docker، نحوهی توزیع نرم افزارها را تغییر دادهاند. اینبار یک image بجای توزیع فقط MongoDB، شامل تمام قسمتهای مورد نیاز User Space نیز هست:
به این ترتیب دیگر مشکلاتی مانند عدم وجود یک وابستگی یا حتی وجود یک وابستگی غیرسازگار با نرم افزار مدنظر، وجود نخواهند داشت. حتی میتوان تصویر فوق را به صورت زیر نیز خلاصه کرد:
به همین جهت بود که برای مثال در قسمت قبل موفق شدیم IIS مخصوص ویندوز سرور با تگ nanoserver را بر روی ویندوز 10 که بسیاری از وابستگیهای مرتبط را به همراه ندارد، با موفقیت اجرا کنیم.
به علاوه چون یک container صرفا به معنای یک running process از یک image است، هر فایل اجرایی داخل آن image را نیز میتوان به صورت یک container اجرا کرد؛ مانند cmd.exe داخل image مرتبط با NET Core. که آنرا بررسی کردیم.
کارآیی Docker Containers نسبت به ماشینهای مجازی بسیار بیشتر است
مزیت دیگر یک چنین توزیعی این است که اگر چندین container در حال اجرا را داشته باشیم:
در نهایت تمام آنها فقط با یک لایهی کرنل کار میکنند و آن هم کرنل اصلی سیستم جاری است. به همین جهت کارآیی docker containers نسبت به ماشینهای مجازی بیشتر است؛ چون هر ماشین مجازی، کرنل مجازی خاص خودش را نسبت به یک ماشین مجازی در حال اجرای دیگر دارد. در اینجا برای ایجاد یک لایه ایزولهی اجرای برنامهها، تنها کافی است یک container جدید را اجرا کنیم و در این حالت وارد فاز بوت شدن یک سیستم عامل کامل، مانند ماشینهای مجازی نمیشویم.
شاید مطابق تصویر فوق اینطور به نظر برسد که هرچند تمام این containers از یک کرنل استفاده میکنند، اما اگر قرار باشد هر کدام OS Apps & Libs خاص خودشان را در حافظه بارگذاری کنند، با کمبود شدید منابع روبرو شویم. دقیقا مانند حالتیکه چند ماشین مجازی را اجرا کردهایم و دیگر سیستم اصلی قادر به پاسخگویی به درخواستهای رسیده به علت کمبود منابع نیست. اما در واقعیت، یک image داکر، از لایههای مختلفی تشکیل میشود که فقط خواندنی هستند و غیرقابل تغییر و زمانیکه docker یک لایهی فقط خواندنی را در حافظه بارگذاری کرد، اگر container دیگری، از همان لایهی تعریف شده، در image خود نیز استفاده میکند، لایهی بارگذاری شدهی فقط خواندنی در حال اجرای موجود را با آن به اشتراک میگذارد (مانند تصویر زیر). به این ترتیب میزان مصرف منابع docker containers نسبت به ماشینهای مجازی بسیار کمتر است:
روش کنترل پروسهای که درون یک کانتینر اجرا میشود
با اجرای دستور docker run -it microsoft/dotnet:nanoserver ابتدا به command prompt داخلی و مخصوص این container منتقل میشویم و سپس میتوان برای مثال با NET Core CLI. کار کرد. اما امکان اجرای این CLI به صورت زیر نیز وجود دارد:
docker run -it microsoft/dotnet:nanoserver dotnet --info
بدیهی است در این حالت تمام فایلهای اجرایی داخل این container را نیز میتوان اجرا کرد. برای مثال میتوان کنسول پاورشل داخل این container را اجرا کرد:
docker run -it microsoft/dotnet:nanoserver powershell
هر کانتینر دارای یک File System ایزولهی خاص خود است
تا اینجا دریافتیم که هر image، به همراه فایلهای user space مورد نیاز خود نیز میباشد. به عبارتی هر image یک file system را نیز ارائه میدهد که تنها درون همان container قابل دسترسی میباشد و از مابقی سیستم جاری ایزوله شدهاست.
برای آزمایش آن، کنسول پاورشل را در سیستم میزبان (سیستم عامل اصلی که docker را اجرا میکند)، باز کرده و دستور \:ls c را صادر کنید. به این ترتیب میتوانید لیست پوشهها و فایلهای موجود در درایو C میزبان را مشاهده نمائید. سپس دستور docker run -it microsoft/dotnet:nanoserver powershell را اجرا کنید تا به powershell داخل کانتینر NET Core. دسترسی پیدا کنیم. اکنون دستور \:ls c را مجددا اجرا کنید. خروجی آن کاملا متفاوت است نسبت به گزارشی که پیشتر بر روی سیستم میزبان تهیه کردیم؛ دقیقا مانند اینکه هارد درایو یک container متفاوت است با هارد درایو سیستم میزبان.
این تصویر زمانی تهیه شدهاست که دستور docker run یاد شده را صادر کردهایم و درون powershell آن قرار داریم. همانطور که مشاهده میکنید یک Disk جدید، به ازای این Container در حال اجرا، به سیستم میزبان اضافه شدهاست. این Disk زمانیکه در powershell داخل container، دستور exit را صادر کنیم، بلافاصله محو میشود. چون پروسهی container، به این ترتیب خاتمه یافتهاست.
اگر دستور docker run یاد شده را دو بار اجرا کنیم، دو Disk جدید ظاهر خواهند شد:
یک نکته: اگر بر روی این درایوهای مجازی کلیک راست کرده، گزینهی change drive letter or path را انتخاب نموده و یک drive letter را به آنها نسبت دهید، میتوانید محتویات داخل آنها را توسط Windows Explorer ویندوز میزبان نیز به صورت یک درایو جدید، مشاهده کنید.
خلاصهای از ایزوله سازیهای کانتینرها تا به اینجا
تا اینجا یک چنین ایزوله سازیهایی را بررسی کردیم:
- ایزوله سازی File System و وجود یک disk مجازی مجزا به ازای هر کانتینر در حال اجرا.
- پروسههای کانتینرها از پروسههای میزبان ایزوله هستند. برای مثال اگر دستور get-process را داخل یک container اجرا کنید، خروجی آن با خروجی اجرای این دستور بر روی سیستم میزبان یکی نیست. یعنی نمیتوان از داخل کانتینرها، به پروسههای میزبان دسترسی داشت و دخل و تصرفی را در آنها انجام داد که از لحاظ امنیتی بسیار مفید است. هر چند اگر به task manager ویندوز میزبان مراجعه کنید، میتوان پروسههای داخل یک container را توسط Job Object ID یکسان آنها تشخیص دهید (مثال آخر قسمت قبل)، اما یک container، قابلیت شمارش پروسههای خارج از مرز خود را ندارد.
- ایزوله سازی شبکه مانند کارت شبکهی مجازی کانتینر IIS که در قسمت قبل بررسی کردیم. برای آزمایش آن دستور ipconfig را در داخل container و سپس در سیستم میزبان اجرا کنید. نتیجهای را که مشاهده خواهید کرد، کاملا متفاوت است. یعنی network stack این دو کاملا از هم مجزا است. شبیه به اینکه به یک سیستم، چندین کارت شبکه را متصل کرده باشید. اینکار در اینجا با تعریف virtual network adaptors انجام میشود و لیست آنها را در قسمت «All Control Panel Items\Network Connections» سیستم میزبان میتوانید مشاهده کنید. یکی از مهمترین مزایای آن این است که اگر در یک container، وب سروری را بر روی پورت 80 آن اجرا کنید، مهم نیست که در سیستم میزبان، یک IIS در حال سرویس دهی بر روی پورت 80 هم اکنون موجود است. این دو پورت با هم تداخل نمیکنند.
- در حالت کار با Windows Containers، رجیستری کانتینر نیز از میزبان آن مجزا است و یا متغیرهای محیطی اینها یکی نیست. برای مثال دستور \:ls env را در کانتینر و سیستم میزبان اجرا کنید تا environment variables را گزارش گیری کنید. خروجی این دو کاملا متفاوت است. برای مثال حداقل computer name، user nameهای قابل مشاهدهی در این گزارشها، متفاوت است و یا دستور \:ls hkcu را در هر دو اجرا کنید تا خروجی رجیستری متعلق به کاربر جاری هر کدام را مشاهده کنید که در هر دو متفاوت است.
- در حالت کار با Linux Containers هر چیزی که ذیل عنوان namespace مطرح میشود مانند شبکه، PID، User، UTS، Mount و غیره شامل ایزوله سازی میشوند.
دو نوع Windows Containers وجود دارند
در ویندوز، Windows Server Containers و Hyper-V Containers وجود دارند. در این قسمت تمام کارهایی را که بر روی ویندوز سرور انجام دادیم، در حقیقت بر روی Windows Server Containers انجام شدند و تمام Containerهای ویندوزی را که در قسمت قبل بر روی ویندوز 10 ایجاد کردیم، از نوع Hyper-V Containers بودند.
تفاوت مهم اینها در مورد نحوهی پیاده سازی ایزوله سازی آنها است. در حالت Windows Server Containers، کار ایزوله سازی پروسهها توسط کرنل اشتراکی بین کانتینرها صورت میگیرد اما در Hyper-V Containers، این ایزوله سازی توسط hypervisor آن انجام میشود؛ هرچند نسبت به ماشینهای مجازی متداول بسیار سریعتر است، اما بحث به اشتراک گذاری کرنل هاست را که پیشتر در این قسمت بررسی کردیم، در این حالت شاهد نخواهیم بود. ویندوز سرور 2016 میتواند هر دوی این ایزوله سازیها را پشتیبانی کند، اما ویندوز 10، فقط نوع Hyper-V را پشتیبانی میکند.
روش اجرای Hyper-V Containers بر روی ویندوز سرور
در صورت نیاز برای کار با Hyper-V Containers، نیاز است مانند قسمت قبل، ابتدا Hyper-V را بر روی ویندوز سرور، فعالسازی کرد:
Install-WindowsFeature hyper-v Restart-Computer -Force
docker run -it --isolation=hyperv microsoft/dotnet:nanoserver powershell
در قسمت قبل، مقدماتی از Pipeها را مورد برسی قرار دادیم؛ از جمله کاربرد Pipeها، نحوه استفاده از آنها، معرفی یکسری Pipe از پیش ساخته شده Angular، نحوه ارسال پارامتر به آنها و همچنین نحوه استفاده از آنها را در داخل Typescript، فراگرفتیم. در این قسمت نحوه ساخت Pipeهای سفارشی و همچنین نکات تکمیلی در مورد آنها را مورد بحث و بررسی قرار میدهیم.
نحوه ساخت Pipe سفارشی
علاوه بر استفاده از Pipeهای از پیش ساخته شده Angular، شما میتوانید Pipeهای سفارشی خود را نیز تعریف و استفاده کنید. به عنوان مثال میخواهیم Pipe ای را با نام perNumber تعریف کنیم، تا تمامی اعداد موجود در عبارت ورودی Pipe را به صورت اعداد فارسی نمایش دهد. یعنی با اعمال این Pipe به عدد 123456 خروجی ۱۲۳۴۵۶ مورد انتظار است. برای ایجاد Pipe سفارشی مراحل زیر را انجام دهید.
قدم اول - ساخت یک فایل با نام دلخواه
طبق Style Guide در Angular.io نام این فایل را per-number.pipe.ts انتخاب میکنیم.
قدم دوم – افزودن ماژولهای مورد نیاز
داخل فایل ایجاد شده ماژولهای Pipe و PipeTransform را با استفاده از دستور import از angular/core@ اضافه میکنیم.
قدم سوم – ساخت کلاس و مزین کردن آن به Pipe@
یک کلاس با نام دلخواه را مثلا به نام PerNumberPipe ایجاد میکنیم. این کلاس علاوه بر اینکه PipeTransform را پیاده سازی خواهد کرد، مزین به متادیتای Pipe@ نیز میباشد. متادیتای Pipe@ هنگام تزئین کلاس، یک نام را دریافت میکند. این نام قرار است به عنوان نام نهایی Pipe برای اعمال بر روی Template expressions مورد استفاده قرار بگیرد.
قدم چهارم – پیاده سازی متد transform
به واسطه اعمال اینترفیس PipeTransform، این کلاس باید متد transform را پیاده سازی کند. این متد در پارامتر اول خود، عبارت ورودی را که قرار است Pipe بر روی آن اعمال شود، دریافت میکند و در ادامه تعداد دلخواهی پارامتر ورودی Pipe را که میخواهد، میتواند دریافت کند.
نکته ۱: نام انتخابی برای Pipe در آذینگر Pipe@ بایستی یک شناسه معتبر در JavaScript باشد.
نکته ۲: متد transform برای Pipe اجباری است و حتما بایستی پیاده سازی شود. اینترفیس PipeTransform این متد را برای کلاس اجباری میکند؛ هرچند استفاده از این اینترفیس برای کلاس Pipe کاملا اختیاری است.
قدم آخر – نوشتن کد تبدیل اعداد
Pipe مورد نظر ما قرار است یک رشته عددی را از ورودی دریافت کند و تمامی اعداد لاتین آن را به فارسی تبدیل کند. همچنین این Pipe هیچگونه پارامتری را دریافت نمیکند. کد زیر نحوه پیاده سازی متد transform را نمایش میدهد.
نحوه معرفی Pipe سفارشی به برنامه
حالا جهت استفاده از Pipe سفارشی در کامپوننتهای خود کافی است آنرا یکبار در قسمت declarations در AppModule خود تعریف کنید.
نحوه استفاده از Pipeهای سفارشی
نحوه استفاده از Pipeهای سفارشی، دقیقا مشابه Pipeهای از قبل ساخته شده Angular میباشد.
Pipeها و تشخیص تغییرات
Angular برای اعمال Pipe بر روی Template expressions بایستی تمامی رخدادهای برنامه را تحت نظر قرار داده و با مشاهده هر تغییری بر روی عبارت ورودی Pipe، فراخوانی Pipe را آغاز کند. از جمله این رخدادها میتوان به رخداد mouse move، timer tick، server response و فشرده شدن کلیدهای ماوس و یا کیبورد اشاره کرد. واضح است که بررسی تغییرات عبارت در این همه رخداد میتواند مخرب باشد و بر روی کارآئی (Performance) تاثیر منفی خواهد گذاشت. اما Angular برای حل این مشکل و همچنین هنگام مشاهده سریع تغییرات هنگام استفاده از Pipeها، الگوریتمهای سریع و سادهای در نظر گرفته است.
در قسمت بعد با انواع Pipeها در Angular و همچنین نحوه پیاده سازی آنها، آشنا خواهیم شد.
نحوه ساخت Pipe سفارشی
علاوه بر استفاده از Pipeهای از پیش ساخته شده Angular، شما میتوانید Pipeهای سفارشی خود را نیز تعریف و استفاده کنید. به عنوان مثال میخواهیم Pipe ای را با نام perNumber تعریف کنیم، تا تمامی اعداد موجود در عبارت ورودی Pipe را به صورت اعداد فارسی نمایش دهد. یعنی با اعمال این Pipe به عدد 123456 خروجی ۱۲۳۴۵۶ مورد انتظار است. برای ایجاد Pipe سفارشی مراحل زیر را انجام دهید.
قدم اول - ساخت یک فایل با نام دلخواه
طبق Style Guide در Angular.io نام این فایل را per-number.pipe.ts انتخاب میکنیم.
قدم دوم – افزودن ماژولهای مورد نیاز
داخل فایل ایجاد شده ماژولهای Pipe و PipeTransform را با استفاده از دستور import از angular/core@ اضافه میکنیم.
import { Pipe, PipeTransform } from '@angular/core';
قدم سوم – ساخت کلاس و مزین کردن آن به Pipe@
یک کلاس با نام دلخواه را مثلا به نام PerNumberPipe ایجاد میکنیم. این کلاس علاوه بر اینکه PipeTransform را پیاده سازی خواهد کرد، مزین به متادیتای Pipe@ نیز میباشد. متادیتای Pipe@ هنگام تزئین کلاس، یک نام را دریافت میکند. این نام قرار است به عنوان نام نهایی Pipe برای اعمال بر روی Template expressions مورد استفاده قرار بگیرد.
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({name: 'perNumber'}) export class PerNumberPipe implements PipeTransform { }
قدم چهارم – پیاده سازی متد transform
به واسطه اعمال اینترفیس PipeTransform، این کلاس باید متد transform را پیاده سازی کند. این متد در پارامتر اول خود، عبارت ورودی را که قرار است Pipe بر روی آن اعمال شود، دریافت میکند و در ادامه تعداد دلخواهی پارامتر ورودی Pipe را که میخواهد، میتواند دریافت کند.
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({name: 'perNumber'}) export class PerNumberPipe implements PipeTransform { transform(value: any, ...args: any[]): any { } }
نکته ۱: نام انتخابی برای Pipe در آذینگر Pipe@ بایستی یک شناسه معتبر در JavaScript باشد.
نکته ۲: متد transform برای Pipe اجباری است و حتما بایستی پیاده سازی شود. اینترفیس PipeTransform این متد را برای کلاس اجباری میکند؛ هرچند استفاده از این اینترفیس برای کلاس Pipe کاملا اختیاری است.
قدم آخر – نوشتن کد تبدیل اعداد
Pipe مورد نظر ما قرار است یک رشته عددی را از ورودی دریافت کند و تمامی اعداد لاتین آن را به فارسی تبدیل کند. همچنین این Pipe هیچگونه پارامتری را دریافت نمیکند. کد زیر نحوه پیاده سازی متد transform را نمایش میدهد.
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({name: 'perNumber'}) export class PerNumberPipe implements PipeTransform { transform(input: string): string{ if (input == undefined) return ''; var str = input.toString().trim(); if (str === "") return ""; str = str.replace(/0/g, '۰'); str = str.replace(/1/g, '۱'); str = str.replace(/2/g, '۲'); str = str.replace(/3/g, '۳'); str = str.replace(/4/g, '۴'); str = str.replace(/5/g, '۵'); str = str.replace(/6/g, '۶'); str = str.replace(/7/g, '۷'); str = str.replace(/8/g, '۸'); str = str.replace(/9/g, '۹'); return str; } }
نحوه معرفی Pipe سفارشی به برنامه
حالا جهت استفاده از Pipe سفارشی در کامپوننتهای خود کافی است آنرا یکبار در قسمت declarations در AppModule خود تعریف کنید.
import { PerNumberPipe } from './pipes/per-number.pipe.ts' ... declarations: [PerNumberPipe]
نحوه استفاده از Pipeهای سفارشی
نحوه استفاده از Pipeهای سفارشی، دقیقا مشابه Pipeهای از قبل ساخته شده Angular میباشد.
<h3>{{'12345679' | perNumber}}</h3>
یکسری از Pipeهای مربوط به زبان فارسی در گیتهاب بنده پیاده سازی شده است که نیازمند همکاری دوستان است. لطفا جهت همکاری برای ساخت یک ابزار جامع برای زبان فارسی در Angular به این لینک مراجعه کنید.
Pipeها و تشخیص تغییرات
Angular برای اعمال Pipe بر روی Template expressions بایستی تمامی رخدادهای برنامه را تحت نظر قرار داده و با مشاهده هر تغییری بر روی عبارت ورودی Pipe، فراخوانی Pipe را آغاز کند. از جمله این رخدادها میتوان به رخداد mouse move، timer tick، server response و فشرده شدن کلیدهای ماوس و یا کیبورد اشاره کرد. واضح است که بررسی تغییرات عبارت در این همه رخداد میتواند مخرب باشد و بر روی کارآئی (Performance) تاثیر منفی خواهد گذاشت. اما Angular برای حل این مشکل و همچنین هنگام مشاهده سریع تغییرات هنگام استفاده از Pipeها، الگوریتمهای سریع و سادهای در نظر گرفته است.
در قسمت بعد با انواع Pipeها در Angular و همچنین نحوه پیاده سازی آنها، آشنا خواهیم شد.
یکی از مهمترین تغییرات ASP.NET Core 2.0، نسبت به نگارشهای قبلی آن، ارائهی یک «متا پکیج» جدید به نام Microsoft.AspNetCore.All است. این بسته به همراه تمام وابستگیهای مورد نیاز جهت توسعهی برنامههای ASP.NET Core 2.0 است؛ این «تمام» شامل تمام بستههای Razor، بستههای MVC، بستههای EF Core و غیره است. به این ترتیب به روز رسانی بستههای وابستهی به هم، بسیار ساده خواهد شد و همچنین به فایلهای csproj بسیار خلوت و قابل مدیریتی، خواهیم رسید.
بستهی Microsoft.AspNetCore.All فقط مخصوص پروژههای netcoreapp2.0 است
این «متا پکیج» تنها در پروژههایی که TargetFramework آنها به netcoreapp2.0 تنظیم شدهاست، قابل استفاده میباشد:
اگر TargetFramework تنظیمی netstandard2.0 باشد، قادر به استفادهی از آن نخواهید بود. در این حالت باید مانند سابق، تک تک بستههای مورد نیاز را در فایل csproj به صورت جداگانهای تعریف کنید.
نحوهی به روز رسانی پروژهها جهت استفادهی از Microsoft.AspNetCore.All
پیش از ناقص کردن برنامه و حذف بستههای نیوگتی که نباید از فایل csproj حذف شوند، ابتدا باید لیستی را که توسط «متا پکیج» Microsoft.AspNetCore.All ارائه میشود، بررسی کرد. این لیست را پس از نصب SDK جدید، در آدرس ذیل میتوانید مشاهده کنید:
روش دیگر یافتن این لیست، مراجعهی به سایت نیوگت و بررسی قسمت dependencies آدرس https://www.nuget.org/packages/Microsoft.AspNetCore.All است:
سپس به فایل csproj ایی که دارای TargetFramework مساوی netcoreapp2.0 است مراجعه کرده و هر کدام از بستههایی را که در این لیست قرار دارند ... حذف کنید. در آخر بجای تمام این مداخل حذف شده، یک مدخل کلی ذیل را تعریف کنید:
سؤال: آیا استفادهی از بستهی Microsoft.AspNetCore.All، ارائهی نهایی برنامه را حجیم نمیکند؟
اگر به مسیر dotnet\store ایی که پیشتر عنوان شد مراجعه کنید، در اینجا بیش از 180 بسته را خواهید یافت. در این حالت شاید به نظر برسد که حجم نهایی قابل توزیع برنامههای ASP.NET Core با استفاده از تک مدخل Microsoft.AspNetCore.All بسیار بالا خواهد رفت. اما ... خیر.
NET Core 2.0. به همراه ویژگی جدیدی است به نام Runtime store. هدف از آن، پیش نصب بستهها بر روی سیستم جاری، در یک مکان مرکزی است تا دیگر در حین توزیع نهایی برنامه، نیازی به توزیع مجدد آنها نباشد. به همین جهت، به آن میتوان شبیه به مفهوم پیشین Global assembly cache یا GAC مخصوص NET Core. نگاه کرد. به علاوه تمام این بستهها ngen شده و سرعت آغاز و اجرای برنامهها را بهبود میبخشند.
زمانیکه SDK جدید NET Core 2.0. را نصب میکنید، تمام بستههای مورد نیاز آن، در مسیر مرکزی C:\Program Files\dotnet\store نصب میشوند. بنابراین سیستمی که به همراه این SDK باشد، حتما حاوی تمام وابستگیهای ذکر شدهی در متاپکیج Microsoft.AspNetCore.All نیز خواهد بود و در این حالت نیازی به توزیع مجدد آنها نیست.
پس از آن مهمترین تفاوتی را که مشاهده خواهید کرد، کاهش حجم نهایی برنامههای ASP.NET Core 2.0 نسبت به نگارشهای 1x است. برای آزمایش، یک برنامهی ASP.NET Core 1.x و سپس یک برنامهی سادهی ASP.NET Core 2.x را publish کنید.
این تصویر، پوشهی نهایی قابل توزیع یک برنامهی ASP.NET Core 1.x را پس از publish نمایش میدهد:
بالا رفتن کارآیی تازه واردان به دنیای ASP.NET Core با متاپکیج جدید Microsoft.AspNetCore.All
یکی از مشکلاتی که به همراه کار با ASP.NET Core 1.x وجود دارد، مشخص نبودن محل قرارگیری ویژگیهای جدید و بستههای مرتبط با آنها است. همچنین به ازای هر ویژگی جدید باید یک بستهی نیوگت جدید را نصب کرد و عموما یافتن اینها و یا دانستن وجود آنها، کار دشواری میباشد.
اما زمانیکه متابستهی Microsoft.AspNetCore.All به قسمت ارجاعات پروژه اضافه میشود، در آغاز کار برنامه، سیستم IntelliSense آنها را پردازش کرده و بلافاصله در اختیار برنامه نویس قرار میگیرند. این قابلیت حتی در VSCode نیز همانند Visual Studio کار میکند و توسعه دهندهها بلافاصله IntelliSense بسیار کاملی را از قابلیتهای موجود در اختیار خواهند داشت؛ به همراه ویژگیهای تکمیلی دیگری مانند افزودن و یا اصلاح سادهتر فضاهای نام مرتبط.
بستهی Microsoft.AspNetCore.All فقط مخصوص پروژههای netcoreapp2.0 است
این «متا پکیج» تنها در پروژههایی که TargetFramework آنها به netcoreapp2.0 تنظیم شدهاست، قابل استفاده میباشد:
<TargetFramework>netcoreapp2.0</TargetFramework>
نحوهی به روز رسانی پروژهها جهت استفادهی از Microsoft.AspNetCore.All
پیش از ناقص کردن برنامه و حذف بستههای نیوگتی که نباید از فایل csproj حذف شوند، ابتدا باید لیستی را که توسط «متا پکیج» Microsoft.AspNetCore.All ارائه میشود، بررسی کرد. این لیست را پس از نصب SDK جدید، در آدرس ذیل میتوانید مشاهده کنید:
C:\Program Files\dotnet\store\x64\netcoreapp2.0
روش دیگر یافتن این لیست، مراجعهی به سایت نیوگت و بررسی قسمت dependencies آدرس https://www.nuget.org/packages/Microsoft.AspNetCore.All است:
سپس به فایل csproj ایی که دارای TargetFramework مساوی netcoreapp2.0 است مراجعه کرده و هر کدام از بستههایی را که در این لیست قرار دارند ... حذف کنید. در آخر بجای تمام این مداخل حذف شده، یک مدخل کلی ذیل را تعریف کنید:
<ItemGroup> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> </ItemGroup>
سؤال: آیا استفادهی از بستهی Microsoft.AspNetCore.All، ارائهی نهایی برنامه را حجیم نمیکند؟
اگر به مسیر dotnet\store ایی که پیشتر عنوان شد مراجعه کنید، در اینجا بیش از 180 بسته را خواهید یافت. در این حالت شاید به نظر برسد که حجم نهایی قابل توزیع برنامههای ASP.NET Core با استفاده از تک مدخل Microsoft.AspNetCore.All بسیار بالا خواهد رفت. اما ... خیر.
NET Core 2.0. به همراه ویژگی جدیدی است به نام Runtime store. هدف از آن، پیش نصب بستهها بر روی سیستم جاری، در یک مکان مرکزی است تا دیگر در حین توزیع نهایی برنامه، نیازی به توزیع مجدد آنها نباشد. به همین جهت، به آن میتوان شبیه به مفهوم پیشین Global assembly cache یا GAC مخصوص NET Core. نگاه کرد. به علاوه تمام این بستهها ngen شده و سرعت آغاز و اجرای برنامهها را بهبود میبخشند.
زمانیکه SDK جدید NET Core 2.0. را نصب میکنید، تمام بستههای مورد نیاز آن، در مسیر مرکزی C:\Program Files\dotnet\store نصب میشوند. بنابراین سیستمی که به همراه این SDK باشد، حتما حاوی تمام وابستگیهای ذکر شدهی در متاپکیج Microsoft.AspNetCore.All نیز خواهد بود و در این حالت نیازی به توزیع مجدد آنها نیست.
پس از آن مهمترین تفاوتی را که مشاهده خواهید کرد، کاهش حجم نهایی برنامههای ASP.NET Core 2.0 نسبت به نگارشهای 1x است. برای آزمایش، یک برنامهی ASP.NET Core 1.x و سپس یک برنامهی سادهی ASP.NET Core 2.x را publish کنید.
این تصویر، پوشهی نهایی قابل توزیع یک برنامهی ASP.NET Core 1.x را پس از publish نمایش میدهد:
و این تصویر، پوشهی نهایی قابل توزیع یک برنامهی ASP.NET Core 2.x را پس از publish نمایش میدهد:
در این حالت پوشهی نهایی نگارش 1x شامل 94 آیتم و پوشهی نهایی نگارش 2x شامل 13 آیتم است. یعنی حجم نهایی را که باید ارائه داد، به شدت کاهش یافتهاست.
بالا رفتن کارآیی تازه واردان به دنیای ASP.NET Core با متاپکیج جدید Microsoft.AspNetCore.All
یکی از مشکلاتی که به همراه کار با ASP.NET Core 1.x وجود دارد، مشخص نبودن محل قرارگیری ویژگیهای جدید و بستههای مرتبط با آنها است. همچنین به ازای هر ویژگی جدید باید یک بستهی نیوگت جدید را نصب کرد و عموما یافتن اینها و یا دانستن وجود آنها، کار دشواری میباشد.
اما زمانیکه متابستهی Microsoft.AspNetCore.All به قسمت ارجاعات پروژه اضافه میشود، در آغاز کار برنامه، سیستم IntelliSense آنها را پردازش کرده و بلافاصله در اختیار برنامه نویس قرار میگیرند. این قابلیت حتی در VSCode نیز همانند Visual Studio کار میکند و توسعه دهندهها بلافاصله IntelliSense بسیار کاملی را از قابلیتهای موجود در اختیار خواهند داشت؛ به همراه ویژگیهای تکمیلی دیگری مانند افزودن و یا اصلاح سادهتر فضاهای نام مرتبط.