مطالب
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 تبدیل کرده‌است.
نظرات اشتراک‌ها
فهرست کامل شهرهای ایران به تفکیک استان

صرف استفاده از محصولات سورس باز، به معنای کار یا روحیه‌ی سورس باز نیست (خصوصا اینکه بخوان اطلاعات رو با ایمیل دریافت کنند). کار سورس باز خوب در این زمینه مثلا تقسیمات کشوری ایران با فرمت JSON و XML هست (مخزن کدی داره، یک issue tracker داره، میشه براش pull request ارسال کرد).

DNTPersianUtils.Core هم این اطلاعات را به همراه دارد.
مطالب
تحلیل و بررسی ده روش آسیب پذیری نرم افزار بر اساس متدولوژی OWASP - قسمت اول SQL Injection
در این سری از مقالات، ده روش برتر آسیب پذیری نرم افزار بر اساس متدولوژی OWASP مورد بررسی قرار میگیرد. یادگیری این روش‌ها منحصر به زبان برنامه نویسی خاصی نیست و رعایت این نکات برای برنامه نویسانی که قصد نوشتن کدی امن دارند، توصیه میشود. کلمه‌ی OWASP مخفف عبارت Open Web Application Security Protocol Project می‌باشد. در واقع OWASP یک متدولوژی و پروژه‌ی متن باز است که معیارهایی را برای ایمن سازی نرم افزار مورد بررسی قرار میدهد.



آسیب پذیری SQL Injection یا به اختصار SQLi

تزریق SQL، یکی از قدیمی ترین، شایع‌ترین و مخرب‌ترین آسیب پذیری‌ها، برای برنامه‌ها می‌باشد و در صورت برقراری شرایط مناسب جهت حمله و با اعمال نفوذ، از طریق تزریق SQL ، مهاجم میتواند با دور زدن فرآیندهای اعتبارسنجی و احراز هویت یک برنامه، به تمامی محتوای پایگاه داده‌ی آن و گاها کنترل سرور، دسترسی پیدا کند. این حمله برای افزودن، ویرایش و حذف رکوردهای یک پایگاه داده مبتنی بر SQL انجام میشود.


عملکرد SQL Injection

برای اجرای SQLهای مخرب در برنامه‌هایی که از پایگاه‌های داده‌ی مبتنی بر SQL مانند (SQL Server ،MySQL ،PostgreSQL ،Oracle و ...) استفاده میکنند، هکر یا مهاجم در اولین گام باید به دنبال ورودی‌هایی در برنامه باشد که درون یک درخواست SQL قرار گرفته باشند (مانند صفحات لاگین، ثبت نام، جستجو و ...).

کد زیر را در نظر بگیرید:

# Define POST variables
uname = request.POST['username']
passwd = request.POST['password']

# SQL query vulnerable to SQLi
sql = "SELECT id FROM users WHERE username='" + uname + "' AND password='" + passwd + "'"

# Execute the SQL statement
database.execute(sql)
در این کد، موارد امنیتی برای جلوگیری از تزریق SQL تعبیه نشده‌است و هکر با اندکی دستکاری پارامترهای ارسالی میتواند نتایج دلخواهی را برای نفوذ، بدست بیاورد. قسمتی از کد که دستور SQL را اجرا میکند و پارامترهای ورودی از کاربر را در خود جای میدهد، بصورت نا امنی کدنویسی شده‌است.

اکنون ورودی password را برای نفوذ، تست میکنیم. مهاجم بدون داشتن نام کاربری، قصد دور زدن احراز هویت را دارد. بجای password عبارت زیر را قرار میدهد:

password' OR 1=1  

در نهایت در بانک اطلاعاتی دستور زیر اجرا میشود:

 SELECT id FROM users WHERE username='username' AND password=  'password' OR 1=1'

میدانیم که 1=1 است. پس بدون در نظر گرفتن اینکه شما برای username و password چه چیزی را وارد نمودید، عبارت درست در نظر گرفته میشود:

شرط اول   and   شرط دوم =
نتیجه  or 1=1
چون 1=1 است 
همیشه شرط کوئری درست خواهد بود


معمولا در بانک اطلاعاتی، اولین کاربری که وارد میکنند Administrator برنامه می‌باشد. پس به احتمال قوی شما میتوانید با مجوز ادمین به برنامه وارد شوید. البته میتوان با دانستن تنها نام کاربری هم به‌راحتی با گذاشتن در قسمت username بدون دانستن password، به برنامه وارد شد؛ زیرا میتوان شرط چک کردن password را کامنت نمود:

-- MySQL, MSSQL, Oracle, PostgreSQL, SQLite
' OR '1'='1' --
' OR '1'='1' /*
-- MySQL
' OR '1'='1' #
-- Access (using null characters)
' OR '1'='1' %00
' OR '1'='1' %16




ابزارهایی برای تست آسیب پذیری SQLi

1) برنامه‌ی DNTProfiler

2) اسکنر اکانتیکس

3) sqlmap
4) روش دستی که بهترین نتیجه را دارد و نیاز به تخصص دارد.


چگونه از SQL Injection جلوگیری کنیم

1) روی داده‌هایی که از کاربر دریافت میگردد، اعتبار سنجی سمت کلاینت و سرور انجام شود. اگر فقط به اعتبارسنجی سمت کلاینت اکتفا کنید، هکر به‌راحتی با استفاده از  پروکسی، داده‌ها را تغییر می‌دهد. ورودی‌ها را فیلتر و پاکسازی و با لیست سفید یا سیاه بررسی کنید ( ^^^^ ).

2) از کوئری‌هایی که بدون استفاده از پارامتر از کاربر ورودی گرفته و درون یک درخواستSQL قرار میگیرند، اجتناب کنید:

[HttpGet]
        [Route("nonsensitive")]
        public string GetNonSensitiveDataById()
        {
            using (SqlConnection connection = new SqlConnection(_configuration.GetValue<string>("ConnectionString")))
            {
                connection.Open();
                SqlCommand command = new SqlCommand($"SELECT * FROM NonSensitiveDataTable WHERE Id = {Request.Query["id"]}", connection);
                using (var reader = command.ExecuteReader())
                {
                    if (reader.Read())
                    {
                        string returnString = string.Empty;
                        returnString += $"Name : {reader["Name"]}. ";
                        returnString += $"Description : {reader["Description"]}";
                        return returnString;
                    }
                    else
                    {
                        return string.Empty;
                    }
                }
            }
        }


