اشتراک‌ها
لیستی از APIهای جدید NET Core 3.0.

.NET Core 3.0 is representing a major step for the .NET community. It is interesting to analyze what’s new in the API directly from the compiled bits. In this post I will first explain how to diff .NET Core 3.0 against .NET Core 2.2 with NDepend, and then how to browse diff results. 

لیستی از APIهای جدید NET Core 3.0.
مطالب
Blazor 5x - قسمت ششم - مبانی Blazor - بخش 3 - چرخه‌های حیات کامپوننت‌ها
در این قسمت می‌خواهیم انواع رویدادهای چرخه‌ی حیات یک کامپوننت را بررسی کنیم. به همین جهت ابتدا دو کامپوننت جدید Lifecycle.razor و Lifecycle‍Child.razor را به مثالی که تا این قسمت تکمیل کرده‌ایم، اضافه کرده و آن‌ها‌را به صورت زیر جهت نمایش رویدادهای چرخه‌ی حیات، تغییر می‌دهیم:

کدهای کامل کامپوننت Pages\LearnBlazor\Lifecycle.razor
@page "/lifecycle"
@using System.Threading

<div class="border">
    <h3>Lifecycles Parent Component</h3>

    <div class="border">
        <LifecycleChild CountValue="CurrentCount"></LifecycleChild>
    </div>

    <p>Current count: @CurrentCount</p>

    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    <br /><br />
    <button class="btn btn-primary" @onclick=StartCountdown>Start Countdown</button> @MaxCount
</div>

@code
{
    int CurrentCount = 0;
    int MaxCount = 5;

    private void IncrementCount()
    {
        CurrentCount++;
        Console.WriteLine("Parnet - IncrementCount is called");
    }

    protected override void OnInitialized()
    {
        Console.WriteLine("Parnet - OnInitialized is called");
    }

    protected override async Task OnInitializedAsync()
    {
        await Task.Delay(100);
        Console.WriteLine("Parnet - OnInitializedAsync is called");
    }

    protected override void OnParametersSet()
    {
        Console.WriteLine("Parnet - OnParameterSet is called");
    }

    protected override async Task OnParametersSetAsync()
    {
        await Task.Delay(100);
        Console.WriteLine("Parnet - OnParametersSetAsync is called");
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            Console.WriteLine("Parnet - OnAfterRender(firstRender == true) is called");
            CurrentCount = 111;
        }
        else
        {
            CurrentCount = 999;
            Console.WriteLine("Parnet - OnAfterRender(firstRender == false) is called");
        }
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await Task.Delay(100);
        Console.WriteLine("Parnet - OnAfterRenderAsync is called");
    }

    protected override bool ShouldRender()
    {
        Console.WriteLine("Parnet - ShouldRender is called");
        return true;
    }

    void StartCountdown()
    {
        Console.WriteLine("Parnet - StartCountdown()");
        var timer = new Timer(TimeCallBack, null, 1000, 1000);
    }

    void TimeCallBack(object state)
    {
        if (MaxCount > 0)
        {
            MaxCount--;
            Console.WriteLine("Parnet - InvokeAsync(StateHasChanged)");
            InvokeAsync(StateHasChanged);
        }
    }
}

و کدهای کامل کامپوننت Pages\LearnBlazor\LearnBlazor‍Components\Lifecycle‍Child.razor
<h3 class="ml-3 mr-3">Lifecycles Child Componenet</h3>

@code
{
    [Parameter]
    public int CountValue { get; set; }

    protected override void OnInitialized()
    {
        Console.WriteLine("  Child - OnInitialized is called");
    }

    protected override async Task OnInitializedAsync()
    {
        await Task.Delay(100);
        Console.WriteLine("  Child - OnInitializedAsync is called");
    }

    protected override void OnParametersSet()
    {
        Console.WriteLine("  Child - OnParameterSet is called");
    }

    protected override async Task OnParametersSetAsync()
    {
        await Task.Delay(100);
        Console.WriteLine("  Child - OnParametersSetAsync is called");
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            Console.WriteLine("  Child - OnAfterRender(firstRender == true) is called");
        }
        else
        {
            Console.WriteLine("  Child - OnAfterRender(firstRender == false) is called");
        }
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await Task.Delay(100);
        Console.WriteLine("  Child - OnAfterRenderAsync is called");
    }

    protected override bool ShouldRender()
    {
        Console.WriteLine("  Child - ShouldRender is called");
        return true;
    }
}
و همچنین برای دسترسی به آن‌ها، مدخل منوی زیر را به کامپوننت Shared\NavMenu.razor اضافه می‌کنیم:
<li class="nav-item px-3">
    <NavLink class="nav-link" href="lifecycle">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Lifecycles
    </NavLink>
