اشتراک‌ها
ساخت یک بازی آنلاین با Blazor و دات نت 7

Spawn an Online Game with Blazor, .NET 7 and Clean Architecture in under 60 minutes

In this fun talk, Luke Parker will show you step-by-step how to build a playable game in under 60 minutes. He will go over some basic game design, project planning, then build the game and finally… play live with the audience! Utilizing code sharing and the magic of Clean Architecture allows for very rapid app development. Also, leveraging MudBlazor as the component library lets you save time and to focus on what really matters.
 

ساخت یک بازی آنلاین با Blazor و دات نت 7
نظرات مطالب
کدامیک از بسته‌های NET Core. را باید دریافت کنیم؟
- ASP.NET Core 3.0 فقط این بسته‌ها را مخفی می‌کند؛ نه اینکه استفاده نمی‌کند. اطلاعات بیشتر
مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 3 - Middleware چیست؟
پیشنیازها
- «با HttpHandler بیشتر آشنا شوید»
یکی از بزرگترین تغییرات ASP.NET Core نسبت به نگارش‌های قبلی آن، مدیریت HTTP pipeline آن است. به عنوان یک توسعه دهنده‌ی ASP.NET به طور قطع با مفاهیمی مانند HttpHandler و HttpModules آشنایی دارید و ... هر دوی این‌ها با نگارش جدید ASP.NET حذف و با مفهوم جدیدی به نام Middleware جایگزین شده‌اند.
 - HttpHandlerها عموما مبتنی بر پسوندهای فایل‌ها عمل می‌کنند. برای نمونه، رایج‌ترین آن‌ها ASP.NET page handler است که هرگاه درخواستی، ختم شده‌ی به پسوند aspx، به موتور ASP.NET Web forms وارد شد، به این page handler، جهت پردازش نهایی هدایت می‌شود. محل تنظیم آن‌ها نیز در فایل web.config است.
 - HttpModuleها مبتنی بر رخدادها عمل می‌کنند. HttpModuleها به عنوان جزئی از request pipeline عمل کرده و دسترسی کاملی دارند به رخدادهای طول عمر درخواست رسیده. آن‌ها را می‌توان توسط فایل‌های global.asax و یا web.config تنظیم کرد.
 - MiddleWareها را که جزئی از طراحی OWIN نیز هستند، می‌توان به عنوان کامپوننت‌های کوچکی از برنامه که قابلیت یکپارچه شدن با HTTP request pipeline را دارند، درنظر گرفت. عملکرد آن‌ها ترکیبی است از هر دوی HttpHandler و HttpModule‌ها که در نگارش‌های قبلی ASP.NET مورد استفاده بودند. از MiddleWareها می‌توان برای پیاده سازی اعمال مختلفی جهت پردازش درخواست‌های رسیده مانند اعتبارسنجی، کار با سشن‌ها، ثبت وقایع سیستم، مسیریابی و غیره استفاده کرد. OWIN یا Open Web Interface for .NET به توسعه دهنده‌ها امکان غیروابسته کردن برنامه‌ی ASP.NET خود را از وب سرور مورد استفاده می‌دهد. به علاوه OWIN امکان پلاگین نویسی اجزای مختلف برنامه را بدون وابسته کردن آن‌ها به یکدیگر فراهم می‌کند. برای مثال می‌توان یک پلاگین logger را تهیه کرد تا اطلاعات مختلفی را از درخواست‌های رسیده ثبت کند.



مواردی که با ارائه‌ی ASP.NET Core 1.0 حذف شده‌اند

- System.Web: یکی از اهداف اصلی OWIN، مستقل کردن برنامه‌ی وب، از هاست آن است تا بتوان از وب سرورهای بیشتری استفاده کرد. System.Web انحصارا برای IIS طراحی شده بود و در این نگارش دیگر وجود خارجی ندارد.
- HttpModules: با Middlewareها جایگزین شده‌اند.
- HttpHandlers: البته HttpHandlers از زمان ارائه‌ی اولین نگارش ASP.NET MVC، در چندین سال قبل منسوخ شدند. زیرا پردازش صفحات وب در ASP.NET MVC برخلاف وب فرم‌ها، از فایل‌هایی با پسوندهای خاص شروع نمی‌شوند و نقطه‌ی آغازین آن‌ها، اکشن متدهای کنترلرها است.
- فایل global.asax: با حذف شدن HttpModules، دیگر ضرورتی به وجود این فایل نیست.


