مطالب
نگاهی به تغییرات فایل Program.cs در نگارش‌های مختلف ASP.NET Core تا نگارش 6
در طی سال‌های قبل، نحوه‌ی آغاز برنامه‌های ASP.NET Core دچار تغییرات زیادی شده‌است که حداقل سه مورد مهم آن‌ها به صورت زیر است:
- استفاده از WebHost.CreateDefaultBuilder: این روش جهت تنظیم شروع به کار یک برنامه‌ی ASP.NET Core 2x مورد استفاده قرار می‌گرفت.
- استفاده از Host.CreateDefaultBuilder: روش پیش‌فرض آغاز برنامه‌های وب NET Core 3x. و NET 5x. که با معرفی generic host، امکان تهیه‌ی Worker services را میسر کردند.
- استفاده از WebApplication.CreateBuilder: روش جدید شروع به کار با برنامه‌های وب مبتنی بر NET 6.


استفاده از WebHost.CreateDefaultBuilder در ASP.NET Core 2.x

در نگارش اول ASP.NET Core، مفهومی به نام هاست پیش‌فرض (default host) وجود نداشت. یکی از مهم‌ترین نکات درنظر گرفته شده در طراحی ASP.NET Core، مفهوم «هزینه کردن به ازای احتیاج» است. یعنی اگر نیاز به قابلیتی نیست، نباید وجود داشته باشد. به این ترتیب یک قالب آغازین نباید به همراه تعداد زیادی بسته‌‌های NuGet و مقدار زیادی کد برای تنظیم باشد؛ زمانیکه واقعا قرار نیست از تمام آن‌ها استفاده شود. به همین جهت از نگارش 2، شروع به ساده‌کردن این قالب اولیه کردند و در این زمان، WebHost.CreateDefaultBuilder ارائه شد. این تنظیم به ظاهر ساده، کدهای پیش‌فرض مورد نیاز قابل توجهی را جهت ساخت ساده‌ی IWebHostBuilder و IWebHost به همراه دارد. در قالب به همراه آن، بین مفاهیم تنظیمات application و host تفاوت قائل شده‌اند؛ یعنی دو فایل Program.cs را برای تنظیمات application و فایل Startup.cs را برای ارائه‌ی تنظیمات هاست، تدارک دیدند.
در این طراحی، بین میدان دید Program و Startup تفاوت وجود دارد. هدف از Program، ارائه‌ی تنظیمات زیرساختی برنامه، مانند تنظیمات HTTP Server، یکپارچگی با IIS و امثال آن شد و عموما در طول عمر برنامه ثابت است. اما برای تغییر رفتار برنامه، بیشتر تغییرات و تنظیمات، به Startup محول شدند؛ مانند تنظیمات تزریق وابستگی‌ها، تنظیمات میان‌افزارها، مسیریابی‌ها و غیره.
public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

     public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
}
نمونه‌ا‌ی از فایل Program.cs برنامه‌های ASP.NET Core 2x را در اینجا ملاحظه می‌کنید این تنظیم ساده، کار خواندن فایل appsettings.json و برپایی تنظیمات برنامه، تنظیمات logging و همچنین تنظیمات یکپارچگی با Kestrel/IIS را در پشت صحنه انجام می‌دهد. همچنین ارجاعی را نیز به کلاس Startup برنامه دارد. متد UseStartup به صورت خودکار به دنبال متدهای ویژه‌ی ConfigureServices و Configure در کلاس آغازین برنامه گشته و آن‌ها را فراخوانی می‌کند تا تنظیمات تزریق وابستگی‌ها، مسیریابی‌ها و میان‌افزارها صورت گیرند.


معرفی Generic Host در ASP.NET Core 3.x/5

