اشتراک‌ها
آیا Null یک نوع داده‌ایی است؟

In C#, null has no type, but most variables can be null; you can't really trust the type system. A Maybe, on the other hand, always has a type, which means that Maybe is a saner approach to the question of values that may or may not be present. 

آیا Null یک نوع داده‌ایی است؟
اشتراک‌ها
فریمورک تهیه شده با Asp.net Mvc و Asp.net Web Api به صورت NTier با پشتیبانی از چند زبانگی

These are some key features of the framework itself:

Modular and NLayered architecture
Multi-tenancy
Dependency Injection
Domain Driven Design
Unit of work implementation
Flexible Localization system
Automatic data filters
Audit logging
Setting management
Menu management
Authorization
Exception handling
Validation
Logging
Event bus for domain events
Auto-creating Web API layer for Application Services
Auto-creating Javascript proxy layer to use Web API layer
Javascript helper methods for ajax, notifications, message boxes, making UI busy...
Easily working with embedded resources
Useful extension and helper methods   

فریمورک تهیه شده با Asp.net Mvc و Asp.net Web Api به صورت NTier با پشتیبانی از چند زبانگی
اشتراک‌ها
سری بررسی مهم‌ترین مفاهیم طراحی سیستم‌ها

system design tutorials
7 videos
This series of videos covers of the the most important concepts related to system design, with a focus on practical system design knowledge for interviews. These system design videos cover topics like vertical vs horizontal scaling, load balancers, database design and scaling, caching, back of the envelope math for estimating capacity requirements for a system, an introduction to distributed systems, and some system design interview style questions walking through a full design implementation

 

سری بررسی مهم‌ترین مفاهیم طراحی سیستم‌ها
اشتراک‌ها
کتابخانه tap
Tap is a Javascript library for easy unified handling of user interactions such as mouse, touch and pointer events.
  • No need to detect what kind of events are supported, Tap handles this for you
  • Small distribution size of 1Kb
  • Use fastest event types supported (majority of browsers has ~300ms delay between touch/pointer events and click). Every millisecond does really matter!
کتابخانه tap
اشتراک‌ها
نکات افزایش پرفرمنس برای وبسایت

In this post, I'll talk about what the different things I've made on this website to improve the performance. Some of the optimizations are just some configuration flags to turn on, others require more changes in your code.

  • Enable HTTP/2
  • Enable TLS 1.3
  • Compress responses using Brotli or gzip
  • Add caching information
  • Optimize JavaScript / CSS files
  • Reduce the number of redirections
  • Optimize images
  • Move your servers near your visitors (GeoDNS, CDN)
  • Resource Hints: Prefetch resources
  • Remove unused resources / features
  • Minify HTML
  • Optimize JavaScript code
  • Automate almost everything! 
