مطالب دوره‌ها
مقایسه بین سبک کدنویسی Lightweight و Verbose
در این فصل با ذکر مثال،به مقایسه نحوه کدنویسی  در #F با استفاده از دو نوع سبک Lightweight و Verbose می‌پردازیم.
استفاده از expression ها

//Lightweight
<expression1> <expression2> //Verbose <expression1>; <expression2>
استفاده از let‌های تودرتو
//Lightweight 

let f x =
    let a = 1
    let b = 2
    x + a + b

//Verbose

let f x =
    let a = 1 in
    let b = 2 in
    x + a + b
محدوده کد
//Lightweight 
<expression1> <expression2> ... //Verbose begin <expression1>; <expression2>; end
حلقه تکرار for do
//Lightweight 

for counter = start to finish do
    ...

 //Verbose
 for counter = start .. finish do ... done
حلقه تکرار while do
//Lightweight
 while <condition> do ...

 //Verbose
 while <condition> do ... done
حلقه تکرار for in
//Lightweight
for var in start .. finish do ...

 //Verbose
 for var in start .. finish do ... done
دستور do
//Lightweight 

do ...

 //Verbose  do ... in
تعریف record
//Lightweight 
type <record-name> = { <field-declarations> } <value-or-member-definitions>  //Verbose  type <record-name> = { <field-declarations> } with <value-or-member-definitions> end
تعریف class
//Lightweight
type <class-name>(<params>) = ... //Verbose
 type <class-name>(<params>) = class ... end
تعریف structure
//Lightweight 
[<StructAttribute>] type <structure-name> = ...

 //Verbose  type <structure-name> = struct ... end
تعریف Interface
//Lightweight 

type <interface-name> =
    ...
 
//Verbose
 type <interface-name> = interface ... end
پیاده سازی Interface
//Lightweight 

interface <interface-name>
    with
        <value-or-member-definitions>
 //Verbose
 interface <interface-name> with <value-or-member-definitions> end
تعریف module
//Lightweight 

module <module-name> =
    ...

  //Verbose
 module <module-name> = begin ... end
نظرات مطالب
اضافه کردن سعی مجدد به اجرای عملیات Migration در EF Core
یک نکته‌ی تکمیلی: مشکل تراکنش‌های صریح با EnableRetryOnFailure

زمانیکه از EnableRetryOnFailure استفاده می‌شود، هر کوئری و هر SaveChanges، یک «عملیات قابل‌تکرار» در صورت شکست خواهد شد (که تعداد بار تکرار آن بستگی به تنظیمات آغازین این متد دارد)؛ البته این در مورد تراکنش‌های ضمنی است. اگر در برنامه، یک تراکنش صریح را با فراخوانی BeginTransaction آغاز کنیم، یعنی قصد داریم یک واحد عملیاتی جدید را خودمان به نحو صریحی مشخص کنیم. در این حالت اگر خطایی رخ دهد، نیاز است کل عملیات تراکنش یکبار دیگر تکرار شود و نه اینکه هر کوئری آن یکبار دیگر؛ که در این حالت به استثنای زیر هم خواهیم رسید:
System.InvalidOperationException: The configured execution strategy ‘SqlServerRetryingExecutionStrategy’ 
does not support user initiated transactions. Use the execution strategy returned by 
‘DbContext.Database.CreateExecutionStrategy()’ to execute all the operations in the transaction as a retriable unit.
یا می‌توان این تنظیمات تکرار عملیات شکست خورده را حذف کرد و یا می‌توان همانطور که در متن خطا هم عنوان کرده، یک CreateExecutionStrategy جدید را سبب شد:
public async Task<IActionResult> UpdateProduct([FromBody]CatalogItem productToUpdate)
{
   var strategy =  _catalogContext.Database.CreateExecutionStrategy();
   await strategy.ExecuteAsync(async () =>
   {
     using (var transaction = _catalogContext.Database.BeginTransaction())
     {
        _catalogContext.CatalogItems.Update(productToUpdate);
        await _catalogContext.SaveChangesAsync();

        transaction.Commit();
     }
   });
}
در این حالت اگر مشکلی روی دهد، «عملیات قابل‌تکرار» همان کدهای async delegate تعریف شده هستند و اینبار حد و مرز آن مشخص شده‌است. اگر هم خواستید این راه حل را عمومی کنید، می‌توان از قطعه کد زیر جهت فراخوانی کدهای سفارشی داخل async delegate استفاده کرد:
public class ResilientTransaction
{
    private readonly DbContext _context;
    private ResilientTransaction(DbContext context) =>
        _context = context ?? throw new ArgumentNullException(nameof(context));

