اشتراک‌ها
آموزش Unit Testing در #C با xUnit

How to become a Zero to Hero in Unit Testing with C# and xUnit ?

Timeline:
Background   0:00:00
Introduction To Fluent Assertions   0:01:12
Setting Up Fluent Assertions 0:02:39
Basic Assertions with Fluent Assertions   0:09:19
Advanced Assertions with Fluent Assertions 0:20:28
Custom Assertions with Fluent Assertions 0:28:32
Test the Custom Person Assertions 0:47:56
Best Practices For Using Fluent Assertions 0:54:21 

آموزش  Unit Testing در #C با xUnit
اشتراک‌ها
دوره 8 ساعته Microservices در دات نت

Introduction to .NET Microservices (.NET 8)

In this Introduction course, we will learn Microservices with .NET 8 (MVC).
Microservices is an upcoming technology, where it is very easy to scale and break down large project in simple and manageable services.
In this course we will build multiple services and see how they function together by communicating in synchronous and asynchronous manner.

⭐️ Course Contents ⭐️
⌨️ (0:00:01) Section 1 -  Welcome & Getting Started
⌨️ (0:28:15) Section 2 -  Coupon API - Fundamentals
⌨️ (1:15:54) Section 3 -  Coupon API - CRUD
⌨️ (2:21:24) Section 4 -  Auth API
⌨️ (3:20:08) Section 5 -  Consuming Auth API
⌨️ (4:26:53) Section 6 - Product API
⌨️ (4:57:59) Section 7 - Home and Details Page
⌨️ (5:09:35) Section 8 - Shopping Cart
⌨️ (6:08:04) Section 9 - Shopping Cart in Web Project
⌨️ (6:58:06) Section 10 - Service Bus
⌨️ (7:23:42) Section 11 - Email API - Service Bus
⌨️ (7:54:11) What's Next? 

دوره 8 ساعته Microservices در دات نت
اشتراک‌ها
ساخت لینک به بخش های مشخصی از ویدیوهای یوتیوب توسط C# 11

انجام کاری شبیه زیر برای ویدیوهای منتشرشده شما در youtube توسط یک اسکریپت C#

 
00:00:00 Introduction
00:01:30 Luce Carter
00:02:55 Luce’s History with Databases
00:08:10 Tables vs. Documents
00:16:48 Term Mapping Summary
ساخت لینک به بخش های مشخصی از ویدیوهای یوتیوب توسط C# 11
مطالب
روش محاسبه‌ی لحظه‌ی سال تحویل
سال قبل نتیجه‌ی جستجوی من برای یافتن فرمول محاسبه‌ی زمان سال تحویل، برای ارسال ایمیل‌های خودکار تبریک آن، در سایت‌های ایرانی حاصلی نداشت. اما واژه‌ی انگلیسی Equinox سرآغازی شد برای یافتن این الگوریتم.
نام علمی لحظه‌ی سال تحویل، Vernal Equinox است. Equinox به معنای نقطه‌ای است که یک فصل، به فصلی دیگر تبدیل می‌شود:


Equinox واژه‌ای است لاتین به معنای «شب‌های مساوی» و به این نکته اشاره دارد که در Equinox، طول شب و روز یکی می‌شوند. هر سال دارای دو Equinox است: vernal equinox و autumnal equinox (بهاری و پائیزی). البته باید درنظر داشت که Equinox بهاری در نیم کره‌ی شمالی بیشتر معنا پیدا می‌کند؛ زیرا در نیم کره‌ی جنوبی در همین زمان، پائیز شروع می‌شود.
بنابراین می‌توان enum زیر را برای تعریف این چهار ثابت رخدادهای خورشیدی تعریف کرد:
public enum SunEvent
{
    /// <summary>
    /// march equinox
    /// </summary>
    VernalEquinox,
 
    /// <summary>
    /// june solstice
    /// </summary>
    SummerSolstice,
 
    /// <summary>
    /// september equinox
    /// </summary>
    AutumnalEquinox,
 
    /// <summary>
    /// december solstice
    /// </summary>
    WinterSolstice
}

در ادامه برای محاسبه‌ی زمان equinox از فصل 27 کتاب Astronomical Algorithms کمک گرفته شده و تمام اعداد و ارقام و جداولی را که ملاحظه می‌کنید از این کتاب استخراج شده‌اند.
/// <summary>
/// Based on Jean Meeus book _Astronomical Algorithms_
/// </summary>
public static class EquinoxCalculator
{
    /// <summary>
    /// Degrees to Radians conversion factor.
    /// </summary>
    public static readonly double Deg2Radian = Math.PI / 180.0;
 
