مطالب
نحوه استفاده از Text template ها در دات نت - قسمت چهارم
در قسمت‌های قبلی (^ و ^ و ^) با Text Template در Visual Studio آشنا شدید. این قسمت برای تکمیل بحث در مورد ابزاری که Microsoft از آن در برنامه‌های خود از جمله Visual Studio جهت تولید کدهای اتوماتیک استفاده می‌نماید، صحبت خواهیم کرد.
قبل از آن بد نیست که بدانید چرا این ابزار T4  نام گرفته !
T4 مخفف  Text Template Transformation Toolkit می‌باشد (TTTT). شکل زیر مراحل اجرای یک کد Text Template را توسط T4 نشان میدهد: 


پس این ابراز، یک ابزار کاربردی می‌باشد که بدون Visual Studio نیز میتوان از آن استفاده کرد. نام فایل این ابزار، TextTransform.exe است و در مسیر زیر وجود دارد :

Program Files (x86)\Common Files\microsoft shared\TextTemplating\10.0
برای اطلاع از نحوه کار با TextTransform.exe خارج از محیط Visual Studio بهتر است دستور زیر را در cmd.exe اجرا کنید تا راهنمای استفاده و پارامتر‌های اختیاری آن را مشاهده نمایید:

  TextTransform.exe –h 

برای آزمایش، یک فایل متنی کنار فایل TextTransform.exe با نام Text2.tt ایجاد نمایید و کد زیر را در داخل آن بنویسید:
<#@ template debug="true" hostspecific="false" language="C#" #>
<#@ output extension=".txt"  #>

<#@ import namespace="System.Diagnostics" #>

Report In : <#= DateTime.Now #>

<#

Process[] Procs = Process.GetProcesses();
    for (int i = 0; i < Procs.Length; i++)
    {
        string Pstr = Procs[i].ProcessName + "  -|-  " + Procs[i].Id + Environment.NewLine ;
 #><#= Pstr #><#
    }

#>
 این مثال بعد از اجرا، لیست تمام Process های جاری سیستم را به همراه Id  آن‌ها، چاپ می‌نماید.
برای تولید فایل خروجی، دستور زیر را در cmd.exe اجرا کنید :
TextTransform.exe  -out  Report1.txt  Text2.tt
توجه کنید که فایل Text2.tt را کنار فایل TextTransform.exe قرار دهید و بعد از اجرای دستور بالا، باید خروجی در فایل Text2.tt در همان مسیر ایجاد گردد.

نکته: اگر User شما به این پوشه دسترسی ندارد و کاربر Admin نیستید احتمالا به مشکل بر می‌خورد. می‌توانید فایل TextTransform.exe را در مکان دیگری قرار دهید و دستور را از آن محل اجرا کنید و یا برای پوشه‌ی مذکور دسترسی ایجاد نمایید.

اگر میخواهید بیشتر در مورد معماری T4  بدانید بهتر است مقاله زیر را مطالعه کنید:  

http://www.olegsych.com/2008/05/t4-architecture/

نکته دیگر این که برای Visual Studio، ابزارهایی جهت بهبود کار با Text Template‌ها وجود دارند که با جستجوی T4 Editor، نمونه‌هایی از آنها را خواهید یافت. tangible T4 Editor نمونه ای از این Pluginها می‌باشد که به Visual Studio  افزوده می‌گردد و یا یک پروژه Open Source  هم برای آشنایی بسیار بیشتر با T4 در t4toolbox.codeplex.com وجود دارد که میتوانید مشاهده کنید.
بازخوردهای دوره
الگوی معکوس سازی کنترل چیست؟
در قسمت‌های بعدی با مثال انجام شده. مثلا در قسمت معرفی IoC Container، در مورد نحوه معکوس سازی ارسال ایمیل به لایه سرویس با مثال بحث شده. یا در قسمت نحوه یافتن وابستگی‌ها در یک پروژه موجود، نحوه معکوس سازی دریافت اطلاعات از وب به لایه‌ای دیگر بحث شده.
مطالب
Angular CLI - قسمت دوم - ایجاد یک برنامه‌ی جدید
اولین کاری را که می‌توان پس از نصب Angular CLI انجام داد، ایجاد یک برنامه‌ی جدید است و نمونه‌ای از آن‌را در قسمت قبل بررسی کردیم. در ادامه می‌خواهیم به پارامترهای بیشتر مرتبط با آن و همچنین نحوه‌ی سفارشی سازی ایجاد برنامه‌های جدید بپردازیم.


ایجاد برنامه‌های جدید توسط Angular CLI

دستور خط فرمان ابتدایی ایجاد یک برنامه‌ی جدید توسط Angular CLI به صورت ذیل است
> ng new my-app
در اینجا ng همان Angular CLI است. new عملی است که قرار است رخ دهد و my-app یک نام دلخواه می‌باشد.
پس از اجرای این دستور، برنامه‌ی جدید ایجاد شده، در پوشه‌ی جدید my-app قرار می‌گیرد.

گزینه‌ی دیگر این دستور، استفاده از پرچم dry-run است:
> ng new my-app --dry-run
کار این پرچم صرفا گزارش دادن جزئیات عملیات ng new است؛ بدون اینکه فایلی را تولید کند. به این ترتیب می‌توان برآوردی را از فایل‌های تولید شده‌ی توسط فرامین ng، پیش از تولید واقعی آن‌ها، مشاهده کرد. برای مثال:
>ng new my-app --dry-run
installing ng
You specified the dry-run flag, so no changes will be written.
  create .editorconfig
  create README.md
  create src\app\app.component.css
  create src\app\app.component.html
.
.
.
Project 'my-app' successfully created.
همانطور که مشاهده می‌کنید، در ابتدای کار پیامی را مبنی بر عدم نوشته شدن این فایل‌ها بر روی فایل سیستم، ارائه داده‌است.

گزینه‌ی دیگر دستور ng new را که در قسمت قبل ملاحظه کردید:
> ng new my-app --skip-install
کار پرچم skip-install عدم فراخوانی خودکار دستور npm install است که سبب خواهد شد، برنامه بدون نصب وابستگی‌های npm آن، با سرعت هرچه بیشتر، ایجاد شود. از این گزینه می‌توان جهت مشاهده‌ی ساختار فایل‌های تولیدی استفاده کرد و در نهایت در این حالت باید دستور npm install را به صورت دستی فراخوانی کرد. پرچم dry-run نیز skip-install را به صورت ضمنی به همراه دارد.

برای مشاهده‌ی سایر پرچم‌های مرتبط با دستور ng new می‌توان از پرچم help استفاده کرد:
> ng new --help


بررسی فایل angular-cli.json.

فایل angular-cli.json‌. حاوی تنظیمات Angular CLI است.
در ابتدای این فایل، نام برنامه‌ی جدید را مشاهده می‌کنید. این نام، همانی است که توسط دستور ng new my-app تعیین گردید.
"project": {
      "name": "my-app"
  },
