NET Fundamentals (مینیمال API)

Summarize this content to 400 words in Persian Lang
🔍 دات نت چیست
دات نت (تلفظ “دات نت”) یک پلت فرم برنامه رایگان و متن باز است. پشتیبانی مایکروسافت و به روز رسانی های منظم و ویژگی های جدید چیزی است که این ابزار را بسیار مفید می کند. می توان از آن برای موارد مختلف استفاده کرد مانند:
برنامه های موبایل
برنامه های دسکتاپ
میکروسرویس ها
توسعه بازی
فراگیری ماشین
توسعه وب
در این مقاله میخواهم روی توسعه وب و مهمترین چیزهایی که هنگام ساخت اولین برنامه وب خود به آن نیاز دارید تمرکز کنم. کاملاً صادقانه بگویم، من فقط جنبه API را پوشش خواهم داد، زیرا می دانم که Blazor همچنین می تواند یک ظاهر یکپارچه برای وب سایت شما ارائه دهد. (یادداشت جانبی، من معمولاً با Angular برای قسمتهای جلویی خود میروم – اگر میخواهید در مورد آن نیز بنویسم، به من اطلاع دهید)
🆚 حداقل API ها در مقابل کنترلر
کنترلکنندههای سنتی از الگوی MVC (Model-View-Controller) پیروی میکنند تا نگرانیها را همانطور که باید از هم جدا کنند. آنها از قراردادهای معمول پیروی می کنند و ساختار بسیار خوبی دارند. از آنجایی که آنها در بیشتر زمان ما تنها راه بودند، واضح است که اکثر برنامه ها از این روش برای نوشتن API استفاده می کنند.
public class HelloController : ControllerBase
{
[HttpGet(“hello”)]
public IActionResult GetHello()
{
return Ok(“Hello World!”);
}
[HttpPost(“echo”)]
public IActionResult Echo([FromBody] string message)
{
return Ok(message);
}
}
API های حداقل در NET 6 برای ساده سازی ایجاد API در دات نت معرفی شدند. نحو مختصرتر است، boilerplate کمتری وجود دارد و شما هنوز هم می توانید بیشتر کارهایی را که می توانید با کنترلرها انجام دهید (در NET 8) انجام دهید. از آنجایی که مایکروسافت به شدت روی برابری ویژگیهای حداقل API کار میکند، فرض میکنم که در آینده، این روش ترجیحی برای ساختن APIها از ابتدا خواهد بود – اما این ممکن است فقط من باشم.
…
app.MapGet(“/hello”, () => “Hello World!”);
app.MapPost(“/echo”, (string message) => Results.Ok(message));
…
فکر میکنم مثالها در حال حاضر بسیار گویا هستند و نیازی به ذکر نیست، که یکی از آنها بیشتر به نظر میرسد حداقل نسبت به دیگری، آیا من؟
🖥️ .NET Cli
برای شروع یک برنامه جدید، باید .NET SDK (کیت توسعه نرم افزار) را نصب کنید و NET CLI را نصب کنید. برای ایجاد یک برنامه جدید اجرا کنید dotnet new web -o [Project Name] و آن را با ویرایشگر / IDE انتخابی باز کنید. من JetBrains Rider را توصیه می کنم، اما اگر می خواهید با نرم افزار رایگان بروید، می توانید از Visual Studio یا Visual Studio Code با برخی پسوندها نیز استفاده کنید. شما می خواهید مراقب باشید Program.cs که نقطه ورود درخواست شماست.
محتوا را بررسی کنید و باید تا حدودی شبیه به این باشد:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet(“/hello”, () => “Hello World!”);
app.Run();
ایجاد یک builder همچنین می تواند مواردی مانند Dependency Injection، اتصالات پایگاه داده، احراز هویت و مجوز و همچنین بسیاری از موارد دیگر را که بعداً در مورد آنها صحبت خواهم کرد، انجام دهد. همانطور که می بینید یک Endpoint برای آن تعریف شده است /hello. اگر برنامه را از طریق IDE (یا NET CLI) اجرا کنیم dotnet run) API منتظر تماس است. سعی کنید تماس بگیرید http://localhost:5292/hello (بررسی /Properties/launchSettings.json پروژه خود را ببینید تا ببینید روی چه پورتی در حال اجرا هستید) در مرورگر خود، و باید پیام “Hello World” را روی صفحه نمایش خود دریافت کنید.
با استفاده از آن می توانید تمام گزینه های دات نت CLI را بررسی کنید dotnet –help در ترمینال شما بیشتر دستورات توسط IDE شما انجام می شود، اما اگر علاقه مند هستید می توانید آنها را از ترمینال نیز اجرا کنید.
📋 اعتبار سنجی
همانطور که در نمونههای قبلی مشاهده کردید، آن APIها واقعاً هستند حداقل. بیایید نگاهی دقیقتر به نقطه پایانی داشته باشیم که درخواست مسیر GET /colorSelector/ را نیز تأیید میکند.
string ColorName(string color) => $”Color specified: {color}!”;
app.MapGet(“/colorSelector/{color}”, ColorName)
.AddEndpointFilter(async (invocationContext, next) =>
{
var color = invocationContext.GetArgument<string>(0);
if (color == “Red”)
{
return Results.Problem(“Red not allowed!”);
}
return await next(invocationContext);
});
همانطور که می بینید، ما مسیر را به عنوان اولین پارامتر تعریف کردیم app.MapGet() و همچنین با قرار دادن پرانتزهای فرفری در اطراف آن و مطابقت با نام، رنگ مشخص شده را به تابع ما نگاشت. اعتبار سنجی با یک فیلتر نقطه پایانی ساخته می شود که فراخوانی نقطه پایانی را برای آرگومان بررسی می کند، سپس بررسی می کند (در این مورد رنگ مجاز نیست قرمز باشد، زیرا قرمز بد است) و فراخوانی می کند. next بنابراین فیلترهای دیگر نیز می توانند اجرا شوند. یک فیلتر همیشه یک اعتبارسنجی نیست، اما گاهی اوقات فقط درخواستها را ثبت میکند، یا یک ورودی برای آمار اضافه میکند یا اثر دیگری را انجام میدهد که باید در هر تماس نقطه پایانی اتفاق بیفتد.
🧭 مسیریابی
در بسیاری از موارد می خواهید چندین نقطه پایانی را خوشه بندی کنید. دلایل می تواند این باشد که می خواهید از یک فیلتر روی همه آنها استفاده کنید یا از مجوز یکسانی برای آنها استفاده کنید یا فقط نمی خواهید مسیر را چندین بار بنویسید. در این حالت می توانیم چندین مسیر را مانند این گروه بندی کنیم
var user = app.MapGroup(“/user”);
var admin = user.MapGroup(“/admin”);
admin.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation(“/admin group filter”);
return next(context);
});
user.MapGet(“/”, () => “Hello!”);
admin.MapGet(“/”, () => “Hi!”).AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation(“Admin route was called.”);
return next(context);
});
این به سازماندهی مسیرها و نقاط پایانی مختلف و همچنین کاهش تکرار کمک می کند. همچنین به شما این امکان را میدهد که نقاط پایانی خود را در پوشهها یا فایلهای خارج از Program.cs بدون از دست دادن ردیابی یک فایل دستهبندی کنید.
💉 تزریق وابستگی (مثلا پایگاه داده) و پیکربندی
برای کاهش پیچیدگی نقطه پایانی، می توانید خدمات را به نقاط پایانی API خود تزریق کنید. بیشتر شما می خواهید منطقی را در سرویس ها استخراج کنید تا بتوانید دوباره از آنها استفاده کنید. در این مثال من یک پایگاه داده در پروژه خود راه اندازی کرده و DbContext را در نقطه پایانی خود تزریق می کنم
Program.cs
using Microsoft.EntityFrameworkCore;
using backend.ShopDbContext;
var builder = WebApplication.CreateBuilder(args);
string? connectionString = builder.Configuration.GetConnectionString(“DefaultConnection”);
builder.Services.AddDbContext<ShopDbContext>(opt => opt.UseNpgsql(connectionString));
var app = builder.Build();
using (var Scope = app.Services.CreateScope())
{
var context = Scope.ServiceProvider.GetRequiredService<ShopDbContext>();
context.Database.Migrate();
}
app.MapGet(“/”, async (ShopDbContext ctx) =>
{
var prod = await ctx.Products.FirstOrDefaultAsync();
return prod;
});
app.Run();
Appsettings.json
{
“ConnectionStrings”: {
“DefaultConnection”: “Server=localhost; Port=5432; Database=postgres; Username=postgres; Password=MYPASSWORD;”
}
}
برای استفاده از Npgsql من یک بسته Nuget را نصب کردم که با EF-Core کار می کند و از پایگاه داده PostreSQL پشتیبانی می کند. کد رشته اتصال ارائه شده در پیکربندی (Appsettings.json) را در شی استخراج می کند. ConnectionStrings. برای تنظیم پایگاه داده برای مطابقت با طرحی که در کد تعریف شده است، باید طرح را با تماس اعمال کنید. Database.Migrate() بنابراین من این کار را در شروع برنامه انجام می دهم.
اکنون Endpoint ShopDbContext را به صورت جادویی تزریق می کند (شما می توانید آن را با استفاده از [FromServices] ویژگی) و اولین عنصر را می گیرد که نمونه ای نسبتاً بی فایده است. به احتمال زیاد می خواهید همه را برگردانید یا شناسه ورودی را که می خواهید دریافت کنید مشخص کنید و آن را در پایگاه داده جستجو کنید.
🙏🏽 با تشکر
اگر این مقاله را تا آخر بخوانید بسیار سپاسگزارم! اگر سوالی دارید کامنت بگذارید، خوشحال می شوم بلافاصله پاسخ دهم. اگر خجالتی هستید میتوانید مستقیماً در GitHub، Instagram یا TikTok به من پیام دهید.
🔍 دات نت چیست
دات نت (تلفظ “دات نت”) یک پلت فرم برنامه رایگان و متن باز است. پشتیبانی مایکروسافت و به روز رسانی های منظم و ویژگی های جدید چیزی است که این ابزار را بسیار مفید می کند. می توان از آن برای موارد مختلف استفاده کرد مانند:
- برنامه های موبایل
- برنامه های دسکتاپ
- میکروسرویس ها
- توسعه بازی
- فراگیری ماشین
- توسعه وب
در این مقاله میخواهم روی توسعه وب و مهمترین چیزهایی که هنگام ساخت اولین برنامه وب خود به آن نیاز دارید تمرکز کنم. کاملاً صادقانه بگویم، من فقط جنبه API را پوشش خواهم داد، زیرا می دانم که Blazor همچنین می تواند یک ظاهر یکپارچه برای وب سایت شما ارائه دهد. (یادداشت جانبی، من معمولاً با Angular برای قسمتهای جلویی خود میروم – اگر میخواهید در مورد آن نیز بنویسم، به من اطلاع دهید)
🆚 حداقل API ها در مقابل کنترلر
کنترلکنندههای سنتی از الگوی MVC (Model-View-Controller) پیروی میکنند تا نگرانیها را همانطور که باید از هم جدا کنند. آنها از قراردادهای معمول پیروی می کنند و ساختار بسیار خوبی دارند. از آنجایی که آنها در بیشتر زمان ما تنها راه بودند، واضح است که اکثر برنامه ها از این روش برای نوشتن API استفاده می کنند.
public class HelloController : ControllerBase
{
[HttpGet("hello")]
public IActionResult GetHello()
{
return Ok("Hello World!");
}
[HttpPost("echo")]
public IActionResult Echo([FromBody] string message)
{
return Ok(message);
}
}
API های حداقل در NET 6 برای ساده سازی ایجاد API در دات نت معرفی شدند. نحو مختصرتر است، boilerplate کمتری وجود دارد و شما هنوز هم می توانید بیشتر کارهایی را که می توانید با کنترلرها انجام دهید (در NET 8) انجام دهید. از آنجایی که مایکروسافت به شدت روی برابری ویژگیهای حداقل API کار میکند، فرض میکنم که در آینده، این روش ترجیحی برای ساختن APIها از ابتدا خواهد بود – اما این ممکن است فقط من باشم.
...
app.MapGet("/hello", () => "Hello World!");
app.MapPost("/echo", (string message) => Results.Ok(message));
...
فکر میکنم مثالها در حال حاضر بسیار گویا هستند و نیازی به ذکر نیست، که یکی از آنها بیشتر به نظر میرسد حداقل نسبت به دیگری، آیا من؟
🖥️ .NET Cli
برای شروع یک برنامه جدید، باید .NET SDK (کیت توسعه نرم افزار) را نصب کنید و NET CLI را نصب کنید. برای ایجاد یک برنامه جدید اجرا کنید dotnet new web -o [Project Name]
و آن را با ویرایشگر / IDE انتخابی باز کنید. من JetBrains Rider را توصیه می کنم، اما اگر می خواهید با نرم افزار رایگان بروید، می توانید از Visual Studio یا Visual Studio Code با برخی پسوندها نیز استفاده کنید. شما می خواهید مراقب باشید Program.cs
که نقطه ورود درخواست شماست.
محتوا را بررسی کنید و باید تا حدودی شبیه به این باشد:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/hello", () => "Hello World!");
app.Run();
ایجاد یک builder
همچنین می تواند مواردی مانند Dependency Injection، اتصالات پایگاه داده، احراز هویت و مجوز و همچنین بسیاری از موارد دیگر را که بعداً در مورد آنها صحبت خواهم کرد، انجام دهد. همانطور که می بینید یک Endpoint برای آن تعریف شده است /hello
. اگر برنامه را از طریق IDE (یا NET CLI) اجرا کنیم dotnet run
) API منتظر تماس است. سعی کنید تماس بگیرید http://localhost:5292/hello
(بررسی /Properties/launchSettings.json
پروژه خود را ببینید تا ببینید روی چه پورتی در حال اجرا هستید) در مرورگر خود، و باید پیام “Hello World” را روی صفحه نمایش خود دریافت کنید.
با استفاده از آن می توانید تمام گزینه های دات نت CLI را بررسی کنید dotnet --help
در ترمینال شما بیشتر دستورات توسط IDE شما انجام می شود، اما اگر علاقه مند هستید می توانید آنها را از ترمینال نیز اجرا کنید.
📋 اعتبار سنجی
همانطور که در نمونههای قبلی مشاهده کردید، آن APIها واقعاً هستند حداقل. بیایید نگاهی دقیقتر به نقطه پایانی داشته باشیم که درخواست مسیر GET /colorSelector/ را نیز تأیید میکند.
string ColorName(string color) => $"Color specified: {color}!";
app.MapGet("/colorSelector/{color}", ColorName)
.AddEndpointFilter(async (invocationContext, next) =>
{
var color = invocationContext.GetArgument<string>(0);
if (color == "Red")
{
return Results.Problem("Red not allowed!");
}
return await next(invocationContext);
});
همانطور که می بینید، ما مسیر را به عنوان اولین پارامتر تعریف کردیم app.MapGet()
و همچنین با قرار دادن پرانتزهای فرفری در اطراف آن و مطابقت با نام، رنگ مشخص شده را به تابع ما نگاشت. اعتبار سنجی با یک فیلتر نقطه پایانی ساخته می شود که فراخوانی نقطه پایانی را برای آرگومان بررسی می کند، سپس بررسی می کند (در این مورد رنگ مجاز نیست قرمز باشد، زیرا قرمز بد است) و فراخوانی می کند. next
بنابراین فیلترهای دیگر نیز می توانند اجرا شوند. یک فیلتر همیشه یک اعتبارسنجی نیست، اما گاهی اوقات فقط درخواستها را ثبت میکند، یا یک ورودی برای آمار اضافه میکند یا اثر دیگری را انجام میدهد که باید در هر تماس نقطه پایانی اتفاق بیفتد.
🧭 مسیریابی
در بسیاری از موارد می خواهید چندین نقطه پایانی را خوشه بندی کنید. دلایل می تواند این باشد که می خواهید از یک فیلتر روی همه آنها استفاده کنید یا از مجوز یکسانی برای آنها استفاده کنید یا فقط نمی خواهید مسیر را چندین بار بنویسید. در این حالت می توانیم چندین مسیر را مانند این گروه بندی کنیم
var user = app.MapGroup("/user");
var admin = user.MapGroup("/admin");
admin.AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("/admin group filter");
return next(context);
});
user.MapGet("/", () => "Hello!");
admin.MapGet("/", () => "Hi!").AddEndpointFilter((context, next) =>
{
app.Logger.LogInformation("Admin route was called.");
return next(context);
});
این به سازماندهی مسیرها و نقاط پایانی مختلف و همچنین کاهش تکرار کمک می کند. همچنین به شما این امکان را میدهد که نقاط پایانی خود را در پوشهها یا فایلهای خارج از Program.cs بدون از دست دادن ردیابی یک فایل دستهبندی کنید.
💉 تزریق وابستگی (مثلا پایگاه داده) و پیکربندی
برای کاهش پیچیدگی نقطه پایانی، می توانید خدمات را به نقاط پایانی API خود تزریق کنید. بیشتر شما می خواهید منطقی را در سرویس ها استخراج کنید تا بتوانید دوباره از آنها استفاده کنید. در این مثال من یک پایگاه داده در پروژه خود راه اندازی کرده و DbContext را در نقطه پایانی خود تزریق می کنم
Program.cs
using Microsoft.EntityFrameworkCore;
using backend.ShopDbContext;
var builder = WebApplication.CreateBuilder(args);
string? connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ShopDbContext>(opt => opt.UseNpgsql(connectionString));
var app = builder.Build();
using (var Scope = app.Services.CreateScope())
{
var context = Scope.ServiceProvider.GetRequiredService<ShopDbContext>();
context.Database.Migrate();
}
app.MapGet("/", async (ShopDbContext ctx) =>
{
var prod = await ctx.Products.FirstOrDefaultAsync();
return prod;
});
app.Run();
Appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost; Port=5432; Database=postgres; Username=postgres; Password=MYPASSWORD;"
}
}
برای استفاده از Npgsql من یک بسته Nuget را نصب کردم که با EF-Core کار می کند و از پایگاه داده PostreSQL پشتیبانی می کند. کد رشته اتصال ارائه شده در پیکربندی (Appsettings.json) را در شی استخراج می کند. ConnectionStrings
. برای تنظیم پایگاه داده برای مطابقت با طرحی که در کد تعریف شده است، باید طرح را با تماس اعمال کنید. Database.Migrate()
بنابراین من این کار را در شروع برنامه انجام می دهم.
اکنون Endpoint ShopDbContext را به صورت جادویی تزریق می کند (شما می توانید آن را با استفاده از [FromServices]
ویژگی) و اولین عنصر را می گیرد که نمونه ای نسبتاً بی فایده است. به احتمال زیاد می خواهید همه را برگردانید یا شناسه ورودی را که می خواهید دریافت کنید مشخص کنید و آن را در پایگاه داده جستجو کنید.
🙏🏽 با تشکر
اگر این مقاله را تا آخر بخوانید بسیار سپاسگزارم! اگر سوالی دارید کامنت بگذارید، خوشحال می شوم بلافاصله پاسخ دهم. اگر خجالتی هستید میتوانید مستقیماً در GitHub، Instagram یا TikTok به من پیام دهید.