    public static bool ApproxEquals(double d1, double d2)
    {
        const double epsilon = 2.2204460492503131E-16;
        if (d1 == d2)
            return true;
        var tolerance = ((Math.Abs(d1) + Math.Abs(d2)) + 10.0) * epsilon;
        var difference = d1 - d2;
        return (-tolerance < difference && tolerance > difference);
    }
 
    /// <summary>
    /// Calculates time of the Equinox and Solstice.
    /// </summary>
    /// <param name="year">Year to calculate for.</param>
    /// <param name="sunEvent">Event to calculate.</param>
    /// <returns>Date and time event occurs as a fractional Julian Day.</returns>
    public static DateTime GetSunEventUtc(this int year, SunEvent sunEvent)
    {
        double y;
        double julianEphemerisDay;
 
        if (year >= 1000)
        {
            y = (Math.Floor((double)year) - 2000) / 1000;
 
            switch (sunEvent)
            {
                case SunEvent.VernalEquinox:
                    julianEphemerisDay = 2451623.80984 + 365242.37404 * y + 0.05169 * (y * y) - 0.00411 * (y * y * y) - 0.00057 * (y * y * y * y);
                    break;
                case SunEvent.SummerSolstice:
                    julianEphemerisDay = 2451716.56767 + 365241.62603 * y + 0.00325 * (y * y) - 0.00888 * (y * y * y) - 0.00030 * (y * y * y * y);
                    break;
                case SunEvent.AutumnalEquinox:
                    julianEphemerisDay = 2451810.21715 + 365242.01767 * y + 0.11575 * (y * y) - 0.00337 * (y * y * y) - 0.00078 * (y * y * y * y);
                    break;
                case SunEvent.WinterSolstice:
                    julianEphemerisDay = 2451900.05952 + 365242.74049 * y + 0.06223 * (y * y) - 0.00823 * (y * y * y) - 0.00032 * (y * y * y * y);
                    break;
                default:
                    throw new NotSupportedException();
            }
        }
        else
        {
            y = Math.Floor((double)year) / 1000;
 
            switch (sunEvent)
            {
                case SunEvent.VernalEquinox:
                    julianEphemerisDay = 1721139.29189 + 365242.13740 * y + 0.06134 * (y * y) - 0.00111 * (y * y * y) - 0.00071 * (y * y * y * y);
                    break;
                case SunEvent.SummerSolstice:
                    julianEphemerisDay = 1721233.25401 + 365241.72562 * y + 0.05323 * (y * y) - 0.00907 * (y * y * y) - 0.00025 * (y * y * y * y);
                    break;
                case SunEvent.AutumnalEquinox:
                    julianEphemerisDay = 1721325.70455 + 365242.49558 * y + 0.11677 * (y * y) - 0.00297 * (y * y * y) - 0.00074 * (y * y * y * y);
                    break;
                case SunEvent.WinterSolstice:
                    julianEphemerisDay = 1721414.39987 + 365242.88257 * y + 0.00769 * (y * y) - 0.00933 * (y * y * y) - 0.00006 * (y * y * y * y);
                    break;
                default:
                    throw new NotSupportedException();
            }
        }
 
        var julianCenturies = (julianEphemerisDay - 2451545.0) / 36525;
 
        var w = 35999.373 * julianCenturies - 2.47;
 
        var lambda = 1 + 0.0334 * Math.Cos(w * Deg2Radian) + 0.0007 * Math.Cos(2 * w * Deg2Radian);
 
        var sumOfPeriodicTerms = getSumOfPeriodicTerms(julianCenturies);
 
        return JulianToUtcDate(julianEphemerisDay + (0.00001 * sumOfPeriodicTerms / lambda));
    }
 
    /// <summary>
    /// Converts a fractional Julian Day to a .NET DateTime.
    /// </summary>
    /// <param name="julianDay">Fractional Julian Day to convert.</param>
    /// <returns>Date and Time in .NET DateTime format.</returns>
    public static DateTime JulianToUtcDate(double julianDay)
    {
        double a;
        int month, year;
 
        var j = julianDay + 0.5;
        var z = Math.Floor(j);
        var f = j - z;
 
        if (z >= 2299161)
        {
            var alpha = Math.Floor((z - 1867216.25) / 36524.25);
            a = z + 1 + alpha - Math.Floor(alpha / 4);
        }
        else
            a = z;
 
        var b = a + 1524;
 
        var c = Math.Floor((b - 122.1) / 365.25);
 
        var d = Math.Floor(365.25 * c);
 
        var e = Math.Floor((b - d) / 30.6001);
 
        var day = b - d - Math.Floor(30.6001 * e) + f;
 
        if (e < 14)
            month = (int)(e - 1.0);
        else if (ApproxEquals(e, 14) || ApproxEquals(e, 15))
            month = (int)(e - 13.0);
        else
            throw new NotSupportedException("Illegal month calculated.");
 
        if (month > 2)
            year = (int)(c - 4716.0);
        else if (month == 1 || month == 2)
            year = (int)(c - 4715.0);
        else
            throw new NotSupportedException("Illegal year calculated.");
 
        var span = TimeSpan.FromDays(day);
 
        return new DateTime(year, month, (int)day, span.Hours, span.Minutes,
            span.Seconds, span.Milliseconds, new GregorianCalendar(), DateTimeKind.Utc);
    }
 