سپس محل پوشه‌ی source برنامه و همچنین خروجی نهایی آن، مشخص می‌شوند:
"apps": [
{
   "root": "src",
   "outDir": "dist",

یکی از تنظیمات مهم این فایل، مقدار prefix است:
"prefix": "app",
از این مقدار برای تنظیم مقدار prefix تمام کامپوننت‌ها و دایرکتیوهای تولیدی توسط Angular CLI استفاده می‌شود. برای مثال اگر به فایل src\app\app.component.ts دقت کنید:
@Component({
  selector: 'app-root',
نام selector آن با app- شروع شده‌است که این app، از مقدار prefix فایل angular-cli.json‌. دریافت شده‌است.
تغییر این مقدار صرفا بر روی کامپوننت‌های جدید تولید شده‌ی توسط Angular CLI تاثیرگذار خواهند بود. اگر می‌خواهید در ابتدای کار تولید یک برنامه، این مقدار را مشخص کنید، می‌توان از پرچم prefix استفاده کرد و در صورت عدم ذکر آن، مقدار پیش فرض app برای آن درنظر گرفته می‌شود:
> ng new my-project --skip-install --prefix myCompany


عدم ایجاد مخزن Git به همراه ng new

با صدور فرمان ng new، کار ایجاد یک مخزن Git نیز به صورت خودکار انجام خواهد شد. برای نمونه اگر خواستید برنامه‌ای را بدون نصب وابستگی‌ها، بدون ایجاد تست‌ها و بدون ایجاد مخزن git آن تولید کنید، می‌توان از دستور ذیل استفاده کرد:
> ng new my-project --skip-install --skip-git --skip-tests --skip-commit


استفاده‌ی از sass بجای css توسط Angular CLI

سیستم Build همراه با Angular CLI مبتنی بر webpack است و به خوبی قابلیت پردازش فایل‌های sass را نیز دارا است. اگر خواستید حالت پیش فرض تولید فایل‌های css این ابزار را که در فایل angular-cli.json‌. نمونه‌ای از آن ذکر شده‌است، به همراه فایل‌هایی مانند app.component.css، به sass تغییر دهید:
"styles": [
     "styles.css"
],

"defaults": {
   "styleExt": "css",
   "component": {}
  }
تنها کافی است پرچم style را با sass مقدار دهی کرد که حالت پیش فرض آن css است:
> ng new my-project --skip-install --style sass
با ذکر این پرچم، تغییرات فایل angular-cli.json‌  به صورت ذیل خواهند بود:
"styles": [
    "styles.sass"
],
"defaults": {
   "styleExt": "sass",
   "component": {}
}
و حتی کامپوننت src\app\app.component.ts نیز به همراه شیوه‌نامه‌ای از نوع sass که در حین ارائه نهایی توسط webpack به صورت خودکار پردازش می‌شود (بدون نیاز به تنظیمات اضافه‌تری)، مقدار دهی شده‌است:
@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.sass']
})
و یا حتی اگر علاقمند به استفاده‌ی از less باشید نیز می‌توان پرچم style less-- را استفاده نمود.


انجام تنظیمات مسیریابی پیش فرض پروژه جدید توسط Angular CLI

حالت پیش فرض تولید برنامه‌های جدید Angular CLI به همراه تنظیمات مسیریابی آن نیست. اگر علاقمند هستید تا مبحث مسیریابی را خلاصه کرده و به سرعت تنظیمات ابتدایی مسیریابی را توسط این ابزار تولید کنید، می‌توان پرچم routing را نیز در اینجا ذکر کرد:
> ng new my-project --skip-install --routing
در این حالت اگر به پوشه‌ی src\app مراجعه کنید، فایل جدید app-routing.module.ts را نیز مشاهده خواهید کرد که AppRoutingModule پیش فرضی در آن تنظیم شده‌است و آماده‌ی استفاده می‌باشد.
const routes: Routes = [
  {
     path: '',
     children: []
  }
];
همچنین فایل app.module.ts را نیز اندکی تغییر داده و این AppRoutingModule جدید را نیز به آن معرفی کرده‌است.
imports: [
   BrowserModule,
   FormsModule,
   HttpModule,
   AppRoutingModule
],
به این ترتیب ارتباطات ابتدایی مورد نیاز سیستم مسیریابی برقرار شده و قابل استفاده‌است. بنابراین ذکر پرچم routing می‌تواند یکی از پرچم‌های اصلی ایجاد برنامه‌های جدید مبتنی بر Angular CLI باشد.


اجرای ابتدایی یک برنامه‌ی مبتنی بر Angular CLI

پس از انتخاب پرچم‌های مناسب جهت ایجاد یک پروژه‌ی جدید مبتنی بر Angular CLI و همچنین نصب وابستگی‌های آن‌ها و یا عدم ذکر پرچم skip-install، اکنون نوبت به اجرای این پروژه‌است. به همین جهت از طریق خط فرمان به ریشه‌ی پوشه‌ی برنامه‌ی جدید ایجاد شده، وارد شوید. سپس دستور ذیل را صادر کنید:
>ng serve -o
در اینجا o- به معنای open است؛ یا گشودن آن در یک مرورگر. به این ترتیب کار کامپایل برنامه صورت گرفته و توسط مرورگر پیش‌فرض سیستم به صورت خودکار باز خواهد شد. آدرس پیش فرض آن نیز به صورت ذیل است:
 http://localhost:4200/


نکته‌ی جالب این وب سرور در این است که تغییرات شما را به صورت خودکار دنبال کرده و بلافاصله ارائه می‌دهد. برای مثال فایل src\app\app.component.html را گشوده و به صورت ذیل تغییر دهید:
 <h1>
Test
  {{title}}
</h1>
پس از ذخیره‌ی آن، بلافاصله خروجی نهایی را در مرورگر خواهید دید.


تغییر پیش فرض‌های عمومی Angular CLI

تا اینجا مشاهده کردیم که اگر بخواهیم مقدار prefix پیش فرض را که به app تنظیم شده‌است به myCompany تغییر دهیم، یا می‌توان از پرچم prefix در ابتدای کار فراخوانی دستور ng new استفاده کرد و یا می‌توان فایل angular-cli.json. را نیز دستی ویرایش نمود. برای تغییر عمومی و سراسری مقدار پیش فرض app می‌توان از دستور ng set استفاده کرد:
>ng set apps.prefix myCompany
>ng set apps.prefix myCompany -g
دستور اول فایل angular-cli.json. پروژه‌ی جاری را ویرایش می‌کند و دستور دوم، فایل angular-cli.json سراسری Angular CLI را مقدار دهی خواهد کرد (با توجه به سوئیچ g- آن). البته بدیهی است ویرایشگرهای امروزی به خوبی قابلیت ویرایش فایل‌های json را ارائه می‌دهند و شاید نیازی به استفاده‌ی از این دستورات،‌حداقل برای اعمال تغییرات محلی نباشد.
و یا اگر بخواهید نوع شیوه‌نامه‌ی مورد استفاده را ویرایش کنید، می‌توان از یکی از دو دستور ذیل استفاده کرد (اولی محلی است و دومی عمومی):
>ng set defaults.styleExt sass
>ng set defaults.styleExt sass -g


اجرای امکانات Linting پروژه‌های مبتنی بر Angular CLI

برای بررسی کیفیت کدهای نوشته شده، می‌توان از امکانات Linting استفاده کرد. برای این منظور تنها کافی است دستور ذیل را در ریشه‌ی پروژه اجرا نمود:
> ng lint
برای مشاهده‌ی تمام گزینه‌های آن دستور زیر را صادر کنید:
> ng lint --help
اگر علاقمند هستید تا خروجی این ابزار، با رنگ‌های بهتری نمایش داده شوند، می‌توان از دستور ذیل استفاده کرد:
> ng lint --format stylish
به علاوه این ابزار قابلیت رفع مشکلات را با اعمال تغییراتی در کدهای موجود نیز به همراه دارد:
>ng lint --fix
برای این منظور می‌توان از پرچم fix آن استفاده کرد.

یک مثال: فایل src\app\app.component.ts‌  را باز کنید و به عمد تعدادی مشکل را در آن ایجاد نمائید. برای نمونه دو سطر ابتدایی آن‌را به صورت ذیل تغییر دهید:
import { Component } from '@angular/core'
let number = 10;
اکنون اگر ng lint را اجرا کنیم، به خروجی ذیل خواهیم رسید:
>ng lint --format stylish

/src/app/app.component.ts[3, 5]: Identifier 'number' is never reassigned; use 'const' instead of 'let'.
/src/app/app.component.ts[1, 42]: Missing semicolon

Lint errors found in the listed files.
عنوان می‌کند که بهتر است number به صورت یک const تعریف شود و همچنین یک سمی‌کالن در سطر اول فراموش شده‌است.
اکنون اگر دستور ng lint --fix را فراخوانی کنیم، تغییرات ذیل به فایل src\app\app.component.ts اعمال خواهند شد:
import { Component } from '@angular/core';
const number = 10;
به صورت خودکار، به سطر اول، یک سمی‌کالن را اضافه کرده و همچنین سطر دوم را نیز به const تبدیل کرده‌است.
مطالب
کاربرد Action ها در Github - خودکار سازی فرآیند کامپایل و آپلود فایل در Release گیت‌هاب
نکته: این آموزش مبتنی بر دات نت نسخه 5 می‌باشد (قابل استفاده در نسخه 3.0 و 3.1 نیز می‌باشد اما تست نشده است). در این آموزش فرض شده‌است که شما توانایی کار کردن با git و گیت‌هاب را دارید. همچنین دقت کنید که گزینه‌های زیر در فایل csproj شما موجود باشد، در غیر این صورت ممکن است با خطا مواجه شوید:
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<PublishSingleFile>true</PublishSingleFile>

چند وقتی می‌شود که گیت‌هاب اکشن‌ها را معرفی کرده که با استفاده از این اکشن‌ها میتوان برخی فعالیت‌های تکراری را، خودکار سازی کرد و در وقت و انرژی صرفه جویی کرد. ما چه کارهایی را میتوانیم با کمک اکشن‌ها انجام بدهیم؟ تقریبا میشود گفت هرکاری را میتوان با اکشن‌ها انجام داد. کامپایل کردن پروژه، تست کردن، پابلیش کردن و...
من معمولا فایل‌های خروجی که برای پروژه‌هایم میگیرم، بدلیل استفاده از ویژگی SelfContained و ایمیج‌های ReadyToRun برای اجرای سریعتر، معمولا حجمی حدود 140 مگ دارند. حالا وقتی آنها را فشرده میکنم، به حدود 50 مگ کاهش پیدا میکنند که اگر من بخواهم هر دفعه که از برنامه خروجی میگیرم، فایل خروجی را فشرده کنم و آن را در گیت‌هاب آپلود کنم، هم فرآیندی زمانبر هست و هم اینکه تکراری و خسته کننده؛ در نتیجه تصمیم گرفتم که از اکشن گیت‌هاب برای خودکارسازی این فرآیند استفاده کنم. 
در این نوشته میخواهیم یک اکشن بنویسیم که بر اساس سورس کد موجود بر روی گیت‌هاب، برنامه را کامپایل کند، فایل اجرایی را بصورت فایل فشرده Zip ایجاد کرده و در نهایت این فایل فشرده را در قسمت Release گیت‌هاب منتشر کند.
برای شروع کار اول باید در مخزن پروژه، در سایت گیت‌هاب، به قسمت Action برویم:

حالا روی قسمت New workflow کلیک میکنیم
 
شما میتونید از قالب‌های پیش‌فرض موجود، هر کدام را که خواستید انتخاب کنید. من ترجیح میدهم با یک قالب خالی شروع کنم. پس بر روی set up a workflow yourself کلیک میکنیم:
 
کدهای پیش‌فرضی که وجود دارند را پاک کنید، تا مثل تصویر زیر، یک فایل کاملا تمیز و خالی را داشته باشیم. نکته‌ای که باید دقت کنید، اسم و مسیر فایل می‌باشد. مسیر فایل را اصلا نباید تغییر داد، ولی اسم فایل را میتوانید اصلاح کنید؛ ولی توجه کنید که پسوند فایل باید yml باشد.
حالا نوبت نوشتن کدهای اکشن رسیده:
اول از همه کد زیر را مینویسیم:
name: "Publish"

این خط، اسم اکشن مارا مشخص میکند که قرار است در لیست workflow‌ها نمایش داده شود:
در کد بعدی که باید بنویسیم (در خط بعدی) باید مشخص بکنیم که این اکشن چه زمانی اجرا بشود. گزینه‌های زیر استفاده بیشتری دارند:
  • push = هر زمان که کامیتی روی گیتهاب پوش شود، اکشن اجرا میشود.
  • pull_request = هر زمانی که یک پول ریکوئست مرج شود، اکشن اجرا میشود.
  • workflow_dispatch = برنامه نویس خودش میتواند با کلیک بر روی دکمه‌ی مشخصی در قسمت اکشن‌ها، اکشن موردنظر را اجرا کند.
لیست کامل تریگر‌ها را میتوانید اینجا مطالعه کنید.
ما از push استفاده میکنیم؛ البته مقداری آن را تغییر میدهیم تا زمانیکه شامل تگ بود، اکشن اجرا شود.
on:
  push:
    tags:
      - "v*"
نکته‌ای که وجود دارد، ما در آخر این دستور، از *v استفاده کردیم که اشاره میکند اگر تگی بصورت v1.0.0 بود، اجرا بشود. * میتواند هر عددی باشد.
3 متغیر ایجاد میکنیم تا محل فایل پروژه، اجرایی و فشرده را نگه دارد، تا فایل اکشن زیاد شلوغ نباشد. 
env:
  PROJECT_PATH: src/HandySub/HandySub.csproj
  ZIP_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub-x86.zip
  EXE_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub.exe
حالا باید دستورات خودکار سازی را بنویسیم. همه دستورات باید در قسمت jobs نوشته شوند:
 jobs:
  deploy:
    runs-on: windows-latest
به قسمت runs-on توجه کنید. این گزینه مشخص میکند که اکشن ما بر روی سرور ویندوزی و آخرین نسخه‌ی از آن اجرا بشود؛ در صورت نیاز میتوانید از linux نیز استفاده کنید.
در خط بعدی باید قدم به قدم دستورات را بنویسیم. ما برای هر قدم، از name استفاده میکنیم که هنگام اجرای اکشن، بصورت مرتب و خوانا بتوانیم بفهمیم که در چه مرحله‌ای از اجرا هستیم.
قدم اول باید اکشن را آماده کنیم. اکثر دستورات مهم در این اکشن موجود است:
 steps:
      - name: Initialize Actions
        uses: actions/checkout@v2
قدم بعدی باید sdk دات نت را بر روی سرور، دانلود و نصب کنیم:
     - name: Initialize .Net
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 5.0.x
قبل از بیلد پروژه، باید کتابخانه‌ها و بسته‌های نیوگت را restore کنیم، تا بیلد، خطا نداشته باشد:
  - name: Restore Project
        run: dotnet restore ${{ env.PROJECT_PATH }}
حالا میتوانیم دستور خروجی گرفتن را بنویسیم (حتما باید در فایل csproj پروژه خود، runtimeidentifier  پروژه مشخص باشد که اینجا ما از win-x86 استفاده کردیم؛ در غیر اینصورت خطا میگیرید)  چون در مرحله قبل پروژه را restore کردیم، هنگام خروجی گرفتن، دستور no-restore را مینویسیم تا دوباره بسته‌های نیوگت ری‌استور نشود.
 - name: Publish Project
        run: dotnet publish ${{ env.PROJECT_PATH }} -c Release --self-contained -r win-x86 --no-restore
حالا که فایل اجرایی را ایجاد کردیم، باید آن را بصورت فشرده و zip در بیاوریم. برای اینکار از یک اکشن دیگر کمک میگیریم. اول آن را به اصطلاح using میکنیم؛ سپس از آن استفاده میکنیم. این اکشن 2 ورودی دارد: files و dest که به ترتیب باید آدرس فایل‌ها و محل ذخیره زیپ را به آن بدهیم که ما از متغیرهایی که قبلا ایجاد کرده‌ایم، استفاده میکنیم. 
 - name: Create Zip File
        uses: papeloto/action-zip@v1
        with:
          files: ${{ env.EXE_PATH }}
          dest: ${{ env.ZIP_PATH }}
در مرحله بعدی باید از یک اکشن دیگر برای ساخت Release در قسمت گیت‌هاب کمک بگیریم. دقت کنید که برای آپلود کردن فایل زیپ داخل این Release، ما باید توکن و id این ریلیز را ذخیره کنیم که در اینجا در متغیر GITHUB_TOKEN و id ذخیره میکنیم. توکن را میتوانیم از قسمت secrets خود گیت‌هاب دریافت کنیم. همچنین ما اسم تگ را از طریق github.ref دریافت میکنیم (که مقدار v1.0.0 را به عنوان مثال برای ما برگشت خواهد داد (شماره نسخه همان تگی است که پوش کرده‌ایم) 
 - name: Initialize Release
        uses: actions/create-release@v1
        id: create_release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}
حالا نوبت این است که فایل زیپ را آپلود کنیم. دوباره باید از اکشن دیگری برای این امر کمک بگیریم. توکنی را که قبلا ذخیره کردیم، همراه با فایل زیپ، به این اکشن میدهیم و در پایان به کمک id که قبلا ذخیره کردیم، لینک فایل آپلود شده را از آن دریافت میکنیم.  
 - name: Create Release 
        uses: csexton/release-asset-action@v2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          file: ${{ env.ZIP_PATH }}
          release-url: ${{ steps.create_release.outputs.upload_url }}
کد کامل را اینجا ببینید: 
name: "Publish"

on:
  push:
    tags:
      - "v*"

env:
  PROJECT_PATH: src/HandySub/HandySub.csproj
  ZIP_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub-x86.zip
  EXE_PATH: src/HandySub/bin/Release/net5.0-windows/win-x86/publish/HandySub.exe
  

jobs:
  deploy:
    runs-on: windows-latest
    steps:
      - name: Initialize Actions
        uses: actions/checkout@v2

      - name: Initialize .Net
        uses: actions/setup-dotnet@v1
        with:
          dotnet-version: 5.0.x
      
      - name: Restore Project
        run: dotnet restore ${{ env.PROJECT_PATH }}

      - name: Publish Project
        run: dotnet publish ${{ env.PROJECT_PATH }} -c Release --self-contained -r win-x86 --no-restore

      - name: Create Zip File
        uses: papeloto/action-zip@v1
        with:
          files: ${{ env.EXE_PATH }}
          dest: ${{ env.ZIP_PATH }}
          
      - name: Initialize Release
        uses: actions/create-release@v1
        id: create_release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: ${{ github.ref }}
      
      - name: Create Release    
        uses: csexton/release-asset-action@v2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          file: ${{ env.ZIP_PATH }}
          release-url: ${{ steps.create_release.outputs.upload_url }}

در آخر بر روی دکمه سبز رنگ بالا سمت راست start commit کلیک کنید تا تغییرات ثبت شوند.
به پروژه خود برگردید و ترمینال را باز کنید و یک تگ جدید را ایجاد کنید. 
git tag v1.0.0
سپس تگ ایجاد شده را به مخزن گیت‌هاب پوش کنید:
git push origin tag v1.0.0

 به مخزن گیت‌هاب مراجعه کنید تا ببینید که اکشن شما بصورت خودکار اجرا شده و در پایان، یک ریلیز برای شما ایجاد میکند.
 در قسمت ریلیز میتوانید ببینید که ریلیز توسط ربات گیت‌هاب ایجاد شده‌است:
نظرات مطالب
EF Code First #12
قبلاً در این باره در سایت بحث شده (+) به جای آن باید به این صورت استفاده شود:
var container = new Container(x => {
// تنظیمات در اینجا
});
در کل باید پیاده سازی آن را به صورت زیر تغییر دهید:
public static class ObjectFactory
    {
        private static readonly Lazy<Container> _containerBuilder =
            new Lazy<Container>(defaultContainer, LazyThreadSafetyMode.ExecutionAndPublication);
 
        public static IContainer Container
        {
            get { return _containerBuilder.Value; }
        }
 
        private static Container defaultContainer()
        {
            return new Container(x =>
            {
                // تنظیمات در اینجا
            });
        }
    }

مطالب
ASP.NET MVC #23

اجرای برنامه‌های ASP.NET MVC توسط نگارش‌های متفاوت IIS

تا اینجا برای اجرای برنامه‌های ASP.NET MVC از وب سرور توکار VS.NET استفاده شد که صرفا جهت آزمایش برنامه‌ها طراحی شده است. تا این تاریخ سه رده از وب سرورهای مایکروسافت ارائه شده‌اند که برای نصب ASP.NET MVC می‌توانند مورد استفاده قرار گیرند و هر کدام هم نکته‌های خاص خودشان را دارند که در ادامه به بررسی آن‌ها خواهیم پرداخت.


اجرای برنامه‌های ASP.NET MVC بر روی IIS 5.x ویندوز XP

پس از ایجاد یک دایرکتوری مجازی بر روی پوشه یک برنامه ASP.NET MVC و سعی در اجرای برنامه، بلافاصله پیغام خطای HTTP 403 forbidden مشاهده می‌شود.
اولین کاری که برای رفع این مساله باید صورت گیرد، کلیک راست بر روی نام دایرکتوری مجازی در کنسول IIS، انتخاب گزینه خواص و سپس مراجعه به برگه «ASP.NET» آن است. در اینجا شماره نگارش دات نت فریم ورک مورد استفاده را به 4 تغییر دهید (برای نمونه ASP.NET MVC 3.0 مبتنی بر دات نت فریم ورک 4 است).
بعد از این تغییر، بازهم موفق به اجرای برنامه‌های ASP.NET MVC بر روی IIS 5.x نخواهیم شد؛ چون در آن زمان مفاهیم مسیریابی و Routing که اصل و پایه ASP.NET MVC هستند وجود خارجی نداشتند. این نگارش از IIS به صورت پیش فرض تنها قادر به پردازش درخواست‌های رسیده‌ای که به یک فایل فیزیکی بر روی سرور اشاره می‌کند، می‌باشد (یعنی مشکلی با اجرای برنامه‌های ASP.NET Web forms ندارد).
برای رفع این مشکل، مجددا بر روی نام دایرکتوری مجازی برنامه در کنسول IIS کلیک راست کرده و گزینه خواص را انتخاب کنید. در صفحه ظاهر شده، در برگه «Virtual directory» آن، بر روی دکمه «Configuration» کلیک نمائید. در صفحه باز شده مجددا بر روی دکمه «Add» کلیک کنید.
در صفحه باز شده، مسیر Executable را C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll وارد کرده و Extension را به .* (دات هرچی) تنظیم کنید. همین مقدار تنظیم، برای اجرای برنامه‌های ASP.NET MVC بر روی IIS 5.x ویندوز XP کفایت می‌کند.

کاری که در اینجا انجام شده است، نگاشت تمام درخواست‌های رسیده صرفنظر از پسوند فایل‌ها، به موتور ASP.NET می‌باشد. به صورت پیش فرض در IIS 5.x درخواست‌ها تنها بر اساس پسوند فایل‌ها پردازش می‌شوند. مثلا اگر فایل درخواستی aspx است، درخواست رسیده به aspnet_isapi.dll یاد شده هدایت خواهد شد. اگر پسوند فایل php است به isapi مخصوص آن (در صورت نصب) هدایت می‌گردد و به همین ترتیب برای سایر سیستم‌های دیگر. زمانیکه Extension به «دات هرچی» و Executable به aspnet_isapi.dll دات نت 4 تنظیم می‌شود، دایرکتوری مجازی تنظیم شده تنها جهت سرویس دهی به یک برنامه ASP.NET عمل خواهد کرد و تمام درخواست‌های رسیده به آن، به موتور اجرایی ASP.NET هدایت می‌شوند.

بدیهی است تنظیمات فوق تنها به یک دایرکتوری مجازی اعمال شدند. اگر نیاز باشد تا بر روی تمام سایت‌ها تاثیر گذار شود، اینبار در کنسول IIS 5.x بر روی «Default web site» کلیک راست کرده و گزینه خواص را انتخاب کنید. در صفحه باز شده به برگه «Home directory» مراجعه کرده و مراحل ذکر شده را تکرار کنید.

مشکل! این روش بهینه نیست.
روش فوق خوبه، کار می‌کنه، اما بهینه نیست؛ از این جهت که «نگاشت تمام درخواست‌ها به موتور ASP.NET» یعنی پروسه پردازش درخواست یک فایل تصویری، js یا css هم باید از فیلتر موتور ASP.NET عبور کند که ضروری نیست.
برای رفع این مشکل، توصیه شده است که سیستم مسیریابی ASP.NET MVC را در IIS 5.x «پسوند دار» کنید. به این نحو که با مراجعه به فایل Global.asax.cs، تعاریف مسیریابی را به نحو زیر ویرایش کنید:

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(
new Route("{controller}.aspx/{action}/{id}", new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
})
});



