‫۱ سال قبل، دوشنبه ۲۰ شهریور ۱۴۰۲، ساعت ۱۳:۵۹
یک نکته‌ی تکمیلی

تا دات نت 7 می‌توان از روش زیر برای انتخاب تصادفی اعضای یک مجموعه استفاده کرد:
‍MyCollection.OrderBy(x => Random.Shared.Next()).Take(10)
Random.Shared، به دات نت 6 برای تولید اعداد تصادفی thread-safe اضافه شد. اهمیت thread-safe بودن آن‌را در مطلب «اثبات قانون مشاهده‌گر در برنامه نویسی» می‌توانید مطالعه کنید.
‫۱ سال قبل، شنبه ۱۸ شهریور ۱۴۰۲، ساعت ۲۳:۲۶
یک نکته‌ی تکمیلی: لطفا ورودی‌های عددی را ()ToEnglishNumbers کنید!

در حین توسعه‌ی « DNTCaptcha.Core »، یکی از مواردی که به صورت مشکل بیان شد، عدم امکان کار با آن، در دستگاه‌های موبایل بود! مشکل اینجاست که در دستگاه‌های موبایل، زمانیکه صفحه کلید در حالت فارسی قرار دارد، اعداد را هم فارسی وارد می‌کند و اعداد این بازه‌ی خاص که در تصویر زیر مشخص هستند، حرف تشخیص داده می‌شوند و نه عدد:


اما ... ما انتظار داریم که اعداد را انگلیسی دریافت کنیم. به همین جهت اکثر سیستم‌های موجود، با دریافت ورودی عددی از طریق دستگاه‌های موبایل، زمانیکه صفحه کلید در حالت فارسی قرار دارد، مشکل دارند! برای رفع این مشکل فقط کافی است متد الحاقی ()ToEnglishNumbers را بر روی رشته‌ی دریافتی، فراخوانی کنید تا تبدیل به اعداد انگلیسی شود و قابلیت پردازش در برنامه را پیدا کند. اگر هم از کامپوننت‌های «DNTPersianComponents.Blazor» استفاده می‌کنید، این تبدیلات به صورت خودکار برای شما انجام خواهد شد.
مهندسی معکوس انواع و اقسام بانک‌های اطلاعاتی از پیش‌موجود به کلاس‌های Context و موجودیت‌های EF Core Code First

الف) SQL Server
وابستگی‌های مورد نیاز در یک پروژه‌ی classlib فرضی:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.10" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
  </ItemGroup>
</Project>
و همچنین نصب ابزارهای خط‌فرمان EF:
dotnet tool update --global dotnet-ef --version 7.0.10
سپس اجرای دستور زیر در ریشه‌ی پروژه:
dotnet ef dbcontext scaffold "Data Source=(localdb)\mssqllocaldb;Initial Catalog=DbName;Encrypt=false;" Microsoft.EntityFrameworkCore.SqlServer -o Output -f

ب) MySQL
وابستگی‌های مورد نیاز در یک پروژه‌ی classlib فرضی:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
    <PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Design" Version="1.1.2" />
  </ItemGroup>
</Project>
 و همچنین نصب ابزارهای خط‌فرمان EF:
dotnet tool update --global dotnet-ef --version 7.0.10
سپس اجرای دستور زیر در ریشه‌ی پروژه:
dotnet ef dbcontext scaffold "server=localhost;port=3306;user=root;password=MyPass;database=MyDbName;TreatTinyAsBoolean=true;AllowZeroDateTime=true;ConvertZeroDateTime=true;" Pomelo.EntityFrameworkCore.MySql -o Output -f

ج) Postgres 
وابستگی‌های مورد نیاز در یک پروژه‌ی classlib فرضی:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.4"/>
  </ItemGroup>
</Project>
و همچنین نصب ابزارهای خط‌فرمان EF:
dotnet tool update --global dotnet-ef --version 7.0.10
سپس اجرای دستور زیر در ریشه‌ی پروژه:
dotnet ef dbcontext scaffold "User ID=Vahid;Password=MyPass;Host=localhost;Port=5432;Database=MyDbName;Pooling=true;" Npgsql.EntityFrameworkCore.PostgreSQL -o Output -f

د) SQLite
وابستگی‌های مورد نیاز در یک پروژه‌ی classlib فرضی: 
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.10" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="7.0.10" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
  </ItemGroup>
</Project>
 و همچنین نصب ابزارهای خط‌فرمان EF:
dotnet tool update --global dotnet-ef --version 7.0.10
سپس اجرای دستور زیر در ریشه‌ی پروژه: 
dotnet ef dbcontext scaffold "Data Source=C:\\Path\\db.sqlite" Microsoft.EntityFrameworkCore.Sqlite -o Output
‫۱ سال قبل، دوشنبه ۱۳ شهریور ۱۴۰۲، ساعت ۱۶:۱۷
یک نکته‌ی تکمیلی: استفاده از nonce بجای هش