شباهت‌های بینMiddleware و HttpModuleها

همانند HttpModuleها، Middlewareها نیز به ازای هر درخواست رسیده اجرا می‌شوند و از هر دو می‌توان جهت تولید response ایی خاص استفاده کرد.


تفاوت‌های بینMiddleware و HttpModuleها

- عموما HttpModule از طریق web.config و یا فایل global.asax تنظیم می‌شوند. اما Middlewareها تنها از طریق کد و در فایل Startup.cs برنامه‌های ASP.NET Core 1.0 قابل معرفی هستند.
- به عنوان یک توسعه دهنده، کنترلی را بر روی ترتیب اجرای انواع و اقسام HttpModuleها نداریم. این مشکل در Middlewareها برطرف شده و اکنون ترتیب اجرای آن‌ها، دقیقا مطابق ترتیب افزوده شدن و تعریف آن‌ها در فایل Startup.cs است.
- ترتیب اجرای HttpModuleها هرچه که باشد، برای حالت‌های request و response یکی است. اما ترتیب اجرای Middlewareهای مخصوص response، عکس ترتیب اجرای Middlewareهای مخصوص request هستند (تصویر ذیل).
- HttpModuleها را صرفا جهت اتصال کدهایی به رخدادهای طول عمر برنامه می‌توان طراحی کرد؛ اما Middleware مستقل هستند از این رخدادها.
- HttpModuleها به System.Web وابسته‌اند؛ برخلاف Middlewareها که وابستگی به هاست خود ندارند.



Middleware‌های توکار ASP.NET Core 1.0

ASP.NET Core 1.0 به همراه تعدادی Middleware توکار است؛ مانند:
- Authentication: جهت پشتیبانی از اعتبارسنجی
- CORS: برای فعال سازی Cross-Origin Resource Sharing
- Routing: جهت تعریف و محدود سازی مسیریابی‌های برنامه
- Session: برای پشتیبانی و مدیریت سشن‌های کاربران
- Diagnostics: پشتیبانی از صفحات خطا و اطلاعات زمان اجرای برنامه
و مواردی دیگر که برای توزیع فایل‌های استاتیک و یا مرور محتویات پوشه‌ها و امثال آن‌ها طراحی شده‌اند که در طی این مطلب و همچنین مطالب آتی، آن‌ها را بررسی خواهیم کرد.

یک مثال: اگر یک پروژه‌ی خالی ASP.NET Core 1.0 را در ویژوال استودیو ایجاد کنید، این پروژه قادر نیست حتی فایل‌های استاتیک مانند تصاویر، فایل‌های پیش فرض مانند index.html و یا قابلیت مرور ساده‌ی فایل‌های موجود در یک پوشه را ارائه دهد (حتی اگر به آن‌ها نیازی نداشته باشید).
طراحی این نگارش از ASP.NET، مبتنی است بر سبک وزن بودن و ماژولار بودن. هر قابلیتی را که نیاز دارید، باید middleware آن‌را نیز خودتان به صورت صریح اضافه کنید و یا در غیر اینصورت فعال نیست. برخلاف نگارش‌های قبلی ASP.NET که HTTP Module‌های از سشن گرفته تا اعتبارسنجی و غیره، همگی به صورت پیش فرض در فایل Web.Config فعال بودند؛ مگر اینکه آن‌ها را به صورت دستی حذف می‌کردید.



ثبت و فعال سازی اولین Middleware