اینبار برای مثال مسیر http://localhost/MyMvcApp/home.aspx/index به علت داشتن پسوند aspx وارد موتور پردازشی ASP.NET خواهد شد. البته در این حالت URL های تمیز ASP.NET MVC را از دست خواهیم داد و مدام باید دقت داشت که مسیرهای کنترلرها حتما باید به aspx ختم شوند. ضمنا با این تنظیم، دیگر نیازی به تغییر تعاریف نگاشت‌ها در کنسول مدیریتی IIS، نخواهد بود.


اجرای برنامه‌های ASP.NET MVC بر روی IIS 6.x ویندوز سرور 2003

تمام نکات عنوان شده جهت IIS 5.x در IIS 6.x نیز صادق هستند. به علاوه برای اجرای برنامه‌های ASP.NET بر روی IIS 6.x باید به دو نکته مهم دیگر نیز دقت داشت:
الف) ASP.NET 4 به صورت پیش فرض در IIS 6.x غیرفعال است که باید با مراجعه به قسمت Web Services Extensions در کنسول مدیریتی IIS، آن‌را از حالت prohibited خارج کرد.
ب) در هر Application pool تنها از یک نگارش دات نت فریم ورک می‌توان استفاده کرد. برای مثال اگر هم اکنون AppPool1 مشغول سرویس دهی به یک سایت ASP.NET 3.5 است، از آن نمی‌توانید جهت اجرای برنامه‌های ASP.NET MVC 3 به بعد استفاده کنید. زیرا برای مثال ASP.NET MVC 3 مبتنی بر دات نت فریم ورک 4 است. به همین جهت حتما نیاز است تا یک Application pool مجزا را برای برنامه‌های دات نت 4 در IIS 6 اضافه نمائید و سپس در تنظیمات سایت، از این Application pool جدید استفاده نمائید.
البته روش صحیح و اصولی کار با IIS از نگارش 6 به بعد هم مطابق شرحی است که عنوان شد. برای دستیابی به بهترین کارآیی و امنیت بیشتر، بهتر است به ازای هر سایت، از یک Application pool مجزا استفاده نمائید.

