مطالب
C# 12.0 - Interceptors
به C# 12 و دات‌نت 8، ویژگی «آزمایشی» جدیدی به نام Interceptors اضافه شده‌است که به آن «monkey patching» هم می‌گویند. هدف از آن، جایگزین کردن یک پیاده سازی، با پیاده سازی دیگری است. به این ترتیب توسعه دهندگان دات‌نتی می‌توانند فراخوانی متدهایی خاص را ره‌گیری کرده (interception) و سپس آن‌را به فراخوانی یک پیاده سازی جدید، هدایت کنند.


Interceptor چیست؟

از زمان ارائه‌ی NET 8 preview 6 SDK. به بعد، امکان ره‌گیری هر متدی از کدهای برنامه، به دات‌نت اضافه شده‌است؛ به همین جهت از واژه‌ی Interceptor/ره‌گیر در اینجا استفاده می‌شود. خود تیم دات‌نت از این قابلیت در جهت بازنویسی پویای قسمت‌هایی از کدهای زیرساخت دات‌نت که از Reflection استفاده می‌کنند، با نگارش‌های کامپایل شده‌ی مختص به برنامه‌ی شما، کمک می‌گیرند. به این ترتیب سرعت و کارآیی برنامه‌های دات‌نت 8، بهبود قابل ملاحظه‌ای را پیدا کرده‌اند. برای مثال ahead-of-time compilation (AOT) در دات‌نت 8 و ASP.NET Core 8x بر اساس این ویژگی پیاده سازی شده‌است. این ویژگی جدید، مکمل source generators است که در نگارش‌های پیشین دات‌نت ارائه شده بود.


بررسی  Interceptors با تهیه‌ی یک مثال ساده

فرض کنید می‌خواهیم فراخوانی متد GetText زیر را ره‌گیری کرده و سپس آن‌را با نمونه‌ی دیگری جایگزین کنیم:
namespace CS8Tests;

public class InterceptorsSample
{
    public string GetText(string text)
    {
        return $"{text}, World!";
    }
}
برای اینکار ابتدا نیاز است یک فایل جدید را به نام InterceptsLocationAttribute.cs با محتوای زیر به پروژه اضافه کرد:
namespace System.Runtime.CompilerServices;

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
public sealed class InterceptsLocationAttribute : Attribute
{
    public InterceptsLocationAttribute(string filePath, int line, int character)
    {
    }
}
همانطور که در مقدمه‌ی بحث هم عنوان شد، این ویژگی هنوز آزمایشی است و نهایی نشده و ویژگی فوق نیز هنوز به دات‌نت اضافه نشده‌است. به همین جهت فعلا باید آن‌را به صورت دستی به پروژه اضافه کرد و احتمالا در نگارش‌های بعدی دات‌نت، امضای آن تغییر خواهد کرد ... یا حتی ممکن است بطور کامل حذف شود!

سپس فرض کنید فراخوانی متد GetText در فایل Program.cs برنامه به صورت زیر انجام شده‌است:
using CS8Tests;

var example = new InterceptorsSample();
var text = example.GetText("Hello");
Console.WriteLine(text); //Hello, World!
یعنی متد GetText، در سطر چهارم و کاراکتر 20 ام آن فراخوانی شده‌است. این اعداد مهم هستند!

در ادامه از این اطلاعات در ره‌گیر سفارشی زیر استفاده خواهیم کرد:
using System.Runtime.CompilerServices;

namespace CS8Tests;

public static class MyInterceptor
{
    [InterceptsLocation("C:\\Path\\To\\CS8Tests\\Program.cs", 4, 20)] 
    public static string InterceptorMethod(this InterceptorsSample example, string text)
    {
        return $"{text}, DNT!";
    }
}
این ره‌گیر که به صورت متدی الحاقی برای کلاس InterceptorsSample دربرگیرنده‌ی متد GetText تهیه می‌شود، کار جایگزینی فراخوانی آن‌را در سطر چهارم و کاراکتر 20 ام فایل Program.cs انجام می‌دهد. امضای پارامترهای این متد، باید با امضای پارامترهای متد ره‌گیری شده، یکی باشد.

اکنون اگر برنامه را اجرا کنیم ... با خطای زیر مواجه می‌شویم:
 error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add