    public static ResilientTransaction New(DbContext context) => new(context);

    public async Task ExecuteAsync(Func<Task> action)
    {
        var strategy = _context.Database.CreateExecutionStrategy();
        await strategy.ExecuteAsync(async () =>
        {
            await using var transaction = await _context.Database.BeginTransactionAsync();
            await action();
            await transaction.CommitAsync();
        });
    }
}

// How to use it

await ResilientTransaction.New(_dbContext).ExecuteAsync(async () =>
{
      // ...
      await _dbContext.SaveChangesAsync();
});
بازخوردهای دوره
نگاهی به انواع Aspects موجود در کتابخانه PostSharp
- بحث در مورد AOP بدون ذکر نامی از PostSharp بی‌معنا بود. به همین جهت چند قسمتی به آن اختصاص داده شد. حداقل از لحاظ بحث مفهومی ارزشمند است.
- در سازمان‌ها امکان تشکیل یک مخزن نیوگت محلی وجود دارد. یعنی فقط کافی است یکی از سیستم‌ها تبدیل به مخزن شود و بقیه از آن استفاده کنند. اطلاعات بیشتر در اینجا
- پیشنهاد من استفاده از پروژه‌های سورس باز مشابهی است مانند Fody. یک نمونه از کاربرد آن‌را در ادامه این دوره بررسی کرده‌ایم: «معرفی پروژه NotifyPropertyWeaver ». امکانات زیادی دارد. یا اینکه اصلا از IL Weaving استفاده نکنید و از dynamic proxy مطرح شده مانند پروژه castle core که در قسمت‌های قبل بررسی شد، استفاده نمائید.
- post sharp زمانیکه از طریق نیوگت نصب می‌شود، خودش را در سیستم build ویژوال استودیو مرتبط با پروژه جاری ثبت می‌کند. پس از اینکه dll یا فایل exe شما توسط VS.NET تولید شد، به صورت خودکار کار post sharp آغاز شده و کدهای IL اضافی پیاده سازی کننده aspects مدنظر را به اسمبلی‌های برنامه اضافه می‌کند.
نظرات مطالب
پیاده سازی RabbitMQ
نکته تکمیلی :
میتوانید با استفاده از متد BasicQos حداکثر تعداد داده‌های ارسالی به Consumer هارا مشخص کنید.
 برای مثال اگر از طرف Consumer متد BasicAck رو صدا نزنید و به RabbitMq اعلام نکنید که داده به Consumer رسیده است, داده‌ها در RabbitMq باقی خواهند ماند.( در این حالت هر داده جدیدی در RabbitMq وارد شود به Consumer ارسال میشود اما هیچ داده ای پاک نمیشود).
 اما میتوانیم با استفاده از متد BasicQos تعداد داده‌های دریافتی را مشخص کنیم.
برای مثال در کد زیر حداکثر 16 داده به Consumer ارسال میشود. یعنی اگر Consumer که  16 داده را دریافت کرده, ack را به RabbitMq ارسال نکنند, هیچ داده دیگری به Consumer ارسال نمیشود تا زمانی ack مربوط به داده‌های قبلی به RabbitMq ارسال شود.
_model.BasicQos(0, 16, true);
این متد را میتوانید بعد از متد QueueBind در هنگام تعریف Consumer مربوط به Queue اضافه کنید.
نظرات مطالب
C# 6 - String Interpolation
یک نکته‌ی تکمیلی: روش رفع خطای CA1305