ASP.NET Core 3.x به همراه تغییرات بزرگی در کدهای آغازین برنامه‌های ASP.NET Core بود. تا پیش از آن، امکانات پایه‌ی ASP.NET Core تنها برای مقاصد وب قابل استفاده بود. اما در نگارش‌های 3x، با ارائه‌ی یک هاست عمومی، امکان پشتیبانی از سایر برنامه‌ها، مانند worker services را نیز میسر کرد؛ برای مثال پیشتیبانی از کارهای طولانی پس زمینه، هاست سرویس‌های gRPC، هاست سرویس‌های ویندوز و غیره. هدف اصلی از این تغییرات، به اشتراک گذاری فریم‌ورک پایه‌ی ASP.NET Core که تنها برای برنامه‌های وب ساخته شده بود و به همراه امکاناتی مانند تنظیمات، ثبت وقایع، تزریق وابستگی‌ها و غیره بود، با سایر انواع برنامه‌های یاد شده است. برای رسیدن به این هدف، Web Host نگارش 2x، به Generic Host نگارش 3x تغییر کرد و سپس ASP.NET Core برفراز آن بنا شد. اینبار بجای IWebHostBuilder، نمونه‌ی جدید IHostBuilder را داریم:
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>();
            }; 
    }
}
در اینجا نمونه‌ا‌ی از فایل Program.cs برنامه‌های ASP.NET Core 3x را ملاحظه می‌کنید. با توجه به عمومی بودن این روش، قسمت ConfigureWebHostDefaults آن، همان کار WebHost.CreateDefaultBuilder نگارش 2 ASP.NET Core را انجام می‌دهد.
ASP.NET Core 5 به همراه تغییرات مهمی در این زمینه نبود و تنها با تغییر target framework در فایل csproj و به روز رسانی بسته‌های نیوگت مرتبط، کار ارتقاء به نگارش جدید در آن صورت می‌گرفت.


معرفی  WebApplicationBuilder در ASP.NET Core 6x  

در دات نت 6، روش آغاز برنامه‌های وب بطور کامل تغییر کرده‌است. در تمام نگارش‌های پیشین ASP.NET Core، همواره شاهد دو فایل Program.cs و Startup.cs بودیم؛ اما در اینجا فقط یک فایل Program.cs بیشتر وجود ندارد. هر چند همانطور که در مطلب «ارتقاء فایل‌های آغازین برنامه‌های ASP.NET Core 5x به 6x» نیز عنوان شد، می‌توان همان سبک و سیاق پیشین را نیز برگرداند و از این لحاظ محدودیتی وجود ندارد.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
   app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.MapGet("/", () => "Hello World!");
app.MapRazorPages();
app.Run();
در اینجا نمونه‌ای از فایل Program.cs برنامه‌های دات نت 6 را مشاهده می‌کنید که تغییرات قابل ملاحظه‌ای داشته‌است:
- استفاده از top level statements
- استفاده از usingهای سراسری و سایر قابلیت‌های C# 10.0
- حذف کامل کلاس Startup؛ اینبار همه چیز فقط یک فایل است.

دیدگاهی را که در اینجا بکار گرفته‌اند شامل این موارد است و بیشتر تازه‌واردان را مدنظر دارند:
- برای شروع به کار، using statements اضافی هستند؛ پس حذف شده‌اند!
- برای شروع به کار، namespaces اضافی هستند؛ پس حذف شده‌اند!
- برای شروع به کار، Program.Main ... هم اضافی است!
- تنظیمات بین دو فایل Program.cs و Startup.cs تقیسم نشده‌اند و همه‌چیز یکجا است و این هم نیازی به توضیح اضافی به تازه‌واردان، ندارد.
- همچنین همانطور که عنوان شد، « ... متد UseStartup به صورت خودکار به دنبال متدهای ویژه‌ی ConfigureServices و Configure در کلاس آغازین برنامه گشته و آن‌ها را فراخوانی می‌کند تا تنظیمات تزریق وابستگی‌ها، مسیریابی‌ها و میان‌افزارها صورت گیرند ...»
نکته‌ی مهم این توضیح، این است که کلاس Startup، هیچ اینترفیسی را پیاده سازی نمی‌کند. یعنی نام این متدها، دقیقا باید به همین صورت باشند (بدون اینکه قرار دادی توسط یک اینترفیس برای آن‌ها وضع شده باشد) و ... چرا واقعا باید به این صورت باشد؟! به همین جهت این‌ها هم حذف شده‌اند!
- در اینجا WebApplication هم مشاهده می‌شود؛ اما آیا واقعا نیازی به آن است؟
پاسخ: خیر! WebApplication.CreateBuilder ای که در اینجا ملاحظه می‌کنید در حقیقت ساده شده‌ی قطعه کد زیر از کدهای ASP.NET Core 3x/5x است:
var hostBuilder = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services => 
    {
        services.AddRazorPages();
    })
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.Configure((ctx, app) => 
        {
            if (ctx.HostingEnvironment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseStaticFiles();
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", () => "Hello World!");
                endpoints.MapRazorPages();
            });
        });
    }); 