با استفاده از پارامتر: (بهتر است نوع دیتا تایپ پارامتر و طول آن ذکر شود)

[HttpGet]
        [Route("nonsensitivewithparam")]
        public string GetNonSensitiveDataByNameWithParam()
        {
            using (SqlConnection connection = new SqlConnection(_configuration.GetValue<string>("ConnectionString")))
            {
                connection.Open();
                SqlCommand command = new SqlCommand($"SELECT * FROM NonSensitiveDataTable WHERE Name = @name", connection);
                command.Parameters.AddWithValue("@name", Request.Query["name"].ToString());
                using (var reader = command.ExecuteReader())
                {
                    if (reader.Read())
                    {
                        string returnString = string.Empty;
                        returnString += $"Name : {reader["Name"]}. ";
                        returnString += $"Description : {reader["Description"]}";
                        return returnString;
                    }
                    else
                    {
                        return string.Empty;
                    }
                }
            }
        }


3) از Stored Procedureها استفاده کنید و بصورت پارامتری داده‌های مورد نیاز را به آن‌ها پاس دهید: (بهتر است نوع دیتا تایپ پارامتر و طول آن ذکر شود)  

 [HttpGet]
        [Route("nonsensitivewithsp")]
        public string GetNonSensitiveDataByNameWithSP()
        {
            using (SqlConnection connection = new SqlConnection(_configuration.GetValue<string>("ConnectionString")))
            {
                connection.Open();
                SqlCommand command = new SqlCommand("SP_GetNonSensitiveDataByName", connection);
                command.CommandType = System.Data.CommandType.StoredProcedure;
                command.Parameters.AddWithValue("@name", Request.Query["name"].ToString());
                using (var reader = command.ExecuteReader())
                {
                    if (reader.Read())
                    {
                        string returnString = string.Empty;
                        returnString += $"Name : {reader["Name"]}. ";
                        returnString += $"Description : {reader["Description"]}";
                        return returnString;
                    }
                    else
                    {
                        return string.Empty;
                    }
                }
            }
        }


4) اگر از داینامیک کوئری استفاده میکنید، داده‌های مورد استفاده‌ی در کوئری را بصورت پارامتری ارسال کنید:

فرض کنید چنین جدولی دارید

CREATE TABLE tbl_Product
(
Name NVARCHAR(50),
Qty INT,
Price FLOAT
)

GO

INSERT INTO tbl_Product (Name, Qty, Price) VALUES (N'Shampoo', 200, 10.0);
INSERT INTO tbl_Product (Name, Qty, Price) VALUES (N'Hair Clay', 400, 20.0);
INSERT INTO tbl_Product (Name, Qty, Price) VALUES (N'Hair Tonic', 300, 30.0);

یک پروسیجر را دارید که عملیات جستجو را انجام میدهد و از داینامیک کوئری استفاده میکند.

