مطالب
آشنایی با الگوی M-V-VM‌ - قسمت چهارم

در این قسمت، MVVM Light Toolkit مورد بررسی قرار گرفته است (دریافت، نصب، به همراه ارائه 4 مثال جهت معرفی توانمند‌ی‌های آن)

فهرست مطالب:
فصل 4- آشنایی با MVVM Light Toolkit
  • سایر کتابخانه‌ها و Framework های موجود MVVM
  • نصب قالب‌های MVVM Light Toolkit مخصوص VS.Net 2008
  • نصب قالب‌های MVVM Light Toolkit مخصوص VS.Net 2010
  • نصب Code Snippets مجموعه MVVM Light Toolkit در VS.Net 2008/2010
  • نصب فایل‌های بایناری کتابخانه‌ی MVVM Light Toolkit
  • نصب قالب‌های MVVM Light Toolkit مخصوص Expression Blend
  • بررسی صحت نصب کتابخانه‌ی MVVM Light Toolkit
  • استفاده از Code Snippets نصب شده
  • مثال اول - بررسی RelayCommand
  • مثال دوم - بررسی Messenger
  • مثال سوم - بررسی Blendability
  • مثال چهارم - بررسی EventToCommand


دریافت قسمت چهارم
دریافت مثال‌های قسمت چهارم

مطالب
یک سرویس (میکروسرویس) چیست؟ و چگونه آن را مستند کنیم؟ (قسمت اول)
معماری میکروسرویس (یا به اختصار: میکروسرویس) یک سبک معماری نرم افزار می‌باشد که در آن یک نرم افزار، به مجموعه‌ای از سرویس‌ها خرد می‌شود؛ به نحوی که هر سرویس مسئولیت انجام بخشی از منطق کسب و کار را به عهده داشته باشد.
این تقسیم بندی مزایای متعددی را به همراه دارد که نهایتا پیاده سازی و توسعه راحت‌تر نرم افزار‌های بزرگ و پیچیده را ممکن می‌نماید. از جمله مزایای این معماری می‌توان به راحت‌تر شدن مباحث continuous delivery/deployment، مقیاس پذیری بهتر، تحمل خطا، مهاجرت به (و یا استفاده از) تکنولوژی‌های جدید در بخش‌های مختلف نرم افزار و ... اشاره نمود.

مهم‌ترین بخش و تصمیمات شما به عنوان یک معمار نرم افزار، هنگام طراحی با استفاده از این معماری، شناسایی بخش‌های مختلف کسب و کار، جدا سازی و مرزبندی نمودن آنها و نهایتا طراحی سرویس‌ها و تعیین نحوه همکاری آنها با یکدیگر می‌باشد. لذا در هنگام استفاده از معماری میکروسرویس، مرکز توجهات باید کسب و کار باشد و نه مسائل تکنیکال و موضوعاتی مانند Docker, Kubernetes , Serverless و ... . (DDD می‌تواند به شما جهت مرزبندی بخش‌های مختلف کسب و کار و شناسایی سرویس‌ها کمک نماید)

تا اینجا متوجه شدیم که میکروسرویس در واقع یک سبک معماری نرم افزار محسوب می‌گردد و در واقع میکروسرویس (در اینجا و ادامه مقاله، منظور از میکروسرویس، معماری میکروسرویس می‌باشد) از چندین سرویس مجزا و مستقل تشکیل شده‌است که هر سرویس معمولا مسئولیت بخشی از منطق کسب و کار را بر عهده خواهد داشت.