hostBuilder.Build().Run();
که ... WebApplication.CreateBuilder بدون شک ساده‌تر از قطعه کد فوق است. همچنین پس از یک سطر زیر:
 var builder = WebApplication.CreateBuilder(args);
با استفاده از خاصیت builder.Configuration، می‌توان به تنظیمات برنامه دسترسی یافت و یا با استفاده از builder.Services می‌توان سرویس‌های جدیدی را ثبت کرد:
builder.Services.AddRazorPages();
builder.Services.AddSingleton<MyThingy>();
و یا با استفاده از خاصیت builder.Logging می‌توان تنظیمات ثبت وقایع برنامه را تغییر داد:
builder.Logging.AddFile();
همچنین در اینجا زمانیکه کار تنظیمات به پایان رسید، نمونه‌ای از WebApplication را به صورت زیر تولید کرده:
var app = builder.Build();
و اکنون می‌توان تنظیمات میان‌افزارها و یا مسیریابی‌ها را انجام داد:
app.UseStaticFiles();
app.MapRazorPages();
که در مقایسه با نگارش‌های قبلی، بسیار ساده‌تر شده‌، هرچند مرز بین این‌ها و ترتیب آن‌ها اندکی کم‌رنگ‌تر شده‌است.
اشتراک‌ها
جلسه پرسش و پاسخ در مورد آینده‌ی ASP.NET Core و Blazor

ASP.NET Core and Blazor futures Q&A | DIS201H

#MSBuild

Join us for a discussion on the future of web development with the ASP.NET Core team. Get the team's perspective first-hand on the roadmap for ASP.NET Core and Blazor in .NET 8 and get all of your burning questions answered. We discuss Blazor, Native AOT, cloud native development, and anything else that you want to ask us about. 

جلسه پرسش و پاسخ در مورد آینده‌ی ASP.NET Core و Blazor
اشتراک‌ها
مدیریت مباحث همزمانی مرتبط با یک Rich Domain Model با استفاده از EFCore و الگوی Aggregate

In summary, the most important issues here are:

  • The Aggregate’s main task is to protect invariants (business rules, the boundary of immediate consistency)
  • In a multi-threaded environment, when multiple threads are running simultaneously on the same Aggregate, a business rule may be broken
  • A way to solve concurrency conflicts is to use Pessimistic or Optimistic concurrency techniques
  • Pessimistic Concurrency involves the use of a database transaction and a locking mechanism. In this way, requests are processed one after the other, so basically concurrency is lost and it can lead to deadlocks.
  • Optimistic Concurrency technique is based on versioning database records and checking whether the previously loaded version has not been changed by another thread.
  • Entity Framework Core supports Optimistic Concurrency. Pessimistic Concurrency is not supported
  • The Aggregate must always be treated and versioned as a single unit
  • Domain events are an indicator, that state was changed so Aggregate version should be changed as well 
public class AggregateRootBase : Entity, IAggregateRoot
{
    private int _versionId;

    public void IncreaseVersion()
    {
        _versionId++;
    }
}
internal sealed class OrderEntityTypeConfiguration : IEntityTypeConfiguration<Order>
{
    public void Configure(EntityTypeBuilder<Order> builder)
    {
        builder.Property("_versionId").HasColumnName("VersionId").IsConcurrencyToken();
 
        //...
    }
}
var order = await _ordersContext.Orders.FindAsync(orderId);
order.AddOrderLine(request.ProductCode); 
var domainEvents = DomainEventsHelper.GetAllDomainEvents(order);
if (domainEvents.Any())
{
    order.IncreaseVersion();
}
await _ordersContext.SaveChangesAsync();


مدیریت مباحث همزمانی مرتبط با یک Rich Domain Model با استفاده از EFCore و الگوی Aggregate
اشتراک‌ها
پیکره بندی JSon در ASP.NET Core MVC

Structured data in earlier versions of ASP.NET meant creating and registering custom types and configuration sections for our applications. In ASP.NET Core and in Core MVC, structured configuration is a breeze with support for JSON documents as the storage mechanism and the ability to flatten hierarchies into highly portable keys.

 