'<InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);CS8Tests</InterceptorsPreviewNamespaces>'
to your project.
عنوان می‌کند که این ویژگی آزمایشی است و باید فایل csproj. را به صورت زیر تغییر داد تا بتوان از آن استفاده نمود:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <!--<NoWarn>Test001</NoWarn>-->
    <InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);CS8Tests</InterceptorsPreviewNamespaces>
  </PropertyGroup>
</Project>
اینبار برنامه کامپایل شده و اجرا می‌شود. در این حالت خروجی جدید برنامه، خروجی تامین شده‌ی توسط ره‌گیر سفارشی ما است:
Hello, DNT!


سؤال: آیا ره‌گیری انجام شده، در زمان کامپایل انجام می‌شود یا در زمان اجرا؟

برای این مورد می‌توان به Low-Level C# code تولیدی مراجعه کرد. برای مشاهده‌ی یک چنین کدهایی می‌توانید از منوی Tools->IL Viewer برنامه‌ی Rider استفاده کرده و در برگه‌ی ظاهر شده، گزینه‌ی Low-Level C# آن‌را انتخاب نمائید:
using CS8Tests;
using System;
using System.Runtime.CompilerServices;

[CompilerGenerated]
internal class Program
{
  private static void <Main>$(string[] args)
  {
    Console.WriteLine(new InterceptorsSample().InterceptorMethod("Hello"));
  }

  public Program()
  {
    base..ctor();
  }
}
همانطور که مشاهده می‌کنید، این ره‌گیری و جایگزینی، در زمان کامپایل انجام شده و کامپایلر، به‌طور کامل نحوه‌ی فراخوانی متد GetText اصلی را به متد ره‌گیر ما تغییر داده و بازنویسی کرده‌است.


سؤال: آیا این قابلیت واقعا کاربردی است؟!

اکنون شاید این سؤال مطرح شود که ... واقعا چه کسی قرار است مسیر کامل یک فایل، شماره سطر و شماره ستون فراخوانی متدی را به اینگونه در اختیار سیستم ره‌گیری قرار دهد؟! آیا واقعا این قابلیت، یک قابلیت کاربردی و مناسب است؟!
اینجا است که اهمیت source generators مشخص می‌شود. توسط source generators دسترسی کاملی به syntax trees وجود دارد و همچنین یکسری اطلاعات تکمیلی مانند FilePath و سپس CSharpSyntaxNodeها که دسترسی به داده‌های متد ()GetLocation را دارند که مکان دقیق سطر و ستون‌های فراخوانی‌ها را مشخص می‌کند.


کاربردهای فعلی ره‌گیرها در دات نت 8

در دات نت 8، این موارد با استفاده از ره‌گیرها بهینه سازی شده و سرعت آن‌ها افزایش یافته‌اند:
- فراخوانی‌هایی که تمام اطلاعات آن‌ها در زمان کامپایل فراهم است، مانند Regex.IsMatch(@"a+b+") که از یک الگوی ثابت و مشخص استفاده می‌کند، ره‌گیری شده و پیاده سازی آن با کدی استاتیک، جایگزین می‌شود.
- در ASP.NET Minimal API، استفاده از lambda expressions جهت ارائه‌ی تعاریفی مانند:
app.MapGet("/products", handler: (int? page, int? pageLength, MyDb db) => { ... })
مرسوم است. این نوع فراخوانی‌ها نیز توسط ره‌گیرها برای جایگزینی handler آن‌ها با کدهای استاتیک، جهت بالابردن کارآیی و کاهش تخصیص‌های حافظه انجام می‌شود.
- بهبود کارآیی foreach loops جهت استفاده از ریاضیات برداری و SIMD در صورت امکان.
- بهبود کارآیی تزریق وابستگی‌ها، زمانیکه به تعاریف مشخصی مانند ()<provider.Register<MyService ختم می‌شود.
- بجای استفاده از expression trees در زمان اجرای برنامه، اکنون می‌توان کدهای SQL معادل را در زمان کامپایل برنامه تولید کرد.
- بهبود کارآیی Serializers، زمانیکه از یک نوع مشخص مانند ()<Serialize<MyType استفاده می‌شود و کامپایلر می‌تواند آن‌را با کدهای زمان کامپایل، جایگزین کند.


محدودیت‌های ره‌گیرها در دات‌نت 8