</li>
با توجه به اینکه برنامه‌ی جاری از نوع Blazor Server است، Console.WriteLine‌های آن، در صفحه‌ی کنسول اجرای برنامه ظاهر می‌شوند و نه در developer tools مرورگر:





رویدادهای OnInitialized و OnInitializedAsync

@code
{
    protected override void OnInitialized()
    {
        Console.WriteLine("Parnet - OnInitialized is called");
    }

    protected override async Task OnInitializedAsync()
    {
        await Task.Delay(100);
        Console.WriteLine("Parnet - OnInitializedAsync is called");
    }
همانطور که در تصویر فوق نیز ملاحظه می‌کنید، اولین رویدادی که فراخوانی می‌شود، OnInitialized نام دارد و پس از آن نمونه‌ی async آن به نام OnInitializedAsync. این رویدادها زمانیکه یک کامپوننت و اجزای UI آن کاملا بارگذاری شده‌اند، فراخوانی می‌شوند. مهم‌ترین کاربرد آن‌ها، دریافت اطلاعات از سرویس‌های برنامه‌است.
در کامپوننت Lifecycle.razor، یک کامپوننت دیگر نیز به نام Lifecycle‍Child.razor فراخوانی شده‌است. در این حالت ابتدا OnInitialized کامپوننت والد فراخوانی شده‌است و پس از آن بلافاصله فراخوانی OnInitialized کامپوننت فرزند را مشاهده می‌کنیم.


رویدادهای OnParametersSet و OnParametersSetAsync

این رویدادها یکبار در زمان بارگذاری اولیه‌ی کامپوننت و بار دیگر هر زمانیکه کامپوننت فرزند، پارامتر جدیدی را از طریق کامپوننت والد دریافت می‌کند، فراخوانی می‌شوند. برای نمونه کامپوننت LifecycleChild، پارامتر CurrentCount را از والد خود دریافت می‌کند:
<LifecycleChild CountValue="CurrentCount"></LifecycleChild>
هرچند این پارامتر در UI کامپوننت فرزند مثال تهیه شده استفاده نمی‌شود، اما مقدار دهی آن از طرف والد، سبب بروز رویدادهای OnParametersSet و OnParametersSetAsync خواهد شد. برای آزمایش آن اگر بر روی دکمه‌ی click me در کامپوننت والد کلیک کنیم، این رویدادهای جدید را مشاهده خواهیم کرد:
Parnet - IncrementCount is called
Parnet - ShouldRender is called
  Child - OnParameterSet is called
  Child - ShouldRender is called
Parnet - OnAfterRender(firstRender == false) is called
  Child - OnAfterRender(firstRender == false) is called
  Child - OnParametersSetAsync is called
  Child - ShouldRender is called
  Child - OnAfterRender(firstRender == false) is called
  Child - OnAfterRenderAsync is called
Parnet - OnAfterRenderAsync is called
  Child - OnAfterRenderAsync is called
ابتدا متد IncrementCount کامپوننت والد فراخوانی شده‌است که سبب تغییر مقدار پارامتر CurrentCount ارسالی به کامپوننت Lifecycle‍Child می‌شود و پس از آن، رویداد OnParameterSet کامپوننت فرزند را مشاهده می‌کنید که عکس العملی است به این تغییر مقدار. یکی از کاربردهای آن، دریافت مقدار جدید پارامترهای کامپوننت و سپس به روز رسانی قسمت خاصی از UI بر اساس آن‌ها است.



رویدادهای OnAfterRender و OnAfterRenderAsync

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

یک نکته: هر تغییری که در مقادیر فیلدها در این رویدادها صورت گیرند، به UI اعمال نمی‌شوند؛ چون در مرحله‌ی آخر رندر UI قرار دارند.

@code
{
    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            Console.WriteLine("Parnet - OnAfterRender(firstRender == true) is called");
            CurrentCount = 111;
        }
        else
        {
            CurrentCount = 999;
            Console.WriteLine("Parnet - OnAfterRender(firstRender == false) is called");
        }
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await Task.Delay(100);
        Console.WriteLine("Parnet - OnAfterRenderAsync is called");
    }
}
در مثال‌های فوق، پارامتر firstRender را نیز مشاهده می‌کنید. یک کامپوننت چندین بار می‌تواند رندر شود. برای مثال هربار که توسط رویدادگردانی مقدار فیلدی را که در UI استفاده می‌شود، تغییر دهیم، کامپوننت مجددا رندر می‌شود. برای نمونه با کلیک بر روی دکمه‌ی click me، سبب تغییر مقدار فیلد CurrentCount می‌شویم. این تغییر و فراخوانی ضمنی StateHasChanged در پایان کار متد و در پشت صحنه، سبب رندر مجدد UI شده و در نتیجه‌ی آن، مقدار جدیدی را در صفحه مشاهده می‌کنیم. در اینجا اگر خواستیم بدانیم که رندر انجام شده برای بار اول است که صورت می‌گیرد یا خیر، می‌توان از پارامتر firstRender استفاده کرد.