    /// <summary>
    /// These values are from Table 27.C
    /// </summary>
    private static double getSumOfPeriodicTerms(double julianCenturies)
    {
        return 485 * Math.Cos(Deg2Radian * 324.96 + Deg2Radian * (1934.136 * julianCenturies))
               + 203 * Math.Cos(Deg2Radian * 337.23 + Deg2Radian * (32964.467 * julianCenturies))
               + 199 * Math.Cos(Deg2Radian * 342.08 + Deg2Radian * (20.186 * julianCenturies))
               + 182 * Math.Cos(Deg2Radian * 27.85 + Deg2Radian * (445267.112 * julianCenturies))
               + 156 * Math.Cos(Deg2Radian * 73.14 + Deg2Radian * (45036.886 * julianCenturies))
               + 136 * Math.Cos(Deg2Radian * 171.52 + Deg2Radian * (22518.443 * julianCenturies))
               + 77 * Math.Cos(Deg2Radian * 222.54 + Deg2Radian * (65928.934 * julianCenturies))
               + 74 * Math.Cos(Deg2Radian * 296.72 + Deg2Radian * (3034.906 * julianCenturies))
               + 70 * Math.Cos(Deg2Radian * 243.58 + Deg2Radian * (9037.513 * julianCenturies))
               + 58 * Math.Cos(Deg2Radian * 119.81 + Deg2Radian * (33718.147 * julianCenturies))
               + 52 * Math.Cos(Deg2Radian * 297.17 + Deg2Radian * (150.678 * julianCenturies))
               + 50 * Math.Cos(Deg2Radian * 21.02 + Deg2Radian * (2281.226 * julianCenturies))
               + 45 * Math.Cos(Deg2Radian * 247.54 + Deg2Radian * (29929.562 * julianCenturies))
               + 44 * Math.Cos(Deg2Radian * 325.15 + Deg2Radian * (31555.956 * julianCenturies))
               + 29 * Math.Cos(Deg2Radian * 60.93 + Deg2Radian * (4443.417 * julianCenturies))
               + 28 * Math.Cos(Deg2Radian * 155.12 + Deg2Radian * (67555.328 * julianCenturies))
               + 17 * Math.Cos(Deg2Radian * 288.79 + Deg2Radian * (4562.452 * julianCenturies))
               + 16 * Math.Cos(Deg2Radian * 198.04 + Deg2Radian * (62894.029 * julianCenturies))
               + 14 * Math.Cos(Deg2Radian * 199.76 + Deg2Radian * (31436.921 * julianCenturies))
               + 12 * Math.Cos(Deg2Radian * 95.39 + Deg2Radian * (14577.848 * julianCenturies))
               + 12 * Math.Cos(Deg2Radian * 287.11 + Deg2Radian * (31931.756 * julianCenturies))
               + 12 * Math.Cos(Deg2Radian * 320.81 + Deg2Radian * (34777.259 * julianCenturies))
               + 9 * Math.Cos(Deg2Radian * 227.73 + Deg2Radian * (1222.114 * julianCenturies))
               + 8 * Math.Cos(Deg2Radian * 15.45 + Deg2Radian * (16859.074 * julianCenturies));
    }
}
خروجی‌های زمانی ستاره شناسی، عموما بر اساس فرمت Julian Date است که آغاز آن  4713BCE January 1, 12 hours GMT است. به همین جهت در انتهای این مباحث، تبدیل Julian Date به DateTime دات نت را نیز ملاحظه می‌کنید. همچنین باید دقت داشت که خروجی نهایی بر اساس UTC است و برای زمان ایران، باید 3.5 ساعت به آن اضافه شود.

خروجی این الگوریتم را برای سال‌های 2014 تا 2022 به صورت ذیل مشاهده می‌کنید:
2014 -> 1392/12/29 20:28:08
2015 -> 1394/01/01 02:16:29
2016 -> 1395/01/01 08:01:21
2017 -> 1395/12/30 14:00:00
2018 -> 1396/12/29 19:46:10
2019 -> 1398/01/01 01:29:29
2020 -> 1399/01/01 07:21:03
2021 -> 1399/12/30 13:08:41
2022 -> 1400/12/29 19:04:37
برای نمونه زمان محاسبه شده‌ی 1394/01/01 02:16:29 با زمان رسمی اعلام شده‌ی ساعت 2 و 15 دقیقه و 10 ثانیه روز شنبه 1 فروردین 1394 و یا برای سال 93 زمان محاسبه شده‌ی 1392/12/29 20:28:08 با زمان رسمی ساعت ۲۰ و ۲۷ دقیقه و ۷ ثانیه پنجشنبه ۲۹ اسفند ۱۳۹۲، تقریبا برابری می‌کند.