اطلاعات تکمیلی:
نکات نصب برنامه‌های ASP.NET 4.0 بر روی IIS 6
مروری بر تاریخچه محدودیت حافظه مصرفی برنامه‌های ASP.NET در IIS



اجرای برنامه‌های ASP.NET MVC بر روی IIS 7.x ویندوز 7 و ویندوز سرور 2008

اگر برنامه ASP.NET MVC در IIS 7.x در حالت یکپارچه (integrated mode) اجرا شود، بدون نیاز به هیچگونه تغییری در تنظیمات سرور یا برنامه، بدون مشکل قابل اجرا خواهد بود. بدیهی است در اینجا نیز بهتر است به ازای هر برنامه، یک Application pool مجزا را ایجاد کرد.
اما در حالت classic (که برای برنامه‌های جدید توصیه نمی‌شود) نیاز است همان مراحل IIS 5,x تکرار شود. البته اینبار مسیر زیر را باید طی کرد تا به صفحه افزودن نگاشت‌ها رسید:
Right-click on a web site -> Properties -> Home Directory tab -> click on the Configuration button -> Mappings tab



نکته‌ای مهم در تمام نگارش‌های IIS

ترتیب نصب دات نت فریم ورک 4 و IIS مهم است. اگر ابتدا IIS نصب شود و سپس دات نت فریم ورک 4، به صورت خودکار، کار نگاشت اطلاعات ASP.NET به IIS صورت خواهد گرفت.
اگر ابتدا دات نت فریم ورک 4 نصب شود و سپس IIS، برای مثال دیگر از برگه ASP.NET در IIS 6.x خبری نخواهد بود. برای رفع این مشکل دستور زیر را در خط فرمان اجرا کنید:

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe /i

