نظرات مطالب
دریافت و نمایش فایل‌های PDF در برنامه‌های Blazor WASM
به روز رسانی به Blazor 6x

اگر مثال فوق را بر اساس Blazor 6x اجرا کنید، با خطای زیر مواجه خواهید شد:
Microsoft.JSInterop.JSException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded. 
Error: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded. at Object.createBlobUrl
علت اینجا است که در جهت بالا رفتن کارآیی برنامه‌های Blazor، دیگر یک byte array به صورت base64 به سمت کدهای جاوااسکریپتی ارسال نمی‌شود و مستقیما به صورت Uint8Array ارسال خواهد شد. اطلاعات بیشتر
بنابراین در کدهای فوق، قطعه کد قبلی زیر:
window.JsBinaryFilesUtils = {
  createBlobUrl: function (byteArray, contentType) {
    // The byte array in .NET is encoded to base64 string when it passes to JavaScript.
    const numArray = atob(byteArray)
      .split("")
      .map((c) => c.charCodeAt(0));
    const uint8Array = new Uint8Array(numArray);
    const blob = new Blob([uint8Array], { type: contentType });
    return URL.createObjectURL(blob);
  },
به صورت زیر ساده می‌شود و دیگر نیازی به encoding و decoding ندارد:
window.JsBinaryFilesUtils = {
  createBlobUrl: function (byteArray, contentType) {
    const blob = new Blob([byteArray], { type: contentType });
    return URL.createObjectURL(blob);
  },
مطالب
بازسازی کد: جایگزینی متغیر موقتی با پرس و جو (Replace temp with query)
زمانیکه متغیری برای نگهداری موقت نتیجه‌ی یک expression تعریف شده‌است، بهتر است expression مربوطه به متدی انتقال پیدا کرده و تمامی استفاده‌ها از متغیر موقتی با فراخوانی متد ایجاد شده جایگزین شوند. 
مشکل اصلی در ارتباط با متغیرهای محلی، ترویج ایجاد متدهای بلند توسط آنها است. مشخص است که این متغیرها در بدنه متد خود قابل استفاده هستند و تنها راه اشتراک مقدار آنها طولانی‌تر شدن متد است. اما زمانیکه این متغیرها با متد پرس و جوی مرتبط با آن جایگزین شوند، این مقدار توسط دیگر متدهای کلاس قابل دسترسی خواهد بود. این کار ایجاد متدهایی با اندازه مناسب را آسان‌تر می‌کند. 
این بازسازی کد بیشتر اوقات در کنار بازسازی استخراج متد استفاده می‌شود؛ به طوری که قبل از انجام استخراج متد، ابتدا تکلیف متغیرهای محلی مشخص می‌شود. یک نوع از متغیرهای محلی که نیاز به بررسی و تغییر خواهند داشت این دسته از متغیرهای محلی هستند.

مراحل انجام این بازسازی کد  

  • متغیر موقتی ای را که تنها یک بار مقداردهی شده است، پیدا کنید (در صورتیکه متغیر چندین بار مقداردهی شده باشد، باید بازسازی جداسازی متغیرهای موقتی را اعمال نمایید).
  • متغیر را به readonly تغییر دهید.
  • کد را کامپایل نمایید تا اطمینان حاصل کنید متغیر تنها یک بار مقداردهی شده‌است.
  • Expression سمت راست مقداردهی متغیر را به متد، منتقل نمایید. دو نکته در مورد متد تازه ایجاد شده:  
    • این متد را به صورت private تعریف نمایید. در صورتی در آینده مصرف دیگری برای آن پیدا کردید می‌توانید سطح دسترسی آن‌را آزادتر نمایید. 
    • اطمینان حاصل نمایید متد مورد نظر، شیء یا خصوصیتی را ویرایش نمی‌کند. در صورتیکه این کار را انجام می‌دهد، باید بخش ویرایش آن را از بخش پرس و جوی آن جدا نمایید (Separate query from modifier). 
  • کد را مجددا کامپایل نمایید.  
  • تمامی استفاده‌های متغیر را با فراخوانی متد ایجاد شده، تغییر دهید. 
مثال: تکه کد زیر را در نظر بگیرید  
public class OrderItem 
{ 
    private double quantity; 
    private double itemPrice; 
    public double CalculateTotal() 
    { 
        double basePrice = quantity * itemPrice; 

        if (basePrice > 1000) 
        { 
            return basePrice * 0.95; 
        } 
        else 
        { 
            return basePrice * 0.98; 
        } 
    } 
}

در این کلاس متدی برای محاسبه قیمت نهایی یک آیتم سفارش ایجاد شده‌است. با دقت در کد می‌توان تشخیص داد که متغیر basePrice یک متغیر محلی موقتی است. این تکه کد را می‌توان به صورت زیر بازسازی کرد   
public class OrderItem 
{ 
    private double quantity; 
    private double itemPrice; 
    public double CalculateTotal() 
    { 
        if (BasePrice() > 1000) 
        { 
            return BasePrice() * 0.95; 
        } 
        else 
        { 
            return BasePrice() * 0.98; 
        } 
    } 
    private double BasePrice() 
    { 
        return quantity * itemPrice; 
    } 
}
کد حاصل از بازسازی انجام شده، شامل یک متد به نام BasePrice است که مقدار قیمت پایه را بر می‌گرداند. این متد را به صورت private تعریف کردیم. اما می‌توان در صورت نیاز به override کردن آن در کلاس‌های مشتق شده‌ی احتمالی، سطح دستری آن را به مقدار مناسبی تغییر داد.  به نظر شما چه بازسازی کد دیگری را می‌توان بر روی متد CalculateTotal انجام داد؟ 

آیا این بازسازی کد تاثیر منفی بر کارآیی خواهد داشت؟ 

پاسخ سخت گیرانه به این پرسش بلی است. اما با وجود پردازنده‌های قوی حال حاضر و بهینه سازی‌های فراوانی که کامپایلرها در زمینه‌ی inlining انجام می‌دهند، این بازسازی کد تاثیر منفی شدیدی را بر روی کارایی نخواهد داشت. حتی با وجود تاثیر جزیی در کارآیی نرم افزار، تاثیر مثبتی که این بازسازی در خوانایی و قدرت مدیریت و توسعه دارد، این بازسازی را یکی از انتخاب‌های جدی اعمال بر روی کدهای مشکل دار می‌کند.  
مطالب
C# 12.0 - Collection Expressions & Spread Operator
C# 12 به همراه روش جدیدی برای آغاز مجموعه‌ها است که با آرایه‌ها، Spanها و هر نوعی که آغازگرهای مجموعه‌ها را بپذیرد، کار می‌کند. همچنین اپراتور جدیدی را هم به نام spread operator به صورت .. به زبان #C اضافه کرده‌است که امکان ساده‌تر ترکیب مجموعه‌ها را میسر می‌کند.


آغاز ساده‌تر مجموعه‌ها با کمک Collection Expressions

تا پیش از C# 12 برای آغاز یک آرایه می‌توان از روش زیر استفاده کرد که در آن نوع آرایه از طریق نوع اعضای آن حدس زده می‌شود:
var numbers1_CS11 = new[] { 1, 2, 3 };
که در حقیقت ساده شده‌ی تعریف اصلی زیر است:
var numbers1_CS_11 = new int[] { 1, 2, 3 };
در C# 12، می‌توان این تعاریف را به کمک collection expressions، خلاصه‌تر هم کرد:
int[] numbers1_CS12 = [ 1, 2, 3 ];
که در اینجا، {}‌ها به [] تبدیل شده‌اند و ذکر نوع آرایه، ضروری است (یعنی نمی‌توان از var جهت تعریف آن‌ها استفاده کرد)؛ در غیراینصورت با خطای زیر متوقف می‌شویم:
error CS9176: There is no target type for the collection expression.

یک collection expression و یا collection literals، به مجموعه‌ای از عناصر گفته می‌شود که بین دو براکت [] قرار می‌گیرند.

نمونه‌ی دیگر آن کار با Spanها است که نمونه کد C# 11 آن:
Span<string> span1_CS11 = new string[] { "AC", "AL" };
در C# 12 به صورت زیر خلاصه می‌شود:
Span<string> span1_CS12 = [ "AC", "AL" ];
و در اینجا امکان کار با ReadOnlySpan‌ها هم وجود دارد:
ReadOnlySpan<string> readOnlySpan_CS12 = [ "Africa",  "Asia", "Europa"];

مثال دیگر، نحوه‌ی آغاز آرایه‌های چندبعدی است:
int[][] array2D_CS11 =
  {
    new int[] { 2002, 2006, 2010},
    new int[] { 2014, 2018},
    new int[] { 2022, 2026, 2030}
  };
که در C# 12 به صورت خلاصه‌ی زیر قابل بیان است:
int[][] array2D_CS12 =
  [
     [2002, 2006, 2010],
     [2014, 2018],
     [2022, 2026, 2030]
  ];

و یا حتی این مورد را در مورد نحوه‌ی آغاز Listهای پیش از C#12
List<string> list_CS11 = new List<string> { "Item 1", "Item 2" };
نیز می‌توان بکار گرفت:
List<string> list_CS12 = [ "Item 1", "Item 2" ];

در کل همانطور که مشاهده می‌کنید، این تغییر، تغییر مثبتی است و حجم قابل ملاحظه‌ای از کدها را کاهش داده و خواندن آن‌ها را نیز ساده‌تر می‌کند.

یک نکته: روش ساده شده‌ی آغاز یک لیست با مجموعه‌ای خالی در C# 12 به صورت زیر است:
// Before C#12
List<User> users = new List<User>();
// or
var users = new List<User>();
// or
List<User> user = new();

// C#12
List<User> users = [];


اضافه شدن spread operator به زبان #C

اگر پیشتر با زبان JavaScript کار کرده باشید، با spread operator هم آشنایی دارید. کار آن ساده سازی یکی کردن مجموعه‌ها و یا افزودن ساده‌تر عناصری به آن‌ها است و .. بالاخره به زبان #C هم راه پیدا کرده‌است! برای مثال دو آرایه‌ی زیر را درنظر بگیرید:
int[] numbers1_CS12 = [ 1, 2, 3 ];
int[] numbers2_CS12 = [ 4, 5, 6 ];
در C# 12 برای یکی کردن آن‌ها می‌توان از spread operator به صورت زیر استفاده کرد:
int[] allItems = [ ..numbers1_CS12, ..numbers2_CS12 ];
Spread به معنای «پخش کردن»/«گسترده کردن»/«باز کردن» هست. برای مثال در اینجا، اعضای دو آرایه را داخل یک آرایه‌ی جدید، پخش کرده‌ایم!

اگر در نگارش‌های قبلی #C بخواهیم چنین کاری را انجام دهیم، یک روش آن به صورت زیر است:
int[] allItems_CS11 = numbers1_CS12.Concat(numbers2_CS12).ToArray();
که ... نگارش C# 12 آن کارآیی بیشتری دارد؛ چون تعداد بار اختصاص حافظه‌ی آن کمتر است. در C# 12، هنگام استفاده از spread operator، کار کپی کردن اطلاعات صورت نمی‌گیرد و همچنین طول نهایی مجموعه‌ی حاصل دقیقا مشخص می‌شود که این مورد از چندین بار تخصیص حافظه برای چسباندن آرایه‌های مختلف به هم جلوگیری می‌کند.

همچنین اپراتور پخش کردن، قابلیت قرارگرفتن در کنار سایر اعضای یک آرایه را هم به سادگی و با خوانایی بیشتری به همراه دارد:
int[] join = [..a, ..b, ..c, 6, 5];

به علاوه محدودیتی در مورد نوع مجموعه‌ی بکار گرفته شده نیز در اینجا وجود ندارد. برای نمونه در مثال زیر، یک آرایه، یک Span و یک لیست، با هم یکی شده‌اند:
int[] a =[1, 2, 3];
Span<int> b = [2, 4, 5, 4, 4];
List<int> c = [4, 6, 6, 5];

List<int> join = [..a, ..b, ..c, 6, 5];

و مثالی دیگر، نحوه‌ی ساده‌ی تعریف لیستی از tuples است:
List<(string, int)> otherScores = [("Dave", 90), ("Bob", 80)];
و سپس باز کردن آن داخل آرایه‌ای از tuples:
(string name, int score)[] scores = [("Alice", 90), ..otherScores, ("Charlie", 70)];
مطالب
لینک‌های هفته‌ی دوم بهمن

وبلاگ‌ها ، سایت‌ها و مقالات ایرانی (داخل و خارج از ایران)

ASP. Net

طراحی و توسعه وب

PHP

سی شارپ

عمومی دات نت

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


مسایل اجتماعی و انسانی برنامه نویسی

متفرقه
مطالب
مراحل تنظیم Let's Encrypt در IIS
روزگاری دریافت مجوزهای SSL، گران و سخت بود. برای رفع این مشکلات مؤسسه‌هایی مانند Let's Encrypt پدیدار شده‌اند که مجوزهای SSL رایگانی را برای سایت‌های اینترنتی صادر می‌کنند. دسترسی به سرویس آن‌ها از طریق API ارائه شده‌ی آن، بسیار ساده بوده، کار با آن رایگان است و نیاز به مجوز خاصی ندارد. فقط باید دقت داشت که گواهینامه‌های Let's Encrypt دو ماهه هستند و وب‌سرور سایت شما باید اجازه‌ی دسترسی به محل ویژه‌ای را که جهت تعیین اعتبار دومین درخواستی ایجاد می‌شود، صادر کند. البته درخواست گواهی مجدد و تمدید آن در هر زمانی، حتی اگر پیش از انقضای آن باشد، مسیر است و از این لحاظ محدودیتی ندارد. در ادامه نحوه‌ی کار با این سرویس را در ویندوزهای سرور بررسی خواهیم کرد.


دریافت برنامه‌ی win-acme

برنامه‌ی win-acme کار دریافت، نصب و تنظیم به روز رسانی خودکار مجوزهای Let’s Encrypt را در ویندوز بسیار ساده کرده‌است و تقریبا به برنامه‌ی استاندارد انجام اینکار تبدیل شده‌است. این برنامه، انجام مراحل زیر را خودکار کرده‌است:
- اسکن IIS برای یافتن bindings و نام سایت‌ها
-  اتصال به Let’s Encrypt certificate authority و دریافت مجوزهای لازم
- درج خودکار مجوزهای دریافتی در Windows certificate store
- ایجاد HTTPS binding خودکار در IIS
- استفاده از Windows Task Scheduler‌، جهت ایجاد وظیفه‌ی به روز رسانی خودکار مجوزهای درخواست شده

به همین جهت پیش از هر کاری نیاز است این برنامه را دریافت کنید:
https://github.com/PKISharp/win-acme/releases

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


آماده سازی برنامه‌ی ASP.NET جهت دریافت مجوزهای Let’s Encrypt

سرور Let’s Encrypt، در حین صدور مجوز برای سایت شما نیاز دارد بررسی کند که آیا شما واقعا صاحب همان دومین هستید یا خیر. به همین جهت مسیر
/.well-known/acme-challenge/id
را بر روی سرور شما بررسی خواهد کرد (بنابراین سرور شما باید به اینترنت متصل بوده و همچنین مجوز دسترسی به این مسیر را عمومی کند). برنامه‌ی win-acme این id را از سرور Let’s Encrypt به صورت خودکار دریافت کرده و فایلی را در مسیر یاد شده ایجاد می‌کند. سپس سرور Let’s Encrypt یکبار این مسیر را خواهد خواند. مشکل اینجا است که دسترسی به این فایل بدون پسوند در برنامه‌های MVC به صورت پیش‌فرض مسیر نیست و نیازی به تنظیمات خاصی دارد:
روش انجام اینکار در ASP.NET Core به صورت زیر است:
[HttpGet("/.well-known/acme-challenge/{id}")]
public IActionResult LetsEncrypt(string id, [FromServices] IHostingEnvironment env)
{
   id = Path.GetFileName(id); // security cleaning
   var file = Path.Combine(env.ContentRootPath, ".well-known", "acme-challenge", id);
   return PhysicalFile(file, "text/plain");
}
این اکشن متد را در هر کنترلری قرار دهید، تفاوتی نمی‌کند و کار خواهد کرد؛ چون attribute routing آن مستقل از محل قرارگیری آن است.
در MVC 5x پارامتر env را حذف و بجای آن از Server.MapPath و در آخر از return File استفاده کنید.
[Route(".well-known/acme-challenge/{id}")]
public ActionResult LetsEncrypt(string id)
{
   id = Path.GetFileName(id); // security cleaning
   var file = Path.Combine(Server.MapPath("~/.well-known/acme-challenge"), id);
   return File(file, "text/plain", id);
}
اگر این مرحله را تنظیم نکنید، در وسط کار دریافت مجوز توسط برنامه‌ی win-acme، به علت اینکه مشخص نیست آیا شما صاحب دامنه هستید یا خیر، خطایی را دریافت کرده و برنامه متوقف می‌شود.


آماده سازی IIS برای دریافت مجوزهای Let’s Encrypt

ابتدا به قسمت Edit bindings وب سایتی که قرار است مجوز را دریافت کند مراجعه کرده:


و سپس bindings مناسبی را ایجاد کنید (از نوع HTTP و نه HTTPS):


برای مثال اگر سایت شما قرار است توسط آدرس‌های www.dotnettips.info و dotnettips.info در دسترس باشد، نیاز است دو binding را در اینجا ثبت کنید. برای تمام موارد ثبت شده هم این تنظیمات را مدنظر داشته باشید:
Type:http
Port:80
IP address:All Unassigned
برنامه‌ی win-acme بر اساس این HTTP Bindings است که معادل‌های متناظر HTTPS آن‌ها را به صورت خودکار ثبت و تنظیم می‌کند.


اجرای برنامه‌ی win-acme بر روی ویندوز سرور 2008

IISهای 8 به بعد (و یا ویندوز سرور 2012 به بعد) دارای ویژگی هستند به نام Server Name Indication و یا SNI که اجاز می‌دهند بتوان چندین مجوز SSL را بر روی یک IP تنظیم کرد.


در اینجا به ازای هر Bindings تعریف شده‌ی در قسمت قبل، یک مجوز Let’s Encrypt دریافت خواهد شد. اما چون ویندوز سرور 2008 به همراه IIS 7.5 است، فاقد ویژگی SNI است. به همین جهت در حالت عادی برای مثال فقط برای www.dotnettips.info مجوزی را دریافت می‌کنید و اگر کاربر به آدرس dotnettips.info مراجعه کند، دیگر نمی‌تواند به سایت وارد شود و پیام غیرمعتبر بودن مجوز SSL را مشاهده خواهد کرد.
برنامه‌ی win-acme برای رفع این مشکل، از ویژگی خاصی به نام «SAN certificate» پشتیبانی می‌کند.
به این ترتیب با ویندوز سرور 2008 هم می‌توان دامنه‌ی اصلی و زیر دامنه‌های تعریف شده را نیز پوشش داد و سایت به این ترتیب بدون مشکل کار خواهد کرد. مراحل تنظیم SAN توسط برنامه‌ی win-acme به این صورت است:

ابتدا که برنامه‌ی win-acme را با دسترسی admin اجرا می‌کنید، چنین منویی نمایش داده می‌شود:
 N: Create new certificate
 M: Create new certificate with advanced options
 L: List scheduled renewals
 R: Renew scheduled
 S: Renew specific
 A: Renew *all*
 V: Revoke certificate
 C: Cancel scheduled renewal
 X: Cancel *all* scheduled renewals
 Q: Quit
گزینه‌ی N یا ایجاد مجوز جدید را انتخاب کنید.
سپس منوی بعدی را نمایش می‌دهد:
 [INFO] Running in Simple mode

 1: Single binding of an IIS site
 2: SAN certificate for all bindings of an IIS site
 3: SAN certificate for all bindings of multiple IIS sites
 4: Manually input host names
 C: Cancel
در این حالت برای ویندوز سرور 2008، فقط و فقط گزینه‌ی 2 را انتخاب کنید.
سپس لیست سایت‌های نصب شده‌ی در IIS را نمایش می‌دهد:
 1: Default Web Site
 C: Cancel

 Choose site: 1
در اینجا برای مثال شماره‌ی 1 یا هر شماره‌ی دیگر متناظر با وب سایت مدنظر را انتخاب کنید.
در ادامه منوی زیر را نمایش می‌دهد:
 * www.dotnettips.info
 * dotnettips.info

 Press enter to include all listed hosts, or type a comma-separated lists of exclusions:
لیستی را که در اینجا مشاهده می‌کنید، همان Bindings است که پیشتر ایجاد کردیم. عنوان می‌کند که برای کدامیک از این‌ها نیاز است مجوز دریافت و نصب شود. کلید enter را فشار دهید تا برای تمام آن‌ها اینکار صورت گیرد.
و ... همین! پس از آن کار دریافت، نصب و به روز رسانی Bindings در IIS به صورت خودکار انجام خواهد شد. اکنون اگر به قسمت Binding سایت مراجعه کنید، این تنظیمات خودکار جدید را مشاهده خواهید کرد:


اگر به لاگ نصب مجوزها دقت کنید این دو سطر نیز در انتهای آن ذکر می‌شوند:
 [INFO] Adding renewal for Default Web Site
 [INFO] Next renewal scheduled at 2018/7/21 4:19:20 AM
علت اینجا است که مجوزهای Let’s Encrypt طول عمر کمی دارند و در صورت به روز نشدن مداوم، کاربران دیگر قادر به مرور سایت نخواهند بود. به همین جهت این برنامه یک Scheduled Task ویندوز را نیز جهت به روز رسانی خودکار این مجوزها ایجاد و تنظیم می‌کند.


اجرای برنامه‌ی win-acme بر روی ویندوزهای سرور 2012 به بعد

چون IIS ویندوزهای سرور 2012 به بعد، از نصب و فعالسازی بیش از یک مجوز SSL به ازای یک IP به صورت توکار تحت عنوان ویژگی SNI پشتیبانی می‌کنند، مراحل انجام آن ساده‌تر هستند.
ابتدا که برنامه‌ی win-acme را با دسترسی admin اجرا می‌کنید، چنین منویی نمایش داده می‌شود:
 N: Create new certificate
 M: Create new certificate with advanced options
 L: List scheduled renewals
 R: Renew scheduled
 S: Renew specific
 A: Renew *all*
 V: Revoke certificate
 C: Cancel scheduled renewal
 X: Cancel *all* scheduled renewals
 Q: Quit
گزینه‌ی N یا ایجاد مجوز جدید را انتخاب کنید.
سپس منوی بعدی را نمایش می‌دهد:
 [INFO] Running in Simple mode

 1: Single binding of an IIS site
 2: SAN certificate for all bindings of an IIS site
 3: SAN certificate for all bindings of multiple IIS sites
 4: Manually input host names
 C: Cancel
در این حالت گزینه‌ی 4 را انتخاب کنید (با فرض اینکه از IIS 8.0 به بعد استفاده می‌کنید).
سپس از شما درخواست می‌کند که لیست دامنه و زیر دامنه‌هایی را که قرار است برای آن‌ها مجوز SSL صادر شوند، به صورت لیست جدا شده‌ی توسط کاما، وارد کنید:
 Enter comma-separated list of host names, starting with the primary one: dotnettips.info, www.dotnettips.info
در ادامه لیست وب سایت‌های ثبت شده‌ی در IIS را نمایش می‌دهد:
1: Default Web Site
2: mysiteName
Choose site to create new bindings: 1
در اینجا شماره‌ی سایتی را که می‌خواهید برای آن مجوز صادر شود، انتخاب کنید.
و ... همین! پس از آن مجوزهای SSL درخواستی، دریافت، نصب و تنظیم خواهند شد. همچنین یک Scheduled Task هم برای به روز رسانی خودکار آن تنظیم می‌شود.