نکات افزایش پرفرمنس برای وبسایت
اشتراک‌ها
ساختن یک برنامه خیلی بزرگ جاوا اسکریپت در TypeScript
How can you survive a project that uses JavaScript massively on both the client and the server using node.js? The project is about on-line development components, such as the TypeScript playground (http://www.typescriptlang.org/Playground/) or Visual Studio Online “Monaco”, which enables users to edit Azure Web Sites online. We had an existing large JavaScript code base and we wanted to give TypeScript a try. Today the project is one of the largest TypeScript code bases inside Microsoft with more than 200k lines of TypeScript in production. This session gives a quick introduction into TypeScript and then takes a deep look at how TypeScript and other technologies were used to successfully scale up a large JavaScript project that ships in some of Microsoft’s biggest products and services
ساختن یک برنامه خیلی بزرگ جاوا اسکریپت در TypeScript
مطالب
Blazor 5x - قسمت 27 - برنامه‌ی Blazor WASM - کار با سرویس‌های Web API
در قسمت‌های Blazor Server مثال این سری، با روش کار با سرویس‌های سمت سرور برنامه، آشنا شدیم. در این نوع برنامه‌ها، فقط کافی است اصل سرویس مدنظر را مستقیما در کامپوننت‌های Razor تزریق کرد و سپس می‌توان به نحو متداولی با آن‌ها کار کرد؛ اما در برنامه‌های Blazor WASM خیر! به این نوع برنامه‌های سمت کلاینت باید همانند برنامه‌های React ، Angular ، Vue و یا حتی برنامه‌های مبتنی بر jQuery نگاه کرد. در تمام فناوری‌های سمت کلاینت، این درخواست‌های Ajax ای هستند که با سرویس‌های یک Web API سمت سرور، ارتباط برقرار کرده، اطلاعاتی را به آن‌ها ارسال و یا دریافت می‌کنند. در برنامه‌های Blazor WASM نیز باید به همین ترتیب عمل کرد و در اینجا HttpClient دات نت، جایگزین برای مثال jQuery Ajax ، Fetch API و یا XMLHttpRequest استاندارد می‌شود (البته jQuery Ajax در اصل یک محصور کننده‌ی استاندارد XMLHttpRequest است که برای اولین بار توسط مایکروسافت در برنامه‌ی Outlook web access معرفی شد).


ایجاد سرویس سمت کلاینت دریافت اطلاعات اتاق‌ها از Web API

در قسمت 24، HotelRoomController را تکمیل کردیم که کار آن، بازگشت اطلاعات تمام اتاق‌ها و یا یک اتاق مشخص به کلاینت است. اکنون می‌خواهیم در ادامه‌ی قسمت قبل، اگر کاربری بر روی دکمه‌ی Go صفحه‌ی اول رزرو اتاقی کلیک کرد، لیست تمام اتاق‌های تعریف شده را به او نمایش دهیم. به همین جهت نیاز به سرویس سمت کلاینتی داریم که بتواند با این Web API endpoint کار کند:
namespace BlazorWasm.Client.Services
{
    public interface IClientHotelRoomService
    {
        public Task<IEnumerable<HotelRoomDTO>> GetHotelRoomsAsync(DateTime checkInDate, DateTime checkOutDate);
        public Task<HotelRoomDTO> GetHotelRoomDetailsAsync(int roomId, DateTime checkInDate, DateTime checkOutDate);
    }
}
این سرویس را در پوشه‌ی Services پروژه‌ی BlazorWasm.Client ایجاد کرده‌ایم که HotelRoomDTO خود را از پروژه‌ی BlazorServer.Models دریافت می‌کند. به این ترتیب می‌توان مدلی را بین یک Web API سمت سرور و یک سرویس سمت کلاینت، به اشتراک گذاشت. بنابراین پروژه‌ی کلاینت، باید ارجاعی را به پروژه‌ی BlazorServer.Models.csproj نیز داشته باشد.

در ادامه اینترفیس فوق را به صورت زیر پیاده سازی می‌کنیم:
namespace BlazorWasm.Client.Services
{
    public class ClientHotelRoomService : IClientHotelRoomService
    {
        private readonly HttpClient _httpClient;

        public ClientHotelRoomService(HttpClient httpClient)
        {
            _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
        }

        public Task<HotelRoomDTO> GetHotelRoomDetailsAsync(int roomId, DateTime checkInDate, DateTime checkOutDate)
        {
            throw new NotImplementedException();
        }

        public Task<IEnumerable<HotelRoomDTO>> GetHotelRoomsAsync(DateTime checkInDate, DateTime checkOutDate)
        {
            // How to url-encode query-string parameters properly
            var uri = new UriBuilderExt(new Uri(_httpClient.BaseAddress, "/api/hotelroom"))
                            .AddParameter("checkInDate", $"{checkInDate:yyyy'-'MM'-'dd}")
                            .AddParameter("checkOutDate", $"{checkOutDate:yyyy'-'MM'-'dd}")
                            .Uri;
            return _httpClient.GetFromJsonAsync<IEnumerable<HotelRoomDTO>>(uri);
        }
    }
}
توضیحات:
- HttpClient یکی از سرویس‌های تنظیم شده‌ی در فایل Program.cs پروژه‌های سمت کلاینت است. بنابراین می‌توان آن‌را از طریق تزریق به سازنده‌ی این سرویس، به دست آورد.
- در اینجا برای دریافت اطلاعات JSON دریافتی از سمت سرور و سپس Deserialize خودکار آن به لیستی از DTO تعریف شده، از متد جدید GetFromJsonAsync استفاده شده‌است. این مورد جزو تازه‌های NET 5x. است.
- در اینجا استفاده از کلاس UriBuilderExt را نیز جهت تشکیل یک URL دارای کوئری استرینگ، مشاهده می‌کنید. هیچگاه نباید URL نهایی را از طریق جمع زدن اجزای آن به سمت سرور ارسال کرد؛ از این جهت که اجزای آن باید URL-encoded شوند؛ وگرنه در سمت سرور قابلیت پردازش نخواهند داشت. در ادامه تعریف کلاس جدید UriBuilderExt را مشاهده می‌کنید:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using BlazorServer.Models;
using BlazorWasm.Client.Utils;

using System;
using System.Collections.Specialized;
using System.Web;

namespace BlazorWasm.Client.Utils
{
    public class UriBuilderExt
    {
        private readonly NameValueCollection _collection;
        private readonly UriBuilder _builder;

        public UriBuilderExt(Uri uri)
        {
            _builder = new UriBuilder(uri);
            _collection = HttpUtility.ParseQueryString(string.Empty);
        }

        public UriBuilderExt AddParameter(string key, string value)
        {
            _collection.Add(key, value);
            return this;
        }

        public Uri Uri
        {
            get
            {
                _builder.Query = _collection.ToString();
                return _builder.Uri;
            }
        }
    }
}
- در اینجا توسط متد AddParameter، کار افزودن کوئری استرینگ‌ها به یک Url از پیش مشخص، انجام می‌شود. کار encoding نهایی به صورت خودکار توسط HttpUtility استاندارد دات نت، انجام خواهد شد.
- تاریخ‌های ارسالی به سمت سرور را با فرمت yyyy'-'MM'-'dd تبدیل رشته کردیم. این قالب، یکی از قالب‌های پذیرفته شده‌است.
- جهت سهولت استفاده‌ی از سرویس فوق و همچنین مدل‌های برنامه، فضای نام آن‌ها را به فایل BlazorWasm.Client\_Imports.razor اضافه می‌کنیم تا در تمام کامپوننت‌های برنامه‌ی سمت کلاینت، قابل دسترسی شوند:
@using BlazorWasm.Client.Services
@using BlazorServer.Models
- در آخر این سرویس جدید را باید به لیست سرویس‌های برنامه معرفی کرد تا قابلیت تزریق در کامپوننت‌ها را پیدا کند:
namespace BlazorWasm.Client
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            // ...

            builder.Services.AddScoped<IClientHotelRoomService, ClientHotelRoomService>();

            // ...
        }
    }
}