در ادامه‌ی تکمیل و معرفی برنامه‌ی خالی ASP.NET Core 1.0، قصد داریم یک Middleware توکار را به نام Welcome Page، بجای نمایش سطر Hello world پیش فرض این برنامه، ثبت و فعال سازی کنیم. این Middleware ویژه، در اسمبلی به نام Microsoft.AspNetCore.Diagnostics قرار دارد. اگر فایل project.json پیش فرض این پروژه را باز کنید، این اسمبلی به صورت پیش فرض در آن ثبت و معرفی شده‌است:
{
    "dependencies": {
        "Microsoft.NETCore.App": {
            "version": "1.0.0",
            "type": "platform"
        },
        "Microsoft.AspNetCore.Diagnostics": "1.0.0",
        "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
        "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
        "Microsoft.Extensions.Logging.Console": "1.0.0"
    },
بنابراین هم اکنون بسته‌ی نیوگت آن نیز به پروژه‌ی جاری اضافه شده و قابل استفاده است. در غیراینصورت همانطور که در قسمت قبل در مطلب «نقش فایل project.json» عنوان شد، می‌توان بر روی گره references کلیک راست کرده و سپس از منوی ظاهر شده،‌گزینه‌ی manage nuget packages را انتخاب کرد. سپس، ابتدا برگه‌ی browse را انتخاب کنید و در اینجا نام Microsoft.AspNetCore.Diagnostics را جستجو کرده و در آخر آن‌را نصب کنید.
پس از اطمینان حاصل کردن از نصب بسته‌ی نیوگت Microsoft.AspNetCore.Diagnostics، اکنون جهت معرفی Middleware توکار Welcome Page ، فایل Startup.cs را گشوده و کدهای آن‌را به نحو ذیل تغییر  دهید:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
 
namespace Core1RtmEmptyTest
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        }
 
        public void Configure(IApplicationBuilder app)
        {
            app.UseWelcomePage();
 
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Hello DNT!");
            });
        }
    }
}
در اینجا نحوه‌ی ثبت این middleware را با افزودن آن به IApplicationBuilder تزریق شده‌ی توسط OWIN، به کمک متد الحاقی UseWelcomePage مشاهده می‌کنید.
به علاوه middleware دومی را نیز با متد الحاقی Run مشاهده می‌کنید. به این نوع middlewareهای خاص، اصطلاحا terminal middleware می‌گویند. از این جهت که درخواستی را دریافت و یک response را تولید می‌کنند و کار همینجا خاتمه می‌یابد و زنجیره‌ی پردازشی middlewareها ادامه نخواهد یافت. در اینجا پارامتر context آن از نوع HttpContext است و باید دقت داشت، زمانیکه کار نوشتن در Response، در اینجا انجام شد، اگر پس از متد Run یک Middleware دیگر را ثبت کنید، هیچگاه اجرا نخواهد شد.

در این حالت اگر برنامه را اجرا کنید، خروجی ذیل را مشاهده خواهید کرد:


welcome page نیز یک terminal middleware است. به همین جهت middleware بعدی ثبت شده‌ی در اینجا یا همان متد Run، دیگر اجرا نخواهد شد.

در قسمت‌های بعدی، تعداد بیشتری از Middlewareهای توکار ASP.NET Core 1.0 را بررسی خواهیم کرد.
مطالب
محدود سازی نرخ دسترسی به منابع در برنامه‌های ASP.NET Core - قسمت دوم - پیاده سازی
در قسمت قبل با مفاهیم، اصطلاحات و الگوریتم‌های مرتبط با میان‌افزار جدید Rate limiting مخصوص ASP.NET Core 7 آشنا شدیم که در پشت صحنه از امکانات موجود در فضای نام System.Threading.RateLimiting استفاده می‌کند. در این قسمت نحوه‌ی استفاده‌ی از آن‌را مرور خواهیم کرد.


روش افزودن میان‌افزار RateLimiter به برنامه‌های ASP.NET Core

شبیه به سایر میان‌افزارها، جهت فعالسازی میان‌افزار RateLimiter، ابتدا باید سرویس‌های متناظر با آن‌را به برنامه معرفی کرد و پس از فعالسازی میان‌افزار مسیریابی، آن‌‌را به زنجیره‌ی مدیریت یک درخواست معرفی نمود. برای نمونه در مثال زیر، امکان دسترسی به تمام درخواست‌ها، به 10 درخواست در دقیقه، محدود می‌شود که پارتیشن بندی آن (در مورد پارتیشن بندی در قسمت قبل بیشتر بحث شد)، بر اساس username کاربر اعتبارسنجی شده و یا hostname یک کاربر غیراعتبارسنجی شده‌است:
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRateLimiter(options =>
{
    options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
        RateLimitPartition.GetFixedWindowLimiter(
            partitionKey: httpContext.User.Identity?.Name ?? httpContext.Request.Headers.Host.ToString(),
            factory: partition => new FixedWindowRateLimiterOptions
            {
                AutoReplenishment = true,
                PermitLimit = 10,
                QueueLimit = 0,
                Window = TimeSpan.FromMinutes(1)
            }));
});

// ...

var app = builder.Build();

// ...

app.UseRouting();
app.UseRateLimiter();

app.MapGet("/", () => "Hello World!");

