نظرات مطالب
ASP.NET MVC #11
با سلام و تشکر
مشکل من در قسمت آپلود فایل به سرور  (مقدار پارامتر file برابر با null بود و خطا ایجاد می‌شد)  از  طریق این پست حل شد .
 
نظرات مطالب
ASP.NET MVC #11
در قسمت آپلود فایل به سرور 
public ActionResult Upload(System.Web.HttpPostedFileBase file)
مقدار پارامتر file برابر با null می‌باشد و خطا ایجاد می‌شود چرا؟
نظرات مطالب
Strong Name
برای مشاهده Public Key Token یک اسمبلی با استفاه از فایل آن نیز میتوان از دستور زیر استفاده کرد:
sn  -T  MyAssembly.dll
پارامتر T حتما باید با حرف بزرگ وارد شود.
مطالب
Closure در JavaScript
در قسمت قبلی درباره علت نیاز به الگوهای طراحی در JavaScript و Function Spaghetti code صحبت شد. در این قسمت Closure در JavaScript مورد بررسی قرار می‌گیرد. 
در JavaScript می‌توان توابع تو در تو نوشت (nested functions) ، زمانی که یک تابع درون تابع دیگر تعریف می‌شود تابع درونی به تمام متغیر‌ها و توابع تابع بیرونی (Parent) دسترسی دارد.
Douglas Crockford برای تعریف Closure می‌گوید : 

an inner function always has access to the vars and parameters of its outer function, even after the outer  function has returned

یک تابع درونی (nested) همیشه به متغیر‌ها و پارامتر‌ها تابع بیرونی دسترسی دارد ، حتی اگر تابع بیرونی مقدار برگردانده باشد. 

تابع زیر را در نظر بگیرید : 
// The getDate() function returns a nested function which refers the 'date' variable defined
// by outer function getDate()
function getDate() {
   var date = new Date();    // This variable stays around even after function returns

   // nested function
   return function () {
      return date.getMilliseconds();
   }
}

  اکنون اگر به صورت زیر تابع getDate فراخوانی شود مشاهده می‌شود که تابع درونی (با کامنت nested function مشخص شده است.) به شیء date دسترسی دارد.
// Once getDate() is executed the variable date should be out of scope and it is, but since
// the inner function
// referenes date, this value is available to the inner function.
var dt = getDate();

alert(dt());
alert(dt());
خروجی هر 2 alert یک مقدار خواهد بود. 
اگر از فردی که به تازگی رو به JavaScript آورده است خواسته شود تابعی بنویسد که میلی ثانیه‌ی زمان جاری را برگداند احتمالا همچین کدی تحویل می‌دهد : 
        function myNonClosure() {
            var date = new Date();
            return date.getMilliseconds();
        }
در کد بالا پس از اجرای myNonClosure متغیر date از بین خواهد رفت ، این مسئله در دنیای JavaScript طبیعی هست.
این مثال را در نظر بگیرید :  
var MyDate = function () {
    var date = new Date();
    var getMilliSeconds = function () {
        return date.getMilliseconds();
    }
}

var dt = new MyDate();