چند اصلاح جزئی در کنترلرها و سرویس‌های سمت سرور

در Url نهایی فوق، دو پارامتر جدید checkInDate و checkOutDate هم وجود دارند. به همین جهت این دو را به اکشن متدهای کنترلر HotelRoom:
namespace BlazorWasm.WebApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class HotelRoomController : ControllerBase
    {
        // ...

        [HttpGet]
        public async Task<IActionResult> GetHotelRooms(DateTime? checkInDate, DateTime? checkOutDate)
        {
          // ...
        }

        [HttpGet("{roomId}")]
        public async Task<IActionResult> GetHotelRoom(int? roomId, DateTime? checkInDate, DateTime? checkOutDate)
        {
           // ...
        }
    }
}
و همچنین سرویس سمت سرور IHotelRoomService نیز اضافه می‌کنیم:
namespace BlazorServer.Services
{
    public interface IHotelRoomService : IDisposable
    {
        Task<List<HotelRoomDTO>> GetAllHotelRoomsAsync(DateTime? checkInDate, DateTime? checkOutDate);
        Task<HotelRoomDTO> GetHotelRoomAsync(int roomId, DateTime? checkInDate, DateTime? checkOutDate);
        // ...
    }
}
البته فعلا پیاده سازی خاصی ندارند و آن‌ها را در قسمت‌های بعد مورد استفاده قرار خواهیم داد.