کدهای کامل این پروژه را از اینجا می‌توانید دریافت کنید
 Equinox.zip
اشتراک‌ها
پیاده سازی معماری کلین و الگوی CQRS

در این قسمت معماری کلین رو پیاده سازی کردیم و الگوی CQRS رو هم در کنارش پیاده سازی کردیم.

06:00 Domain Layer 

07:00 Application Layer 

08:37 Infrastructure/Persistence Layer 

11:00 Presentation Lauer 

12:20 Inside of Domain Layer ( enums, value objects, exceptions, entities) 

18:00 Inside of Application Layer (CQRS, MediatR, Command, and Query Handler) 

26:00 Inside of Infrastructure ( Adapter, EF Core) 

29:00 Query and Command Bus 

37:00 Fluent Validation 

41:00 Behaviour Pipeline 

پیاده سازی معماری کلین و الگوی CQRS
نظرات مطالب
انجام کارهای زمانبندی شده در برنامه‌های ASP.NET توسط DNT Scheduler
شرط رو به این صورت گذاشتم : return now.Minute % 50 == 0  && now.Second==1 
انتظار این بود که در لحظاتی که دقیقه صفر و ثانیه یک و یا دقیقه 50 و ثانیه یک باشد عملیات مورد نظر (در اینجا تهیه نسخه پشتیبان صورت پذیرد ) به عبارتی در هر ساعت دو بار این شرایط مهیا می‌شود ولی نتیجه به صورت ذیل شد :
12:50:01      12:50:02   13:00:01   13:00:02   13:50:01   13:50:02    14:00:01   14:50:01   15:00:01   15:00:02

زمانهایی که بولد شدند قاعدتا نباید جاب اجرا می‌شد . احتمالا مشکل چی می‌تونه باشه ؟
اشتراک‌ها
قسمت چهارم از سری بررسی معماری نرم افزار Architecture Characteristics and Design Principles - Part

در قسمت 4 ام به یه جمع بندی در مورد تعریف معماری رسیدیم و چهار بعد اصلی یه معماری رو بررسی کردیم و از جلسه بعدی میریم توی بحث الگوهای معماری مثل کلین و اون هارو کامل بررسی میکنیم.


01:00 Previous Session
02:35 Frozen Caveman anti-pattern
08:00 Architecture Characteristics
09:00 NFR
11:35 Architecture Decisions
15:14 Design Principles

#design #architecture

👀 مدت زمان ویدیو : 23 دقیقه 

قسمت چهارم از سری بررسی معماری نرم افزار Architecture Characteristics and Design Principles - Part
اشتراک‌ها
انواع بلاکینگ و کانتکست سوییچ بین ترد های درون یه پروسس

در ادامه قسمت اول اینسری در مورد فرق بین پروسس و ترد صحبت کردیم و انواع بلاک شدن و کانتکست سوییچ بین ترد‌های درون یه پروسس صحبت کردیم.

01:10 Main Thread 

02:50 Multi-Thread Process 

04:25 Thread for GC & Finalization 

05:22 Demo 

08:00 Context switch on threads 

10:50 Thread Blocking 

15:11 Blocking Type (I/O and Compute Bound) 

مدت زمان ویدیو : 19 دقیقه 

انواع بلاکینگ و کانتکست سوییچ بین ترد های درون یه پروسس
مطالب
آشنایی با CLR: قسمت دوازدهم
متادیتاها شامل بلوکی از داده‌های باینری هستند که شامل چندین جدول شده و جدول‌ها نیز به سه دسته تقسیم می‌شوند:
  1. جداول تعاریف Definition Table
  2. جداول ارجاع References Table
  3. جداول manifest

جداول تعریف