app.Run();
توضیحات:
- فراخوانی builder.Services.AddRateLimiter، سبب معرفی سرویس‌های میان‌افزار rate limiter به سیستم تزریق وابستگی‌های ASP.NET Core می‌شود.
- در اینجا می‌توان برای مثال خاصیت options.GlobalLimiter تنظیمات آن‌را نیز مقدار دهی کرد. GlobalLimiter، سبب تنظیم یک محدود کننده‌ی سراسری نرخ، برای تمام درخواست‌های رسیده‌ی به برنامه می‌شود.
- GlobalLimiter را می‌توان با هر نوع PartitionedRateLimiter مقدار دهی کرد که در اینجا از نوع FixedWindowLimiter انتخاب شده‌است تا بتوان «الگوریتم‌های بازه‌ی زمانی مشخص» را به برنامه اعمال نمود تا برای مثال فقط امکان پردازش 10 درخواست در هر دقیقه برای هر کاربر، وجود داشته باشد.
- در پایان کار، فراخوانی app.UseRateLimiter را نیز مشاهده می‌‌کنید که سبب فعالسازی میان‌افزار، بر اساس تنظیمات صورت گرفته می‌شود.

برای آزمایش برنامه، آن‌را  اجرا کرده و سپس به سرعت شروع به refresh کردن صفحه‌ی اصلی آن کنید. پس از 10 بار ریفرش، پیام  503 Service Unavailable را مشاهده خواهید کرد که به معنای مسدود شدن دسترسی به برنامه توسط میان‌افزار rate limiter است.


بررسی تنظیمات رد درخواست‌ها توسط میان‌افزار rate limiter

اگر پس از محدود شدن دسترسی به برنامه توسط میان افزار rate limiter از status code = 503 دریافتی راضی نیستید، می‌توان آن‌را هم تغییر داد:
builder.Services.AddRateLimiter(options =>
{
    options.RejectionStatusCode = 429;

    // ...
});
برای مثال بسیاری از سرویس‌ها بجای 503، از status code دیگری مانند 429 Too Many Requests استفاده می‌کنند که نحوه‌ی تنظیم آن‌را در مثال فوق مشاهده می‌کنید.
علاوه بر آن در اینجا گزینه‌ی OnRejected نیز پیش بینی شده‌است تا بتوان response ارائه شده را در حالت رد درخواست، سفارشی سازی کرد تا بتوان پیام بهتری را به کاربری که هم اکنون دسترسی او محدود شده‌است، ارائه داد:
builder.Services.AddRateLimiter(options =>
{
    options.OnRejected = async (context, token) =>
    {
        context.HttpContext.Response.StatusCode = 429;
        if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
        {
            await context.HttpContext.Response.WriteAsync(
                $"Too many requests. Please try again after {retryAfter.TotalMinutes} minute(s). " +
                $"Read more about our rate limits at https://example.org/docs/ratelimiting.", cancellationToken: token);
        }
        else
        {
            await context.HttpContext.Response.WriteAsync(
                "Too many requests. Please try again later. " +
                "Read more about our rate limits at https://example.org/docs/ratelimiting.", cancellationToken: token);
        }
    };

    // ...
});
برای نمونه در مثال فوق ابتدا status code، به 429 تنظیم می‌شود و سپس یک response با معنا به سمت کاربر ارسال می‌گردد که دقیقا مشخص می‌کند آن کاربر چه زمانی می‌تواند مجددا سعی کند و همچنین لینکی را به مستندات محدود سازی برنامه جهت توضیحات بیشتر ارائه می‌دهد.

یک نکته: باتوجه به اینکه در اینجا به HttpContext دسترسی داریم، یعنی به context.HttpContext.RequestServices نیز دسترسی خواهیم داشت که توسط آن می‌توان برای مثال سرویس ILogger را از آن درخواست کرد و رخ‌داد واقع شده را برای بررسی بیشتر لاگ نمود؛ برای مثال چه کاربری مشکل پیدا کرده‌است؟
context.HttpContext.RequestServices.GetService<ILoggerFactory>()?
                .CreateLogger("Microsoft.AspNetCore.RateLimitingMiddleware")
                .LogWarning("OnRejected: {RequestPath}", context.HttpContext.Request.Path);
همچنین باید دقت داشت که اگر در اینجا از بانک اطلاعاتی استفاده کرده‌اید، تعداد کوئری‌های آن‌را محدود کنید؛ وگرنه واقعا rate limiter از لحاظ محدود کردن دسترسی به منابع، کمک زیادی را به شما نخواهد کرد.