- ره‌گیرهای دات‌نت 8 فقط با متدها کار می‌کنند.
- مسیر ارائه شده حتما باید یک مسیر کامل و مشخص باشد. یعنی اگر این قطعه کد، به سیستم دیگری منتقل شود، کامپایل نخواهد شد و امکان ارائه‌ی مسیرهای نسبی وجود ندارد.
- امضای متدها، حتما باید یکی باشد. یعنی نمی‌توان یک ره‌گیر جنریک را تعریف کرد.
نظرات مطالب
غیرمعتبر شدن کوکی‌های برنامه‌های ASP.NET Core هاست شده‌ی در IIS پس از ری‌استارت آن
البته مشکل عدم رمزگشایی بعد از ریست شدن سرور مختص ویندوز نیست. در حالت پیش فرض محل ذخیره کلیدهای رمزنگاری تولید شده در حافظه است و همانطور که اشاره کردید باید با فراخوانی متد PersistKeysToFileSystem محلی را برای ذخیره سازی دائمی آنها تدارک دید. این محل میتواند پوشه ای در هاست شما باشد. (با توجه به عدم پشتیبانی از دات نت core توسط سرویس دهندگان در حال حاضر) و همچنین میتوان با پیاده‌سازی سفارشی از واسطهای IXmlDecryptor و IXmlEncryptor  و تزریق آنها به سیستم از یک Certificate غیرمعتبر استفاده کرد و نیازی به ثبت آن در Root store نیست. 
نظر شخصی بنده اینست که کلاسهای پیاده سازی شده برای رمزنگاری و رمزگشایی به شدت نگاه امنیتی بالایی را تدارک دیده است که در بیشتر سناریوها واقعا نیازی به اینهمه سطح از پیچیدگی وجود ندارد. در واقع میتوان با پیاده سازی واسط IDataProtectionProvider و تزریق آن به سیستم از روش رمزنگاری و رمزگشایی دلخواهی استفاده کرد.
نظرات مطالب
حمله چینی‌ها به سایت‌های ایرانی !
اتفاقا این مطلب برای یک نفر دیگه در یک تاریخ جلوتر از شما دقیقا با کدهای شما اتفاق افتاده جالب نیست.
www.rtraction.com/blog/devit/sql-injection-hack-using-cast-html
اشتراک‌ها
مقایسه‌ای کوتاه بین ABP Framework و DNTFrameworkCore

In this post, I want to compare “DNTFrameworkCore” with “ABP Framework”.


ABP is one of most popular and well documented frameworks with high level abstraction that I learned a lot from it. It has many other features that I don’t list them in this post, because, DNTFrameworkCore has not them actually. Behind of ABP, there is a team. It has 123 contributors in GitHub. Also, all of features have related unit-tests.

In other side, DNTFrameworkCore is lightweight with low level abstraction. It is personal open-source project without any contributor and has unit-tests for small part. 

I wrote this post to prove that thinking behind of DNTFrameworkCore completely different from ABP (at least in most sections)  

مقایسه‌ای کوتاه بین ABP Framework و DNTFrameworkCore
مطالب
نرمال سازی (قسمت دوم: Second Normal Form)
وابستگی تابعی
برای وارد شدن به بحث نظری نرمالسازی نیاز هست با مفهوم وابستگی تابعی آشنا شویم.
وابستگی تابعی یک مبحث نسبتا مفصل و تئوری هست که زمان زیادی برای شرح جزئیات آن نیاز هست در نتیجه در حد آشنایی و نیازمان به آن توجه خواهیم داشت.