مشخصات یک سرویس
هر سرویس در معماری میکروسرویس دارای چندین ویژگی اصلی به شرح زیر می‌باشد:
- Loosely coupled with other services - باید به طور مستقل از سایر سرویس‌ها عمل کند. به این معنا که تغییر و توسعه سایر سرویس‌ها موجب اختلالی در عملکرد این سرویس نگردد و برعکس، تغییر و توسعه این سرویس نباید عملکرد سایر سرویس‌ها را مختل نماید.
- Independently deployable - تیم توسعه دهنده سرویس قادر باشد تا بدون نیاز به هماهنگی با سایر تیم‌ها، خدمات خود (شامل ویژگی‌های جدید و تغییرات) را مستقر (Deploy) نماید.
- Capable of being developed by a small team – سرویس، امکان توسعه توسط یک تیم کوچک را داشته باشد. این مورد به جهت جلوگیری از سربار زیاد ناشی از هماهنگی در تیم‌های بزرگ، ضرورت دارد.
- Highly maintainable and testable – سرویس بسیار قابل نگهداری و قابل آزمایش باشد؛ امکان توسعه، تست و استقرار سریع را داشته باشد.

ساختار یک سرویس
حال که با ویژگی‌ها و مشخصات اصلی یک سرویس آشنا شدیم، در دیاگرام زیر، ساختار درونی یک سرویس را که از معماری هگزاگون (hexagonal architecture) استفاده می‌نماید، بررسی میکنیم. در این معماری، هسته سرویس، منطق کسب کار (Business logic) می‌باشد که توسط چندین آداپتور (جهت ارتباط با سایر سرویس‌ها) احاطه شده است.

بیایید با دقت به هر یک از بخش‌های یک سرویس (با توجه به دیاگرام فوق) نگاه کنیم

هر سرویس  احتمالا دارای یک یا چندین API می‌باشد
از دید مصرف کنندگان یک سرویس (Consumers)، تنها مورد با اهمیت یک سرویس، APIهای آن سرویس می‌باشد. APIهای یک سرویس نیز (با توجه به تصویر فوق) شامل عملیات یا Operations و وقایع منتشر شده یا Published events می‌باشند. که در ادامه این انواع را بررسی میکنیم.

- عملیات (Operations)
به صورت کلی و همانطور که در دیاگرام فوق قابل مشاهده می‌باشد، عملیات به دو نوع دستورات (Commands) و جستارها (Queries) تقسیم می‌شوند. دستورات نوعی از عملیات می‌باشند که موجب تغییر داده‌ها می‌شود؛ اما در مقابل جستارها، عملیاتی در جهت واکشی داده‌ها می‌باشند. برای مثال یک سرویس  ثبت سفارش (OrderService) را در نظر بگیرید. عملیاتی مانند ثبت سفارش ()CreateOrder، انصراف از سفارش ثبت شده  ()CancelOrder و ... عملیاتی از نوع دستورات هستند و عملیاتی مانند یافتن یک سفارش خاص ()FindOrder که هیچ دیتایی را تغییر نمیدهد، از نوع جستارها می‌باشند.
عملیات ارائه شده توسط یک سرویس میتواند از ترکیبی از پروتکل‌های همزمان (Synchronous protocols) مانند REST یا gRPC و پروتکل‌های غیر همزمان (Asynchronous protocols) مانند messaging باشند.
پروتکل‌های همزمان، به ویژه REST، بیشتر در مواردی که قصد ارائه API به کلاینت‌های خارجی (External clients) را داریم، مانند موبایل اپلیکیشن‌ها و یا نرم افزارهای تک صفحه‌ای (SPA) کاربرد دارند.
از پروتکل‌های غیر همزمان مانند messaging نیز بیشتر در مواردی که میخواهیم الگوی ساگا (SAGA) را پیاده سازی نماییم و به روز نگه داشتن داده‌ها را بین سرویس‌های مختلف حفظ کنیم، نیاز به استفاده داریم. برای مثال در همان سیستم ثبت سفارش، عملیات ()CreateOrder به صورت Rest و با متد Post در Endpoint ای مانند /Order پیاده سازی می‌شود و پس از فراخوانی، یک عملیات غیرهمزمان مانند CreateOrderSaga را نیز به صورت messaging آغاز میکند.