ALTER PROCEDURE sp_GetProduct(@Name NVARCHAR(50))
AS
BEGIN
    DECLARE @sqlcmd NVARCHAR(MAX);
    SET @sqlcmd = N'SELECT * FROM tbl_Product WHERE Name = ''' + @Name + '''';
    EXECUTE(@sqlcmd)
END

با اینکه از Stored Procedure استفاده میکنید، باز هم در معرض خطر SQLi می‌باشید. فرض کنید هکر چنین درخواستی را ارسال میکند:

Shampoo'; DROP TABLE tbl_Product; --

نتیجه، تبدیل به دستور زیر میشود:

SELECT * FROM tbl_Product WHERE Name = 'Shampoo'; DROP TABLE tbl_Product; --'

برای جلوگیری از SQLi در کوئریهای داینامیک SP بشکل زیر عمل میکنیم:

ALTER PROCEDURE sp_GetProduct(@Name NVARCHAR(50))
AS
BEGIN
    DECLARE @sqlcmd NVARCHAR(MAX);
    DECLARE @params NVARCHAR(MAX);
    SET @sqlcmd = N'SELECT * FROM tbl_Product WHERE Name = @Name';
    SET @params = N'@Name NVARCHAR(50)';
    EXECUTE sp_executesql @sqlcmd, @params, @Name;
END
در اینجا در پارامتر params@ نوع دیتاتایپ و طول آن را مشخص میکنید و کارکتر quote به صورت خودکار حذف میشود و از SQLi جلوگیری میکند. 


5) میتوان از تنظیمات IIS یا وب سرورهای دیگر برای جلوگیری از SQLi استفاده نمود.

6) استفاده از چند کاربرِ دیتابیس در برنامه و بکارگیری سطح دسترسی محدود و مناسب( ^ , ^ ).

7) از  ORM استفاده کنید و اگر نیاز به سرعت بیشتری دارید از یک Micro ORM استفاده کنید؛ با در نظر داشتن نکات لازم  

مطالب
خواندن فید گزارش آب و هوای یاهو با استفاده از روش Xml serialization

در مطلب قبلی (در مورد کتابخانه anti-xss مایکروسافت) از روش xml serialization برای خواندن فایل xml حملات استفاده کردیم.
ایجاد این کلاس و نگاشت اشیاء با توجه به ساختار ساده آن به صورت دستی و به‌سادگی انجام شد. اکنون به مثال زیر دقت بفرمائید:
سرویس آب و هوای یاهو برای شهرهای مختلف ایران از طریق لینک زیر قابل استفاده است:
http://weather.yahoo.com/regional/IRXX.html
اگر به صفحات شهرهای مختلف مراجعه نمائید، یک فید rss هم مشاهده خواهید کرد، برای مثال در مورد تهران داریم:
http://weather.yahooapis.com/forecastrss?p=IRXX0018&u=c
ساختار این فایل xml تا حدودی با یک rss استاندارد تطابق دارد. اما اگر به سورس xml آن دقت کنیم تگ‌های دیگری را نیز مشاهده خواهیم کرد که برای مثال دما ، تاریخ و شرایط جوی را به صورت دقیقی و با استفاده از اصول xml ارائه می‌دهند.

<yweather:condition text="Partly Cloudy" code="29" temp="10" date="Tue, 11 Nov 2008 5:30 pm IRT" />

خوب، برای دریافت این اطلاعات چه باید کرد؟ یکی از روش‌های متداول برای کار با این نوع داده‌ها، استفاده از کلاس DataSet در دات نت و فراخوانی متد ReadXml آن است (یک آدرس اینترنتی را هم می‌تواند دریافت کند). سپس مطابق روش‌های معمول ADO.Net می‌توان به تگ‌ها ومقادیر آنها دسترسی داشت.
روش‌ بالا هر چند مشکلی ندارد اما به زیبایی کار با خواص یک کلاس متناظر با آن فایل xml نیست. اما در اینجا برای استفاده از روش xml serialization یک مشکل وجود دارد! ایجاد دستی این کلاس که بیانگر عملکرد آن فایل xml است کار ساده‌ای نیست.
خوشبختانه به همراه SDK‌ دات نت فریم ورک 2، برنامه‌ای به نام xsd.exe نیز همراه است که کار ایجاد یک کلاس cs یا vb را از یک فایل xml جهت این منظور انجام می‌دهد (این برنامه برای مثال در مسیر C:\Program Files\Microsoft.NET\SDK\v2.0\Bin قرار دارد).

برای ایجاد فایل کلاس به صورت خودکار از روی یک فایل xml موجود باید به ترتیب زیر عمل کرد:
الف) ایجاد فایل xsd متناظر (XML Schema Definition)
برای اینکار در خط فرمان تایپ کنید:
xsd.exe file.xml

نکته 1:
روش دیگر انجام این کار : فایل xml را در VS.net باز کنید، از منوی بالای صفحه گزینه xml را انتخاب نموده و بر روی دکمه Create Schema کلیک کنید.

ب) ایجاد فایل cs یا vb از روی فایل(های) xsd ایجاد شده
در اینجا برای فید آب و هوای یاهو سه فایل xsd تولید خواهد شد. برای تبدیل آنها به کلاس cs باید دستور زیر را در خط فرمان اجرا کرد:

Xsd.exe file_1.xsd file_2.xsd file_3.xsd /c

این مورد نکته مهمی است و تنها اگر یکی از فایل‌ها اینجا ذکر شوند، کلاس ناقصی تشکیل خواهد شد. (برای نمونه فایل xssAttacks.xml مطلب قبلی، ساختار ساده‌ای داشته و تنها به یک فایل xsd ختم خواهد شد)

نکته 2:
برای انتخاب زبان VB (با توجه به این‌که پیش فرض آن CS است) می‌توان به صورت زیر عمل کرد:
xsd.exe file.xsd /c  /l:vb

نکته 3:
برای تولید فایل xsd ، از برنامه Infer.exe نیز می‌توان استفاده کرد (خروجی نهایی دقیق‌تری را ارائه می‌دهد). این برنامه را از اینجا دریافت کنید.

تصاویر زیر مقایسه دو فایل کلاس نهایی تولید شده از xsd های این دو برنامه است:






پس از طی این مراحل فایل کلاس ما برای xml serialization آماده خواهد شد. مرحله بعد دریافت اطلاعات و نگاشت آن به این کلاس تولید شده است:

public static rss DeserializeFromXML()
{
XmlSerializer deserializer =
new XmlSerializer(typeof(rss));
using (XmlReader reader = XmlReader.Create("http://weather.yahooapis.com/forecastrss?p=IRXX0018&u=c"))
{
return (rss)deserializer.Deserialize(reader);
}
}

کلاس rss از فید xml و فایل‌های xsd آن که تولید کردیم به صورت خودکار ایجاد شده است.
اکنون برای مثال خواندن وضعیت فعلی جوی از فید دریافتی به سادگی زیر است:

rss data = DeserializeFromXML();
MessageBox.Show(data.channel.item.condition.text);


مطالب
اضافه کردن آیتم ورود با حساب کاربری دیگر در شیرپوینت 2016 و شیرپوینت 2013 ( اضافه کردن آیتم منو Sign in as different user )
در شیرپوینت 2016 و شیرپوینت 2013  به صورت پیش فرض گزینه Sign in as different user وجود ندارد. در این مقاله قصد دارم نحوه اضافه کردن آیتم ورود با کاربر دیگر را توضیح دهم. به این منظور مراحل زیر را دنبال نمایید.  

اگر از شیرپوینت 2016 استفاده می‌کنید به آدرس زیر بروید: 

C:\Program Files\Common Files\microsoft shared\Web ServerExtensions\16\TEMPLATE\CONTROLTEMPLATES  

واگر از شیرپوینت 2013 استفاده می‌کنید به آدرس زیر بروید: 

C:\Program Files\Common Files\microsoft shared\Web ServerExtensions\15\TEMPLATE\CONTROLTEMPLATES 

و از آدرس مذکور به دنبال فایلی به نام welcome.ascx بگردید.  

به منظور اضافه کردن آیتم " ورود با حساب کاربری دیگر " باید همین فایل را ویرایش کنیم. جهت ویرایش فایل می‌توانید از یک ویرایشگر متن ساده ( Text Editor ) همانند Notepad++ یا ویژوال استودیو استفاده نمایید.

تنها کاری که باید انجام دهید اینست که کدهای زیر را به فایل مذکور اضافه نمایید: 

<SharePoint:MenuItemTemplate runat="server" ID="ID_LoginAsDifferentUser"
  Text="<%$Resources:wss,personalactions_loginasdifferentuser%>"
  Description="<%$Resources:wss,personalactions_loginasdifferentuserdescription%>"
  MenuGroupId="100"
  Sequence="100"
  UseShortId="true"
/>

در فایل welcome.ascx باید به دنبال تگ "ID_RequestAcess" بگردید و کد بالا را قبل از آن اضافه نمایید. اما توجه بفرمایید که مکان دقیق اضافه کردن این قطعه کد، دقیقا با ترتیب آیتم منویی که تصمیم دارید در آن جایگاه قرار گیرد، رابطه مستقیم دارد؛  بدین معنا که اگر تمایل دارید ترتیب نمایش جایگاه این آیتم منو را عوض نمایید، براحتی می‌توانید در جایگاه مناسب کد بالا را کپی نمایید:  

بلافاصله پس از ذخیره کردن فایل welcome.ascx، با فشردن کلیدهای Ctrl+F5 می‌توانید نتیجه تغییرات‌تان را مشاهده نمایید. در صورت لزوم می‌توانید کش مرورگر را خالی نمایید.

اشتراک‌ها
Autocomplate که لیست نهایی را مانند جدول نمایش میدهد

کتابخانه جاوا اسکریپتی برای نمایش متن مورد جستجو به صورت یک جدول و امکان هایلایت کردن متن مورد جستجو

من بعد از استفاده از این کتابخانه به این نتیجه رسیدم که بهترین Autocomplate همان jquery Ui Autocomplate هست.

برای پیاده سازی جدولی شکل آن از این لینک استفاده کنید.

Autocomplate که لیست نهایی را مانند جدول نمایش میدهد
مطالب
پیاده سازی Option یا Maybe در #C

Options یا Maybe در یک زبان تابعی مثل #F، نشان دهنده‌ی این است که شیء (Object) ممکن است وجود نداشته باشد(Null Reference) که یکی از مهمترین ویژگی‌های یک زبان شیءگرا مثل #C و یا Java محسوب می‌شودما برنامه نویس‌ها (اغلب) از هرچیزی که باعث کرش برنامه می‌شود، بیزاریم و برای اینکه برنامه کرش نکند، مجبور میشویم تمام کد‌های خود  را از Null Reference محافظت کنیم. تمام این مشکلات توسط Tony Hoare مخترع ALOGL است که تنها دلیل وجود Null References را سادگی پیاده سازی آن می‌داند و او این مورد را یک «خطای  میلیون دلاری» نامیده‌است. 

به این مثال توجه بفرمایید: 

public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

public class UserService : IUserService
    {
        private IList<User> _userData;

        public UserService()
        {
            _userData = new List<User>
            {
                new User {Id = 1,Name = "ali"},
                new User {Id = 2,Name = "Karim"}
            };
        }

        public User GetById(int id)
        {
            return _userData.FirstOrDefault(x => x.Id == id);
        }
    }  

public class UserController : Controller
    {
        private readonly IUserService _userService;

        public UserController(IUserService  userService)
        {
            _userService = userService;
        }
        public ActionResult Details(int id)
        {
            var user=_userService.GetById(3); // این متد ممکن است مقداری برگرداند و یا مقدار نال برگرداند                           
            if( user == null)
                 return HttpNotFound();    
            return View(user);  
        }
    }

این کدی است که ما برنامه نویسان به صورت متداولی با آن سروکار داریم. اما چه چیزی درباره این کد اشکال دارد؟

مشکل از آن جایی هست که ما نمی‌دانیم متد GetById مقداری را برمیگرداند و یا Null را بر می‌گرداند. این متد هرگاه که امکان برگرداندن Null وجود داشته باشد، خطای  NullReferenceException را در زمان اجرا بر می‌گرداند و همان طور که میدانید، به ازای هر شرطی که به برنامه اضافه میکنیم، پیچیدگی برنامه هم افزایش می‌یابد و کد خوانایی خود را از دست می‌دهد. تصور کنید دنیایی بدون NullReferenceException چه دنیایی زیبایی می‌بود؛ ولی متاسفانه این مورد از ویژگی‌های زبان #C است. خوشبختانه راه‌حل‌های برای حل NRE ارائه شده‌اند که در ادامه به آن‌ها می‌پردازیم.

ما می‌خواهیم متد GetById همیشه چیزی غیر از نال را برگرداند و یکی از راه‌هایی که ما را به این هدف می‌رساند این است که این متد یک توالی را برگرداند.

به نگاری جدید کد توجه بفرمایید:
public class UserService : IUserService
    {
        private IList<User> _userData;

        public UserService()
        {
            _userData = new List<User>
            {
                new User {Id = 1,Name = "ali"},
                new User {Id = 2,Name = "Karim"}
            };
        }

        public IEnumerable<User> GetById(int id)
        {
            var user = _userData.FirstOrDefault(x => x.Id == id);
            if (user == null) return new User[0];
            return new[] { user };
        }
    } 

اگر به امضای متد GetById توجه کنید، به جای اینکه User را برگرداند، این متد یک توالی از User را بر می‌گرداند و اگر در اینجا کاربری یافت شد، این توالی دارای یک المان خواهد بود و در غیر این صورت اگر User یافت نشد، این متد یک توالی را بر می‌گرداند که دارای هیچ المانی نیست. در ادامه اگر کلاینت بخواهد از متد GetById استفاده کند، به صورت زیر خواهد بود:

 public ActionResult Details(int id)
        {
            var user = _userService
                            .GetById(3)
                            .DefaultIfEmpty(new User())
                            .Single();
            return View(user);
        }

 متد GetById دارای دو وجه است و وجه مثبت آن این است که اگر مجموعه دارای مقداری باشد، هیچ مشکلی نیست؛ ولی اگر مجموعه دارای المانی نباشد، باید یک شیء را به صورت پیش فرض به آن اختصاص دهیم که این کار را با استفاده از متد DefualtIfEmpty انجام داده‌ایم. 

 در اول مقاله هم اشاره کردیم که  Maybe یا Options، مجموعه‌ای است که دارای یک المان و یا هیچ المانی است. اگر به امضای متد GetById توجه کنید، متوجه خواهید شد که این متد می‌تواند مجموعه‌ای را برگرداند و نمی‌تواند گارانتی کند که حتما مجموعه‌ای را بر می‌گرداند که دارای یک المان و یا هیچ باشد. برای حل این مشکل می‌توانیم از کلاس Option استفاده کنیم:

public class Option<T> : IEnumerable<T>
    {
        private readonly T[] _data;

        private Option(T[] data)
        {
            _data = data;
        }

        public static Option<T> Create(T element) => new Option<T>(new[] { element });

        public static Option<T> CreateEmpty() => new Option<T>(new T[0]);

        public IEnumerator<T> GetEnumerator() => ((IEnumerable<T>) _data).GetEnumerator();

        IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
    }

تنها دلیل استفاده از متد‌های Create و CreateEmpty این است که به خوانایی برنامه کمک کنیم؛ نه بیشتر. در ادامه اگر بخواهیم از کلاس option استفاده کنیم، به صورت زیر خواهد بود:

 public class UserService : IUserService
    {
       ...
       ...
       public Option<User> GetById(int id)
        {
            var user = _userData.FirstOrDefault(x => x.Id == id);
            return user == null ? Option<User>.CreateEmpty() : Option<User>.Create(user);
        }
    }

 public class UserController : Controller
    {
       ...
       ...
       public ActionResult Details(int id)
        {
            var user = _userService
                            .GetById(3)
                            .DefaultIfEmpty(new User())
                            .Single();
            return View(user);
        }
    }


چکیده:

مدیریت کردن References کار بسیار پیچیده‌ای است. قبل از آن که تلاش کنیم مقداری را برگردانیم و یا عملیاتی را بر روی آن انجام دهیم، اول باید مطمئن شویم که این شیء به جایی اشاره می‌کند. نمونه‌های متفاوتی از Option و یا Maybe را می‌توانید در اینترنت پیدا کنید که هدف نهایی آن‌ها، حذف NullReferenceException است و آشنایی با این ایده، شما را به دنیای برنامه نویسی تابعی در#C هدایت می‌کند.

مطالب
کار با Docker بر روی ویندوز - قسمت دوم - نصب Docker
پس از آشنایی با مفهوم Containers، در این قسمت قصد داریم برنامه‌ی تقریبا 500 مگابایتی Docker for Windows Installer.exe را نصب کنیم.
 
پیش‌نیازهای نصب Docker بر روی ویندوز

مطابق مستندات آن، برای نصب داکر بر روی ویندوز به حداقل‌های زیر نیاز است:
- استفاده از ویندوز 10 نگارش enterprise، که شماره نگارش آن حداقل 1607 باشد (حداقل Anniversary Update باشد).
- مجازی سازی در BIOS فعال شده باشد.
البته مجازی سازی عموما به صورت پیش‌فرض فعال است. برای بررسی آن، taskmanager ویندوز را اجرا کرده و در برگه‌ی Performance آن، جائیکه مشخصات CPU را نمایش می‌دهد، یک سطر به Virtualization اختصاص دارد که مقدار آن باید enabled باشد (تصویر زیر) و اگر نیست، برای فعال کردن آن باید به تنظیمات BIOS سیستم خود مراجعه کنید:


روش دیگر دریافت این اطلاعات، اجرای دستور systeminfo در خط فرمان، با دسترسی مدیریتی است. در خروجی آن، عبارت «Virtualization Enabled In Firmware» را جستجو کنید که باید مقدار آن yes باشد.

- داشتن CPU با قابلیت SLAT یا Second Level Address Translation.
برای یافتن این موضوع، برنامه‌ی coreinfo را دریافت کرده و آن‌را به صورت coreinfo -v اجرا کنید. خروجی آن سه سطر مرتبط با مجازی سازی را به همراه دارد. اگر قابلیتی موجود نباشد، جلوی آن یک خط تیره و اگر قابلیتی موجود باشد، روبروی آن یک ستاره را مشاهده خواهید کرد.

روش دیگر بررسی آن، اجرای دستور msinfo32 در قسمت run ویندوز و سپس enter است. در قسمت system summary، اطلاعات Second Level Address Translation قابل مشاهده هستند (اگر No باشد، امکان اجرای containerهای لینوکسی را بر روی ویندوز نخواهید داشت):


- داشتن حداقل 4 گیگابایت RAM.
- فعال بودن Hyper-V نیز برای اجرای Linux Containers بر روی ویندوز، ضروری است (نصاب Docker، این‌کار را به صورت خودکار انجام می‌دهد).


دریافت نصاب Docker for Windows

برای دریافت نصاب داکر مخصوص ویندوز، به آدرس زیر مراجعه کنید:
https://store.docker.com/editions/community/docker-ce-desktop-windows
که بلافاصله با تصویر کریه زیر مواجه خواهید شد:


برای رفع این مشکل، می‌توان از روش مطرح شده‌ی در مطلب «یک روش ساده برای دور زدن تحریم‌ها!» استفاده کرد؛ یعنی تنظیم DNS به 178.22.122.100 به صورت زیر:


پس از این تغییر، چون IP قابل مشاهده‌ی سیستم شما توسط سایت داکر تغییر می‌کند، اینبار صفحه‌ی دریافت Docker Community Edition for Windows به صورت زیر ظاهر می‌شود:


همانطور که مشاهده می‌کنید، عنوان کرده‌است که لطفا لاگین کنید تا بتوانید این برنامه را دریافت کنید. به همین جهت بر روی لینک آن کلیک کرده، یک اکانت جدید را در سایت docker ایجاد کنید (با یک ایمیل واقعی که تائیدیه آن‌را دریافت خواهید کرد). پس از آن، با این اکانت جدید به سایت داکر وارد شوید تا لینک دریافت فایل exe نصاب آن‌را دریافت کنید.
در این حالت مرورگر و یا حتی دانلودمنیجر شما بدون مشکل می‌توانند این فایل را دریافت کنند و همان تنظیم DNS فوق، مشکل عدم دسترسی را برطرف می‌کند.


نصب Docker for Windows

پس از اجرای نصاب آن و پایان عملیات نصب (که تنها کافی است در صفحه‌ی ابتدایی آن تیک مربوط به Windows Containers را نیز قرار دهید)، نیاز دارد تا شما را یکبار از سیستم Logout و login کند. پس از ورود به سیستم، تنظیمات ابتدایی آن به صورت خودکار صورت گرفته و در صورت فعال نبودن Hyper-V، پیام زیر را مشاهده خواهید کرد:


بر روی OK کلیک کنید تا اینکار با موفقیت به پایان برسد. البته پس از آن، منتظر حداقل یکبار ری‌استارت شدن خودکار سیستم، بدون اطلاع قبلی نیز باشید.

یک نکته: کاری که در قسمت فعالسازی Hyper-V به صورت خودکار انجام می‌شود، شامل اجرای سه دستور زیر، در کنسول پاور شل، با دسترسی مدیریتی و سپس ری استارت سیستم است:
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All -Verbose
Enable-WindowsOptionalFeature -Online -FeatureName Containers -All -Verbose
bcdedit /set hypervisorlaunchtype Auto
پس از آن، خط فرمان را باز کرده و با ستفاده از docker CLI نصب شده، دستور docker info را صادر کنید، تا بتوانید مشخصات نگارش نصب شده را مشاهده نمائید.
C:\Users\Vahid>docker info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 0
Server Version: 18.06.1-ce
OSType: windows
OSType را در صورتیکه سیستم شما توانمندی‌های سخت افزاری لازم را داشته باشد، می‌توان به Linux نیز تغییر داد.


بررسی تنظیمات سوئیچ کردن بین Linux Containers و Windows Containers

پس از اتمام ری‌استارت‌ها، برای آزمایش فعال بودن Hyper-V، در قسمت Run ویندوز، عبارت Virtmgmt.msc را نوشته و enter کنید. اگر تصویر زیر را مشاهده نمی‌کنید:


یکبار بر روی آیکن Docker در قسمت Tray Icons ویندوز کلیک راست کرده و گزینه‌ی switch to Linux containers را انتخاب کنید تا پس از مدتی، آیکن MobyLinuxVM در قسمت virtual machines (تصویر فوق) ظاهر شود.


اگر پس از انتخاب این گزینه، پیام زیر را دریافت کردید:


و یا اگر بر روی این ماشین مجازی کلیک راست کردید و گزینه‌ی Start آن‌را انتخاب کردید و پیام زیر ظاهر شد:


قسمت «پیش‌نیازهای نصب Docker بر روی ویندوز» را با دقت بررسی کنید (خصوصا قسمت BIOS و SLAT). نبود یکی از موارد ذکر شده، سبب بروز این مشکل می‌شود.
برای مثال اجرای دستور coreinfo -v بر روی سیستم من چنین خروجی را به همراه دارد:
E:\>coreinfo -v

AuthenticAMD
Microcode signature: 00000000
HYPERVISOR      -       Hypervisor is present
SVM             *       Supports AMD hardware-assisted virtualization
NP              -       Supports AMD nested page tables (SLAT)
روبروی HYPERVISOR و همچنین SLAT یک - را قرار داده‌است. یعنی این موارد یا پشتیبانی نمی‌شوند و یا در BIOS فعال نشده‌اند.
همانطور که مشاهده می‌کنید، قابلیت SLAT در CPU این سیستم وجود ندارد. به همین جهت نمی‌توان به Linux containers سوئیچ کرد. هرچند windows containers آن کار می‌کند.

روش دیگر مشاهده‌ی این خطا، مراجعه‌ی به event viewer ویندوز است. در قسمت خطاهای سیستم، ممکن است خطای زیر را مشاهده کنید:
Hypervisor launch failed; Second Level Address Translation is required to launch the hypervisor.


آزمایش Docker نصب شده

پس از نصب docker، خط فرمان ویندوز را گشوده و دستور زیر را صادر کنید:
docker run hello-world
اگر از قسمت قبل به‌خاطر داشته باشید، hello-world در اینجا نام یک image است. البته چون این image بر روی سیستم ما موجود نیست، این دستور، ابتدا آن‌را از docker hub دریافت کرده و سپس اجرا می‌کند. بنابراین می‌شد ابتدا دستور pull را صادر کرد و سپس run. اما دستور run قادر است هر دو عمل را با هم انجام دهد.

یک نکته: این image، یک image لینوکسی است. به همین جهت پیش از اجرای این دستور، همانطور که پیشتر نیز عنوان شد، یکبار بر روی آیکن Docker در قسمت Tray Icons ویندوز کلیک راست کرده و گزینه‌ی switch to Linux containers را انتخاب کنید. سپس دستور docker run hello-world را اجرا نمائید.

و یا در همین حال دستور docker run -p 80:80 nginx را صادر کنید تا وب سرور لینوکسی nginx را بتوانید تحت ویندوز اجرا کنید. پس از خاتمه‌ی عملیات دریافت و اجرای وب سرور، با توجه به تنظیم  p 80:80-، پورت 80 میزبان (اولین عدد)، به پورت 80 کانتینر نگاشت شده‌است. به همین جهت تنها با اجرای دستور http://localhost، خروجی این وب سرور را می‌توانید در مرورگر سیستم خود مشاهده کنید.
همانطور که مشاهده می‌کنید، با استفاده از داکر، پیش از آنکه بدانیم چگونه باید یک نرم افزار را نصب کرد، می‌توان از آن استفاده کرد!


روش متوقف کردن Containers در حال اجرا

اگر دستور docker ps را در خط فرمان ویندوز اجرا کنید، لیست پروسه‌های اجرا شده‌ی توسط آن قابل مشاهده هستند. در این لیست container id در حال اجرا نیز مشخص است. برای خاتمه‌ی کار آن، تنها کافی است دستور docker stop id را اجرا کنید.
یک نکته: ضرورتی به ذکر کامل id نیست. برای مثال ذکر سه حرف اول آن نیز کفایت می‌کند.


روش اجرای مجدد یک Container

فرض کنید می‌خواهیم سرور nginx را مجددا اجرا کنیم. یک روش آن، اجرای مجدد دستور docker run -p 80:80 nginx است که پیشتر آن‌را انجام دادیم. در این حالت این image تبدیل به container شده و همانند روش‌های متداول نصب نرم افزار، اکنون به عنوان یک نرم افزار نصب شده در دسترس است. برای مشاهده‌ی لیست آن‌ها، دستور docker ps -a را اجرا کنید. این لیست تا این لحظه باید شامل containerهای nginx و hello-world باشد. متوقف کردن یک container، سبب تخریب یا حذف آن نمی‌شود. در این حالت در لیستی که توسط دستور docker ps -a نمایش داده شده‌است، باز هم container idها قابل مشاهده هستند. فقط کافی است برای اجرای یکی از آن‌ها، دستور docker start id را اجرا کرد. به این صورت دیگر نیازی به ذکر دستور کامل docker run با تمام پارامترهای آن نیست. این id نیز همانطور که ذکر شد، می‌تواند سه حرف ابتدایی این id باشد تا حدی که نسبت به سایر idهای موجود، منحصربفرد شناخته شود. یا بجای container id می‌توان container name نمایش داده شده‌ی در این لیست را استفاده کرد.
پس از اجرای nginx توسط دستور docker start id، دو روش برای بررسی در حال اجرا بودن آن وجود دارد:
الف) مرورگر را باز کنیم و آدرس http://localhost را بررسی کنیم.
ب) دستور docker ps را در خط فرمان اجرا کنیم، تا مشخص شود که آیا پروسه‌ی nginx در حال اجرا است یا خیر؟

بنابراین دستور docker ps -a لیست تمام containers در حال اجرا و همچنین متوقف شده را نمایش می‌دهد. اما دستور docker ps تنها لیست containers در حال اجرا را نمایش خواهد داد.


روش حذف Containers از Docker

همانطور که در قسمت قبل نیز بحث شد، معادل نصب نرم افزار در اینجا، ایجاد یک container از یک image دریافتی از docker hub است. روش عکس آن، یعنی تخریب یک container، دقیقا معادل عزل نرم افزار از سیستم، در حالت‌های متداول است. برای اینکار مجددا دستور docker ps -a را اجرا می‌کنیم تا لیست تمام containerهای در حال اجرا و همچنین متوقف شده نمایش داده شوند. لیستی که در اینجا نمایش داده می‌شود، شبیه به لیستی است که در قسمت add/remove programs ویندوز مشاهده می‌کنید. این لیست معادل لیست نرم افزارهای نصب شده‌ی بر روی سیستم است و یا برای مشاهده‌ی لیست imageهای دریافتی از docker hub می‌توان دستور docker images را صادر کرد.
قبل از حذف یک container نیاز است آن‌را متوقف کنیم. برای این منظور از دستور docker stop id استفاده می‌شود. سپس اجرای دستور docker rm id، سبب حذف کامل این container خواهد شد. برای آزمایش آن، مجددا دستور docker ps -a را اجرا کنید.
دستور docker rm چندین id را نیز می‌پذیرد. می‌توان این idها و یا حتی سه حرف ابتدایی آن‌ها را با فاصله در اینجا ذکر کرد. علاوه بر id، ذکر نام containers نیز مجاز است.


روش حذف Imageهای دریافتی از Docker Hub

دستور docker rm، فقط containers را از سیستم حذف می‌کند (نرم افزارهای نصب شده). اما خود imageهای اصلی دریافت شده‌ی از docker hub را حذف نمی‌کند (معادل همان فایل‌های zip دریافت نرم افزار یا برنامه‌های نصاب، در حالت متداول و سنتی نصب نرم افزار). برای آزمایش آن دستور docker images را اجرا کنید. هنوز هم در لیست آن، تمام موارد دریافتی موجود هستند.
برای حذف یک image می‌توان از دستور docker rmi id استفاده کرد (rmi بجای rm). این id نیز در لیست docker images ظاهر می‌شود و ذکر قسمتی از آن، تا حدی که نسبت به سایر idهای لیست شده منحصربفرد باشد، کافی است. در اینجا بجای id، از نام image نیز می‌توان استفاده کرد. همچنین ذکر چندین id و یا نام نیز پس از دستور docker rmi، میسر است.


روش جستجوی imageها در Docker Hub توسط Docker CLI

فرض کنید می‌خواهیم image مربوط به راهنمای Docker را از Docker Hub دریافت کنیم. یک روش آن مراجعه‌ی مستقیم به سایت آن است و استفاده از امکانات جستجوی فراهم شده‌ی در آن سایت. روش دیگر، استفاده از Docker CLI است. اگر دستور docker search docs را در خط فرمان اجرا کنیم، لیست تمام مخازن کدی که در آن‌ها واژه‌ی docs قرار دارد، نمایش داده می‌شود. البته پیش از نصب image آن بهتر است به برگه‌ی tags مخزن کد آن نیز مراجعه کنید تا بتوانید حجم آن‌را نیز مشاهده نمائید که حدود یک گیگابایت است. مخازن docker hub، حاوی imageهای نصاب containerهای متناظر هستند. برای دریافت و اجرای آن می‌توان دستور docker run -p 4000:4000 docs/docker.github.io را اجرا کرد.
پس از دریافت یک گیگابایت مستندات، container آن بر روی پورت 4000 در سیستم ما (http://localhost:4000)، به صورت یک وب سایت استاتیک، قابل دسترسی خواهد بود. به این صورت می‌توان به مستندات کامل داکر به صورت آفلاین دسترسی داشت.


مفهوم Interactive Terminal در Docker

زمانیکه دستور اجرای مستندات آفلاین را صادر می‌کنید، در انتهای آن عنوان می‌کند که وب سایت محلی آن بر روی پورت 4000 قابل دسترسی است. سپس در ذیل آن ذکر شده‌است که اگر ctrl+c را فشار دهید، اجرای آن به پایان می‌رسد. اما عملا اینطور نیست و اگر دستور docker ps را صادر کنید، هنوز container در حال اجرای آن را می‌توان مشاهده کرد.
اما اگر اینبار دستور اجرای docker run را به همراه یک interactive terminal با سوئیچ it و نام docs صادر کنیم:
 docker run -p 4000:4000 -it --name docs docs/docker.github.io
اکنون اگر ctrl+c را فشار دهیم و پس از آن دستور docker ps را صادر کنیم، دیگر در لیست آن، container در حال اجرای docs مشاهده نمی‌شود.
سوئیچ it یا interactive terminal سبب می‌شود تا یک container در foreground، بجای background اجرا شود. به این ترتیب دستور ctrl+c، سبب خاتمه‌ی واقعی پروسه‌ی درحال اجرای در container می‌شود.
روش دیگر خاتمه‌ی این container، استفاده از نام ذکر شده‌است؛ یعنی اجرای دستور docker stop docs.

یک نکته: اگر می‌خواهید از terminal باز شده قطع شوید (مجددا به command prompt باز گردید) اما سبب خاتمه‌ی container آن نشوید، از ترکیب ctrl+p+q استفاده کنید.


اجرای containerهای ویندوزی

در مورد نحوه‌ی سوئیچ بین نوع‌های مختلف containerهای ویندوزی و لینوکسی پیشتر توضیح دادیم. برای این منظور می‌توان بر روی آیکن Docker در قسمت Tray Icons ویندوز کلیک راست کرده و گزینه‌ی switch to Windows/Linux containers را انتخاب کرد. باید دقت داشت که پشتیبانی از containerهای ویندوزی، از ویندوز 10، نگارش  1607، یا همان Anniversary Update آن به بعد، به ویژگی‌های ویندوز اضافه شده‌اند که به صورت خودکار توسط docker فعالسازی می‌شوند:



اجرای IIS به عنوان یک Windows Container

تا اینجا imageهای دریافتی، لینوکسی بودند. اگر گزینه‌ی Windows Containers را به روشی که گفته شد، فعال کنید، اینبار با اجرای دستورات docker ps و یا docker images، هیچ خروجی را دریافت نخواهید کرد. از این جهت که کانتینرهای ویندوزی و لینوکسی، به صورت کاملا ایزوله‌ای از هم اجرا و مدیریت می‌شوند. علت آن‌را هم در MobyLinuxVM که پیشتر با اجرای دستور Virtmgmt.msc بررسی کردیم، می‌توان یافت. Containerهای لینوکسی، در داخل MobyLinuxVM اجرا می‌شوند.
در اینجا به عنوان مثال می‌توان image رسمی مربوط به IIS را از docker hub دریافت و به صورت یک کانتینر ویندوزی اجرا کرد. البته پیش از اجرای دستورات آن بهتر است به برگه‌ی tags آن مراجعه کرده و حجم‌های نگارش‌های مختلف آن‌را بررسی کرد. اجرای دستور docker pull microsoft/iis به معنای دریافت tag ای به نام latest است (به حجم 6 گیگابایت!)؛ یعنی با دستور docker pull microsoft/iis:latest یکی است. بنابراین در اینجا بر اساس tagهای مختلف، می‌توان دستور pull متفاوتی را صادر کرد. برای مثال اگر دستور docker pull microsoft/iis:nanoserver را صادر کردید، نگارش مخصوص nano server آن‌را که فقط 449 مگابایت است، دریافت می‌کند. بنابراین از این پس به tagهای هر مخزن docker hub خوب دقت کنید و نگارش مختص به سیستم عامل خود را دریافت نمائید. عدم ذکر tag ای، همواره tag ویژه‌ای را به نام latest، دریافت می‌کند.
با اجرای دستور زیر
 docker run -p 81:80 -d --name iis microsoft/iis:nanoserver
داکر، ابتدا image مخصوص nanoserver آن‌را دریافت و سپس اجرا می‌کند. چون وب سرور است، نیاز به تنظیمات پورت آن‌را داریم. p 81:80- به این معنا است که پورت 80 کانتینر را (پورتی که IIS درون آن بر روی آن اجرا می‌شود)، به پورت 81 بر روی سیستم میزبان (یا همین ویندوز فعلی که داکر را اجرا می‌کند)، نگاشت کن. پارامتر d در اینجا به معنای detach است. یعنی به محض اجرای این دستور، کار اجرای این کانتینر در background انجام شده و سپس به خط فرمان، بازگشت داده می‌شویم. همچنین نامی نیز به این container انتساب داده شده‌است تا ساده‌تر بتوان با آن کار کرد.

یک نکته: مشکلی با اجرای IIS مخصوص نانوسرور بر روی ویندوز 10 به این صورت و توسط داکر نیست. بنابراین پس از اجرای دستور فوق، کار دریافت image و ساخت container و سپس اجرای آن به صورت خودکار انجام شده و بلافاصله به command prompt بازگشت داده می‌شویم (به علت استفاده‌ی از پارامتر d). اکنون اگر دستور docker ps را صادر کنیم، مشاهده می‌کنیم که کانتینر IIS مخصوص نانوسرور، هم اکنون بر روی ویندوز 10 در حال اجرا است و در آدرس http://localhost:81 قابل دسترسی است.

جهت تکمیل این بحث، بهتر است image مخصوص nanoserver را نیز از docker hub دریافت و اجرا کنیم:
 docker run microsoft/windowsservercore
حجم image آن 6GB است.


تنظیمات کارت شبکه‌ی Containers

هنگامیکه پروسه‌ای درون یک container اجرا می‌شود، ایزوله سازی‌های بسیاری نیز در مورد آن اعمال خواهد شد؛ به همین جهت گاهی از اوقات عده‌ای containerها را با ماشین‌های مجازی نیز مقایسه می‌کنند. برای مثال کانتینرها به همراه network adapter خاص خود نیز هستند؛ درست مانند اینکه یک کامپیوتر مجزای از سیستم جاری می‌باشند و اگر این network adapter را ping کنیم، می‌توان به این صورت نیز به آن کانتینر، دسترسی داشته باشیم.
برای یافتن آن، دستور docker inspect iis را صادر می‌کنیم. خروجی آن به همراه یک قسمت network نیز هست که داخل آن یک IP Address قابل مشاهده است. این IP است که مختص و منحصربفرد این container است. در ابتدا برای آزمایش آن، می‌توان آن‌را ping کرد؛ مانند ping 172.27.49.47. همچنین به تمام برنامه‌های داخل این container توسط این IP نیز می‌توان دسترسی یافت. برای مثال فراخوانی http://172.27.49.47:81 در مرورگر، سبب نمایش صفحه‌ی اول IIS می‌شود. البته اگر اینکار را انجام دهیم، کار نمی‌کند. علت اینجا است، نگاشت پورتی را که تعریف کرده‌ایم (پورت 81)، به پورتی در کامپیوتر میزبان است و نه این IP ویژه. برنامه‌ی اصلی IIS در داخل container، به پورت 80 بر روی این آدرس IP گوش فرا می‌دهد. اکنون اگر آدرس http://172.27.49.47:80 را در کامپیوتر میزبان فراخوانی کنیم، کار می‌کند.
بنابراین هرچند containerها به معنای نرم افزارهای از پیش نصب شده‌ی در حال اجرا هستند، اما ... به همراه ایزوله سازی‌های قابل توجهی بر روی کامپیوتر میزبان اجرا می‌شوند؛ درست مانند یک کامپیوتر مجزای از آن.
نظرات نظرسنجی‌ها
در محیط کاری از کدام سورس کنترل استفاده می‌کنید؟
خیلی ساده هستش که شما در یک شرکت برای مثال هم برای اندروید پروژه داشته باشید، و هم برای VB6 و هم برای Silverlight
یه شرکت با قدمت چند ساله می‌تونه چند نا سورس کنترلر رو با هم داشته باشه، سوال شده که در محیط کاری از چه سورس کنترلرهایی استفاده می‌کنید، من در حال انتقال یه پروژه جاوایی اندروید به #C هستم، و همزمان توسعه خیلی کمی نیز دارم روی پروژه جاوایی انجام می‌دم تا پروژه برسه
حالا من همزمان از 2 تا سورس کنترلر در محیط کارم دارم استفاده می‌کنم
اگه مثل سوال‌های قبلی تون فرموده بودید اکثر، یا اغلب یا بیشتر از چه چیزی استفاده می‌کنید، اون وقت Radio Button کاملا OK بود، به عنوان سوال بیشتر دقت کنید، متوجه می‌شوید