به این ترتیب، اطلاعات مرتبط با موتور ASP.NET مجددا به تنظیمات IIS اضافه خواهند شد.


مطالب
PowerShell 7.x - قسمت نهم - آشنایی با Crescendo
همانطور که در ابتدای این سری نیز اشاره شد، یکی از ویژگی‌های منحصربه‌فرد PowerShell، طراحی شیءگرای آن است، به‌طوریکه خروجی cmdletهای آن، به صورت آبجکت هستند. همچنین، در PowerShell امکان اجرای کامندهای native نیز وجود دارد. به عنوان مثال اگر کامند زیر را وارد کنید: 
git log --oneline
خروجی، همانطوری که در دیگر shellها انتظار میرود، نمایش داده خواهد شد؛ یعنی به صورت string. همچنین امکان intellisense را نیز برای پارامترهای کامند موردنظر نخواهیم داشت؛ چون در اصل، به اصطلاح یک legacy command است و نه یک cmdlet. برای بهره بردن از امکانات PowerShell میتوانیم این نوع کامندها را توسط یک wrapper به cmdlet تبدیل کنیم، اما آپدیت نگه‌داشتن این wrapper و نوشتن آن فرآیند سختی است. برای سهولت انجام اینکار، یک فریم‌ورک تحت عنوان Crescendo توسط مایکروسافت ارائه شده است.
یک مثال
فرض کنید میخواهیم کامند git log را به همراه تعدادی از دستورات آن به یک PowerShell cmdlet تبدیل کنیم؛ برای اینکار ابتدا نیاز است ماژول عنوان شده را نصب کنیم: 
Install-Module -Name Microsoft.PowerShell.Crescendo
بعد از نصب ماژول فوق، یکسری cmdlet به مجموعه کامندهای PowerShell اضافه خواهند شد. یکی از این کامندها New-CrescendoCommand است. با کمک این کامند، فایل JSON موردنیاز Crescendo را میتوانیم تولید کنیم: 
$Configuration = @{
    '$schema' = "https://aka.ms/PowerShell/Crescendo/Schemas/2021-11"
    Commands  = @()
}
$parameters = @{
    Verb = "Get"
    Noun = "GitLog"
    OriginalName = "git"
}
$Configuration.Commands += New-CrescendoCommand @parameters