طراحی فعلی میان‌افزار rate limiter، کمی محدود است. برای مثال «retry after»، تنها metadata مفیدی است که جهت بازگشت ارائه می‌دهد و همچنین مانند GitHub مشخص نمی‌کند که در لحظه‌ی جاری چند درخواست دیگر را می‌توان ارسال کرد و امکان دسترسی به اطلاعات آماری درونی آن وجود ندارد. اگر نیاز به یک چنین اطلاعاتی دارید شاید استفاده از میان‌افزار ثالث دیگری به نام AspNetCoreRateLimit برای شما مفیدتر باشد!


الگوریتم‌های پشتیبانی شده‌ی توسط میان‌افزار rate limiter

در قسمت قبل با چند الگوریتم استاندارد طراحی میان‌افزارهای rate limiter آشنا شدیم که میان‌افزار توکار rate limiter موجود در ASP.NET Core 7x، اکثر آن‌ها را پشتیبانی می‌کند:
- Concurrency limit: ساده‌ترین نوع محدود سازی نرخ درخواست‌ها است و کاری به زمان ندارد و فقط برای آن، تعداد درخواست‌های همزمان مهم است. برای مثال پیاده سازی «مجاز بودن تنها 10 درخواست همزمان».
- Fixed window limit: توسط آن می‌توان محدودیت‌هایی مانند «مجاز بودن تنها 60 درخواست در دقیقه» را اعمال کرد که به معنای امکان ارسال یک درخواست در هر ثانیه در هر دقیقه و یا حتی ارسال یکجای 60 درخواست در یک ثانیه است.
- Sliding window limit: این محدودیت بسیار شبیه به حالت قبل است اما به همراه قطعاتی که کنترل بیشتری را بر روی محدودیت‌ها میسر می‌کند؛ مانند مجاز بودن 60 درخواست در هر دقیقه که فقط در این حالت یک درخواست در هر ثانیه مجاز باشد.
- Token bucket limit: امکان کنترل نرخ سیلان را میسر کرده و همچنین از درخواست‌های انفجاری نیز پشتیبانی می‌کند (این مفاهیم در قسمت قبل بررسی شدند).

علاوه بر این‌ها امکان ترکیب گزینه‌های فوق توسط متد کمکی PartitionedRateLimiter.CreateChained نیز میسر است:
builder.Services.AddRateLimiter(options =>
{
    options.GlobalLimiter = PartitionedRateLimiter.CreateChained(
        PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
            RateLimitPartition.GetFixedWindowLimiter(httpContext.ResolveClientIpAddress(), partition =>
                new FixedWindowRateLimiterOptions
                {
                    AutoReplenishment = true,
                    PermitLimit = 600,
                    Window = TimeSpan.FromMinutes(1)
                })),
        PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
            RateLimitPartition.GetFixedWindowLimiter(httpContext.ResolveClientIpAddress(), partition =>
                new FixedWindowRateLimiterOptions
                {
                    AutoReplenishment = true,
                    PermitLimit = 6000,
                    Window = TimeSpan.FromHours(1)
                })));

    // ...
});
برای نمونه در مثال فوق به ازای یک آدرس IP مشخص، تنها می‌توان 600 درخواست را در دقیقه ارسال کرد؛ با این محدودیت که جمع آن‌ها در ساعت، بیشتر از 6000 مورد نباشد.
در این مثال فرضی، متد الحاقی ResolveClientIpAddress اهمیتی ندارد. بهتر است برای برنامه‌ی خود از کلید پارتیشن بندی بهتر و معقول‌تری استفاده کنید.


امکان در صف قرار دادن درخواست‌ها بجای رد کردن آن‌ها

در تنظیمات مثال‌های فوق، در کنار PermitLimit، می‌توان QueueLimit را نیز مشخص کرد. به این ترتیب با رسیدن به PermitLimit، به تعداد QueueLimit، درخواست‌ها در صف قرار می‌گیرند، بجای اینکه کاملا رد شوند:
PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
    RateLimitPartition.GetFixedWindowLimiter(httpContext.ResolveClientIpAddress(), partition =>
        new FixedWindowRateLimiterOptions
        {
            AutoReplenishment = true,
            PermitLimit = 10,
            QueueLimit = 6,
            QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
            Window = TimeSpan.FromSeconds(1)
        })));