جدول زیر تعدادی از جداول تعریف‌ها را توضیح می‌دهد:
 ModuleDef  شامل آدرس یا مدخلی است که ماژول در آن تعریف شده است. این آدرس شامل نام ماژول به همراه پسوند آن است؛ بدون ذکر مسیر. در صورتی که کامپایل به صورت GUID انجام گرفته باشد، Version ID ماژول هم همراه آن‌ها خواهد بود. در صورتیکه نام فایل تغییر کند، این جدول باز نام اصلی ماژول را به همراه خواهد داشت. هر چند تغییر نام فایل به شدت رد شده و ممکن است باعث شود CLR نتواند در زمان اجرا آن را پیدا کند.
 TypeDef  شامل یک مدخل ورودی برای هر نوعی است که تعریف شده است. هر آدرس ورودی شامل نام نوع ، پرچمها (همان مجوز‌های public و private و ...) می‌باشد. همچنین شامل اندیس هایی به متدها است که شامل جدول MethodDef می‌باشند یا فیلدهایی که شامل جدول FieldDef می‌باشند و الی آخر...
 MethodDef  شامل آدرسی برای هر متد تعریف شده در ماژول است که شامل  نام متد و پرچم هاست. همچنین شامل امضای متد و نقطه‌ی آغاز کد IL آن در ماژول هم می‌شود و آن آدرس هم میتواند ارجاعی به جدول ParamDef جهت شناسایی پارامترها باشد.
 FieldDef  شامل اطلاعاتی در مورد فیلدهاست که این اطلاعات ، پرچم، نام و نوع فیلد را مشخص می‌کنند.
 ParamDef  حاوی اطلاعات پارامتر متدهاست که این اطلاعات شامل پرچم‌ها (in , out ,retval) ، نوع و نام است.
 PropertyDef   برای هر پراپرتی یا خصوصیت، شامل یک آدرس است که شامل نام، نوع و پرچم می‌شود.
 EventDef  برای هر رویداد شامل یک آدرس است که این آدرس شامل نام و نوع است.

جداول ارجاعی
موقعی که کد شما کامپایل می‌شود، اگر شما به اسمبلی دیگری ارجاع داشته باشید، از جداول ارجاع کمک گرفته می‌شود که در جدول زیر تعدادی از این جداول فهرست شده‌اند:
 AssemblyRef  شامل آدرس اسمبلی است که ماژولی به آن ارجاع داده است و این آدرس شامل اطلاعات ضروری جهت اتصال به اسمبلی می‌شود و این اطلاعات شامل نام اسمبلی (بدون ذکر پسوند و مسیر)، شماره نسخه اسمبلی، سیستم فرهنگی و منطقه‌ای تعیین شده اسمبلی culture و یک کلید عمومی که عموما توسط ناشر ایجاد می‌گردد که هویت ناشر آن اسمبلی را مشخص می‌کند. هر آدرس شامل یک پرچم و یک کد هش هست که بری ارزیابی از صحت و بی خطا بودن بیت‌های اسمبلی ارجاع شده Checksum استفاده می‌شود.
 ModuleRef  شامل یک آدرس ورودی به هدر PE ماژول است به نوع‌های پیاده سازی شده آن ماژول در آن اسمبلی. هر آدرس شامل نام فایل و پسوند آن بدون ذکر مسیر است. این جدول برای اتصال به نوع‌هایی استفاده می‌شود که در یک ماژول متفاوت از ماژول اسمبلی صدا زده شده پیاده سازی شده است.
 TypeRef  شامل یک آدرس یا ورودی برای هر نوعی است که توسط ماژول ارجاع داده شده است. هر آدرس شامل نام نوع و آدرسی است که نوع در آن جا قرار دارد. اگر این نوع داخل نوع دیگری پیاده سازی شود، ارجاعات به سمت یک جدول TypeDef خواهد بود. اگر نوع داخل همان ماژول تعریف شده باشد، ارجاع به سمت جدول ModuleDef خواهد بود و اگر نوع در ماژول دیگری از آن اسمبلی پیاده سازی شده باشد، ارجاع به سمت یک جدول ModuleRef خواهد بود و اگر نوع در یک اسمبلی جداگانه تعریف شده باشد، ارجاع به جدول AssemblyRef خواهد بود.
 MemberRef  شامل یک آدرس ورودی برای هر عضو (فیلد و متدها و حتی پراپرتی و رویدادها) است که توسط آن آن ماژول ارجاع شده باشد. هر آدرس شامل نام عضو، امضاء و یک اشاره‌گر به جدول TypeRef است، برای نوع‌هایی که به تعریف عضو پرداخته‌اند. 