- وقایع (Events)
سرویس‌ها، اغلب وقایعی (Event) را نیز منتشر میکنند. منظور از وقایع یا events معمولا همان مفهوم domain event درDDD می‌باشد که در همان ادبیات DDD وقایع توسط aggregate‌ها در زمان هایی مانند ایجاد، ویرایش، حذف و یا سایر مفاهیم موجود در منطق کسب و کار منتشر می‌شوند. سرویس نیز معمولا این وقایع را روی یک کانال ارتباطی (message channel) که توسط یک message broker (مانند RabbitMQ, Apache Kafka, ActiveMQ و ...) پیاده سازی شده است، منتشر میکند. و علاقمندان به دریافت این وقایع می‌توانند وقایع را پس از انتشار، بر روی کانال ارتباطی دریافت نمایند.


منطق کسب و کار (Business Logic)
منطق کسب و کار، قلب هر سرویس و دلیل وجود آن سرویس می‌باشد که API هایی را در قالب عملیات (Opertaions) پیاده سازی و همچنین مواردی را در قالب وقایع (Events) منتشر می‌نماید. همچنین منطق کسب و کار می‌تواند بنا بر نیاز خود، عملیات مربوط به سایر سرویس‌ها را فراخوانی و یا در کانال‌های ارتباطی (channels) مربوط به وقایع آنها، مشترک (Subscribes) شود و نهایتا داده‌ها را در دیتابیس خود نگهداری نماید.

نحوه همکاری سرویس‌ها با یکدیگر (Services Collaborations)
با توجه به مفاهیم فوق، زمانی که صحبت از همکاری (collaborate) بین سرویس‌ها می‌شود، معمولا منظور، ارتباط آنها از طریق APIهای یکدیگر (شامل عملیات و وقایع که پیش‌تر توضیح داده شد) می‌باشد (به جای خواندن و نوشتن مستقیم در دیتابیس‌های مربوط به یکدیگر می‌باشد).
برای مثال یک سرویس ممکن است عملیات مربوط به ایجاد سفارش ()CreateOrder را از سرویس ثبت سفارش (OrderService) فراخوانی نماید و یا برعکس خود سرویس ثبت سفارش (OrderService) ممکن است بر حسب نیاز منطق کسب و کار خود، عملیات ارائه شده توسط سرویس انبار را فراخوانی نماید.
همچنین یک سرویس جهت همکاری با دیگر سرویس‌ها میتواند در وقایع منتشر شده (Published events) توسط آنها مشترک (Subscribes) شود. برای مثال سرویس ثبت سفارش احتمالا در وقایع منتشر شده از سوی سرویس رستوران مشترک می‌شود.

دیتابیس اختصاصی
معمولا هر سرویس دارای یک یا چند دیتابیس می‌باشد که دیتای اختصاصی مربوط به منطق کسب و کار خود و در مواردی بخشی از دیتای مربوط به سایر سرویس‌ها را در آن‌(ها) نگهداری میکند. برای مثال اطلاعات سفارش‌ها را هم سرویس ثبت سفارش و هم سرویس رستوران، هر دو نگهداری میکنند و عملا این دیتا ابتدا در سرویس رستوران و سپس در سرویس ثبت سفارش، مجددا نگهداری می‌شود و به نوعی دیتای فوق Replicate شده و تکراری می‌باشد. اما به جهت اطمینان از کاهش وابستگی (loose coupling) این تکرار داده‌ها انجام می‌شود. در مجموع استفاده از یک دیتابیس مشترک (منظور table مشترک می‌باشد) بین سرویس‌ها ایده‌ی بدی می‌باشد و سرویس‌ها باید از طریق API‌های یکدیگر باهم همکاری نمایند.