در این مثال هر کلاینت می‌تواند 10 درخواست در ثانیه را ارسال کند. در صورت رسیدن به این محدودیت، تا 6 عدد از درخواست‌های جدید رسیده، بجای رد شدن، در صف قرار می‌گیرند تا در ثانیه‌ی بعدی که این بازه‌ی مشخص به پایان می‌رسد، پردازش شوند.
این تنظیم، تجربه‌ی کاربری بهتری را برای استفاده کنندگان از برنامه‌ی شما به همراه خواهد داشت؛ بجای رد قاطع درخواست‌های ارسالی توسط آن‌ها.

یک نکته: بهتر است QueueLimitهای بزرگی را انتخاب نکنید؛ خصوصا برای بازه‌های زمانی طولانی. چون یک مصرف کننده نیاز دارد تا سریع، پاسخی را دریافت کند و اگر این‌طور نباشد، دوباره سعی خواهد کرد. تنها چند ثانیه‌ی کوتاه در صف بودن برای کاربران معنا دارد.


امکان ایجاد سیاست‌های محدود سازی سفارشی

اگر الگوریتم‌های توکار میان‌افزار rate limiter برای کار شما مناسب نیستند، می‌توانید با پیاده سازی <IRateLimiterPolicy<TPartitionKey، یک نمونه‌ی سفارشی را ایجاد کنید. پیاده سازی این اینترفیس، نیاز به دو متد را دارد:
الف) متد GetPartition که بر اساس HttpContext جاری، یک rate limiter مخصوص را باز می‌گرداند.
ب) متد OnRejected که امکان سفارشی سازی response رد درخواست‌ها را میسر می‌کند.

در مثال زیر پیاده سازی یک rate limiter سفارشی را مشاهده می‌کنید که نحوه‌ی پارتیشن بندی آن بر اساس user-name کاربر اعتبارسنجی شده و یا host-name کاربر وارد نشده‌ی به سیستم است. در اینجا کاربر وارد شده‌ی به سیستم، محدودیت بیشتری دارد:
public class ExampleRateLimiterPolicy : IRateLimiterPolicy<string>
{
    public RateLimitPartition<string> GetPartition(HttpContext httpContext)
    {
        if (httpContext.User.Identity?.IsAuthenticated == true)
        {
            return RateLimitPartition.GetFixedWindowLimiter(httpContext.User.Identity.Name!,
                partition => new FixedWindowRateLimiterOptions
                {
                    AutoReplenishment = true,
                    PermitLimit = 1_000,
                    Window = TimeSpan.FromMinutes(1),
                });
        }

        return RateLimitPartition.GetFixedWindowLimiter(httpContext.Request.Headers.Host.ToString(),
            partition => new FixedWindowRateLimiterOptions
            {
                AutoReplenishment = true,
                PermitLimit = 100,
                Window = TimeSpan.FromMinutes(1),
            });
    }

    public Func<OnRejectedContext, CancellationToken, ValueTask>? OnRejected { get; } =
        (context, _) =>
        {
            context.HttpContext.Response.StatusCode = 418; // I'm a 🫖
            return new ValueTask();
        };
}
و نحوه‌ی معرفی آن به سیستم به صورت زیر است:
options.AddPolicy<string, ExampleRateLimiterPolicy>("myPolicy");


امکان تعریف سیاست‌های محدود سازی نرخ دسترسی به گروهی از endpoints

تا اینجا روش‌های سراسری محدود سازی دسترسی به منابع برنامه را بررسی کردیم؛ اما ممکن است در برنامه‌ای بخواهیم محدودیت‌های متفاوتی را به گروه‌های خاصی از endpoints اعمال کنیم و یا شاید اصلا نخواهیم تعدادی از آن‌ها را محدود کنیم:
builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("Api", options =>
    {
        options.AutoReplenishment = true;
        options.PermitLimit = 10;
        options.Window = TimeSpan.FromMinutes(1);
    });

    options.AddFixedWindowLimiter("Web", options =>
    {
        options.AutoReplenishment = true;
        options.PermitLimit = 10;
        options.Window = TimeSpan.FromMinutes(1);
    });

    // ...
});
در این مثال روش تعریف دو سیاست مختلف محدودسازی را مشاهده می‌کنید که اینبار «نامدار» هستند؛ نام یکی Api است و نام دیگری Web.
البته باید درنظر داشت که متدهای الحاقی Add داری را که در اینجا ملاحظه می‌کنید، محدود سازی را بر اساس نام درنظر گرفته شده انجام می‌دهند. یعنی درحقیقت یک محدودسازی سراسری بر اساس گروهی از endpoints هستند و امکان تعریف پارتیشنی را به ازای یک کاربر یا آدرس IP خاص، ندارند. اگر نیاز به اعمال این نوع پارتیشن بندی را دارید، باید از متدهای AddPolicy استفاده کنید:
options.AddPolicy("Api", httpContext =>
        RateLimitPartition.GetFixedWindowLimiter(httpContext.ResolveClientIpAddress(),
        partition => new FixedWindowRateLimiterOptions
        {
            AutoReplenishment = true,
            PermitLimit = 10,
            Window = TimeSpan.FromSeconds(1)
        }));