با «غنی سازی کامپایلر C# 9.0 با افزونه‌ها» نکات جالبی در کدها ظاهر می‌شوند که یکی از آن‌ها CA1305 است و به صورت خلاصه عنوان می‌کند که اگر متد در حال استفاده، دارای overload ای با پارامتر از نوع IFormatProvider هست، حتما از آن استفاده کنید؛ تا شاهد مشکلاتی مانند « تغییرات مهم مقایسه‌ی رشته‌ها در NET 5.0. » و « از متد DateTime.ToString بدون پارامتر استفاده نکنید! » نباشید. در مورد C# 6 - String Interpolation در متن جاری نکاتی در این مورد عنوان شده‌است. می‌توان جهت تکمیل آن، نکته‌ی ریز زیر را هم مدنظر داشت:
using static System.FormattableString;


var number = 11;
var text = Invariant($"{number}");
System.FormattableString استاندارد، به همراه متد استاتیک Invariant هم هست که همان کار ToString(CultureInfo.InvariantCulture) را انجام می‌دهد. جهت ساده سازی آن هم از ویژگی using static استفاده شده‌است.
نظرات مطالب
EF Code First #1
- زمانیکه از Trusted_Connection=true استفاده می‌شود (در حالت Windows authentication)، مشخصات کاربر IIS Identity (همان کاربر Application Pool سایت) بجای تنظیمات دیگر استفاده خواهد شد.
- برای حل مشکل Login failed for user ALIPC\ali ،‌دقیقا باید به «همین کاربر» در تنظیمات امنیتی SQL Server، دسترسی‌های لازم را بدهید:
  management studio -> select server -> expand Security -> right click Logins ->  select "New Login..."
در قسمت security و Logins سرور، باید یک لاگین جدید را ایجاد کنید و در اینجا دقیقا همین نام ALIPC\ali را وارد کرده و ok کنید (این کاربر را جستجو نکنید؛ به همین نحو فقط آن‌را وارد کنید). تا اینجا مشکل login failed برطرف می‌شود. اما این لاگین جدید دسترسی خاصی را ندارد. بنابراین در مرحله‌ی بعد:
Right click on db-> properties -> permission -> View Server permission
در اینجا باید به خواص بانک اطلاعاتی مراجعه کرده و در لیست permissions آن، این کاربر جدید اضافه شده را یافته و به آن، دسترسی‌های لازم مانند db owner را داد.
نظرات مطالب
ASP.NET MVC #23
- گزینه‌ی «"uncheck “Verify that file exists» را هم امتحان کنید.
- این سؤال خارج از بحث است. بازگرداندن View هیچ ارتباطی به مسیریابی ندارد. فقط کافی است بنویسید:
return View("~/Views/....مسیر کامل فایل", model);
تولید URLهای خودکار بر اساس اطلاعات مسیریابی در Viewهای برنامه، توسط متدهای توکار ActionLink و امثال آن انجام می‌شود.
- تمام خطاهای مدیریت نشده‌ی برنامه‌های وب در لاگ ویندوز ثبت می‌شوند. آن‌ها را بررسی کنید. همچنین ELMAH را هم نصب کنید تا خطاها را برای بررسی بیشتر لاگ کند.
- روش‌های قدیمی را با MVC کار نکنید. صفحه‌ی اول سایت، همان صفحه‌ای است که در مسیریابی پیش فرض تعریف شده‌است. یعنی همان اکشن متد Index در کنترلر Home، به همراه View ایی که مد نظر شما است.
نظرات مطالب
تغییر عملکرد و یا ردیابی توابع ویندوز با استفاده از Hookهای دات نتی
- نگارش 1.1 آن‌را از اینجا دریافت کنید.
- لطفا برای گزارش خطا از قسمت مخصوص بازخوردهای پروژه آن در سایت استفاده کنید.
همچنین در این حالت فایل ErrosLog.Log آن‌را هم فراموش نکنید (ریز خطاها در آن ثبت می‌شوند).