$Configuration | ConvertTo-Json -Depth 3 | Out-File ./git-ps.json
در اینجا تعیین کرده‌ایم که کامندی که میخواهیم برایمان تولید شود، چه ویژگی‌هایی باید داشته باشد. به عنوان مثال Verb آن Get و Noun آن باید GitLog باشد (براساس استانداری که مایکروسافت برای نامگذاری cmdletها پیشنهاد میدهد). در نهایت میتوانیم به صورت Get-GitLog از آن استفاده کنیم. همچنین legacy command اصلی که میخواهیم برای آن cmdlet ایجاد کنیم نیز توسط OriginalName تعیین شده‌است. لازم به ذکر است که در ویندوز باید مسیر کامل آن را وارد کنید. سپس با اجرای دستورات فوق، خروجی زیر برایمان تولید خواهد شد: 
{
  "Commands": [
    {
      "Verb": "Get",
      "Noun": "GitLog",
      "OriginalName": "git",
      "OriginalCommandElements": null,
      "Platform": [
        "Windows",
        "Linux",
        "MacOS"
      ],
      "Elevation": null,
      "Aliases": null,
      "DefaultParameterSetName": null,
      "SupportsShouldProcess": false,
      "ConfirmImpact": null,
      "SupportsTransactions": false,
      "NoInvocation": false,
      "Description": null,
      "Usage": null,
      "Parameters": [],
      "Examples": [],
      "OriginalText": null,
      "HelpLinks": null,
      "OutputHandlers": null
    }
  ],
  "$schema": "https://aka.ms/PowerShell/Crescendo/Schemas/2021-11"
}
نکته: دقت داشته باشید که schema$ باید درون single quote نوشته شود؛ چون در غیراینصورت، key آن درون فایل تولید شده، خالی خواهد بود: 
"": "https://aka.ms/PowerShell/Crescendo/Schemas/2021-11",
با کمک این schema درون Visual Studio Code امکان Intelisense را نیز خواهیم داشت: 


اکنون باید این فایل Configuration را به Crescendo معرفی کنیم تا cmdlet را برایمان تولید کند. اینکار را توسط Export-CrescendoModule انجام خواهیم داد: 

Export-CrescendoModule -Configuration ./git-ps.json -ModuleName ./git-ps.psm1

با اجرای دستور فوق، فایل‌های git.psm1 و همچنین git.psd1 تولید خواهند شد. نیاز به بررسی فایل‌های جنریت شده نیست؛ چون تنها جایی که با آن باید در ارتباط باشیم، همان فایل JSON ابتدای بحث است که در ادامه آن را بررسی خواهیم کرد. اما قبل از آن اجازه دهید ماژول تولید شده را Import کنیم و دستور Get-GitLog را وارد کنیم: 

PP /> Import-Module ./git-ps.psd1
PS /> Get-GitLog

usage: git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           [--super-prefix=<path>] [--config-env=<name>=<envvar>]
           <command> [<args>]

These are common Git commands used in various situations:

start a working area (see also: git help tutorial)
   clone     Clone a repository into a new directory
   init      Create an empty Git repository or reinitialize an existing one

work on the current change (see also: git help everyday)
   add       Add file contents to the index
   mv        Move or rename a file, a directory, or a symlink
   restore   Restore working tree files
   rm        Remove files from the working tree and from the index

examine the history and state (see also: git help revisions)
   bisect    Use binary search to find the commit that introduced a bug
   diff      Show changes between commits, commit and working tree, etc
   grep      Print lines matching a pattern
   log       Show commit logs
   show      Show various types of objects
   status    Show the working tree status

grow, mark and tweak your common history
   branch    List, create, or delete branches
   commit    Record changes to the repository
   merge     Join two or more development histories together
   rebase    Reapply commits on top of another base tip
   reset     Reset current HEAD to the specified state
   switch    Switch branches
   tag       Create, list, delete or verify a tag object signed with GPG

collaborate (see also: git help workflows)
   fetch     Download objects and refs from another repository
   pull      Fetch from and integrate with another repository or a local branch
   push      Update remote refs along with associated objects

'git help -a' and 'git help -g' list available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.
See 'git help git' for an overview of the system.

همانطور که مشاهده میکنید، خروجی دستور git، نمایش داده شده‌است. دلیل آن نیز این است که در فایل configuration، هیچ آرگومانی را به عنوان ورودی آن تعیین نکرده‌ایم. برای اضافه کردن آرگومان‌های موردنظر باید پراپرتی OrginalCommandElements را مقدار دهی کنیم: 

"OriginalCommandElements": ["log", "--oneline"],

بنابراین با فراخوانی دستور Get-GitLog، در اصل دستور git log —oneline فراخوانی خواهد شد:  

PS /> Get-GitLog

e9590e8 init

اما تا اینجا نیز خروجی به صورت رشته‌ایی است. برای داشتن یک خروجی Object، باید پراپرتی OutputHandlers را از Configuration، تغییر دهیم: 

"OutputHandlers": [
  {
    "ParameterSetName": "Default",
    "Handler": "$args[0] | ForEach-Object { $hash, $message = $_.Split(' ', 2) ; [PSCustomObject]@{ Hash = $hash; Message = $message } }"
  }
]

در اینجا توسط args$ به خروجی کامند اصلی دسترسی خواهیم داشت. این خروجی را سپس با کمک ForEach-Object، به یک شیء با پراپرتی‌های Hash و Message تبدیل کرده‌ایم. در اینجا فقط میخواستم روال تهیه یک آبجکت را از کامندهایی که خروجی JSON ندارند، نشان دهم؛ اما خوشبختانه توسط پرچم pretty در git log، امکان تهیه‌ی خروجی JSON را نیز داریم: 

git log --pretty=format:'{"commit": "%h", "author": "%an", "date": "%ad", "message": "%s"}'

در نتیجه عملاً نیازی به split کردن نیست و بجای آن میتوانیم به صورت مستقیم، خروجی را توسط ConvertFrom-Json پارز کنیم: 

"OutputHandlers": [
  {
    "ParameterSetName": "Default",
    "Handler": "$args[0] | ConvertFrom-Json"
  }
]

همچنین درون فایل schema با کمک پراپرتی Parameters، امکان تعریف پارامتر را نیز برای کامند Get-GitLog خواهیم داشت. به عنوان مثال میتوانیم فلگ reverse را نیز به کامند اصلی از طریق PowerShell ارسال کنیم: 

"Parameters": [
  {
    "Name": "reverse",
    "OriginalName": "--reverse",
    "ParameterType": "switch",
    "Description": "Reverse the order of the commits in the output."
  }
],

دقت داشته باشیم که با هربار تغییر فایل schema باید توسط دستور Export-CrescendoModule ماژول موردنظر را تولید کنید:

Export-CrescendoModule -Configuration ./git-ps.json -ModuleName ./git-ps.psm1
Import-Module ./git-ps.psd1

در نهایت cmdletمان به این صورت قابل استفاده خواهد بود:

مطالب
کامپوننت‌های متداول طرحبندی صفحات در بوت استرپ 4
بوت استرپ، به همراه کامپوننت‌هایی برای پیاده سازی اعمال متداول طرحبندی صفحات است؛ مانند jumbotron ،media ،table و card.


کامپوننت jumbotron

از Jumbotron برای نمایش متنی مشخص در بالای یک صفحه، استفاده می‌شود. دو روش استفاده‌ی از آن در بوت استرپ 4 وجود دارند:
- داخل container:
    <div class="container">
        <header class="jumbotron mt-4">
            <div class="display-2 mb-4">Our Mission</div>
            <p class="lead">Wisdom Pet Medicine strives to blend the best in
                traditional and alternative medicine in the diagnosis and
                treatment of companion animals including dogs, cats, birds,
                reptiles, rodents, and fish. We apply the wisdom garnered in
                the centuries old tradition of veterinary medicine, to find the
                safest treatments and cures.</p>
        </header>
با این خروجی:


در اینجا با اعمال کلاس jumbotron، متن header، داخل یک قاب با گوشه‌های گرد قرار می‌گیرد و مشخص‌تر نمایش داده خواهد شد. همچنین با mt-4، فاصله‌ای را بین آن و بالای صفحه ایجاد کرده‌ایم.

- خارج از container:
    <header class="jumbotron jumbotron-fluid">
        <div class="container">
            <div class="display-2 mb-4">Our Mission</div>
            <p class="lead">Wisdom Pet Medicine strives to blend the best in
                traditional and alternative medicine in the diagnosis and
                treatment of companion animals including dogs, cats, birds,
                reptiles, rodents, and fish. We apply the wisdom garnered in
                the centuries old tradition of veterinary medicine, to find the
                safest treatments and cures.</p>
        </div>
    </header>
