حذف پردازش درخواست‌های فایل‌های استاتیک در متد Application_AuthenticateRequest
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: یک دقیقه

پروژه‌ی «فروشگاه شهر طلایی من» را اگر در برنامه‌ی DNTProfiler بررسی کنیم، در برگه‌ی Urls آن یک چنین گزارش‌هایی را می‌توان مشاهده کرد:


همانطور که مشاهده می‌کنید، درخواست یک فایل استاتیک، سبب اجرای یک کوئری بر روی بانک اطلاعاتی شده‌است و یک Context خاص خودش را نیز ایجاد کرده‌است. اگر به قسمت سابقه‌ی متدهایی که سبب بروز این امر شده‌اند (در همان برگه‌، در پایین صفحه) دقت کنیم، به متد Application_AuthenticateRequest فایل global.asax.cs می‌رسیم. هر چند در فایل RouteConfig.cs مسیرهای اسکریپت‌ها و فایل‌های CSS جهت صرفنظر شدن معرفی شده‌اند، اما این موارد بر روی متد خاص Application_AuthenticateRequest تاثیری ندارند و این متد به ازای هر درخواست رسیده‌ی به IIS یکبار اجرا می‌شود؛ زیرا یک چنین تنظیمی در فایل web.config وجود دارد:
 <modules runAllManagedModulesForAllRequests="true">
به همین دلیل است که حتی درخواست فایل‌های استاتیک نیز سبب اجرای ماژول forms authentication و بروز صدور یک کوئری شده‌اند.


کنترل ASP.NET MVC Bundles در حین Forms Authentication

