در عنوان و متن این نوشته، اگر جایی کلمه ی core نوشته شده، در پرانتز قرار گرفته، به این علت که از ماه نوامبر سال 2020، مایکروسافت کلمه ی core را حذف کرد و NET 5. را منتشر کرد. ولی به جهت اهمیت تفکیک اسامی، من در این نوشته - بعضی جاها - از عبارت NET Core. استفاده کرده ام تا از NET Framework. جدا شود.
برنامه نویس ها، زمانی که قصد یاد گرفتن یک زبان جدید را دارند، با یک برنامه ی خیلی ساده شروع می کنند که تنها یک متن در خروجی نمایش می دهد: Hello World
این یک رسم در دنیای برنامه نویسی است، و ما هم می خواهیم به همین رسم، یک کنسول اپلیکیشن ساده، با استفاده از NET Command-Line Interface. یا CLI، بسازیم و deploy کنیم.
اگر هیچ آشنایی با NET (Core). ندارید، خواندن قسمت اول به فهم بهتر این مطلب کمک می کند:
آشنایی با NET Core.
اولین قدم برای شروع، دانلود و نصب NET SDK. است.
برای دانلود NET SDK. یک آدرس خیلی سرراست وجود دارد: https://dot.net
کلمه SDK کوتاه شده ی عبارت Software Development Kit است. Kit، به مجموعه ای از آیتم ها گفته می شود، که برای انجام کار مشخصی، یا برای رسیدن به یک هدف استفاده می شوند. یکی از Kit های معروف، که همه می شناسیم First Aid Kit است که مجموعه ای از وسایل مورد استفاده در کمک های اولیه ست، که همه در یک بسته قرار گرفته اند.
قطعا برای نوشتن نرم افزار هم یک سری ابزار، library، سند، نمونه کد و ... وجود دارد که به برنامه نویس ها اجازه می دهد در یک platform بخصوص، نرم افزار تولید کنند. به همین دلیل، زمانی که می خواهیم شروع کنیم به ایجاد یک نرم افزار تحت یک platform خاص، باید ابتدا SDK مناسب رو تهیه کنیم که ابزار لازم را برای تولید نرم افزار، در اختیارمان بگذارد.
با مراجعه به آدرسی که معرفی شد، امکان دانلود SDK برای سیستم عامل های مختلف وجود دارد:
یک نمونه برنامه ی Hello World ساده در NET SDK. وجود دارد که دستورالعمل ساخت آن را با هم می بینیم:
در این نوشته، برای ساخت و اجرای برنامه ها، از CLI استفاده می کنیم. ولی همه ی این عملیات، با VisualStudio هم قابل انجام است.
اگر تصمیم گرفتید که از CLI استفاده کنید، فقط دو ابزار زیر را لازم دارید:
1. Command Line (در ویندوز کافی است یک command prompt باز کنید)
2. text editor (برای مثال notepad در ویندوز)
فرض کنیم می خواهیم یک فولدر به اسم DotNetConsoleSample ایجاد کنیم و فایل های اپلیکیشن را در آن قرار دهیم. برای این کار می توانیم از امکانات ویندوز برای ساختن فولدر استفاده کنیم، یا این که یک cmd باز کنیم و دستورهای زیر را تایپ کنیم:
mkdir DotNetConsoleSample cd DotNetConsoleSample
یک فولدر با نام DotNetConsoleSample ساخته شد و working directory را تغییر دادیم به همین فولدر.
تا اینجا هنوز با دستورهای dotnet کار نکرده ایم، اولین دستور:
dotnet new console
دستور dotnet new console یک کنسول اپلیکیشن Hello World در فولدر جاری می سازد. اگر محتویات فولدر را نگاه کنیم این دو فایل را می بینیم:
محتویات فایل Program.cs:
using System; namespace DotNetConsoleSample { class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); } } }
همان طور که مشخص است، این برنامه فقط یک عبارت Hello World نمایش می دهد.
و فایل DotNetConsoleSample.csproj: (دقت کنید که فایل csproj همنامِ فولدرِ پروژه است)
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net5.0</TargetFramework> </PropertyGroup> </Project>
فایل csproj در واقع توصیف کننده ی پروژه است. به صورت پیش فرض، همه ی فایل ها و subfolder هایی که در فولدر پروژه قرار دارند، در این فایل include هستند.
اگر قبلا با NET Framework. کار کرده باشید، احتمالا متوجه یک تفاوت مهم شده اید. در NET Framework. لیست همه ی فایل های پروژه، در فایل csproj وجود داشت، در نتیجه اگر پروژه بزرگ بود و تعداد فایل های زیادی داشت، فایل csproj خیلی شلوغ می شد.
ولی در NET (Core). تنها در صورتی که فایلی وجود دارد که در بیرون از فولدر پروژه است، باید آن را به فایل csproj. معرفی کنیم.
با این حال، هنوز هم یک سری اطلاعات در فایل csproj. قرار می گیرد. برای مثال:
1. مشخص کردن نسخه ی framework این برنامه:
<PropertyGroup> <TargetFramework>net5.0</TargetFramework> </PropertyGroup>
یا اگر می خواهید چندین نسخه مشخص کنید:
<PropertyGroup> <TargetFrameworks>netcoreapp3.1;net462</TargetFrameworks> </PropertyGroup>
2. اگر می خواهید برنامه ای که نوشته اید را به صورت یک package منتشر کنید:
<PropertyGroup> <PackageId>ClassLibDotNetStandard</PackageId> <Version>1.0.0</Version> <Authors>John Doe</Authors> <Company>Contoso</Company> </PropertyGroup>
3. برای مشخص کردن فایلی که خارج از فولدر پروژه است:
<ItemGroup> <Content Include="..\Extras\**\*.cs" LinkBase="Shared"/> </ItemGroup>
4. مشخص کردن یک نسخه ی خاص از زبان برنامه نویسی (برای مثال C# preview):
<PropertyGroup> <LangVersion>preview</LangVersion> </PropertyGroup>
5. فعال کردن، یا تعیین نوعِ قوانینِ کیفیتِ کد (Code quality rules):
<PropertyGroup> <AnalysisMode>AllEnabledByDefault</AnalysisMode> </PropertyGroup>
اگر نمی دانید که analyzer چیست:
از NET 5.، مایکروسافت، analyzer های کد را به NET SDK. اضافه کرد. این analyzer ها قبلا هم وجود داشتند ولی در صورت نیاز، باید جداگانه نصب می شدند. در SDK جدید، نیاز به نصب جداگانه نیست و به صورت پیش فرض، فعال هستند.
این analyzer ها می توانند هنگام کامپایل یا هنگام ویرایش کد، از دو جهت کد را بررسی کنند و در صورت نیاز خطا یا هشدار نشان دهند:
1. سبک نوشتن کد
2. کیفیت کد
این ها چند نمونه از آیتم ها و ویژگی های فایل csproj. بود. لیست کامل را اینجا ببینید:
https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props
ما تا اینجا فقط از دستور dotnet new console برای ساخت یک کنسول اپلیکیشن استفاده کردیم، ولی دستور dotnet new امکانات دیگری هم دارد. برای نمونه:
لیست کامل را اینجا ببینید:
https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-new
برای restore کردن package ها از فرمان زیر استفاده می کنیم:
dotnet restore
همچنین، CLI با اجرای دستورهای زیر، به صورت اتوماتیک، restore هم اجرا می کند:
اگر نمی دانید منظور از restore کردن پکیج ها چیست:
یک ابزار مهم که هر platform برنامه نویسی باید داشته باشد، ابزاری است که به برنامه نویس ها اجازه دهد کدهایی را که می نویسند به اشتراک بگذارند. یعنی اگر یک برنامه نویس، یک کد reusable و مفید می نویسد، که احتمالا برای بقیه قابل استفاده است، آن را pack کرده و به صورت یک package، در اختیار بقیه قرار دهد. این package ها معمولا شامل کد کامپایل شده (dll) و یا سایر فایل های مرتبط با اون کد هستند.
برای NET.، مایکروسافت یک مکانیزم اشتراک گذاری کد فراهم کرده، به اسم NuGet، که همه ی کارهای مربوط به ساخت پکیج ها و استفاده از آن توسط دیگران را انجام می دهد. NuGet یک repository مرکزی دارد که همه ی package ها آنجا قرار دارند و می توانند توسط برنامه نویس های NET. استفاده شوند.
مثلا اگر نیاز داشته باشیم که برای Serialize کردن object ها، از Newtonsoft.Json استفاده کنیم این دستور را اجرا می کنیم:
dotnet add package Newtonsoft.Json
با اجرای این دستور، پکیج مربوط به Newtonsoft.Json به پروژه اضافه شده و می توانیم از امکانات آن استفاده کنیم.
بعد، هربار که دستور dotnet restore را اجرا می کنیم، NuGet دو فایل را برای پیدا کردن dependency ها چک می کند:
فایل csproj.
فایل packages.config
بعد از پیدا کردن dependency ها، آن ها را، به همراه وابستگی های آن ها، دانلود کرده و داخل یک فولدر قرار می دهد. این که از کجا دانلود کند و در چه فولدری ذخیره کند، همه قابل configure کردن هستند.
در نتیجه دیگر نیازی به دانلود dll مربوط به کامپوننت هایی که نیاز داریم اضافه کردن آنها به reference های پروژه نیست. فقط برای اضافه کردن dependency ها به پروژه از یک دستور استفاده می کنیم و با هر بار build یا run ، نسخه ی مناسبِ این پکیج -اگر لازم باشد- restore شده و امکانات آن قابل استفاده است. از این جا به بعد، همه ی کارهای مربوط به package ها، مثل مدیریت آپدیت شدن نسخه ها و ... را NuGet انجام می دهد.
برای اجرای برنامه، کافیست در cmd این دستور را اجرا کنیم:
dotnet run
نگران بیلد شدن برنامه نباشید، dotnet ، هر زمان لازم باشد بیلد را انجام خواهد داد.
با این حال، دستور build هم وجود دارد:
dotnet build
بعد از اجرای dotnet run، برنامه باید عبارت Hello World را نمایش دهد:
برای برنامه های وب هم، مثل کنسول اپلیکیشن، یک نمونه برنامه ی Hello World وجود دارد. این برنامه وقتی اجرا شود، یک سرویس HTTP می سازد، که در پاسخ به یک GET Request، عبارت Hello World را برمی گرداند.
دستور ساختن یک وب اپلیکیشن:
dotnet new web
بعد از اجرای این دستور، علاوه بر فایل های Program.cs و csproj.، یک فایل نام Startup.cs هم ساخته می شود. ASP.NET برای مدیریتِ نحوه ی پاسخگویی به request ها، از این کلاس استفاده می کند.
در این برنامه، Program.cs دو وظیفه بر عهده دارد:
فایل Program.cs:
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); }
همانطور که مشخص است، وقتی سرور شروع به کار می کند، از کلاس برای start کردن اپلیکیشن، از کلاس Startup استفاده می کند.
اگر برای این برنامه، دستور زیر را اجرا کنیم:
dotnet run
وب اپلیکیشن روی port مشخص، آماده ی جواب دادن به request هاست. کافی است browser را باز کرده و به آدرس مشخص شده در تصویر بالا مراجعه کنیم:
طراحی NET (Core). به گونه ای است که، deploy کردن اپلیکیشن، به سادگیِ کپی کردن چند فایل باشد.
در NET CLI. این امکان وجود دارد، که همه ی binary های مورد نیاز برای پابلیش اپلیکیشن، در یک فولدر جمع آوری شود. کافی است دستور زیر را اجرا کنیم:
dotnet publish -c Release
دقت کنید که در دستور بالا، Release نام فولدری است که می خواهید فایل های برنامه در آن قرار بگیرند. این فایل ها را روی یک سیستم دیگر که NET SDK. روی آن نصب است کپی کنید و سپس دستور زیر را (از همان فولدر) اجرا کنید:
dotnet DotNetConsoleSample.dll
به این روشِ پابلیش، framework-dependent deployment گفته می شود. یعنی وقتی فایل ها را روی سیستمِ مقصد کپی می کنیم، برای اجرای برنامه، باید NET SDK. روی آن سیستم موجود باشد.
اگر می خواهیم بدون نیاز به NET SDK. برنامه را اجرا کنیم باید از روش self-contained application استفاده کنیم.
ابتدا باید در فایل csproj. مشخص کنیم که نرم افزار روی چه runtime ای قابلیت اجرا دارد:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net5.0</TargetFramework> <RuntimeIdentifiers>win10-x64;osx.10.11-x64;linuxmint.17.1x64</RuntimeIdentifiers> </PropertyGroup> </Project>
و دستور زیر را اجرا می کنیم:
dotnet publish -c Release -r linuxmint.17.1-x64
با این روش، تمام فایل های مورد نیاز برای اجرای برنامه، شامل dll های dotnet، در فولدر مشخص شده قرار می گیرند. همچنین اگر پروژه شامل package خاصی باشد، فایل های آن هم در این فولدر کپی خواهد شد.
بنابراین این فولدر، می تواند روی هر ماشینی کپی شده و بدون نیاز به SDK اجرا شود.
گاهی نرم افزارهایی می نویسیم که وابسته به محیط اجرا هستند. یعنی برنامه نویس روی سیستم خودش، یک سری فایل، تنظیمات و ابزار دارد، توسعه ی نرم افزار و تست آن را روی همین محیط انجام می دهد و همه چیز به درستی کار می کند. بعد از پابلیش، همان نرم افزار، هر جا که مستقر می شود باگ دارد.
وقتی مسئول تست، سیستم را تست می کند و باگ پیدا می کند، و یا وقتی مدیر، در مورد یک باگ از برنامه نویس سوال می پرسد، یک جمله ی معروف هست که هیچ کس مایل نیست بشنود:
"روی سیستم من درست کار می کند!"
این جمله هیچ ارزشی ایجاد نمی کند، چون هیچ کاربری قرار نیست به سیستم برنامه نویس متصل شود و از برنامه استفاده کند. نرم افزار باید ثبات داشته باشد و روی محیط های مختلف، از مرحله ی تست تا عملیاتی شدن به درستی کار کند. برای تحقق این امر، باید محیط توسعه ی مناسب فراهم باشد.
طراحی NET (Core). به گونه ای است که به هیچ چیزی در بیرون از خودش وابسته نیست و هر آنچه که نیاز دارد، درون خودش هست. به همین دلیل با containerها کاملا سازگار است، پس روی همان container که کار توسعه را انجام می دهیم، کار تست و عملیات هم قابل انجام است. پس قرار نیست یک خطا را روی محیط عملیاتی ببینیم ولی روی محیط توسعه اثری از آن نباشد، چون همه ی تنظیمات و بستر اجرایی، روی محیط توسعه و عملیات، یکی است.
اگر نمی دانید container چیست:
container یک واحد است، که همه اجزای یک اپلیکیشن، شامل کد و dependency ها را در خودش بسته بندی می کند. این "بسته بندی"، هر جا که اجرا شود، رفتار یکسانی خواهد داشت. از لپ تاپِ برنامه نویس، تا یک دیتاسنتر اختصاصی، یا cloud.
در نتیجه برنامه نویس، فقط به پیاده سازیِ logic نرم افزار و وابستگی هاش فکر خواهد کرد، تیم استقرار هم فقط به deployment می پردازد و دغدغه ای در خصوص جزئیات پیاده سازی، مثل نسخه های مختلف و config ها نخواهد داشت.
همانطور که در قسمت قبل دیدیم، پابلیش روی Linux، macOS و Windows، به سادگی امکان پذیر است. کافی است محتویات فولدرِ publish را روی سیستم مقصد کپی کنیم.
برای داکر هم همان روش به درستی کار می کند، تنها تفاوت اینجاست که باید یک container بسازیم.
برای نوشتن برنامه با NET. اولین کاری که کردیم نصب SDK بود.
هنگام کار با Docker، کافیست دستور زیر را اجرا کنیم تا image مربوط به dotnet را دریافت کنیم.
این image شامل NET SDK. است:
docker run -it microsoft/dotnet:latest
حالا برای ساختن container:
یک فایل text به نام Dockerfile در فولدری که اپلیکیشن آنجا قرار دارد (همانجایی که فایل .csproj هست) بسازید. محتویات این فایل باید به این صورت باشد:
FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base COPY bin/Release/net5.0/publish/ /root/ ENTRYPOINT dotnet /root/DotNetConsoleSample.dll
در باکس بالا، دقت کنید که bin/Release/net5.0/publish/ آدرس جایی است که محتویات اپلیکیشن بعد از پابلیش آن جا قرار دارد و DotNetConsoleSample.dll نام dll مربوط به برنامه است.
بعد از ساخت و ذخیره ی فایل، دستور زیر را اجرا می کنیم تا container ساخته شود:
docker build -t dotnetconsolesample .
این دستور از Dockerfile ای که ساختیم استفاده می کند تا container را بسازد. حالا باید در لیست image های Docker، این image را ببینید:
dotnetconsolesample
برای اجرای برنامه در Docker، دستور زیر را اجرا می کنیم:
docker run -it dotnetconsolesample
برای پابلیش وب اپلیکیشن روی یک container، باید مقداری تنظیمات انجام دهیم:
در فایل Program.cs
webBuilder .UseUrls("http://*:5000/") .UseStartup<Startup>();
با استفاده از متد UseUrls، مشخص می کنیم که سرور باید روی چه آدرس و port مشخصی، به request ها پاسخ دهد.
فایل Dockerfile به صورت زیر خواهد بود:
FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base COPY bin/release/net5.0/publish/ /root/ EXPOSE 5000/tcp ENTRYPOINT dotnet /root/DotNetWebSample.dll
دستور Expose، به Docker می گوید که container در هنگام اجرا، باید به کدام port شبکه گوش بدهد.
بعد از ذخیره کردن Dockerfile، دستورهای زیر را به ترتیب اجرا می کنیم:
dotnet publish -c release
docker build -t dotnetwebsample .
docker run -it -p 5000:5000 dotnetwebsample
و روی آدرس http://localhost:5000 می تونیم Hello World را مشاهده کنیم.
اگر می خواهید اپلیکیشن خود را به صورت یک پکیج در اختیار دیگران قرار دهید یک دستور ساده برای این کار وجود دارد:
dotnet pack -c Release
بعد از اجرای این دستور، یک فایل با نام DotNetConsoleSample.1.0.0.nupkg ساخته می شود. این فایل یک NuGet Packge است و امکان به اشتراک گذاشته شدن کد شما را فراهم می کند.
تا اینجا ما با دستورهای زیر کار کردیم:
به جز این ها، دستورهای دیگری هم توسط CLI قابل اجراست:
لیست کامل را اینجا ببینید:
https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet
در این نوشته، یک شروع ساده با NET. را طی مراحل زیر توضیح دادیم:
منابع:
.Net Core in Action | Dustin Metzgar