البته جداولی که در بالا هستند فقط تعدادی از آن جداول هستند، ولی قصد ما تنها یک آشنایی کلی با جداول هر قسمت بود. در مورد جداول manifest بعد‌تر صحبت می‌کنیم.
ابزارهای متنوع و زیادی هستند که برای بررسی و آزمایش متادیتاها استفاده می‌شوند. یکی از این ابزارها ILDasm.exe می‌باشد. برای دیدن متادیتاهای یک فایل اجرایی فرمان زیر را صادر کنید:
ILDasm Program.exe
صدور فرمان بالا باعث اجرای ILDasm و بارگزاری اسمبلی‌های program.exe می‌شود. برای مشاهده‌ی اطلاعات جداول متا به صورت شکیل و قابل خواندن برای انسان، در منوی برنامه، مسیر زیر را طی کنید:
View/MetaInfo/Show
با طی کردن گزینه‌های بالا، اطلاعات به صورت زیر نمایش داده می‌شوند:
===========================================================
ScopeName : Program.exe
MVID : {CA73FFE8­0D42­4610­A8D3­9276195C35AA}
===========================================================
Global functions
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Global fields
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Global MemberRefs
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
TypeDef #1 (02000002)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
TypDefName: Program (02000002)
Flags : [Public] [AutoLayout] [Class] [Sealed] [AnsiClass]
[BeforeFieldInit] (00100101)
Extends : 01000001 [TypeRef] System.Object
Method #1 (06000001) [ENTRYPOINT]
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
MethodName: Main (06000001)
Flags : [Public] [Static] [HideBySig] [ReuseSlot] (00000096)
RVA : 0x00002050
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
ReturnType: Void
No arguments.
Method #2 (06000002)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
MethodName: .ctor (06000002)
Flags : [Public] [HideBySig] [ReuseSlot] [SpecialName]
[RTSpecialName] [.ctor] (00001886)
RVA : 0x0000205c
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #1 (01000001)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x01000001
ResolutionScope: 0x23000001
TypeRefName: System.Object
MemberRef #1 (0a000004)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Member: (0a000004) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #2 (01000002)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x01000002
ResolutionScope: 0x23000001
TypeRefName: System.Runtime.CompilerServices.CompilationRelaxationsAttribute
MemberRef #1 (0a000001)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Member: (0a000001) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
1 Arguments
Argument #1: I4
TypeRef #3 (01000003)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x01000003
ResolutionScope: 0x23000001
TypeRefName: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute
MemberRef #1 (0a000002)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Member: (0a000002) .ctor:
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
TypeRef #4 (01000004)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x01000004
ResolutionScope: 0x23000001
TypeRefName: System.Console
MemberRef #1 (0a000003)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Member: (0a000003) WriteLine:
CallCnvntn: [DEFAULT]
ReturnType: Void
1 Arguments
Argument #1: String
Assembly
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x20000001
Name : Program
Public Key :
Hash Algorithm : 0x00008004
Version: 0.0.0.0
Major Version: 0x00000000
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x00000000
Locale: <null>
Flags : [none] (00000000)
CustomAttribute #1 (0c000001)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
CustomAttribute Type: 0a000001
CustomAttributeName:
System.Runtime.CompilerServices.CompilationRelaxationsAttribute ::
instance void .ctor(int32)
Length: 8
Value : 01 00 08 00 00 00 00 00 > <
ctor args: (8)
CustomAttribute #2 (0c000002)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
CustomAttribute Type: 0a000002
CustomAttributeName: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute ::
instance void .ctor()
Length: 30
Value : 01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78 > T WrapNonEx<
: 63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01 >ceptionThrows <
ctor args: ()
AssemblyRef #1 (23000001)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x23000001
Public Key or Token: b7 7a 5c 56 19 34 e0 89
Name: mscorlib
Version: 4.0.0.0
Major Version: 0x00000004
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x00000000
Locale: <null>
HashValue Blob:
Flags: [none] (00000000)
User Strings
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
70000001 : ( 2) L"Hi"
Coff symbol name overhead: 0
لازم نیست که تمامی اطلاعات بالا را به طور کامل بفهمید. همین که متوجه شوید برنامه شامل  TypeDef است که نام آن Program است و این نوع به صورت یک کلاس عمومی sealed است که از نوع system.object ارث بری کرده است (یک نوع ارجاع از اسمبلی دیگر) و برنامه شامل دو متد main و یک سازنده ctor. است، کافی هست.
متد Main یک متد عمومی و ایستا static است که شامل کد IL است و هیچ خروجی ندارد و هیچ آرگومانی را نمی‌پزیرد. متد سازنده عمومی است و شامل کد IL است، سازنده هیچ نوع خروجی ندارد و هیچ آرگومانی هم نمی‌پذیرد و یک اشاره‌گر که به یک object در حافظه که موقع صدا زدن ساخته خواهد شد.
ابزار ILDasm امکاناتی بیشتری از آنچه که دیدید ارائه می‌کند. به عنوان نمونه اگر مسیر زیر را در منوها طی کنید:
View/statistics
اطلاعات آماری زیر نمایش داده می‌شود:
File size : 3584
PE header size : 512 (496 used) (14.29%)
PE additional info : 1411 (39.37%)
Num.of PE sections : 3
CLR header size : 72 ( 2.01%)
CLR meta­data size : 612 (17.08%)
CLR additional info : 0 ( 0.00%)
CLR method headers : 2 ( 0.06%)
Managed code : 20 ( 0.56%)
Data : 2048 (57.14%)
Unaccounted : ­1093 (­30.50%)
Num.of PE sections : 3
.text ­ 1024
.rsrc ­ 1536
.reloc ­ 512
CLR meta­data size : 612
Module ­ 1 (10 bytes)
TypeDef ­ 2 (28 bytes) 0 interfaces, 0 explicit layout
TypeRef ­ 4 (24 bytes)
MethodDef ­ 2 (28 bytes) 0 abstract, 0 native, 2 bodies
MemberRef ­ 4 (24 bytes)
CustomAttribute­ 2 (12 bytes)
Assembly ­ 1 (22 bytes)
AssemblyRef ­ 1 (20 bytes)
Strings ­ 184 bytes
Blobs ­ 68 bytes
UserStrings ­ 8 bytes
Guids ­ 16 bytes
Uncategorized ­ 168 bytes
CLR method headers : 2
Num.of method bodies ­ 2
Num.of fat headers ­ 0
Num.of tiny headers ­ 2
Managed code : 20
Ave method size ­ 10
اطلاعات بالا شامل نمایش حجم فایل به بایت و سایر قسمت‌های تشکیل دهنده فایل است...
توجه: ILDasm یک باگ دارد که بر نمایش اندازه‌ی فایل تاثیر می‌گذارد و باعث می‌شود شما نتوانید به اطلاعات ثبت شده اعتماد داشته باشید.
مطالب
استفاده‌ی گسترده از DateTimeOffset در NET Core.
اگر به سورس‌های ASP.NET Identity نگارش‌های 2 و 3 دقت کنیم، این تفاوت به وضوح قابل مشاهده‌است:
در نگارش 2
public virtual DateTime? LockoutEndDateUtc { get; set; }
در نگارش 3
public virtual DateTimeOffset? LockoutEnd { get; set; }
و در کل، در طراحی تمام قسمت‌ها و اجزای NET Core. بجای استفاده‌ی از DateTime متداول، شاهد استفاده‌ی گسترده‌ای از DateTimeOffset هستیم که از زمان ارائه‌ی NET 3.5. معرفی شده‌است. چرا؟