سؤال: با توجه به مقدار دهی‌های 111 و 999 صورت گرفته‌ی در متد OnAfterRender، در اولین بار نمایش کامپوننت، چه عددی به عنوان CurrentCount نمایش داده می‌شود؟
در اولین بار نمایش صفحه، لحظه‌ای عدد 111 و سپس عدد 999 نمایش داده می‌شود. عدد 111 را در بار اول رندر و عدد 999 را در بار دوم رندر که پس از مقدار دهی پارامتر کامپوننت فرزند است، می‌توان مشاهده کرد.
اما ... اگر پس از نمایش اولیه‌ی صفحه، چندین بار بر روی دکمه‌ی click me کلیک کنیم، همواره عدد 1000 مشاهده می‌شود. علت اینجا است که تغییرات مقادیر فیلدها در متد OnAfterRender، به UI اعمال نمی‌شوند؛ چون در این مرحله، رندر UI به پایان رسیده‌است. در اینجا فقط مقدار فیلد CurrentCount به 999 تغییر می‌کند و به همین صورت باقی می‌ماند. دفعه‌ی بعدی که بر روی دکمه‌ی click me کلیک می‌کنیم، یک واحد به آن اضافه شده و اکنون است که کار رندر UI، مجددا شروع خواهد شد (در واکشن به یک رخ‌داد و فراخوانی ضمنی StateHasChanged در پشت صحنه) و اینبار حاصل 999+1 را در UI مشاهده می‌کنیم و باز هم در پایان کار رندر، مجددا مقدار CurrentCount به 999 تغییر می‌کند که ... دیگر به UI منعکس نمی‌شود تا زمان کلیک بعدی و همینطور الی آخر.


رویدادهای StateHasChanged و ShouldRender

- اگر خروجی رویداد ShouldRender مساوی true باشد، اجازه‌ی اعمال تغییرات به UI داده خواهد شد و برعکس. بنابراین اگر حالت UI تغییر کند و خروجی این متد false باشد، این تغییرات نمایش داده نخواهند شد.
- اگر رویداد StateHasChanged فراخوانی شود، به معنای درخواست رندر مجدد UI است. کاربرد آن در مکان‌هایی است که نیاز به اطلاع رسانی دستی تغییرات UI وجود دارد؛ درست پس از زمانیکه رندر UI به پایان رسیده‌است. برای آزمایش این مورد و فراخوانی دستی StateHasChanged، کدهای تایمر زیر تهیه شده‌اند:
@page "/lifecycle"
@using System.Threading

button class="btn btn-primary" @onclick=StartCountdown>Start Countdown</button> @MaxCount

@code
{
    int MaxCount = 5;

    void StartCountdown()
    {
        Console.WriteLine("Parnet - StartCountdown()");
        var timer = new Timer(TimeCallBack, null, 1000, 1000);
    }

    void TimeCallBack(object state)
    {
        if (MaxCount > 0)
        {
            MaxCount--;
            Console.WriteLine("Parnet - InvokeAsync(StateHasChanged)");
            InvokeAsync(StateHasChanged);
        }
    }
}
تایمر تعریف شده، یک thread timer است. یعنی callback آن بر روی یک ترد جدید و مجزای از ترد UI اجرا می‌شود. در این حالت اگر StateHasChanged را جهت اطلاع رسانی تغییر حالت UI فراخوانی نکنیم، در حین کار تایمر، هیچ تغییری را در UI مشاهده نخواهیم کرد.