نتیجه
در این مقاله عنوان شد که میکروسرویس یک سبک معماری می‌باشد و در این معماری، نرم افزار و منطق کسب و کار، به چندین سرویس مختلف  تقسیم می‌شود. مشخصات کلیدی که هر سرویس باید در این سبک معماری (microservice architecture) داشته باشد و همچنین ساختار درونی هر سرویس بررسی شد.
در قسمت بعدی این مقاله، در مورد نحوه مستند سازی این سرویس‌ها صحبت می‌شود. چرا که با زیاد شدن تعداد سرویس‌ها، در صورت عدم وجود یک مستندات مناسب (documents)، ارتباط و هماهنگی تیم‌ها با یکدیگر خود موجب سربار خواهد شد.

منابع
برگرفته شده از مقاله آقای ریچاردسون (whats-a-service
نظرات مطالب
Angular CLI - قسمت ششم - استفاده از کتابخانه‌های ثالث
یک نکته‌ی تکمیلی: تغییرات در فایل angular-cli.json نیاز به راه اندازی مجدد watchers را دارد

فرض کنید برنامه را توسط دستورات ng build --watch و یا ng serve -o تهیه و یا اجرا کرده‌اید. در این حال، برای مثال جهت افزودن مجموعه آیکن‌های قلم font-awesome به صورت زیر عمل کرده‌اید:
 npm install font-awesome --save
و سپس تعریف css آن‌را نیز به قسمت styles فایل angular-cli.json افزوده‌اید:
"styles": [
   "../node_modules/bootstrap/dist/css/bootstrap.css",
   "../node_modules/font-awesome/css/font-awesome.css",
   "styles.css"
],
اکنون اگر برنامه مجددا به صورت خودکار build شود، فونت‌ها و آیکن‌ها را مشاهده نخواهید کرد. علت اینجا است که دستورات یاد شده که در حالت watch اجرا می‌شوند، تنها به تغییرات پوشه‌ی src واکنش نشان می‌دهند و تغییرات فایل angular-cli.json از دید آن‌ها مخفی است.
به همین جهت باید یکبار آن‌ها را بسته و مجددا از ابتدا اجرا کنید تا اینبار قلم آیکن font-awesome اعمال شده و قابل نمایش شود.
مطالب
آموزش MDX Query - قسمت دوازدهم – استفاده از توابع Head , Filter , TopCount , tail
در ادامه به بررسی توابع Head , Filter , TopCount و tail  می‌پردازیم

Select
{
[Measures].[Internet Sales Amount],
[Measures].[Internet Tax Amount]
} on columns,
head(
[Customer].[Customer Geography].[Country],
2
)on rows
From [Adventure Works]

تابع Head، تعداد مشخص شده بر اساس پارامتر اول از آن محور را بر اساس نحوه‌ی نمایش تنظیم شده در SSAS، واکشی می‌کند. 

حال تصور کنید بخواهیم شرط زیر را بر روی کوئری بالا اجرا کنیم

( [Measures].[Internet Sales Amount] >= '2500000' )

به عبارت دیگر ما می‌خواهیم دو کشوری را انتخاب کنیم که میزان فروش اینترنتی آنها بالای 2500000 باشد.

کوئری مشابه زیر می‌باشد

 Select  {
[Measures].[Internet Sales Amount],
[Measures].[Internet Tax Amount]
} on columns,
head(
[Customer].[Customer Geography].[Country],
2
)on rows
From [Adventure Works]
Where
( [Measures].[Internet Sales Amount] >= '2500000' )

البته خطای زیر را خواهیم داشت. 

به یاد داشته باشیم در صورتیکه بخواهیم ایجاد محدودیت در نمایش داده‌ها را در یک محور داشته باشیم، باید از تابع Filter استفاده کنیم؛ به صورت زیر:

Select
Filter(
{
[Measures].[Internet Sales Amount],
[Measures].[Internet Tax Amount]
} ,
[Measures].[Internet Sales Amount] >= 2644017.71
  ) on columns,
head(
[Customer].[Customer Geography].[Country],
3
)on rows
From [Adventure Works]

تابع Filter دو پارامتر می گیرد. پارامتر اول نام ردیف یا ستونی می باشد که روی آن می خواهیم عمل فیلتر را انجام دهیم. پارامتر دوم شرط فیلترینگ می باشد که می بایست مانند T/SQL دارای یک خروجی Boolean باشد

همچنان نتیجه درست نمی‌باشد ! چرا؟

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

کوئری زیر را اجرا نمایید

Select {
[Measures].[Internet Sales Amount]
,[Measures].[Internet Tax Amount]
  }
on columns,
head(
Filter(
  [Customer].[Customer Geography].[Country] ,
  [Measures].[Internet Sales Amount] >= 2644017.71
),
3)
on rows
From [Adventure Works]

البته توجه کنید که این کوئری، سه کشور اول که در شرط زیر قرار دارند را بر می گرداند و الزاما این سه کشور از تمام  کشور های دیگر بیشتر نمی باشند.

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

اگر بخواهیم سه کشوری را که بالاترین میزان فروش را دارند پیدا کنیم و شرط هم همواره اعمال گردد، کوئری زیر درست می باشد:

Select {
[Measures].[Internet Sales Amount]
,[Measures].[Internet Tax Amount]
  }
on columns,
TopCount(
Filter(
  [Customer].[Customer Geography].[Country] ,
  [Measures].[Internet Sales Amount] >= 2644017.71
  ),
3, [Measures].[Internet Sales Amount])
on rows
From [Adventure Works]

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

حال اگر بخواهیم سه ردیف انتهایی جدول را واکشی کنیم داریم:

Select
{
[Measures].[Internet Sales Amount],
[Measures].[Internet Tax Amount]
}on columns,
tail([Customer].[Customer Geography].[Country],
3)on rows
From [Adventure Works]

این تابع برعکس تابع Head  کار میکند و N ردیف آ اخر مجموعه را بدست می‌ آورد . البته در بالا فقط 3 ردیف انتهایی را در خروجی آورده ایم و هیچ شرطی اعمال نگردیده است.


نظرات مطالب
مفاهیم برنامه نویسی ـ آشنایی با سازنده‌ها
سلام،
آقای فرقانی بسیار عالی بود، واقعا لذت بردم،
فقط خواهشی از شما دارم این هستش که : دقت و حساسیت مبحث شی گرایی رو احیانا فدای چیز‌های دیگر نکنید!، منظورم این هستش که تا حد توان اصول مهندسی نرم افزار رو به صورت کامل رعایت بفرمایید و نگران کاربر مبتدی نباشید، کاربر مبتدی ، ناخودآگاه خودش مطالب غیر قابل فهم رو فیلتر میکنه و در بدترین حالت، در آن مورد، از شما سوال خواهند کرد و شما هم آنها را به موضوع مناسب ارجاع خواهید داد هر چند اگر موضوع ارائه شده بعدا قراره باز بشه، خیلی راحت می‌تونید در متن نوید توضیحات بیشتر رو به خواننده بدهید و در غیر این صورت ارجاع به توضیحات مناسب.
به هر حال باز هم تاکید می‌کنم و سفارش میکنم که دقت بیان و رعایت اصول رو فدای هیچ چیزی نکنید.
ممنونم.
نظرات مطالب
Dependency Injection
مشکلی که ما داریم دید ادغام وزارت ICT و وزارت راه و برداشت‌هایی در رده‌های بالا در این حد و اندازه است که نهایتا منجر به عدم وجود صنعت برنامه نویسی به شکلی که در کشورهای دیگر هست شده است. با این اوصاف وقتی برنامه‌ها در حد چند سفارش کوچک خلاصه می‌شود یا عموما تک کاربره یا یکی دو کاربره هستند، شاید زیاد تفاوتی نکند که ابزار شما VB6 باشد یا دلفی یا دات نت (همچنین بحث پشتیبانی سیستم‌های قدیمی هم مطرح است).
اما زمانیکه تعداد کاربران شما بالای 200 نفر همزمان بودند و در یک شرکت باید این‌ها رو جمع و جور و پشتیبانی می‌کردید، استفاده از دلفی و دید برنامه نویسی دسکتاپ فقط در حد یک شوخی قابل طرح بود (فقط یکبار این تصور را بکنید که برنامه شما باید در طی روز حداقل سه بار بر اساس درخواست‌های رسیده به روز شود. اگر تونستید ادمینی رو پیدا کنید که 200 تا کامپیوتر رو برای شما روزی سه بار به روز کند به من خبر بدید)
مطالب
دسته بندی کردن لاگ‌ها در Serilog

در Serilog لاگ‌ها به صورت ترتیبی در فایل و یا در Elasticsearch ذخیره میشوند. این لاگ‌ها زمانیکه تعداد کاربران سایت زیاد میشوند و تعداد آن‌ها نیز افزایش می‌یابد، به صورت تصادفی ( به ازای ریکوئست کاربران ) در Elasticsearch و یا فایل متنی ذخیره میشوند. برای مثال یک کاربر مشغول ثبت سفارش است و کاربر دیگری عملیات استرداد را انجام میدهد و لاگ این دو کاربر به صورت همزمان به مقصد مورد نظر شما ( Elasticsearch و یا فایل متنی ) ارسال میشوند و لاگ‌ها شکل نامرتبی را به خود میگیرند و عملا نمیتوانید یک سفارش را پیگیری کنید. هر چقدر تعداد کاربران و ریکوئست‌ها بیشتر شود، تقریبا پیدا کردن لاگ‌های مربوط به یک اکشن یا api کاملا سخت و یا غیرممکن میشود. اما با استفاده از Serilog.Context.LogContext.PushProperty میتوانید یک scope را تعریف کنید که شامل یک نام و یک مقدار است و تمامی لاگ‌های داخل آن scope، شامل همان نام و مقداری هستند که شما آن‌ها را ایجاد کرده‌اید.
public IActionResult ConfirmOrder(Order order)
{
    using (Serilog.Context.LogContext.PushProperty("OrderId", order.Id))
    {
        _logger.LogInformation("Check order validation");
        //DoSomething
        _logger.LogInformation("Order validation successfully");
        //DoSomething
        _orderService.ConfirmOrder(order);
        _logger.LogInformation("Order confirmed successfully");
    }
    return Ok();
}
با این کار تمامی لاگ‌های ثبت شده در scope مربوط به OrderId، شامل یک پراپرتی به نام OrderId و مقدار order . Id هستند که با این کار میتوانید تمامی ریکوست‌های مربوط به یک اکشن خاص را با آیدی سفارش پیدا کنید. حتی اگر در متد ConfirmOrder مربوط به orderService هم از ILogger استفاده کرده باشید، تمامی لاگ‌های مربوط به orderService هم شامل پراپرتی OrderId هستند. یک نمونه از لاگ‌ها:
{
   "Timestamp":"2020-10-20T23:01:01.0492132+03:30",
   "Level":"Information",
   "MessageTemplate":"Order Confirmed successfully",
   "Properties":{
      "SourceContext":"SerilogExamlpe.WebApplication.Controllers.WeatherForecastController",
      "ActionId":"870582be-312f-4065-88eb-5675e2df4928",
      "ActionName":"SerilogExamlpe.WebApplication.Controllers.WeatherForecastController.Get (SerilogExamlpe.WebApplication)",
      "RequestId":"0HM3L5QM34E6K:00000001",
      "RequestPath":"/weatherforecast",
      "SpanId":"|da92fcac-4169ab4e937de2ae.",
      "TraceId":"da92fcac-4169ab4e937de2ae",
      "ParentId":"",
      "OrderId":12345,//<-- NOTE THIS
      "MachineName":"FARHAD-PC",
      "Environment":"Development"
   }
}
لاگ ثبت شده، مربوط به آخرین لاگ نوشته شده است؛ با مقدار "Order Confirmed successfully". در این لاگ، پراپرتی OrderId را با مقدار 12345 مشاهده میکنید؛ در حالیکه ما فقط یک متن را ثبت کرده‌ایم، ولی در لاگ ثبت شده، اطلاعات اضافه‌ای را برای لاگ ثبت کرده‌است. با این کار میتوانید تمامی لاگ‌های مربوط به سفارش با آیدی 12345 را به راحتی پیدا کنید.
اگر از Serilog استفاده نمیکنید و از ILogger خود دات نت برای ثبت لاگها استفاده میکنید، میتوانید به جای PushProperty از متد BeginScope به صورت زیر استفاده کنید:
using (_logger.BeginScope("OrderId : {orderId}", 12345))
همچنین میتوانید یک میان افزار را ایجاد کنید که آی‌دی و آی‌پی کاربر را در تمامی لاگ‌ها ذخیره کند :
app.Use(async (httpContext, next) =>
{
    //Get username  
    var username = httpContext.User.Identity.IsAuthenticated ? httpContext.User.Identity.Name : "anonymous";
    LogContext.PushProperty("User", username);

    //Get remote IP address  
    var ip = httpContext.Connection.RemoteIpAddress.ToString();
    LogContext.PushProperty("IP", !String.IsNullOrWhiteSpace(ip) ? ip : "unknown");

    await next.Invoke();
});
با این  کار تمامی لاگ‌ها شامل پراپرتی‌های User و IP می‌باشند.
مطالب
ویدئوهای آموزشی Entity Framework با زیرنویس فارسی
یه سری ویدئو آموزشی EF  که توسط PulralSight به سفارش مایکروسافت خیلی وقت پیش تهیه شده بود رو با کمک یکی از دوستان داریم زیرنویس می کنیم (البته بیشترش رو دوست خوبم آقا حامد زحمتش رو کشیدن و من فقط تونستم پارت اول رو زیرنویس کنم و در حال زیرنویس پارت سوم هستم) در حال حاضر چهار پارت از این مجموعه زیرنویس شده :
پاسخ به بازخورد‌های پروژه‌ها
درخواست مستندات
هدف از انجام این است که کاربر(End User) بتواند گزارش‌های مورد نظر خود را ساخته، فایل xml تولید شده را به برنامه بدهد و برنامه مطابق فایل xml  و تگ‌ها گزارش را ساخته و به کاربر نمایش دهد.
در غیر اینصورت کاربر باید به ازای هر گزارش به برنامه نویس آن سفارش دهد تا گزارش مدنظر برای وی ساخته شود و به برنامه اضافه گردد.
یا حتی برای تغییر کوچکی در گزارش‌های برنامه : 
به عنوان مثال تغییر در سبک نمایش فاکتور فروش (هنگام چاپ)
هدف حذف این کارهای اضافه است که بعضا توسط کاربر برنامه نیز قابل اجراست. 
بازخوردهای پروژه‌ها
راهنمایی در مورد سفارش و جزییات سفارش و اتصال به درگاه بانک
با سلام و تشکر فراوان بابت انتشار پروژه
میخواستم ببینم جدول سفارش و جزییاتش چه زمانی اطلاعات داخلشون ذخیره مشه؟ زمانی که کاربر روی دکمه پرداخت کلیک میکنه یا وقتی نتیجه پرداخت از بانک برمیگرده و نتیجه پرداخت موفقیت امیز بوده؟ یا...؟
مورد بعدی اینکه با توجه به اینکه بانک برای هر درخواست یک شماره منحصر به فرد میخواد این شماره قراره کجا ذخیره بشه و چجوری بررسی میشه؟