مشکل ساختار DateTime چیست؟

تمام کسانیکه مدتی با NET Framework. کار کرده‌اند، قطعا از ساختار DateTime برای ذخیره سازی اطلاعاتی زمانی محلی استفاده کرد‌ه‌اند. اما مشکل DateTime چیست؟
فرض کنید در حال استفاده‌ی از یک وب سرویس قرار گرفته‌ی در یک منطقه‌ی زمانی غربی هستید و این وب سرویس تاریخ تولد افراد را با یک چنین فرمتی ارائه می‌دهد:
 2012-03-01 00:00:00-05:00
در این حالت برای استفاده‌ی متداول از این زمان می‌توان به صورت زیر عمل کرد:
 var dateString = "2012-03-01 00:00:00-05:00";
var birthDay = DateTime.Parse(dateString);
هرچند این عملیات ساده به نظر می‌رسد، اما با توجه به قرارگیری سرور برنامه در یک منطقه‌ی زمانی دیگر، زمان پردازش شده به صورت ذیل خواهد بود:
 2012-02-29 11:00:00 PM
اتفاقی که رخ داده‌است، تبدیل DateTime رسیده به زمان محلی سرور است و در این حالت تاریخ تولد شخص از یکم ماه، به 29 ام ماه قبل تغییر کرده‌است. علت آن هم وجود 05:00 یا offset (فاصله‌ی با UTC) در تاریخ ارائه شده‌است.
چگونه می‌توان offset را در تاریخ ذکر کرد، اما از تبدیل آن به زمان محلی جلوگیری کرد؟ این مورد جایی‌است که ساختار DateTimeOffset بکار خواهد آمد.


DateTimeOffset و ذخیره‌ی DateTime به همراه Offset

ساختار کلی DateTimeOffset بسیار واضح بوده و تشکیل شده‌است از Date + Time + Offset. اهمیت آن نیز به ذخیره سازی اطلاعات منطقه‌ی زمانی، در قسمت Offset ساختار ارائه شده بر می‌گردد. ساختار DateTimeOffset در بسیاری از موارد با DateTime متداول یکسان است و تفاوت‌های آن شامل خواص اضافی ذیل هستند:
- DateTime: قسمت DateTime مقدار را بدون توجه به offset باز می‌گرداند (به زمان محلی تبدیل نخواهد شد).
- LocalDateTime: قسمت DateTime را با توجه به منطقه زمانی سروری که برنامه بر روی آن اجرا می‌شود، بر می‌گرداند.
- Offset: فاصله‌ی زمانی با UTC را بیان می‌کند. یک TimeSpan است که فاصله‌ی با UTC را بیان می‌کند.
- UtcDateTime: قسمت DateTime را با توجه به UTC time ارائه می‌کند.