اگر بخواهیم درخواست‌های رسیده‌ی به Application_AuthenticateRequest را کنترل کنیم، می‌توان چنین متدی را تدارک دید:
private bool shouldIgnoreRequest()
{
    string[] reservedPath =
    {
        "/__browserLink",
        "/img",
        "/fonts",
        "/Scripts",
        "/Content"
    };
 
    var rawUrl = Context.Request.RawUrl;
    if (reservedPath.Any(path => rawUrl.StartsWith(path, StringComparison.OrdinalIgnoreCase)))
    {
        return true;
    }
 
    return BundleTable.Bundles.Select(bundle => bundle.Path.TrimStart('~'))
              .Any(bundlePath => rawUrl.StartsWith(bundlePath, StringComparison.OrdinalIgnoreCase));
}
در اینجا یک سری مسیر مشخص مانند پوشه‌ی تصاویر، قلم‌ها و اسکریپت‌ها و امثال آن معرفی شده‌اند. همچنین BundleTable.Bundles نیز مورد بررسی قرار گرفته‌است. در حین استفاده‌ی از ASP.NET MVC Bundles دیگر مسیرها الزاما به پوشه‌ی Content ختم نخواهند شد:
 bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
 "~/Scripts/modernizr-*"));
 و بر اساس تعریف پارامتر bundles/modernizer/~ مسیری مانند localhost/bundles/modernizer درخواست خواهد شد. برای دسترسی به این مسیرهای سفارشی تعریف شده می‌توان از مجموعه‌ی BundleTable.Bundles، مطابق متد فوق کوئری گرفت و مسیرهای درخواستی را که با مسیرهای bundles سفارشی تعریف شده تطابق دارند، دیگر پردازش نکرد:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    if (shouldIgnoreRequest()) return;
 
    if (Context.User == null)
        return;
  • #
    ‫۹ سال و ۶ ماه قبل، پنجشنبه ۱۳ فروردین ۱۳۹۴، ساعت ۰۴:۵۲
    یک نکته‌ی تکمیلی  
    گزارش گیری از یک چنین درخواست‌هایی را در افزونه‌ی static resources queries نیز می‌توانید مشاهده کنید:

  • #
    ‫۸ سال و ۱۰ ماه قبل، سه‌شنبه ۱۰ آذر ۱۳۹۴، ساعت ۱۹:۵۶
    آقای نصیری ، پیرو این بازخورد ، از شما تشکر میکنم که پاسخ دادید و مشخص شد مشکل از کدهای من بوده و درخواست‌ها واقعا ارسال میشه. ولی مشکل من هنوز پابرجاست. چون ربطی به بازخورد قبلی نداره این "نظر ارسالی" من ، برای همین مشکلم رو در اینجا دوباره بیان میکنم.

    من کدهای این مطلب رو در برنامه قرار دادم  ولی مشکل هنوز پا برجاست. در قسمت سابقه متدها چک کردم و متوجه شدم از کلاس CustomSecurityStampValidator  درخواست‌ها ارسال میشن :

    http://s3.picofile.com/file/8225764968/dd.jpg

    همونطور که مشاهده می‌کنید درخواست‌ها درست است در Application_AuthenticateRequest رد میشن ولی در اینجا نیز فراخوانی میشن و یا به عبارتی یک کوئری برای هر فایل استایک روی بانک اجرا میشه.

    واقعیت امر اینه اصلا نمیدونم چرا این اتفاق رخ میده ولی یک متد با کدهای شما در کلاس CustomSecurityStampValidator قرار دادم و فراخوانی کردم اون رو و مشکل حل شد و دیگه درخواستی ارسال نمیشه و همه‌ی درخواست‌های فایل‌های مورد نظر رد میشن. به این نحو :


      private static bool ShouldIgnoreRequest(CookieValidateIdentityContext context)
            {
                string[] reservedPath =
                {
                    "/__browserLink",
                    "/img",
                    "/fonts",
                    "/Scripts",
                    "/Content",
                    "/Uploads",
                    "/Images"
                };
                return reservedPath.Any(
                    path => context.OwinContext.Request.Path.Value.StartsWith(path, StringComparison.OrdinalIgnoreCase)) ||
                       BundleTable.Bundles.Select(bundle => bundle.Path.TrimStart('~'))
                           .Any(
                               bundlePath =>
                                   context.OwinContext.Request.Path.Value.StartsWith(bundlePath,
                                       StringComparison.OrdinalIgnoreCase));
            }
    و برای فراخوانی :

                        //...
                        if (ShouldIgnoreRequest(context)) return;
                        var manager = context.OwinContext.GetUserManager<ApplicationUserManager>();
                        var userId = getUserIdCallback(context.Identity);
                        //...

    لطفا اگر اطلاع دارید که چرا این اتفاق ممکنه رخ میده راهنمایی کنید. چرا در اونجا رد میشن ولی باز در این کلاس فراخوانی میشن.

  • #
    ‫۶ سال و ۱۰ ماه قبل، چهارشنبه ۱۷ آبان ۱۳۹۶، ساعت ۱۶:۵۰
    یک نکته‌ی تکمیلی
    پیاده سازی مطلب جاری برای ASP.NET Identity 2.x یک چنین تغییراتی را پیدا می‌کند:
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
       // ...
        Provider = new CookieAuthenticationProvider
        {
            OnValidateIdentity = context =>
            {
                if(shouldIgnoreRequest(context)) // How to ignore Authentication Validations for static files in ASP.NET Identity
                {
                    return Task.FromResult(0);
                }
                return container.GetInstance<IApplicationUserManager>().OnValidateIdentity().Invoke(context);
            }
        },
        // ...
    });
    با این متد بررسی درخواست‌ها:
    private static bool shouldIgnoreRequest(CookieValidateIdentityContext context)
    {
        string[] reservedPath =
        {
            "/__browserLink",
            "/img",
            "/fonts",
            "/Scripts",
            "/Content",
            "/Uploads",
            "/Images"
        };
        return reservedPath.Any(path => context.OwinContext.Request.Path.Value.StartsWith(path, StringComparison.OrdinalIgnoreCase)) ||
                           BundleTable.Bundles.Select(bundle => bundle.Path.TrimStart('~')).Any(bundlePath => context.OwinContext.Request.Path.Value.StartsWith(bundlePath,StringComparison.OrdinalIgnoreCase));
    }