با این خروجی:


اگر می‌خواهیم این قاب، تمام عرض صفحه را پر کند و همچمنین لبه‌های گرد آن نیز حذف شوند، می‌توان از کلاس jumbotron-fluid استفاده کرد و آن‌را خارج از container قرار داد. سپس برای اینکه متن داخل آن با container زیر آن تراز شود، می‌توان یک container را در اینجا داخل jumbotron تعریف کرد.


کنترل ظاهر جداول، در بوت استرپ 4

بوت استرپ 4 به همراه تعدادی کلاس ویژه است که برای بهبود ظاهر المان استاندارد جدول، ارائه شده‌اند. آن‌ها را در طی مثال‌هایی بررسی خواهیم کرد.


برای رسیدن به چنین تصویری، تغییرات زیر را بر روی یک جدول استاندارد HTML اعمال کرده‌ایم:
<table class="table table-striped table-hover table-bordered table-responsive">
  <thead class="thead-light">
- کلاس table، کلاس پایه اعمال شیوه‌نامه‌های بوت استرپ 4 به المان جدول است که سبب خواهد شد آیتم‌های آن با فاصله‌ی بهتری نسبت به یکدیگر ظاهر شوند. با استفاده از کلاس table-dark می‌توان یک قالب مشکی را به جدول اعمال کرد.
- کلاس table-striped سبب می‌شود تا ردیف‌ها، یک در میان با رنگی متمایز نمایش داده شوند.
- با افزودن table-hover، رنگ ردیف‌های جدول با عبور اشاره‌گر ماوس از روی آن‌ها تغییر می‌کند.
- کلاس table-bordered کار نمایش قاب جدول را انجام می‌دهد.
- کلاس table-responsive سبب می‌شود تا در اندازه‌های کوچک صفحه، یک اسکرول بار افقی برای نمایش آیتم‌های جدول ظاهر شود و یا می‌توان از کلاس table-sm نیز استفاده کرد تا padding تعریف شده‌ی در جدول، کاهش یابند. این کلاس، قابلیت پذیرش break-pointها را نیز دارد؛ مانند table-responsive-md.
- کلاس‌های thead-light و یا thead-dark که بر روی تگ thead قرار می‌گیرند، رنگ پس زمینه‌ی هدر جدول را مشخص می‌کنند.
- برای تغییر رنگ پس زمینه و متن یک ردیف می‌توان از کلاس‌های bg-color و text-color استفاده کرد:
<tr class="bg-danger text-light">
- برای تغییر رنگ سلول‌های جدول از کلاس‌های table-color استفاده می‌کنیم:
<td class="table-success">$100.00 </td>
فرمول‌های رنگ‌های قابل اعمال به ردیف‌ها، سلول‌ها و متون جداول بوت استرپ 4 را در تصویر ذیل مشاهده می‌کنید:



کامپوننت جدید card در بوت استرپ 4

پنل‌های بوت استرپ 3 حذف و بجای آن کامپوننت جدیدی به نام card در نگارش 4 آن ارائه شده‌است که با افزودن کلاس آن به یک div، بلافاصله قابی با گوشه‌های گرد به آن اضافه می‌شود.


        <section class="card mb-5" id="drwinthrop">
            <div class="card-body">
                <img class="card-img img-fluid" src="images/testimonial-mcphersons.jpg"
                    alt="Doctor Winthrop Photo">
                <h2 class="card-title">Dr. Stanley Winthrop</h2>
                <h5 class="card-subtitle">Behaviorist</h5>
                <p class="card-text">Dr. Winthrop is the guardian of Missy, a
                    three-year old Llaso mix, who he adopted at the shelter.
                    Dr. Winthrop is passionate about spay and neuter and pet
                    adoption, and works tireless hours outside the clinic,
                    performing free spay and neuter surgeries for the shelter.</p>
                <a class="card-link" href="#">About Me</a>
                <a class="card-link" href="#">My Pets</a>
                <a class="card-link" href="#">Client Slideshow</a>
            </div>
        </section>
- برای اینکه عناصر داخل card با فاصله‌ی مناسبی از لبه‌های آن قرار گیرند و همچنین شیوه‌نامه‌های قسمت‌های مختلف آن به درستی اعمال شوند، نیاز است محتوای section ای که با کلاس card مشخص شده (تعیین container)، داخل یک div با کلاس card-body قرار گیرد. در اینجا امکان تعریف card-header و card-footer نیز وجود دارد.
- سپس یک card می‌تواند دارای تصویری واکنشگرا باشد که عرض card را پوشش می‌دهد. این تصویر با کلاس card-img مشخص می‌شود.
در اینجا امکان تعریف card-img-top و card-img-bottom نیز وجود دارند. این موارد تصویر card را در بالا و یا پایین آن، بدون padding، نمایش می‌دهند. اگر می‌خواهید متنی را بر روی این تصویر نمایش دهید، از کلاس card-img-overlay استفاده کنید. در این حالت‌ها باید تصویر را خارج از card-body قرار دهید.
- عنوان و زیرعنوان یک card، توسط کلاس‌های card-title و card-subtitle تعیین می‌شوند.
- متن داخل آن‌را با کلاس card-text مشخص می‌کنیم.
- لینک‌های ذیل آن نیز توسط کلاس card-link در طی یک ردیف نمایش داده می‌شوند.

امکان تعیین رنگ پس زمینه، حاشیه و متن یک card نیز وجود دارند:
<section class="card mb-5 bg-primary text-light border-warning" id="drchase">
با این خروجی:


و فرمول کلی رنگ‌های آن نیز به صورت زیر می‌باشد:


می‌توان برای یک card، هدر و فوتر نیز تعریف کرد:
        <section class="card mb-5" id="drsanders">
            <div class="card-header">
                <h2 class="card-title">Dr. Kenneth Sanders</h2>
                <h5 class="card-subtitle">Nutritionist</h5>
            </div>
            <div class="card-body">
                <img class="card-img img-fluid" src="images/testimonial-mcphersons.jpg"
                    alt="Doctor Sanders Photo">
                <p class="card-text">Leroy walked into Dr. Sanders front door
                    when she was moving into a new house. After searching for
                    weeks for Leroy's guardians, she decided to make Leroy a
                    part of her pet family, and now has three cats.</p>
            </div>
            <div class="card-footer">
                <a class="card-link" href="#">About Me</a>
                <a class="card-link" href="#">My Pets</a>
                <a class="card-link" href="#">Client Slideshow</a>
            </div>
        </section>
در اینجا همان card قبلی را مشاهده می‌کنید که عناوین آن به card-header و لینک‌های ذیل آن به card-footer منتقل شده‌اند:


برای تعریف یک list-group در داخل یک card، به صورت زیر عمل می‌کنیم:
        <section class="card mb-5" id="drwong">
            <div class="card-body">
                <img class="card-img img-fluid" src="images/testimonial-mcphersons.jpg"
                    alt="Doctor Wong Photo">
                <h2 class="card-title">Dr. Olivia Wong</h2>
                <h5 class="card-subtitle">Preventive Care</h5>
                <p class="card-text">Dr. Wong is a cancer survivor who was
                    fortunate enough to get to spend time with a therapy dog
                    during her recovery. She became passionate about therapy
                    animals, and has started her own foundation to train and
                    provide education to patients in recovery. Now she gets her
                    own dose of daily therapy from her husky, Lilla.</p>
            </div>
            <div class="list-group list-group-flush">
                <a class="list-group-item" href="#">About Me</a>
                <a class="list-group-item" href="#">My Pets</a>
                <a class="list-group-item" href="#">
                    Client Slideshow
                </a>
            </div>
        </section>