روش دیگری هم برای مشخص کردن اسکریپت‌ها و شیوه‌نامه‌های inline وجود دارد که nonce نامیده می‌شود. nonce، یک مقدار منحصربفرد است که باید به ازای هر درخواست، یکبار دیگر به صورت خودکار، مجددا تولید شود (اگر ثابت باشد، مهاجم می‌تواند مقدار مشخص آن‌را به اسکریپت‌های خودش اضافه کند):
script-src 'nonce-rAnd0m'
یعنی قبل از هرکاری باید میان‌افزاری که کار تولید CSP Headers فوق را انجام می‌دهد، این مقدار را تولید کند. سپس می‌توان این مقدار را به ویژگی nonce برای مثال تگ اسکریپت، اضافه کرد:
<script nonce="rAnd0m">
</script>
مزیت آن، عدم نیاز به محاسبه و یا درج هش این قطعه اسکریپت، مطابق نکات مطلب جاری است؛ اما باید به صورت پویا به ازای هر درخواستی، مجددا در سمت سرور، تولید شود. همچنین تولید مجدد این مقدار، با کش شدن اطلاعات صفحه در تضاد است و باید به آن دقت داشت.

اگر از کتابخانه‌ی NetEscapades.AspNetCore.SecurityHeaders استفاده می‌کنید، فراخوانی متد WithNonce آن:
builder.AddScriptSrc().Self().WithNonce()
به صورت خودکار هدر مرتبط را تولید می‌کند. همچنین مقدار تولیدی آن‌را نیز در HttpContext.Items، درج می‌کند:
HttpContext.Items["NETESCAPADES_NONCE"]
به این روش، برای مثال یک Tag Helper و یا قسمت دیگری از برنامه که کار مقدار دهی nonce را به عهده دارد، می‌تواند به مقدار خودکار تولید شده‌ی توسط میان‌افزار، دسترسی داشته باشد (ابتدا میان‌افزار CSP اجرا می‌شود و سپس کار رندر صفحه به صورت جداگانه‌ای انجام می‌شود).

یک نکته: هنگام درج مقدار nonce در attributes، به HTML encoding آن دقت داشته باشید؛ این مقدار نباید encode شود (یا تغییر کند).
‫۱ سال قبل، دوشنبه ۲۳ مرداد ۱۴۰۲، ساعت ۱۴:۲۲
- مطلب جاری هیچ ارتباطی به درخواست‌های درون برنامه‌ای ندارد و فقط مرتبط با تنظیمات امنیتی مرورگرها است. این مرورگرها هستند که عنوان می‌کنند، من اینکار خاص را تحت این شرایط ویژه انجام نمی‌دهم؛ اما برنامه‌ی شما در پشت صحنه و توسط HttpClient یا هر روش مشابه دیگری، چنین محدودیتی ندارد.
- موردی که عنوان کردید فقط مرتبط با تنظیمات HttpClient مورد استفاده‌است که چنین گزینه‌ای را تنظیم نکرده.
این مشکل نیست. این توکن‌ها متکی به خود (self contained) هستند و همه چیز را جهت استفاده‌ی کامل از آن‌ها، درون خود دارند و تا زمانیکه یکسری از claims موجود در آن‌ها منقضی نشود (مانند طول عمر تنظیم شده‌ی آن‌ها) یا تغییر نکنند، از سمت سرور بدون هیچ مشکلی، اعتبارسنجی خواهند شد. زمانیکه logout می‌کنید، فقط این توکن‌ها را از کش‌های مختلف مرورگر حذف می‌کنید؛ اما ردی از حذف شدن و غیرمعتبر شدن آن، در سمت سرور ذخیره نمی‌شود و اگر کاربری قبلا این توکن را ذخیره کرده باشد، باز هم باتوجه به متکی به خود بودن آن، می‌تواند از آن استفاده‌ی مجدد کند. برای برگشت زدن توکن‌های متکی به خود، در سمت سرور، باید داخل آن‌ها یک claim سفارشی مانند serial number، قرار داد و همچنین در سمت سرور هم این serial number را ذخیره کرد. بعد در حین logout، این serial number را در بانک اطلاعاتی تغییر داد تا دفعه‌ی بعدی که قرار است از توکن متکی به خود استفاده شود، اعتبارسنجی ثانویه‌ای بر روی این claim دریافتی از کاربر و مقایسه‌ی آن با مقدار موجود در بانک اطلاعاتی در سمت سرور هم انجام شود (حالت پیش‌فرض اکثر سیستم‌های اعتبارسنجی، فاقد این مرحله است). اینکار در ASP.NET Core Identity تحت عنوان مفهوم security stamp پیاده سازی شده و وجود دارد؛ در JWTها توسط TokenValidatorService و در کوکی‌ها، توسط CookieValidatorService قابل پیاده سازی است. در نگارش‌های قبلی ASP.NET و حالت استفاده‌ی از Forms authentication، امکان بررسی سفارشی وضعیت کاربر جاری در authenticate request هم وجود دارد. مطلب جاری، به غنی‌سازی Validator Service‌های اشاره شده، می‌پردازد.