متدهای AddPolicy دار، هم امکان دسترسی به httpContext جاری را میسر می‌کنند و هم نامدار هستند که قابلیت اعمال آن‌ها را به گروهی از endpoints ممکن می‌کند.


محدود سازی نرخ دسترسی به منابع در ASP.NET Core Minimal API

پس از تعریف نامی برای سیاست‌های دسترسی، اکنون می‌توان از آن‌ها به صورت زیر جهت محدود سازی یک endpoint و یا گروهی از آن‌ها استفاده کرد:
// Endpoint
app.MapGet("/api/hello", () => "Hello World!").RequireRateLimiting("Api");

// Group
app.MapGroup("/api/orders").RequireRateLimiting("Api");
و یا حتی می‌توان بطور کامل محدود سازی نرخ دسترسی را برای یک endpoint و یا گروهی از آن‌ها غیرفعال کرد:
// Endpoint
app.MapGet("/api/hello", () => "Hello World!").DisableRateLimiting();

// Group
app.MapGroup("/api/orders").DisableRateLimiting();


محدود سازی نرخ دسترسی به منابع در ASP.NET Core MVC

می‌توان سیاست‌های نرخ دسترسی تعریف شده را بر اساس نام آن‌ها به کنترلرها و یا اکشن متدها اعمال نمود:
[EnableRateLimiting("Api")]
public class Orders : Controller
{
    [DisableRateLimiting]
    public IActionResult Index()
    {
        return View();
    }

    [EnableRateLimiting("ApiListing")]
    public IActionResult List()
    {
        return View();
    }
}
در اینجا سیاست نرخ دسترسی با نام Api، به کل کنترلر و اکشن متدهای آن اعمال شده، اما اکشن متد Index آن با بکارگیری ویژگی DisableRateLimiting، از این محدودیت خارج و اکشن متد List، از سیاست نام دار دیگری استفاده کرده‌است.
و یا حتی می‌توان این سیاست‌های محدود سازی نرخ دسترسی را به تمام کنترلرها و صفحات razor نیز به صورت زیر اعمال کرد:
app.UseConfiguredEndpoints(endpoints =>
{
    endpoints.MapRazorPages()
        .DisableRateLimiting();

    endpoints.MapControllers()
        .RequireRateLimiting("UserBasedRateLimiting");
});
اشتراک‌ها
بررسی بهبودهای کارآیی در ASP.NET Core 8

ASP.NET Core 8 and .NET 8 bring many exciting performance improvements. In this blog post, we will highlight some of the enhancements made in ASP.NET Core and show you how they can boost your web app’s speed and efficiency.  

بررسی بهبودهای کارآیی در ASP.NET Core 8
اشتراک‌ها
اعتبارسنجی کاربران بدون هاردکد کردن نقشها

You already know how role-based authorization works in ASP.NET Core.

[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
}

But what if you don't want hardcode roles on the Authorize attribute or create roles later and specify in which controller and action it has access without touching source code?

DynamicAuthorization helps you authorize users without hardcoding role(s) on the Authorize attribute with minimum effort. DynamicAuthorization is built at the top of ASP.NET Core Identity and use identity mechanism for managing roles and authorizing users. 

اعتبارسنجی کاربران بدون هاردکد کردن نقشها
اشتراک‌ها
سوالات مصاحبه ای ASP.NET Core
What is .NET Core?
What is ASP.NET Core?
Can ASP.NET Core work with the .NET framework?
What is Kestrel?
Dependency Injection in ASP.NET Core?
The configuration in ASP.NET Core?
Talk about Logging in ASP.NET Core?
Explain Middleware in ASP.NET Core?
Explain startup process in ASP.NET Core?
سوالات مصاحبه ای ASP.NET Core