alert(dt.getMilliSeconds());  // This will throw error as getMilliSeconds is not accessible.
در صورت اجرای مثال بالا خطایی با این مضمون دریافت خواهد شد که getMilliSeconds دستیابی پذیر نیست. (کپسوله شده)  برای اینکه آن را دستیابی پذیر کنیم کد را به این صورت تغییر می‌دهیم :
// This is closure 
var MyDate = function () {
    var date = new Date();   // variable stays around even after function returns
    var getMilliSeconds = function () {
        return date.getMilliseconds();
    };
    return {
        getMs : getMilliSeconds
    }
}
آنچه در تابع بالا انجام شده کپسوله سازی همه‌ی منطق کار (منطق کار در اینجا برگرداندن میلی ثانیه زمان جاری می‌باشد) در یک فضای نام به نام MyDate می‌باشد. همچنین فقط متد‌های عمومی در اختیار استفاده کننده این تابع قرار داده شده است. برای استفاده می‌توان بدین صورت عمل کرد : 
var dt = new MyDate();
alert(dt.getMs());  // This should work.
در کد بالا برای توابع و متغیر‌های درونی یک container ایجاد کردیم که باعث جلوگیری از تداخل در نام متغیر‌ها با دیگر کد‌ها خواهد شد . (برای مشاهده‌ی تداخل‌ها به قسمت قبلی  توجه کنید.)
اگر بخواهیم Closure را تشبیه کنیم ، Closure شبیه به کلاس‌ها در C# یا Java هست. 
Closure یک حوزه (scope) برای متغیر‌ها و توابع درونی خودش ایجاد می‌کند.
jQuery بهترین مثال کاربردی برای Closure می‌باشد : 
(function($) {

    // $() is available here

})(jQuery);
در ادامه این مفاهیم بیشتر توضیح داده می‌شودند ، اکنون می‌خواهیم مشکلی که در قسمت قبلی مطرح کردیم به کمک Closure حل کنیم : 
 در آن مثال گفته شد که اگر : 
