.NET على Linux: أبسط مما يبدو
نشرت: 2022-08-16لطالما كان تطوير حلول .NET على Linux يمثل تحديًا لأن Visual Studio من Microsoft يتطلب Windows حتى يعمل. بعد العمل على العديد من مشاريع .NET ، قررت اختبار حدود تطوير .NET على Linux. يركز هذا البرنامج التعليمي البسيط على تطبيق ASP.NET MVC مع SQL Server لإظهار مدى أناقة وفعالية تطوير .NET على نظام التشغيل المفضل لدي.
بيئة التطوير
أولاً ، يجب أن نتأكد من تثبيت أدوات .NET و SDK المرتبطة بنكهة Linux الخاصة بنا باستخدام دليل Microsoft القياسي.
تتكون بيئة التطوير المفضلة لدي من بيئة تطوير متكاملة (IDE) ، وأداة قوية لإدارة قواعد البيانات والاستعلام ، وقاعدة البيانات نفسها ، وأدوات للبناء والنشر. أستخدم الأدوات التالية لتحقيق وظائف قوية وتمكين تجربة تشفير رائعة:
- IDE: رمز الاستوديو المرئي
- أداة إدارة قواعد البيانات والاستعلام: DBeaver
- قاعدة البيانات: Microsoft SQL Server (تثبيت Linux)
- أدوات البناء: واجهة سطر أوامر .NET SDK (CLI)
- الآلة والحاويات الافتراضية: Docker
تأكد من تثبيت هذه الأدوات بشكل صحيح قبل متابعة نموذج التطبيق الخاص بنا.
مشروع السقالات
في نموذج التطبيق هذا ، سنسلط الضوء على تطوير ASP.NET ووظائفه من خلال سلسلة من حالات الاستخدام لنظام افتراضي لإدارة مخزون متجر الأحذية. كما هو الحال مع أي تطبيق .NET جديد ، سنحتاج إلى إنشاء حل ثم إضافة مشروع إليه. يمكننا الاستفادة من أدوات .NET SDK CLI لدعم حلنا الجديد:
mkdir Shoestore && cd Shoestore dotnet new sln
بعد ذلك ، قم بإنشاء مشروع ASP.NET يحتوي على فئة رئيسية صريحة من أجل البساطة ، حيث أن بنية المشروع هذه مألوفة لمطوري ASP.NET. لنقم بإنشاء مشروعنا باستخدام نمط MVC:
mkdir Shoestore.mvc && cd Shoestore.mvc dotnet new mvc --use-program-main=true
بعد ذلك ، أضف المشروع إلى الحل:
# Go to the root of the solution cd .. dotnet sln add Shoestore.mvc/
لدينا الآن حل افتراضي ومشروع ASP.NET المضمن به. قبل المتابعة ، تأكد من أن كل شيء يبني:
cd Shoestore.mvc/ dotnet restore dotnet build
تشجع ممارسات التطوير الجيدة وضع الخدمات الأساسية ووقت تشغيل التطبيق في حاويات Docker لتحسين النشر وإمكانية النقل. لذلك ، دعونا ننشئ حاوية Docker بسيطة لدعم تطبيقنا.
قابلية التطبيق
تشير صور Docker عادةً إلى صورة Docker رئيسية أخرى كنقطة بداية مقبولة للمتطلبات الأساسية مثل نظام التشغيل والحلول الأساسية ، بما في ذلك قواعد البيانات. باتباع أفضل ممارسات Docker هذه ، أنشئ ملف Dockerfile وملف Docker Compose لتهيئة الخدمة المناسبة أثناء الرجوع إلى الصور الأصلية التي تنشرها Microsoft. سنستخدم مراحل Docker للحفاظ على صورتنا صغيرة. تسمح لنا المراحل باستخدام .NET SDK أثناء إنشاء تطبيقنا بحيث يكون وقت تشغيل ASP.NET مطلوبًا فقط أثناء تشغيل تطبيقنا.
قم Shoestore.mvc
بالمحتويات التالية:
# Shoestore\Shoestore.mvc\Dockerfile # Build stage FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /shoestore COPY Shoestore.mvc/*.csproj ./ # Restore project packages RUN dotnet restore COPY Shoestore.mvc/* ./ # Create a release build RUN dotnet build -c Release -o /app/build # Run the application and make it available on port 80 FROM mcr.microsoft.com/dotnet/aspnet:6.0 WORKDIR /app EXPOSE 80 # Assets and views COPY Shoestore.mvc/Views ./Views COPY Shoestore.mvc/wwwroot ./wwwroot COPY --from=build /app/build ./ ENTRYPOINT [ "dotnet", "Shoestore.mvc.dll" ]
بعد ذلك ، سننشئ ملف docker-compose.yml
في الدليل الجذر للحل الخاص بنا. في البداية ، سيحتوي فقط على إشارة إلى .Dockerfile
الخاص بخدمة التطبيق:
# Shoestore/docker-compose.yml version: "3.9" services: web: build: context: . dockerfile: Shoestore.mvc/Dockerfile ports: - "8080:80"
لنقم أيضًا بتهيئة بيئتنا باستخدام ملف .dockerignore لضمان نسخ عناصر البناء فقط إلى صورتنا.
مع توقف خدمة التطبيق لدينا الآن وبيئة التنفيذ جاهزة للتشغيل ، نحتاج إلى إنشاء خدمة قاعدة البيانات الخاصة بنا وربطها بتكوين Docker الخاص بنا.
خدمة قاعدة البيانات
تعد إضافة Microsoft SQL Server إلى تكوين Docker الخاص بنا أمرًا مباشرًا ، خاصة وأننا نستخدم صورة Docker المقدمة من Microsoft دون تغييرها. أضف كتلة التكوين التالية إلى أسفل ملف docker-compose.yml
لتكوين قاعدة البيانات:
db: image: "mcr.microsoft.com/mssql/server" environment: SA_PASSWORD: "custom_password_123" ACCEPT_EULA: "Y" ports: - "1433:1433"
هنا ، يمنع ACCEPT_EULA
التثبيت من التوقف ، ويسمح إعداد ports
الخاص بنا لمنفذ SQL Server الافتراضي بالمرور دون ترجمة. مع ذلك ، يتضمن ملف Compose الخاص بنا كلاً من خدمة التطبيق وقاعدة البيانات الخاصة بنا.
قبل تخصيص رمز التطبيق ، دعنا نتحقق من عمل بيئة Docker الخاصة بنا:
# From the root of the solution docker compose up --build
بافتراض عدم ظهور أخطاء أثناء بدء التشغيل ، يجب أن يكون تطبيقنا النموذجي غير المكتمل متاحًا من خلال مستعرض ويب على العنوان المحلي http://localhost:8080
.
أدوات توليد الكود
الآن نركز على الجزء الممتع: تخصيص كود التطبيق والتأكد من استمرار بيانات التطبيق في قاعدة بيانات Microsoft SQL Server. سنستخدم كلاً من Entity Framework (EF) وأدوات .NET SDK لتوصيل التطبيق بقاعدة البيانات وسقالة نموذج التطبيق وطريقة العرض ووحدة التحكم والتكوين المطلوب لـ EF.
قبل أن نتمكن من تحديد الأدوات التي نحتاجها ، يجب علينا إنشاء ملف tool-manifest
:
# From the root of the solution dotnet new tool-manifest
أضف أدوات EF و SDK إلى هذا الملف باستخدام هذه الأوامر البسيطة:
dotnet tool install dotnet-ef dotnet tool install dotnet-aspnet-codegenerator
للتحقق من التثبيت الصحيح لهذه الأدوات ، قم بتشغيل dotnet ef
. إذا ظهر وحيد القرن ، فهذا يعني أنه تم تثبيته بشكل صحيح. بعد ذلك ، قم بتشغيل dotnet aspnet-codegenerator
لاختبار أدوات ASP.NET ؛ يجب أن يكون الناتج كتلة استخدام CLI عامة.
الآن يمكننا استخدام هذه الأدوات لإنشاء تطبيقنا.
MVC: نموذج
المهمة الأولى في بناء تطبيقنا هي إنشاء النموذج. نظرًا لأنه سيتم إضافة هذا النموذج إلى قاعدة البيانات لاحقًا ، فسنقوم بتضمين حزم MS SQL Server و EF في مشروعنا:
cd Shoestore.mvc/ dotnet add package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet add package Microsoft.EntityFrameworkCore.Tools dotnet restore
بعد ذلك ، قم بإنشاء كائن سياق قاعدة بيانات EF يحدد النماذج التي يتم إضافتها إلى قاعدة البيانات ، ويسمح لكودنا بالوصول بسهولة إلى تلك البيانات والاستعلام عنها من قاعدة البيانات.
قم بإنشاء دليل Data
لإيواء التعليمات البرمجية الخاصة بـ EF وإنشاء ملف Data/ApplicationDBContext.cs
بالمحتويات التالية:
// Shoestore/Shoestore.mvc/Data/ApplicationDBContext.cs using Microsoft.EntityFrameworkCore; namespace Shoestore.mvc.Data; public class ApplicationDBContext : DbContext { public ApplicationDBContext(DbContextOptions<ApplicationDBContext> options):base(options){} }
بعد ذلك ، قم بتكوين سلسلة اتصال قاعدة البيانات ، والتي يجب أن تتطابق مع بيانات الاعتماد التي قمنا بتكوينها في Dockerfile
بنا. قم بتعيين محتويات Shoestore/Shoestore.mvc/appsettings.json
على ما يلي:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "ConnectionStrings": { "Shoestore": "Server=db;Database=master;User=sa;Password=custom_password_123;" } }
مع تكوين سلسلة اتصال قاعدة البيانات وتشفير سياق قاعدة البيانات ، نحن على استعداد لتشفير الوظيفة Main
لتطبيقنا. سنقوم بتضمين معالجة استثناء قاعدة البيانات لتبسيط تصحيح أخطاء النظام. بالإضافة إلى ذلك ، نظرًا لأن خطأ .NET في الكود الذي تم إنشاؤه يتسبب في قيام حاوية Docker بخدمة طرق العرض الخاصة بنا بشكل غير صحيح ، فسنحتاج إلى إضافة رمز محدد إلى تكوين خدمة العرض لدينا. سيؤدي هذا بشكل صريح إلى تعيين مسارات الملفات إلى موقع العرض الخاص بنا في صورة Docker الخاصة بنا:
using Microsoft.EntityFrameworkCore; using Shoestore.mvc.Data; namespace Shoestore.mvc; // ... public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Associate our EF database context and configure it with our connection string var connectionString = builder.Configuration.GetConnectionString("Shoestore"); builder.Services.AddDbContext<ApplicationDBContext>( options => options.UseSqlServer(connectionString)); // Middleware to catch unhandled exceptions and display a stack trace builder.Services.AddDatabaseDeveloperPageExceptionFilter(); // Add services to the container. // ASP.NET has a known issue where the final built app doesn't know where the view // files are (in the Docker container). // The fix is to specifically add view locations. builder.Services .AddControllersWithViews() .AddRazorOptions(options => { options.ViewLocationFormats.Add("/{1}/{0}.cshtml"); options.ViewLocationFormats.Add("/Shared/{0}.cshtml"); });
انتقل إلى IsDevelopment
if
داخل نفس الملف لإضافة نقطة نهاية ترحيل قاعدة البيانات إلى نظامنا عندما يكون في وضع التطوير. أضف عبارة else
بالكود التالي:
// Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { // Leave the contents of the if block alone. These are hidden for clarity. } else { app.UseMigrationsEndPoint(); }
بعد ذلك ، قم بإجراء اختبار سريع للتأكد من تجميع الحزم الجديدة وتعديلات التعليمات البرمجية المصدر بشكل صحيح:
// Go to mvc directory cd Shoestore.mvc dotnet restore dotnet build
الآن ، دعنا نملأ النموذج بالحقول المطلوبة عن طريق إنشاء ملف Shoestore.mvc\Models\Shoe.cs
:
namespace Shoestore.mvc.Models; public class Shoe { public int ID { get; set; } public string? Name { get; set; } public int? Price { get; set; } public DateTime CreatedDate { get; set; } }
تنشئ EF SQL بناءً على النموذج المرتبط وملف السياق وأي كود EF في تطبيقنا. ثم يتم ترجمة نتائج SQL وإعادتها إلى التعليمات البرمجية الخاصة بنا ، حسب الحاجة. إذا أضفنا نموذج Shoe
الخاص بنا إلى سياق قاعدة البيانات الخاصة بنا ، فستعرف EF كيفية الترجمة بين MS SQL Server وتطبيقنا. لنفعل ذلك في ملف سياق قاعدة البيانات ، Shoestore/Shoestore.mvc/Data/ApplicationDBContext.cs
:
using Microsoft.EntityFrameworkCore; using Shoestore.mvc.Models; namespace Shoestore.mvc.Data; public class ApplicationDBContext : DbContext { public ApplicationDBContext(DbContextOptions<ApplicationDBContext> options) : base(options) { } private DbSet<Shoe>? _shoe { get; set; } public DbSet<Shoe> Shoe { set => _shoe = value; get => _shoe ?? throw new InvalidOperationException("Uninitialized property" + nameof(Shoe)); } }
أخيرًا ، سنستخدم ملف ترحيل قاعدة البيانات لإدخال نموذجنا في قاعدة البيانات. تنشئ أداة EF ملف ترحيل خاص بـ MS SQL Server بناءً على سياق قاعدة البيانات والنموذج المرتبط بها (على سبيل المثال ، Shoe
):
cd Shoestore.mvc/ dotnet ef migrations add InitialCreate
دعنا نتوقف عن تشغيل الترحيل لدينا حتى يكون لدينا وحدة تحكم وعرض في مكانها.
MVC: تحكم وعرض
سنقوم بإنشاء وحدة التحكم الخاصة بنا باستخدام أداة إنشاء رمز ASP.NET. هذه الأداة قوية جدًا ولكنها تتطلب فئات مساعدة محددة. استخدم حزم نمط Design
لبنية وحدة التحكم الأساسية وتكامل EF الخاص بها. دعنا نضيف هذه الحزم:
cd Shoestore.mvc\ dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design && \ dotnet add package Microsoft.EntityFrameworkCore.Design && \ dotnet restore
الآن ، يعد إنشاء وحدة التحكم الافتراضية الخاصة بنا أمرًا بسيطًا مثل استدعاء الأمر التالي:
cd Shoestore.mvc\ dotnet dotnet-aspnet-codegenerator controller \ -name ShoesController \ -m Shoe \ -dc ApplicationDBContext \ --relativeFolderPath Controllers \ --useDefaultLayout \ --referenceScriptLibraries
عندما ينشئ مُنشئ الكود وحدة التحكم الخاصة بنا ، فإنه ينشئ أيضًا عرضًا بسيطًا لوحدة التحكم هذه. مع اكتمال أسس MVC الخاصة بنا ، نحن على استعداد لتشغيل كل شيء.
اختبار الهجرة والتطبيق
عادةً ما تكون عمليات ترحيل EF أمرًا بسيطًا ، ولكن عندما يشارك Docker ، تصبح العملية أكثر تعقيدًا. في المقالة التالية في سلسلتنا ، سنستكشف المسار الملتوي الرائع لجعل عمليات الترحيل هذه تعمل في حل Docker الخاص بنا ، ولكن في الوقت الحالي ، نريد فقط تشغيل عملية الترحيل.
يتم تضمين جميع ملفات التكوين والترحيل في مستودعنا. لنقم باستنساخ المشروع بالكامل على أجهزتنا المحلية وإجراء الترحيل:
git clone https://github.com/theZetrax/dot-net-on-linux.git cd ./dot-net-on-linux docker composer up
تقوم عملية docker composer
ببناء تطبيقنا وتشغيل الترحيل وتشغيل تطبيق ASP.NET الخاص بنا مع وقت تشغيل .NET. للوصول إلى حل التشغيل ، تفضل بزيارة http://localhost:8080/Shoes
.
على الرغم من أن واجهة التطبيق الخاصة بنا بسيطة ، إلا أنها توضح الوظائف من خلال جميع المستويات ، من العرض وصولاً إلى قاعدة البيانات.
.NET على Linux يعمل فقط
راجع المستودع الكامل للحصول على نظرة عامة على الحل الذي نقدمه. ستغطي المقالة التالية ترحيلنا بالتفصيل ، بالإضافة إلى النصائح والحيل لجعل صور Docker الخاصة بنا ضعيفة.
يعد .NET على Linux أكثر من مجرد حلم بعيد المنال: إنه مزيج من اللغة ووقت التشغيل ونظام التشغيل. قد لا يكون لدى العديد من المطورين الذين نشأوا في Visual Studio خبرة في استخدام .NET CLI على أكمل وجه ، ولكن هذه الأدوات فعالة وقوية.
مزيد من القراءة على مدونة Toptal Engineering:
- بناء واجهة برمجة تطبيقات ويب ASP.NET مع ASP.NET Core
- 8 أسباب لماذا لا يزال Microsoft Stack خيارًا قابلاً للتطبيق
- كيفية تحسين أداء تطبيق ASP.NET في Web Farm باستخدام التخزين المؤقت
- برنامج تعليمي Elasticsearch لمطوري .NET
- ما هو Kubernetes؟ دليل الحاوية والنشر
تعرب مدونة Toptal Engineering عن امتنانها لـ Henok Tsegaye لمراجعة عينات التعليمات البرمجية المقدمة في هذه المقالة.