ابتدا list-group را به خارج از card-body منتقل می‌کنیم. سپس برای حذف حاشیه‌ی آن و همچنین گوشه‌های گرد آن، جهت یکی شدن با قاب card، کلاس list-group-flush را به آن اضافه می‌کنیم:



تعیین نحوه‌ی چیدمان cards در بوت استرپ 4

اگر چندین card در یک صفحه تعریف شده‌اند، برای تعیین نحوه‌ی قرارگیری آن‌ها در کنار یکدیگر می‌توان یا از سیستم طرحبندی متداول بوت استرپ استفاده کرده و یا امکان تعریف گروهی از آن‌ها نیز وجود دارد. برای اینکار کافی است یک div با کلاس card-group را تعریف و سپس تمام cards را داخل آن قرار دهیم:
    <div class="container">
        <div class="card-group">
که سبب خواهد شد تمام cards در کنار یکدیگر بدون فاصله‌ای نمایش داده شوند. اگر بجای آن از کلاس card-deck استفاده شود، فاصله‌ای بین cards قرار می‌گیرد.


اگر از کلاس card-columns استفاده کنیم، تمام cards را به صورت خودکار در ستون‌ها و ردیف‌ها، قرار می‌دهد که بعضی از آن‌ها بلندتر و بعضی دیگر کوتاه‌تر هستند (نوعی نمایش کاشی‌کاری شده‌است):


ولی در کل اگر نیاز به کنترل بیشتری دارید، از همان روش متداول تعریف ردیف‌ها و ستون‌های سیستم طرحبندی بوت استرپ استفاده کنید.


المان media در بوت استرپ 4

برای نمایش متداول متن و تصویر که قرار است تصویر، در یک ستون و متن، در ستونی دیگر باشد، بوت استرپ 4 به همراه کلاس media است که بر اساس Flexbox بازنویسی شده‌است.
<body>
    <div class="container">
        <section class="media mb-5" id="drwinthrop">
            <img class="d-flex align-self-center img-fluid rounded mr-3" style="width:30%"
                src="images/testimonial-mcphersons.jpg" alt="Doctor Winthrop Photo">
            <div class="media-body">
                <h2>Dr. Stanley Winthrop</h2>
                <h5>Behaviorist</h5>
                <p>Dr. Winthrop is the guardian of Missy,
                    a three-year old Llaso mix, who he adopted at the
                    shelter. Dr. Winthrop is passionate about spay and neuter
                    and pet adoption, and works tireless hours outside the
                    clinic, performing free spay and neuter surgeries for the
                    shelter.</p>
        </section>
    </div>
</body>
با این خروجی:


ابتدا توسط کلاس media یک container را تعریف می‌کنیم. سپس تصویر، یک ستون و media-body ستون دیگر را تشکیل می‌دهد.
با استفاده از d-flex، المان تصویر را به یک Flexbox container تبدیل کرده و با استفاده از کلاس align-self-center، آن‌را در میانه‌ی ستون قرار می‌دهیم. همچنین در اینجا توسط mr-3، فاصله‌ی آن‌را با متن ستون کناری تنظیم کرده‌ایم.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: Bootstrap4_09.zip
نظرات مطالب
EF Code First #12
«No Default Instance» یعنی در تنظیمات اولیه IoC Container مورد استفاده، برای اینترفیس خاصی، کلاس پیاده سازی کننده‌ای را تعریف نکرده‌اید. برای مشاهده بحث مشابهی در این مورد به نظرات مطلب «تزریق خودکار وابستگی‌ها در برنامه‌های ASP.NET MVC » مراجعه کنید.
مطالب
MongoDb در سی شارپ (بخش پنجم)
یکی از رکن‌های اساسی یک دیتابیس، حفظ اطلاعات موجود بر روی سرور میباشد تا از لحاظ نگهداری و امنیت، تضمین بازگشت اطلاعات سابق وجود داشته باشد. برای پشتیبان گیری از اطلاعات، از فایل جداگانه‌ی دیگری درشاخه Bin استفاده میکنیم که MongoDump نام دارد و یک فایل دامپ را ایجاد میکند. این فایل شامل تعدادی از سوییچ‌های زیر میباشد:

 نام پارامتر
شرح کارکرد
 c- یا collection--
 میتواند پشتیبانی گیری را به یک کالکشن خاص محدود کند.
 d- یا db--
از دیتابیسی مشخص استفاده کند.
 u- یا username-
نام کاربری سرور
 p- یا password--
 کلمه عبور سرور
 dbpath--
 مسیر پوشه‌ای را که دیتاها داخل آن است، دریافت میکند و بجای ایجاد یک Instance مستقیم پشتیبانی گیری را آغاز میکند.
توجه : در این حالت پوشه به طور کامل قفل خواهد شد و سرور نباید در حالت اجرا قرار گرفته باشد.
 DirectoryPerDb--
در صورتیکه هر دیتابیسی دارای محل جداگانه‌ای برای پشتیبان گیری باشد.
 o- یا out--
محل خروجی و ذخیره پشتیبان را مشخص میکند.
 q- یا query--
پشتیبان، در قالب کوئری‌های جی‌سون خواهد بود.
 repair-- اصلاح اسناد در صورت خراب شدن دیتابیس. در این حالت باید مکان ذخیره و نام دیتابیس، با پارامترهای بالا ذکر شود.

به عنوان مثال دستور زیر از دیتابیس publisher و کالکشن Books، پشتیبان تهیه میکند و در مسیر گفته شده آن را ذخیره میکند:

D:\Program Files\MongoDB\Server\3.4\bin>mongodump --db "publisher" --collection books --out "D:\mydumps"
2017-03-04T21:23:04.615+0330    writing publisher.books to
2017-03-04T21:23:04.637+0330    done dumping publisher.books (7 documents)
در این حالت اگر تنها دستور را بدون هیچ  پارامتری صادر کنید:
D:\Program Files\MongoDB\Server\3.4\bin>mongodump
نتیجه پشتیبان گیری از همه دیتابیس‌ها و همه قسمت‌ها به انضمام فایل‌ها در شاخه‌ای به اسم dump در پوشه Bin صورت میگیرد.

برای بازگردانی از دستوری به نام Mongorestore استفاده می‌شود که در شاخه Bin قرار گرفته است و تعدادی از پارامترهای آن به شرح زیر میباشد:

 پارامتر شرح کارکرد
 c- یا collection--
 میتواند پشتیبانی گیری را به یک کالکشن خاص محدود کند.
 d- یا db--
از دیتابیسی مشخصی استفاده کند.  
 u- یا username-
نام کاربری سرور
 p- یا password--
 کلمه عبور سرور 
 port--
شماره پورت سرور
 host-- هاست مونگو ، ترکیب hostname:port میتواند استفاده از سوییچ  port را بی نیاز کند.
 ipv6-- فعال سازی  IPV6
 dbpath--
 مسیر پوشه‌ای را که دیتاها داخل آن است، دریافت میکند و بجای ایجاد یک Instance مستقیم پشتیبانی گیری را آغاز میکند.
توجه : در این حالت پوشه به طور کامل قفل خواهد شد و سرور نباید در حالت اجرا قرار گرفته باشد. 
 DirectoryPerDb--
در صورتی که هر دیتابیسی دارای محل جداگانه‌ای برای پشتیبان گیری باشد.  
keepIndexVersion --
موقع بازگردانی، ایندکس‌ها را با نسخه جدید به روزرسانی نمی‌کند.

مثال زیر کل پشتیبان‌های مسیر مربوطه را بازگردانی میکند:
mongorestore "D:\mydumps"
یا دستور زیر تنها کالکشن خاصی را از یک دیتابیس خاص به روزرسانی میکند:
mongorestore "D:\mydumps\publisher\books.bson" --db publisher -c books
یا دستور زیر کل اطلاعاتی را که mongodb بدون پارامتر، پشتیبان گرفته است، از همان مسیر بازگردانی میکند:
mongorestore