در این ساختار خواص Now و UtcNow نیز یک DateTimeOffset را باز می‌گردانند.


چه زمانی از DateTime و چه زمانی از DateTimeOffset استفاده کنیم؟

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

در این حالت روش پردازش صحیح مثال ابتدای بحث به صورت ذیل خواهد بود:
 string birthDay = "2012-03-01 00:00:00-05:00";
var dtOffset = DateTimeOffset.Parse(birthDay);
و در اینجا اگر علاقمند به مقایسه‌ی این مقدار با یک زمان محلی هستیم، می‌توان از خاصیت Date آن استفاده کرد:
 var theDay = dtOffset.Date;
مطابق توصیه‌ی تیم BCL، استفاده از DateTimeOffset روش ترجیح داده شده‌ی برای ذخیره سازی اطلاعات اکثر سناریوهای زمانی است.


SQL Server و پشتیبانی از DateTimeOffset

ساختار داده‌ای datetime در SQL Server نیز اطلاعات منطقه‌ی زمانی را ذخیره نمی‌کند و درصورت بازیابی آن در برنامه، این زمان، به زمان محلی تبدیل خواهد شد. برای رفع این مشکل، از زمان ارائه‌ی SQL Server 2008، ساختار DateTimeOffset نیز به نوع‌های داده‌آی SQL Server اضافه شده‌است:


این ساختار، اطلاعات +00:00 timezone را نیز ذخیره می‌کند.


مشکلات نوع datetime در بانک‌های اطلاعاتی برای ذخیره سازی اطلاعات UTC در آن‌ها

یکی از روش‌های توصیه شده‌ی جهت ذخیره سازی اطلاعات زمانی در بانک‌های اطلاعاتی، استفاد‌ه‌ی از DateTime.UtcNow است. اما زمانیکه از DateTime.UtcNow برای ذخیره سازی اطلاعاتی زمانی استفاده می‌کنیم، به معنای دریافت زمان محلی بر اساس و نسبت به UTC است. در این حالت هنگامیکه آن‌را از یک فیلد datetime بانک اطلاعاتی بازیابی می‌کنیم، از نوع Unspecified خواهد بود (DateTimeKind.Unspecified) و به صورت خودکار به DateTimeKind.Local ترجمه می‌شود. یعنی مقدار آن مجددا به زمان محلی شیفت پیدا خواهد کرد چون نوع datetime بانک اطلاعاتی درکی از DateTimeKind و منطقه‌ی زمانی ندارد.
به همین جهت روش بازیابی صحیح این زمان UTC، نیاز به قید صریح DateTimeKind.Utc را خواهد داشت:
public static class SqlDataReaderExtensions
{
   public static DateTime GetDateTimeUtc(this SqlDataReader reader, string name)
   {
      int fieldOrdinal = reader.GetOrdinal(name);
      DateTime unspecified = reader.GetDateTime(fieldOrdinal);
      return DateTime.SpecifyKind(unspecified, DateTimeKind.Utc);
   }
}
اما اگر نوع فیلد را DateTimeOffset قرار دهیم و از DateTimeOffset.UTCNow برای ذخیره سازی اطلاعات زمانی استفاده کنیم، SqlDataReader بدون نیاز به تبدیلات فوق، قادر است اطلاعات آن‌را به نحو صحیحی دریافت و پردازش کند.


خلاصه‌ی بحث

اگر برنامه‌ی وب شما امروز در یک سرور در اروپا هاست می‌شود و سال بعد در یک سرور کانادایی، استفاده‌ی DateTime.UtcNow کمک زیادی به برنامه نکرده و خروجی SQL Server در این حالت DateTimeKind.Unspecified است و این زمان مجددا بر اساس محل سرور جدید و تنظیمات منطقه‌ی زمانی آن، به حالت DateTimeKind.Local شیفت داده می‌شود که الزاما خروجی صحیحی را به همراه نخواهد داشت و یا اگر قرار است از وب سرویس شما در مناطق زمانی مختلفی استفاده کنند نیز DateTime.UtcNow انتخاب مناسبی نیست. جهت درج فاصله‌ی صحیح با UTC و ذخیره سازی آن در بانک اطلاعاتی، روش توصیه شده، استفاده از نوع DateTimeOffset است و در این حالت دیگر SQL Server اطلاعات را با فرمت زمانی Unspecified بازگشت نمی‌دهد و در سمت کلاینت نیازی به تبدیلات خاصی نخواهد بود.