// file1.js
function saveState(obj) {
    // write code here to saveState of some object
    alert('file1 saveState');
}
// file2.js (remote team or some third party scripts)
function saveState(obj, obj2) {
     // further code...
    alert('file2 saveState");
}
اگر تابعی به نام saveState در 2 فایل مختلف داشته باشیم و این 2 فایل را بدین صورت در برنامه آدرس دهیم : 
<script src="file1.js" type="text/javascript"></script>
<script src="file2.js" type="text/javascript"></script>
تابع saveState در فایل دوم تابع saveState فایل اول را override می‌کند. یک از توابع بالا را به صورت زیر باز نویسی می‌کنیم و منطق کار را کپسوله می‌کنیم : 
function App() {
    var save = function (o) {
        // write code to save state here..
        // you have acces to 'o' here...
        alert(o);
    };

    return {
        saveState: save
    };
}
بدون نگرانی تداخل saveState با بقیه saveState‌ها در هر پلاگین یا فایل دیگری می‌توان از saveState می‌توان اینگونه استفاده کرد : 
var app = new App();

app.saveState({ name: "rajesh"});
برای اطلاعات بیشتر در مورد Closure ها این لینک  را بررسی کنید.
مطالب
PersianToolkit تقویم و DatePicker شمسی به همراه مناسبت‌ها با استایل زیبا برای WPF
همانطور که اطلاع دارید، کنترل‌های Calendar و DatePicker در WPF، از تقویم‌های مختلف پشتیبانی نمی‌کنند و نمونه‌هایی که در سطح اینترنت موجود است، ظاهر و استایل مناسبی ندارند. بنابر این تصمیم گرفتم تا خودم دست به کار شوم و این کمبود را حل کنم. نتیجه‌ی آن شد کتابخانه‌ی PersianToolkit که بصورت استاندارد تقویم شمسی را به کنترل‌های Calendar و DatePicker اضافه می‌کند و استایل‌های زیبایی را هم به همراه خود دارد. این کتابخانه شامل تمام مناسبت‌های شمسی، قمری و میلادی بوده و امکان نمایش روزهای تعطیل را نیز داراست.
همچنین پرشین تولکیت شامل توابع قدرتمندی جهت دریافت تاریخ بصورت شمسی، قمری و میلادی است. لازم به ذکر است که توابع محاسبه تاریخ قمری بسیار دقیق بوده و خطای بسیار کمی دارد. علاوه بر موارد گفته شده، پرشین تولکیت شامل استایل‌ها و براش‌های پیشفرض متنوعی می‌باشد که کاربر می‌تواند با توجه به سلیقه‌ی خویش، رنگ بندی تقویم را تغییر دهد.
بروزرسانی:
نمونه مثال کامل به گیتهاب پروژه اضافه شد
کنترل تاریخ زمان به این مجموعه اضافه شد

پرشین تولکیت در 3 استایل مختلف موجود است که بصورت Runtime هم قابلیت تغییر استایل را دارد (روشن، تاریک، بنفش):



نحوه‌ی نصب و استفاده
  ابتدا پرشین تولکیت را از نیوگت نصب کنید:
  Install-Package PersianToolkit
سپس منابع برنامه را در فایل App.xaml بارگزاری کنید:
<ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <ResourceDictionary.MergedDictionaries>
                        <ResourceDictionary Source="pack://application:,,,/PersianToolkit;component/Themes/SkinDefault.xaml"/>
                        <ResourceDictionary Source="pack://application:,,,/PersianToolkit;component/Themes/Theme.xaml"/>
                    </ResourceDictionary.MergedDictionaries>
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>  
در هر کجا که نیاز به تقویم دارید ابتدا فضای نام برنامه را فراخوانی کنید سپس از اجزای آن استفاده کنید
 
  xmlns:pc="http://github.com/ghost1372/PersianToolkit"
         <pc:Calendar/>
    <pc:DatePicker/>  
تغییر پوسته برنامه
پرشین تولکیت شامل 3 پوسته پیشفرض است که میتوانید به راحتی در زمان اجرا، پوسته برنامه را تغییر دهید. قبل از آن نیاز است تا تابع تغییر پوسته را پیاده سازی کنید:
internal void UpdateSkin(SkinType skin)
        {
            ResourceDictionary skins0 = Resources.MergedDictionaries[0];
            skins0.MergedDictionaries.Clear();
            skins0.MergedDictionaries.Add(ResourceHelper.GetSkin(skin));
            skins0.MergedDictionaries.Add(new ResourceDictionary
            {
                Source = new Uri("pack://application:,,,/PersianToolkit;component/Themes/Theme.xaml")
            });
            Current.MainWindow?.OnApplyTemplate();
        }
ورودی تابع از نوع SkinType می‌باشد که شامل Dark, Violet و Default است:
UpdateSkin(SkinType.Violet);


تغییر تقویم به حالت میلادی یا شمسی
برای تغییر نوع تقویم میتوانید از کلاس ConfigHelper استفاده کنید (به صورت پیشفرض تقویم شمسی فعال است و نیازی به تغییر تقویم به شمسی نیست):
ConfigHelper.Instance.SetLanguage(ConfigHelper.Language.Persian);
نکته: فقط یکبار آن هم در زمان شروع شدن برنامه میتوانید نوع تقویم را تغییر دهید. در زمان اجرا نمیتوانید نوع تقویم را تغییر دهید.

گزینه‌های موجود

ShowHoliday :مناسبت‌ها
جهت نمایش مناسبت‌ها و روز‌های تعطیل بر روی تقویم، میتوانید آن را فعال کنید:
 <pc:Calendar pc:Holiday.ShowHoliday="True"/>

رنگ‌ها : روز جاری، روز انتخاب شده، روزهای تعطیل، کادر مناسبت‌ها
شما میتوانید براحتی رنگ روز فعلی، روز انتخاب شده و روزهای تعطیل را تغییر دهید:
<pc:Calendar pc:ColorStyle.HolidayDayBrush="{DynamicResource SuccessBrush}"
    pc:ColorStyle.SelectedDateBrush="{DynamicResource WarningBrush}" 
    pc:ColorStyle.TodayDateBrush="{DynamicResource InfoBrush}"/>
بصورت پیشفرض رنگ‌های زیر موجود است و با نوشتن آنها میتوانید از رنگ‌های پیشفرض استفاده کنید:
PrimaryBrush
SuccessBrush
InfoBrush
DangerBrush
WarningBrush
AccentBrush

برای تغییر رنگ کادر عنوان مناسبت‌ها باید از پراپرتی HolidayContentStyle استفاده کنید. دقت کنید که این پراپرتی ورودی از نوع Style را برای کنترل Label دریافت می‌کند. بصورت پیشفرض استایل‌های زیر موجود است:
 <pc:Calendar pc:ColorStyle.HolidayContentStyle="{StaticResource LabelPrimary}"/>
LabelDefault
LabelPrimary
LabelSuccess
LabelInfo
LabelDanger
LabelWarning

تغییر رنگ‌ها و استایل به وسیله کدهای سی شارپ
شما میتوانید رنگ‌ها و استایل‌های موجود را با سی شارپ هم تغییر دهید برای این منظور وارد کلاس ColorStyle شوید و پراپرتی موردنظر را انتخاب کنید و مقدار دلخواه را تنظیم کنید. برای سادگی کار، استایل‌ها و رنگ‌های پیشفرض توسط کلاس ResourceHelper و ResourceBrushToken یا ResourceHolidayContentStyleToken قابل دسترسی هستند.
ColorStyle.SetHolidayDayBrush(pc, ResourceHelper.GetResource<Brush>(ResourceBrushToken.SuccessBrush)); 
ColorStyle.SetHolidayContentStyle(pc, ResourceHelper.GetResource<Style>(ResourceHolidayContentStyleToken.LabelPrimary));
 
مطالب
متغیرها در ES 6
در ES 6 تغییراتی جهت ساده سازی خواندن، نوشتن و همچنین بالا بردن امنیت متغیرها و پارامترها صورت گرفته‌اند، تا دیگر شاهد یک سری رفتارهای عجیب و غریب، در حین کار با متغیرهای جاوا اسکریپتی نباشیم.


واژه‌ی کلیدی let

تاکنون به کمک واژه‌ی کلیدی var امکان تعریف متغیرها در جاوا اسکریپت مهیا بودند. برای نمونه در مثال زیر، متغیر x داخل بدنه‌ی if با استفاده از var تعریف شده‌است:
var doWork = function(flag){
   if(flag){
     var x = 3;
   }
   return x;
};
در اینجا اگر متد doWork را با پارامتر true اجرا کنیم، خروجی 3  و اگر آن‌را با پارامتر false اجرا کنیم، خروجی undefined را دریافت خواهیم کرد:


زمانیکه از var استفاده می‌شود، برای یک متغیر دو نوع میدان دید را می‌توان متصور شد:
- اگر خارج از بدنه‌ی تابع تعریف شود، این متغیر عمومی خواهد بود.
- اگر داخل بدنه‌ی تابع تعریف شود، میدان دید آن محدود به همان بدنه‌ی تابع می‌شود. در این حالت چیزی به نام block scope بی‌مفهوم است. در متد doWork فوق، هرچند متغیر x داخل بدنه‌ی بلاک if تعریف شده‌است، اما این x در کل بدنه‌ی تابع در دسترس است و نه صرفا داخل بلاک if. این مورد تا پیش از ES 6 منشاء بسیاری از باگ‌ها بوده‌است.
بنابراین در اینجا چون x تعریف شده، میدان دیدی در سطح متد دارد، return x معتبر بوده و در حالت دریافت پارامتر true، مقدار 3 را بر می‌گرداند و در حالت false هم همچنان مقداری را دریافت خواهیم کرد و این مقدار undefined است (اما پیام خطای عدم دسترسی به x را دریافت نمی‌کنیم).
به این رفتار اصطلاحا hoisting می‌گویند. در این حالت موتور جاوا اسکریپت، تمام متغیرهای تعریف شده‌ی توسط var را به صورت ضمنی به ابتدای تعریف متد منتقل کرده و آن‌ها را در آن‌جا تعریف می‌کند. به همین جهت است که return x تعریف شده‌ی در انتهای متد، قابلیت دسترسی به x داخل بدنه‌ی if را دارد.

در ES 6 برای رفع این مشکل، واژه‌ی کلیدی جدیدی به نام let معرفی شده‌است و هدف آن مهیا کردن block scoping تعریف متغیرها است:
var doWork = function(flag){
    if(flag){
      let x = 3;
    }
    return x;
};
اینبار اگر متد doWork را با پارامتر true فراخوانی کنیم، به خروجی ذیل خواهیم رسید:


بله. همانطور که مشاهده می‌کنید، اینبار میدان دید x به if block تعریف شده‌ی در آن محدود گشته و دیگر خارج از آن مفهومی ندارد و تعریف نشده‌است. به همین جهت زمانیکه به return x می‌رسیم، پیام تعریف نشده بودن x را دریافت خواهیم کرد. برای اینکه قطعه کد فوق کار کند، نیاز است return x را به داخل بدنه‌ی قطعه‌ی if تعریف شده، انتقال داد.

این block scoping مهیا شده‌ی توسط let، با حلقه‌ی for نیز کار می‌کند:
var doWork = function(){
   for(let i = 0; i< 10; i++){
   }

   /* return i won't work */
  return 0;
};
در مثال فوق اگر return i را در انتهای متد قرار دهیم، با همان خطای Uncaught ReferenceError پیشین مواجه خواهیم شد؛ از این جهت که برخلاف var، متغیر تعریف شده‌ی با let، میدان دیدی در سطح قطعه و بلاک تعریف شده‌ی در آن دارد و در اینجا بلاک متغیر i همان حلقه‌ی for است.


یک نکته

مفهوم block scoping با تعریف {} معنا پیدا می‌کند. بنابراین می‌توانید یک قطعه‌ی دلخواه را با تعریف {} نیز مشخص کنید:

و یا در مثال ذیل چندین قطعه‌ی تو در تو را مشاهده می‌کنید:
let outer = 'I am so eccentric!'
{
  let inner = 'I play with neighbors in my block and the sewers'
  {
    let innermost = 'I only play with neighbors in my block'
  }
  // accessing innermost here would throw
}
// accessing inner here would throw
// accessing innermost here would throw
در اینجا میدان دید متغیرهای تعریف شده، محدود است به قطعه‌ی آن‌ها. به همین جهت است که نمی‌توان به متغیر innermost در خارج از بلاک آن دسترسی یافت.

نمونه‌ی دیگر آن تعریف یک متد داخل یک بلاک است:
{
  let _nested = 'secret'
  function nested () {
    return _nested
  }
}
console.log(nested())
اگر این قطعه کد را اجرا کنیم، به خطای ذیل خواهیم رسید:


در ES 6 نمی‌توان به متغیرهای تعریف شده‌ی توسط let داخل یک بلاک، در خارج از آن دسترسی یافت. اگر می‌خواهید سطح دسترسی به متد را افزایش دهید، نیاز است به شکل ذیل عمل کنید و متد را خارج از بدنه‌ی بلاک با سطح دسترسی بیشتری تعریف نمائید:
var nested;
{
  let _nested = 'secret'
  nested = function () {
    return _nested
  }
}
console.log(nested())
// <- 'secret'


واژه‌ی کلیدی const

در ES 6 برای ایجاد و مقدار دهی متغیرهای فقط خواندنی، واژه‌ی کلیدی const افزوده شده‌است. در اینجا const نیز مانند let دارای block scoping است.
doWork = function()
{
   const value = 10;
   value = 11;
   return value;
}
در این مثال ابتدا متغیر value به صورت یک ثابت تعریف شده‌است و سپس مقدار 11 به آن نسبت داده شده‌است. اگر آن‌را در کروم 47 اجرا کنید، از مقدار 11 صرفنظر شده و خروجی 10 را بازگشت می‌دهد. اما اگر آن‌را در فایرفاکس 43 اجرا کنید، خطای متناظر با ES 6 را بازگشت می‌دهد:


در ES 6، انتساب یک مقدار به یک const، پس از تعریف آن، منجر به بروز خطای syntax error خواهد شد. همچنین تعریف مجدد آن نیز چنین خطایی را سبب خواهد شد.

یک نکته
هر چند const سبب read only شدن یک متغیر می‌شود، اما آن‌را immutable نمی‌کند:
const items = { people: ['you', 'me'] }
items.people.push('test')
console.log(items)
با این خروجی:

همانطور که مشاهده می‌کنید، هنوز هم می‌توان به شیء تعریف شده، آیتمی را اضافه کرد (در اینجا test به آرایه‌ی people اضافه شده‌است).


آشنایی با مفهوم shadowing

همان مثال ابتدای بحث را در نظر بگیرید:
var doWork = function(flag){
   if(flag){
        let x = 10;
        var x = 3;
        return x;
   }
};
داخل بدنه‌ی if، متغیر x یکبار توسط let و بار دیگر توسط var تعریف شده‌است.  در این حالت خطای Uncaught SyntaxError: Identifier 'x' has already been declared را دریافت خواهیم کرد (اگر let اول را به var تغییر دهید، مشکلی نخواهد بود و برنامه کامپایل می‌شود). اما اگر let x را به پیش از متد انتقال دهیم، اینبار مثال کامپایل می‌شود و خروجی متد (doWork(true مساوی 3 خواهد بود:
let x = 10;
var doWork = function(flag){
    if(flag){
      var x = 3;
      return x;
   }
};
در این حالت x تعریف شده‌ی داخل بلاک توسط var (یا حتی let) مقدار x تعریف شده‌ی در بلاک بالاتر را مخفی می‌کند که به آن shadowing نیز می‌گویند. در این حالت اگر در خارج از متد doWork، به x دسترسی پیدا کنیم، مقدار آن همان 10 است.
مثال ذکر شده، با مثال ذیل که یک بلاک را توسط {} ایجاد کرده‌ایم، یکی است:
let x = 10;
{
   let x = 3;
   console.log(x);
}
console.log(x);


در اینجا نیز ابتدا مقدار 3 که مرتبط با بلاک داخلی است چاپ خواهد شد و سپس مقدار 10 که مرتبط است به بلاک خارجی‌تر.
نظرات مطالب
تبدیل فایل‌های pfx به snk
مطلب خوبی بود وحید جان. ممنونم.
البته من بعد از اینکه مطلب شما رو خوندم و متوجه شدم که دو نوع فایل pfx و snk هست که با اون میشه sign کرد اندکی تو اینترنت گشتم و  متوجه یک نکته شدم که گفتم بد نیست اینجا مطرح کنم.
هر چند مطلب شما درباره تبدیل فایل pfx به snk است اما متنی که نوشتید این موضوع را القا میکند که نمیشود به سادگی این فایل رو ساخت.
به هر روی، میتوان فایل snk را از طریق فایل زبانه signing در خواص پروژه ساخت. برای این کار کافیست که گزینه Protect my key file with a password  را آنتیک کرد و در این حالت به جای اینکه فایل pfx ساخته شود فایل snk ساخته میشود.
مطلب دیگر اینکه من پروژه‌های متن باز دیگری را دیده ام که الان حضور ذهن ندارم بگم(احتمالاً یکیشون RavenDB بود) که از طریق خواص پروژه ویژوال استودیو کار signing را انجام نمیدهند یعنی در آنجا گزینه sign کردن را انتخاب نکرده اند. چون فایل snk را اگر منتشر کنیم همه میتونند با اون اسمبلی‌ها را sign کنند و معنای strong name بودن اسمبلی به طور کلی میره زیر سوال. در عوض از یک customized build استفاده میکنند که فقط توسط خودشون(مالکان پروژه) قابل فراخوانی است و توسط اون اسمبلی‌های release را میسازند. البته در اینباره باید بیشتر بررسی کنم و شاید دقیقاً ماجرا 100 درصد به این شکل که گفتم نیست.
نظرات مطالب
حذف اعراب از حروف و کلمات
جستجوی بهینه‌ی متنی بر روی حجم بالایی از اطلاعات بهتر است توسط روش‌های full text search انجام شود. مثلا از لوسین استفاده کنید، به همراه Lucene.Net.Analysis.Analyzer.ArabicAnalyzer آن که مخصوص جستجو بر روی متون عربی است.
همچنین اگر از FTS در SQL Server استفاده می‌کنید باید از accent insensitive collate استفاده کنید.
مطالب
Minimal API's در دات نت 6 - قسمت سوم - ایجاد endpoints مقدماتی
در دو قسمت قبل، ساختار ابتدایی برنامه‌ی Minimal API's بلاگ دهی را ایجاد کردیم. در این قسمت می‌خواهیم بررسی کنیم، معادل‌های کنترلرهای MVC و اکشن متدهای آن‌ها در سیستم جدید Minimal API، به چه صورتی ایجاد می‌شوند.


ایجاد اولین endpoint از نوع Get مبتنی بر Minimal API

برای افزودن اولین endpoint برنامه، به فایل Program.cs برنامه مراجعه کرده و آن‌را به صورت زیر تکمیل می‌کنیم:
// ...

app.UseHttpsRedirection();

app.MapGet("/api/authors", async (MinimalBlogDbContext ctx) =>
{
    var authors = await ctx.Authors.ToListAsync();
    return authors;
});

app.Run();
app.MapGet، معادل یک اکشن متد کنترلرهای MVC را که از نوع HttpGet هستند، ارائه می‌دهد. در همینجا می‌توان آدرس دقیق این endpoint را به عنوان پارامتر اول، مشخص کرد که پس از فراخوانی آن در مرورگر، یک Delegate که هندلر نام دارد (پارامتر دوم این متد)، اجرا می‌شود تا Response ای را ارائه دهد.
همانطور که مشاهده می‌کنید می‌توان در اینجا، این Delegate را از نوع Lambda expressions تعریف کرد و با ذکر MinimalBlogDbContext به صورت یک پارامتر آن، کار تزریق وابستگی‌های خودکار آن نیز صورت می‌گیرد. شبیه به حالتی که می‌توان یک سرویس را به عنوان پارامتر یک اکشن متد، با ذکر ویژگی [FromServices] در کنترلرهای MVC معرفی کرد؛ البته در اینجا بدون نیاز به ذکر این ویژگی (هرچند هنوز هم قابل ذکر است). مزیت آن این است که هر endpoint، تنها سرویس‌های مورد نیاز خودش را دریافت می‌کند و نه یک لیست قابل توجه از تمام سرویس‌هایی که قرار است در قسمت‌های مختلف یک کنترلر استفاده شوند.
پس از آن می‌توان با Context ای که در اختیار داریم، عملیات مدنظر را پیاده سازی کرده و یک خروجی را ارائه دهیم. در اینجا دیگر نیازی به تعریف IActionResult‌ها و امثال آن نیست و همه چیز ساده شده‌است.


ایجاد اولین endpoint از نوع Post مبتنی بر Minimal API

app.MapPost، معادل یک اکشن متد کنترلرهای MVC را که از نوع HttpPost هستند، ارائه می‌دهد:
//...

app.UseHttpsRedirection();

//...

app.MapPost("/api/authors", async (MinimalBlogDbContext ctx, AuthorDto authorDto) =>
{
    var author = new Author();
    author.FirstName = authorDto.FirstName;
    author.LastName = authorDto.LastName;
    author.Bio = authorDto.Bio;
    author.DateOfBirth = authorDto.DateOfBirth;

    ctx.Authors.Add(author);
    await ctx.SaveChangesAsync();

    return author;
});

app.Run();

internal record AuthorDto(string FirstName, string LastName, DateTime DateOfBirth, string? Bio);
در ابتدا یک Dto را که حاوی اطلاعات نویسنده‌ی جدیدی است، معادل خواص مدل Author دومین برنامه، تعریف می‌کنیم. سپس می‌توان این Dto را نیز به صورت یک پارامتر جدید به Lambda Expression متد app.MapPost معرفی کرد تا کار نگاشت اطلاعات دریافتی به آن، به صورت خودکار انجام شود (حالت پیش‌فرض آن [FromBody] است که نیازی به ذکر آن نیست).
سعی شده‌است تا این مثال در ساده‌ترین شکل ممکن خودش ارائه شود. در ادامه کار نگاشت خواص Dto را به مدل دومین برنامه، توسط AutoMapper انجام خواهیم داد.
مابقی نکات متد app.MapPost نیز مانند متد app.MapGet است؛ برای مثال در اینجا نیز تعریف مسیر endpoint، توسط اولین پارامتر این متد صورت می‌گیرد و نحوه‌ی تزریق سرویس DbContext برنامه نیز یکی است.


آزمایش برنامه‌ی Minimal API's

برنامه‌ی Minimal API's تهیه شده، به همراه یک Swagger از پیش تنظیم شده نیز هست. به همین جهت برای کار با این API الزاما نیازی به استفاده‌ی از مثلا برنامه‌ی Postman یا راه حل‌های مشابه نیست. بنابراین فقط کافی است تا برنامه‌ی API را اجرا کرده و در رابط کاربری ظاهر شده در آدرس https://localhost:7085/swagger/index.html، بر روی دکمه‌ی Try it out هر کدام از endpointها کلیک کنیم. برای مثال اگر چنین کاری را در قسمت Post انجام دهیم، به تصویر زیر می‌رسیم:



در اینجا پس از ویرایش اطلاعات شیء JSON ای که برای ما تدارک دیده‌است، فقط کافی است بر روی دکمه‌ی execute ذیل آن کلیک کنیم تا اطلاعات این Dto را به app.MapPost متناظر فوق ارسال کند و برای نمونه خروجی بازگشتی از سرور را نیز در همینجا نمایش می‌دهد که در آن، Id رکورد نیز پس از ثبت در بانک اطلاعاتی، مشخص است:



شروع به Refactoring و خلوت کردن فایل Program.cs

اگر بخواهیم به همین نحو تمام endpoints و dtoها را داخل فایل Program.cs اضافه کنیم، پس از مدتی به یک فایل بسیار حجیم و غیرقابل نگهداری خواهیم رسید. بنابراین در مرحله‌ی اول، تنظیمات سرویس‌ها و میان افزارها را به خارج از آن منتقل می‌کنیم. برای این منظور پوشه‌ی جدید Extensions را به همراه دو کلاس زیر ایجاد می‌کنیم:
using Microsoft.EntityFrameworkCore;
using MinimalBlog.Dal;

namespace MinimalBlog.Api.Extensions;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddApplicationServices(this IServiceCollection services,
        WebApplicationBuilder builder)
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }

        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();

        var connectionString = builder.Configuration.GetConnectionString("Default");
        builder.Services.AddDbContext<MinimalBlogDbContext>(opt => opt.UseSqlServer(connectionString));

        return services;
    }
}
کار این متد الحاقی، خارج کردن تنظیمات سرویس‌های برنامه از کلاس Program است.

همچنین نیاز به متد الحاقی دیگری برای خارج کردن تنظیمات میان‌افزارها داریم:
namespace MinimalBlog.Api.Extensions;

public static class WebApplicationExtensions
{
    public static WebApplication ConfigureApplication(this WebApplication app)
    {
        if (app == null)
        {
            throw new ArgumentNullException(nameof(app));
        }

        if (app.Environment.IsDevelopment())
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }

        app.UseHttpsRedirection();

        return app;
    }
}
پس از این تغییرات، اکنون ابتدای کلاس Program برنامه‌ی Api به صورت زیر تغییر می‌کند و خلاصه می‌شود:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddApplicationServices(builder);

var app = builder.Build();
app.ConfigureApplication();

در قسمت بعد، endpoints را از این کلاس آغازین برنامه خارج می‌کنیم.