تنظیمات ویژه‌ی HttpClient برنامه‌ی سمت کلاینت

سرویس ClientHotelRoomService فوق، از HttpClient تزریق شده‌ی در سازنده‌ی خود استفاده می‌کند که BaseAddress خود را مطابق تنظیمات ابتدایی برنامه، از HostEnvironment دریافت می‌کند. در اینجا علاقمندیم تا بجای این تنظیم پیش‌فرض، فایل جدید appsettings.json را به پوشه‌ی BlazorWasm.Client\wwwroot\appsettings.json کلاینت اضافه کرده (محل قرارگیری آن در برنامه‌های سمت کلاینت، داخل پوشه‌ی wwwroot است و نه در داخل پوشه‌ی ریشه‌ی اصلی پروژه):
{
    "BaseAPIUrl": "https://localhost:5001/"
}
و از این تنظیم جدید به عنوان BaseAddress برنامه‌ی Web API استفاده کنیم که روش آن‌را در کدهای ذیل مشاهده می‌کنید:
namespace BlazorWasm.Client
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            // ... 

            // builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
            builder.Services.AddScoped(sp => new HttpClient
            {
                BaseAddress = new Uri(builder.Configuration.GetValue<string>("BaseAPIUrl"))
            });

            // ... 
        }
    }
}

تکمیل کامپوننت دریافت لیست تمام اتاق‌ها

در قسمت قبل، کامپوننت خالی HotelRooms.razor را تعریف کردیم. کاربران پس از کلیک بر روی دکمه‌ی Go صفحه‌ی اول، به این کامپوننت هدایت می‌شوند. اکنون می‌خواهیم، لیست تمام اتاق‌ها را در این کامپوننت، از Web API برنامه دریافت کنیم:
@page "/hotel/rooms"

@inject ILocalStorageService LocalStorage
@inject IJSRuntime JsRuntime
@inject IClientHotelRoomService HotelRoomService

<h3>HotelRooms</h3>

@code {
    HomeVM HomeModel = new HomeVM();
    IEnumerable<HotelRoomDTO> Rooms = new List<HotelRoomDTO>();

    protected override async Task OnInitializedAsync()
    {
        try
        {
            var model = await LocalStorage.GetItemAsync<HomeVM>(ConstantKeys.LocalInitialBooking);
            if (model is not null)
            {
                HomeModel = model;
            }
            else
            {
                HomeModel.NoOfNights = 1;
            }
            await LoadRooms();
        }
        catch (Exception e)
        {
            await JsRuntime.ToastrError(e.Message);
        }
    }

    private async Task LoadRooms()
    {
        Rooms = await HotelRoomService.GetHotelRoomsAsync(HomeModel.StartDate, HomeModel.EndDate);
    }
}
در اینجا در ابتدا سعی می‌شود تا HomeModel، از Local Storage که در قسمت قبل آن‌را تنظیم کردیم، خوانده شود. سپس با استفاده از متد GetHotelRoomsAsync، لیست اتاق‌ها را از Web API دریافت می‌کنیم. تمام این عملیات آغازین نیز باید در روال رویدادگران OnInitializedAsync صورت گیرند.


روش اجرای پروژه‌های Blazor WASM