به جدول زیر نگاه کنید:

 
این جدول نشان می‌دهد هر عرضه کننده(S#) چه قطعه (P#) را به چه تعداد (Qty) تولید کرده است. City هم شهریست که عرضه کننده در آن سکونت دارد.

از داده‌های فعلی جدول می‌شود برداشت‌های مختلفی داشت که چندتای آن به قرار زیر:

  • عرضه کنندگان یکسان دارای شهرهای یکسان هستند
  • هر عرضه کننده و قطعه تنها با یک مقدار از qty در تنظار است.
تعریف وابستگی تابعی یا functional dependency
تعریف رسمی:
اگر r یک رابطه و X و Y زیر مجموعه‌های دلخواهی از مجموعه خصیصه‌های r باشند آنگاه می‌گوییم Y به صورت تابعی وابسته به X است و آن را به صورت زیر می‌نویسیم:
X-->Y
اگر و تنها اگر در هر مقدار مجاز و ممکن از r، هر مقدار X متناظر با دقیقا یک مقدار از Y باشد. یعنی به ازای هر X تنها یک Y داشته باشیم. به بیان دیگر هرگاه دو چندتایی از r مقدار مقدار X یکسانی داشته باشند آنگاه مقدار Y آنها یکسان باشد.

گفته شد که هر عرضه کنند تنها با یک شهر تناظر دارد. مثلا عرضه کنده ای با مقدار S1 تنها با شهر London در تناظر است. و به ازای هر عرضه کننده قطعه تنها یک QTY خواهیم داشت مثلا به ازای عرضه کننده با مقدار S4 و قطعه با مقدار P2 تنها یک سطر (در نتیجه یک Qty) وجود دارد (این دو خصیصه کلید هستند)

اما #P به #S وابستگی تابعی ندارد. مثلا به ازای S4 ما چند عرضه کننده خواهیم داشت.

وابستگی تابعی را می‌توان بشکل نمودار در آورد. در زیر نمودار وابستگی همراه با وابستگی‌های تابعی جدول مورد نظر آمده است:

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

بر می‌گردیم به آخرین جدول مطلب گذشته یعنی:

کلید اولیه این جدول از ترکیب دو ستون کد دانشجو و ترم تشکیل شده است.
معدل را کلید اولیه تعیین می‌کند یعنی معدل وابسته به مقدار کلید اولیه است، اما نام دانشجو وابستگی به کلید اولیه ندارد و به جای آن وابسته به ستون کد دانشجو است. در نتیجه طبق تعریفی که داشتیم این جدول به شکل دوم نرمال نیست.
این جدول دقیقا مشابه به جدول عرضه کننده - قطعات است (که در ابتدا مطلب آمده است) پس نمودار FD آن نیز با FD این جدول برابر است.

برای تبدیل از فرم 1 به فرم 2 نرمال باید جدول را تجزیه کنیم به دو جدول:
  • جدول دانشجو (کد دانشجو - نام دانشجو)
  • جدول معدل (کد دانشجو - ترم - معدل)

به نمودار FD جدول فوق بعد از تجزیه شدن دقت بفرمایید:

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

و بالاخره فرم دوم نرمال جدول سابق:

کلید‌های اولیه با نقطه بنفش علامت گذاری شده است.
 

در اینجا با تجزیه جدول، به شکل سوم نرمال رسیدیم. در پست بعدی مثالی از یک جدول نرمال دوم خواهم آورد و همزمان با بررسی معایب آن شکل سوم نرمال را نیز معرفی خواهم نمود.

مرجع
کتاب پایگاه داده‌ی C.J. Date

مطالب
استفاده از کتابخانه DotNetZip و CPUهای چند هسته‌ای
هرچند از دات نت 4 و نیم به بعد، الگوریتم Zip به صورت توکار پشتیبانی می‌شود، اما برای نگارش‌های پایین‌تر، کتابخانه DotNetZip جزو پرکاربردترین‌‌ها در این زمینه است.
از همین کتابخانه مدتی در یک سرور معمولی بدون مشکل استفاده کرده بودم تا اینکه پس از ارتقاء به سرور جدید با خراب بودن فایل‌های Zip حاصل مواجه شدم. پس از بررسی مشخص شد که این کتابخانه با CPUهای چند هسته‌ای مشکل دارد و باید این نوع پردازش موازی را در آن خاموش کرد:
using (var zf = new ZipFile())
{
   zf.UseUnicodeAsNecessary = true;
   zf.ParallelDeflateThreshold = -1;
   zf.Comment = "….";
   zf.AddFile(path, "programName");
   zf.Save(whereToSave);
}
همانطور که مشاهده می‌کنید، برای غیرفعال سازی پردازش موازی، فقط کافی است پارامتر ParallelDeflateThreshold با منهای یک مقدار دهی شود.
همچنین اگر نام فایل‌های شما فارسی است نیاز است UseUnicodeAsNecessary نیز به true تنظیم گردد.

در کل گاهی از اوقات همین نکات کوتاه می‌توانند از صدمات جدی در آینده جلوگیری کنند. خصوصا اگر از این محصول جهت تهیه پشتیبان استفاده شده باشد.
اشتراک‌ها
دریافت کتابخانه های جاوا

منبعی بزرگ از فایل‌های باینری جاوا که میتوانید در برنامه‌های اندرویدی به صورت وابستگی maven استفاده کنید یا اینکه فایل باینری خود را در آن به به اشتراک بگذارید.

کتابخانه jcenter گوگل نیز بر روی این سایت قرار دارد

دریافت کتابخانه های جاوا