یک نکته: متدهای رویدادگردان در Blazor، می‌توانند sync و یا async باشند؛ مانند متدهای OnClick و OnClickAsync زیر که هر دو پس از پایان متدها، سبب فراخوانی ضمنی StateHasChanged نیز می‌شوند (به این دلیل است که با کلیک بر روی دکمه‌ای، UI هم به روز رسانی می‌شود). البته متدهای رویدادگردان async، دوبار سبب فراخوانی ضمنی StateHasChanged می‌شوند؛ یکبار زمانیکه قسمت sync متد به پایان می‌رسد و یکبار هم زمانیکه کار فراخوانی کلی متد به پایان خواهد رسید:
<button @onclick="OnClick">Synchronous</button>
<button @onclick="OnClickAsync">Asynchronous</button>
@code{
    void OnClick()
    {
    } // StateHasChanged is called after the method

    async Task OnClickAsync()
    {
        text = "click1";
        // StateHasChanged is called here as the synchronous part of the method ends

        await Task.Delay(1000);
        await Task.Delay(2000);
        text = "click2";
    } // StateHasChanged is called after the method
}
بنابراین یکی دیگر از دلایل نیاز به فراخوانی صریح InvokeAsync(StateHasChanged) در callback تایمر تعریف شده، عدم فراخوانی خودکار آن، در پایان کار رویداد callback تایمر است.


کدهای کامل این مطلب را از اینجا می‌توانید دریافت کنید: Blazor-5x-Part-06.zip
اشتراک‌ها
بزرگترین مخزن Git دنیا!

As a refresher, the Windows code base is approximately 3.5M files and, when checked in to a Git repo, results in a repo of about 300GB .  

بزرگترین مخزن Git دنیا!
اشتراک‌ها
انتشار asp.net 5 Beta 8
ASP.NET 5 beta8 is now available both on NuGet and as a tooling update to Visual Studio 2015
انتشار asp.net 5 Beta 8
اشتراک‌ها
ساخت برنامه های CLI در NET.

It can be useful to create console apps to support backend processes such as data anonymisation or batch processing. This post demonstrates how to develop console apps in .NET, including support for built-in help, arguments, configuration, logging, dependency injection, and more. 

ساخت برنامه های CLI در NET.
اشتراک‌ها
Application service در DDD

It's important to note that an Application Service doesn't have any business behaviour. It knows only what model to use but not how that model works. So, the AS knows which Aggregate to invoke, it knows about some Domain Services that might be required, but that's it. 

Application service در DDD
اشتراک‌ها
کتابخانه DoFilter

DoFilter is a Full Responsive Bootstrap Multipurpose Filtering and Shorting plugin built on Latest Version of Bootstrap Framework (v3.3.7), HTML5, CSS3 and jQuery. Its wonderful features can be used to Filtering and Shorting your website content as like Portfolio, Service, Team, Blog, Products, Pricing, FAQ etc. Also you can customize it for Filtering and Shorting any your website content.

DoFilter is a Full Responsive Isotope Multipurpose Filtering and Shorting plugin. Filtering can hide and show item elements with the filter option. Items that match that filter will be shown. DoFilter Responsive Isotope Multipurpose Filtering and Shorting can rearrange the order of item elements based on their data. Items that do not match will be hidden.

There are 19+ filter styles with 100% responsive design. Indeed, you will be able to showcase your content on mobile devices such as smart phones and tablets. It has many features like CSS3 and jQuery animations, single and multiple Shorting and Filtering. All the codes are clean and well organized. Also have proper help documentation. It looks great with all types of devices. 

کتابخانه DoFilter
اشتراک‌ها
Syntax highlighting شبیه به GitHub

Apparently, GitHub’s own syntax highlighting approach isn’t open source, but this takes a similar approach and is. It’s admittedly quite 'heavy' (due to using a WASM build of the Oniguruma regex engine) but that’s the price of quality. 

Syntax highlighting شبیه به GitHub