تا اینجا اگر برنامه‌ی سمت کلاینت را توسط دستور dotnet watch run اجرا کنیم، هرچند صفحه‌ی خالی نمایش لیست اتاق‌ها ظاهر می‌شود، اما یک خطای fetch error را هم دریافت خواهیم کرد؛ چون نیاز است ابتدا پروژه‌ی Web API را اجرا کرد و سپس پروژه‌ی WASM را.
برای ساده سازی اجرای همزمان این دو پروژه، اگر از ویژوال استودیوی کامل استفاده می‌کنید، بر روی نام Solution کلیک راست کرده و از منوی ظاهر شده، گزینه‌ی «Set Startup projects» را انتخاب کنید. در صفحه دیالوگ ظاهر شده، گزینه‌ی «multiple startup projects» را انتخاب کرده و از لیست پروژه‌های موجود، دو پروژه‌ی Web API و WASM را انتخاب کنید و Action مقابل آن‌ها را به Start تنظیم کنید. در اینجا حتی می‌توان ترتیب اجرای این پروژه‌ها را هم تغییر داد. در این حالت زمانیکه بر روی دکمه‌ی Run، در ویژوال استودیو کلیک می‌کنید، هر دو پروژه را با هم برای شما اجرا خواهد کرد.

نکته‌ی مهم! در این حالت هم برنامه‌ی کلاینت نمی‌تواند با برنامه‌ی Web API ارتباط برقرار کند! چون شماره پورت iisExpress درج شده‌ی در فایل appsettings.json آن، باید به شماره sslPort مندرج در فایل Properties\launchSettings.json پروژه‌ی Web API تغییر داده شود که برای نمونه در اینجا این عدد 44314 است:
{
  "iisSettings": {
    "iisExpress": {
      "applicationUrl": "http://localhost:62930",
      "sslPort": 44314
    }
  }
}
و یا اگر می‌خواهید پروژه را از طریق NET Core CLI. با اجرای دستور dotnet watch run اجرا کنید ... به صورت پیش‌فرض نمی‌شود! چون برای اینکار باید به پوشه‌ی ریشه‌ی پروژه‌های Web API و WASM وارد شد و دوبار دستور یاد شده را به صورت مجزا اجرا کرد. در این حالت، هر دو پروژه، بر روی پورت پیش‌فرض 5001 اجرا می‌شوند. روش تغییر این پورت، مراجعه به فایل Properties\launchSettings.json این پروژه‌ها است. برای مثال همان پورت پیش‌فرض 5001 را که در فایل appsettings.json انتخاب کردیم، ثابت نگه می‌داریم. یعنی فایل launchSettings.json پروژه‌ی Web API را ویرایش نمی‌کنیم. اما این پورت را در پروژه‌ی کلاینت برای مثال به عدد 5002 تغییر می‌دهیم تا برنامه‌ی کلاینت، بر روی پورت پیش‌فرض برنامه‌ی Web API اجرا نشود:
{
    "BlazorWasm.Client": {
      "applicationUrl": "https://localhost:5002;http://localhost:5003",
    }  
}


کدهای کامل این مطلب را از اینجا می‌توانید دریافت کنید: Blazor-5x-Part-27.zip
اشتراک‌ها
آماری از وضعیت فریم ورکهای جاوااسکریپتی در سال 2019 با رای گیری بیش از بیست هزار توسعه دهنده

But what do you know, turns out JavaScript isn’t quite done changing just yet! And so after over 21,717 respondents took this year's survey we had to dig up our components and charts, curse us-from-a-year-ago for writing such crappy code, and get to work digging through the data. 

آماری از وضعیت فریم ورکهای جاوااسکریپتی در سال 2019 با رای گیری بیش از بیست هزار توسعه دهنده
اشتراک‌ها
کتابخانه jose-jwt

Ultimate Javascript Object Signing and Encryption (JOSE) and JSON Web Token (JWT) Implementation for .NET and .NET Core  

کتابخانه jose-jwt