اگر پروژه را خودتان کامپایل کرده‌اید (که اینطور به نظر می‌رسد با توجه به پوشه debug)، برنامه اجرا نمی‌شود چون تمام فایل‌های exe و dll همراه easy hook را برای اجرا نیاز دارد و این‌ها باید کنار فایل اجرایی اصلی برنامه همانند بسته‌ای که برای دریافت در سایت قرار گرفته، کپی شوند.
این نکته در متن هم ذکر شده؛ قسمت «چند نکته تکمیلی مهم برای کار با کتابخانه Easy hook» انتهای بحث: «برای توزیع هوک‌های خود باید تمام فایل‌های همراه کتابخانه easy hook را نیز توزیع کنید و فقط به چند DLL ابتدایی آن بسنده نباید کرد»
نظرات مطالب
آشنایی با FileTable در SQL Server 2012 بخش 1

- به چه نحوی از SQL Server استفاده می‌کنید؟ آیا سرور و برنامه دسکتاپ شما روی یک کامپیوتر هستند؟ برای اینکار بهتر است از SQL CE یا SQLite استفاده کنید؛ یا حتی LocalDB. هدف از SQL Server نصب آن روی یک سرور و خدمات دهی به چندین و چند کامپیوتر تحت شبکه است. برای استفاده روی یک کامپیوتر یعنی کسب و کار کوچک و عملا نیازی به SQL Server 2012 ندارد اینکار. زندگی مصرف کننده را سخت نکنید. نصب و نگهداری یک سرور کار هر شخصی نیست و برای سازمان‌ها طراحی شده و نه مصارف کوچک تک کاربره دسکتاپ.

- با این توضیح اگر کسی به سرور شما دسترسی دارد، آیا نمی‌تواند مثلا اگر فایل‌ها در دیتابیس ذخیره می‌شدند، اون‌ها رو دستی با یک کوئری حذف کند؟ امنیت کار با سرور این‌جا است که مطرح می‌شود و همچنین اطمینان به ادمین‌ها.

- در مورد امنیت file table مراجعه کنید به مستندات مایکروسافت. مثلا: FileTables are secured by SQL Server security only

نظرات مطالب
ASP.NET MVC #12
- ابتدا نیاز است با مفهوم ViewModel آشنا باشید.
- اگر لیستی قرار است در تمام صفحات نمایش داده شود و محل آن هم باید در layout باشد، یعنی باید این لیست در هر بار نمایش و یا تولید هر View (تمام Viewهای سایت)، تولید شود. بنابراین در BaseViewModelایی که عنوان شد، تعریف خاصیت این لیست را قرار دهید و در layout از آن استفاده کنید.
// در پایه مدل‌ها
public abstract class BaseViewModel
{
    public IList<Post> Posts { get; set; } // خاصیت عمومی که قرار است در فایل مستر قابل دسترسی باشد
}

// در اکشن متد
 return View(model: new HomeViewModel { Posts = .... });

// در اینجا ویوومدل ارسالی از پایه مدل‌ها مشتق می‌شود
public class HomeViewModel : BaseViewModel
- و اگر نمی‌خواهید به ازای هر Viewایی که در سایت تولید می‌شود یکبار این لیست را مقدار دهی کنید، بهتر است از روش Html.RenderAction استفاده کنید (بحث «نمایش اطلاعات از کنترلر‌های مختلف در یک صفحه» در مطلب فوق). مباحث Caching را هم برای لیست‌های عمومی فراموش نکنید.