پیکره بندی JSon در ASP.NET Core MVC
نظرات مطالب
اعتبارسنجی مبتنی بر کوکی‌ها در ASP.NET Core 2.0 بدون استفاده از سیستم Identity
- خیر. یافتن یک کاربر بر اساس ID آن که کلید اصلی جدول را هم تشکیل می‌دهد و بر روی آن ایندکس وجود دارد، فوق العاده سریع است. یک چنین کوئری گرفتنی در ASP.NET Core Identity هم وجود دارد. البته ASP.NET Core Identity برای انجام اینکار، بیش از یک کوئری را صادر می‌کند.
- وجود ICookieValidatorService که سبب بروز این کوئری اضافه می‌شود، در جهت پیاده سازی logout آنی و بررسی به روز بودن محتوای کوکی دریافتی، ضروری هست. نیاز هست تا بتوان مقدار public string SerialNumber مطلب جاری را بین اطلاعات موجود در سرور و اطلاعات قبلی موجود در کوکی صادر شده‌ی در حین لاگین، مقایسه کرد. اگر این بررسی صورت نگیرد، تا زمانیکه طول عمر کوکی کاربر به پایان نرسیده، با موفقیت و بدون هیچ کوئری اضافه‌ای، اطلاعات موجود در آن، در سمت سرور اعتبارسنجی شده و استفاده می‌شود. از آن اطلاعات در جهت تامین خودکار user claims و roles کاربر جاری استفاده می‌شود (همان شیء this.User قابل دسترسی در اکشن متدها)؛ چون زیر ساخت ASP.NET Core در جهت بررسی اطلاعات کوکی رسیده، به همراه دریافت اطلاعات مجدد آن از بانک اطلاعاتی سمت سرور نیست. اگر کوکی را معتبر تشخیص دهد و هنوز طول عمر آن به پایان نرسیده باشد، از اطلاعات آن در جهت ساخت شیء this.User استفاده می‌کند. اینجا است که اهمیت وجودی ICookieValidatorService در جهت تامین یک لایه‌ی اضافی امنیتی بررسی محتوای کوکی دریافتی، مشخص می‌شود. برای مثال فرض کنید که کاربری را به دلیل خاصی غیرفعال یا ممنوع الورود کرده‌اید. اگر سرویس ICookieValidatorService را نداشته باشید، این کاربر تا زمانیکه طول عمر کوکی آن معتبر تشخیص داده شود، می‌تواند در سایت خراب کاری کند؛ چون اطلاعات کوکی او، شیء this.User معتبری را تولید می‌کند که وابسته‌ی به اطلاعات جدید بانک اطلاعاتی برنامه نیست. همچنین قرار دادن دستی بررسی دوباره‌ی اعتبار user claim حاصل از اطلاعات کوکی کاربر جاری در هر اکشن متد و مقایسه‌ی آن با اطلاعات جدید بانک اطلاعاتی، سبب شلوغ شدن و تکرار کدهای اضافه‌ای می‌شود که به صورت متمرکز و یکجا در ICookieValidatorService وجود دارد. نمونه‌ی دیگر کاربرد این سرویس، پیاده سازی خودکار مفهوم single sign out است؛ به این معنا که اگر کاربری logout کرد، بتوان با تغییر SerialNumber او در سمت سرور، سایر افرادی را که در همان لحظه از اکانت او (کوکی‌های معتبر او) در سیستم‌های دیگری استفاده می‌کنند، logout کرد.
- استفاده از کش، به همراه بحث invalidation دقیق آن هم در صورت بروز تغییرات در بانک اطلاعاتی هست. هستند کتابخانه‌هایی که این‌کارها را به صورت خودکار و بدون نیازی به تغییری در کدها برای شما انجام دهند.
اشتراک‌ها
ASP.NET Core 2.0 منتشر شد

The ASP.NET team is proud to announce general availability of ASP.NET Core 2.0.  This release features compatibility with .NET Core 2.0, tooling support in Visual Studio 2017 version 15.3, and the new Razor Pages user-interface design paradigm.  For a full list of updates, you can read the release notes.  The latest SDK and tools can be downloaded from https://dot.net/core. Read the .NET Core 2.0 release announcement for more information and watch the launch video on Channel 9.

 
ASP.NET Core 2.0 منتشر شد
اشتراک‌ها
بررسی <IAsyncEnumerable<T در NET Core 3.

One of the most exciting features of .NET Core 3 and C# 8.0 has been the addition of IAsyncEnumerable<T> (aka async streams). But what's so special about it? What can we do now that wasn't possible before? 

بررسی <IAsyncEnumerable<T در NET Core 3.