مطالب
بالا بردن سرعت بارگذاری اولیه NHibernate

در زمان اولین بارگذاری NHibernate ، ساخت تمام نگاشت‌ها صورت گرفته و همچنین session factory ایجاد می‌گردد. به همین جهت به کمک الگوی thread safe singleton نسبت به کش کردن آن در طول عمر یک برنامه استفاده می‌گردد.
در برنامه‌ای که در یک محیط کاری مورد استفاده قرار می‌گیرد این زمان اصلا مهم نیست، زیرا تنها یکبار باید انجام شود. اما به عنوان یک برنامه نویس شاید در طول روز صدها بار نیاز به باز و بسته کردن برنامه جهت آزمودن آن داشته باشیم و این مورد پس از مدتی تبدیل به عذاب می‌شود! خوشبختانه امکان serialize نمودن تنظیمات تولیدی session factory به فایل و سپس خواندن از آن نیز وجود دارد که این امر در حین توسعه‌ی برنامه بسیار ارزشمند است.
جهت مطالعه بیشتر می‌توان به مطالب زیر مراجعه کرد:

و حاصل تمام این مقالات در پروژه‌ی Effectus، فایل Effectus\Infrastructure\BootStrapper.cs آن گردآوری شده است.

نظرات مطالب
ارتقاء به ASP.NET Core 2.0 - معرفی بسته‌ی Microsoft.AspNetCore.All
امکان اجرای درون پروسه‌ای در نگارش 2.2 میسر هست و دقیقا جزئی از بسته‌ی هاستینگ آن است (لینک مطرح شده‌ی در نظر فوق قدیمی است). فقط در این حالت ممکن است برنامه مسیرهای فایل‌های مشخص شده‌ی در آن را پیدا نکند. باید با دستور dotnet ./proj.dll برنامه را اجرا کنید (و یا یکی از روش‌های مطرح شده‌ی در مطلب «بررسی خطاهای ممکن در حین راه اندازی اولیه برنامه‌های ASP.NET Core در IIS») و دقیقا مشاهده کنید که مشکل از کجاست. چند مثال از این نوع:
هر دو مورد به این اشاره می‌کنند که در نگارش فعلی این ماژول درون پروسه‌ای، متد Directory.GetCurrentDirectory بجای اینکه مسیر برنامه را باز گرداند، مسیر C:\windows\system32\inetsrv یا همان پروسه‌ی IIS را بر می‌گرداند و باید به این موضوع دقت داشت.  
نظرات مطالب
نمایش رکوردها به ترتیب اولویت به کمک jQuery UI sortable در ASP.NET MVC

«این کار احتمالا در ASP.NET WebForm  کار سختی نیست»

اتفاقا کار ساده‌ای نیست و همین مراحل باید طی شود. ضمن اینکه کار با jquery ajax در آنجا به این یک دستی نیست. نیاز است در code behind فرم، متد وب سرویس مانندی  به صورت استاتیک تعریف شود (که خودش سبب می‌شود تا دسترسی به اعتبار سنجی توکار مبتنی بر فرم‌ها محدود شود) یا اینکه از یک هندلر مجزا بجای یک اکشن متد کمک گرفته شود ... خلاصه خیلی داستان دارد.

بازخوردهای پروژه‌ها
آموزش استفاده از JQuery, Ajax, Javascript در برنامه های ASP.NET MVC
سری آموزش ASP.NET MVC یکی از بهترین آموزش‌های فارسی حال حاضر هستش و کاربران استقبال زیادی از این سری آموزشی کردند.
ای کاش مطالب بیشتری را به نحوه استفاده از JQuery, Javascript, JSON, ... در برنامه‌های MVC، اختصاص میدادید. مثلاً ثبت و ویرایش یا حذف اطلاعات از یک Table در View تماماً با استفاده از موارد ذکر شده.
ممنون.
مطالب
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
نظرات مطالب
شروع به کار با EF Core 1.0 - قسمت 2 - به روز رسانی ساختار بانک اطلاعاتی
- متد Seed به نگارش بعدی EF Core اضافه خواهد شد (نگارش 2.1). یک نمونه پیاده سازی آن در نگارش فعلی.
- روش کار چندسکویی با NET Core. مبتنی بر CLI آن هست. بهتر است سری کار با VSCode را پیگیری کنید تا بیشتر با CLI آن آشنا شوید. اما اگر می‌خواهید از PowerShell استفاده کنید (هنوز حال و هوای EF 6.x را دارید)، پیشنیازهای فعالسازی این مورد در نظرات قسمت بعدی مطرح شده‌است.
مطالب
سازماندهی برنامه‌های Angular توسط ماژول‌ها
یک برنامه‌ی Angular، از گروهی از کامپوننت‌ها تشکیل می‌شود؛ برای مثال یک کامپوننت App وجود دارد که آن نیز از تعدادی کامپوننت مختلف تشکیل می‌شود. ماژول‌ها کار سازماندهی و بسته بندی این کامپوننت‌ها را انجام می‌دهند و با بزرگتر شدن برنامه می‌توان قسمت‌های مختلف را در ماژول‌های متفاوتی قرار داد. مزایای این روش به شرح زیر هستند:
- بهبود کپسوله سازی قسمت‌های مختلف برنامه با بسته بندی آن‌ها در ماژول‌های متفاوت
- فراهم آوردن امکان lazy loading و بهبود کارآیی برنامه


انواع ماژول‌های توصیه شده‌ی در برنامه‌های Angular

منهای App Module پیش‌فرض یک برنامه‌های Angular، ایجاد سه نوع ماژول دیگر نیز در جهت سازماندهی اینگونه برنامه‌ها توصیه می‌شوند:
- Core Module
هدف از آن فراهم آوردن سرویس‌های Singleton اشتراکی بین کامپوننت‌ها و ماژول‌های مختلف برنامه است. علت این‌جا است که سیستم تزریق وابستگی‌های Angular، به ازای هر ماژولی که Lazy loaded باشد، سرویس تزریقی در آن‌ها را مجددا وهله سازی می‌کند. به همین جهت نیاز است تک ماژول اختصاصی را برای مدیریت سرویس‌هایی که نیازی است تنها یکبار در طول عمر برنامه وهله سازی شوند، تدارک ببینیم و Core Module مکان مناسبی برای این‌کار است.
همچنین Code Module باید شامل کامپوننت‌هایی در سطح برنامه باشد. دراینجا منظور از «در سطح برنامه»، کامپوننت‌هایی که قرار است در بین تمام ماژول‌ها به اشتراک گذاشته شوند، نیست. منظور تنها کامپوننت‌هایی هستند که در App Component اصلی برنامه قرار است استفاده شوند؛ مانند منوی راهبری بالای سایت.

- Shared Module
هدف از آن مدیریت و بسته بندی کامپوننت‌ها، دایرکتیوها و Pipes اشتراکی بین تمام اجزای برنامه است. برای مثال کامپوننت «لطفا منتظر بمانید ...» اگر قرار است در تمام قسمت‌های برنامه استفاده شود، نیاز است در Shared Module تعریف شود. از این جهت که در یک برنامه‌ی Angular نمی‌توان یک کامپوننت را بین دو ماژول مختلف به اشتراک گذاشت. به همین جهت نیاز است یک مکان مرکزی برای تعریف این کامپوننت‌های اشتراکی ایجاد شود و سپس این تک ماژول را در قسمت‌های مختلف برنامه، بدون مشکل مورد استفاده قرار داد.

- Feature Module
این ماژول‌ها به ازای هر ویژگی برنامه ایجاد شده و کامپوننت‌ها، سرویس‌ها، دایرکتیوها و Pipes اختصاصی آن ویژگی را بسته بندی می‌کنند.


ایجاد Core Module

فرض کنید می‌خواهید اطلاعات کاربر جاری لاگین شده را در طول عمر برنامه نگهداری کنید و از آن در تمام قسمت‌های برنامه استفاده نمائید. یک چنین سرویسی نیاز است دارای طول عمر Singleton باشد و تنها یکبار وهله سازی شود تا اطلاعات کاربر جاری از دست نرود. به همین جهت بهترین مکان تعریف این سرویس، در Core Module است.
برای این منظور در ساختار برنامه‌ی خود، پوشه‌ی جدید src\app\core را ایجاد می‌کنیم. سپس فایل core.module.ts را به صورت ذیل در آن تعریف خواهیم کرد:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';

import { UserRepositoryService } from './user-repository.service';
import { NavBarComponent } from './nav-bar.component';
import { AccountMenuComponent } from './account-menu.component';

@NgModule({
  imports: [ CommonModule, RouterModule ],
  exports: [ NavBarComponent, AccountMenuComponent ],
  declarations: [ NavBarComponent, AccountMenuComponent ],
  providers: [ UserRepositoryService ]
})
export class CoreModule { };
 - CoreModule در ابتدا تنها CommonModule و RouterModule را در صورت نیاز import می‌کند.
 - سپس سرویس‌های اشتراکی و Singleton برنامه در قسمت providers آن قرار می‌گیرند.
 - در اینجا همچنین دو کامپوننت منو که توسط app.component.ts مورد استفاده قرار می‌گیرند نیز import شده‌اند.
 - فایل‌های account-menu.component.ts، nav-bar.component.ts و user-repository.service.ts نیز به درون پوشه‌ی src\app\core منتقل خواهند شد (به همراه تمام فایل‌های html و css متناظر با آن‌ها).
 - اگر دقت کنید، قسمت exports این ماژول نیز مقدار دهی شده‌است. چون این کامپوننت‌ها قرار است خارج از این ماژول و در AppModule استفاده شوند، نیاز است آن‌ها را به صورت خروجی نیز معرفی کنیم.

اکنون جهت استفاده‌ی از این قابلیت‌ها، تنها کافی است تعریف CoreModule را به AppModule در فایل app.module.ts اضافه کنیم:
import { CoreModule } from "./core/core.module";

@NgModule({
  imports:      [
//...
    CoreModule,
//...
    RouterModule.forRoot(appRoutes)
  ],
//...
})
export class AppModule { }


ایجاد Shared Modules

در Shared Module اجزایی را قرار خواهیم داد که قرار است در بیش از یک ماژول مورد استفاده قرار گیرند. به همین جهت در ساختار برنامه‌ی خود، پوشه‌ی جدید src\app\shared را ایجاد می‌کنیم. سپس در آن، ماژول جدید shared.module.ts را ایجاد خواهیم کرد:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { LoadingSpinnerComponent } from './loading-spinner.component';

@NgModule({
  imports: [ CommonModule ],
  declarations: [ LoadingSpinnerComponent ],
  exports: [ LoadingSpinnerComponent, CommonModule ],
  providers: [ ]
})
export class SharedModule { };
ساختار این ماژول نیز شبیه به Core Module است. ابتدای CommonModule به آن import شده‌است. سپس کامپوننت‌هایی که قرار است در بین سایر ماژول‌های سایت به اشتراک گذاشته شوند (برای مثال یک کامپوننت Loading Spinner فرضی)، در هر دو قسمت declarations و exports این ماژول اشتراکی قرار می‌گیرند. همچنین فایل loading-spinner.component.ts و تمام اجزای وابسته‌ی به آن نیز به پوشه‌ی src\app\shared منتقل می‌شوند.
از این جهت که اجزای خروجی این ماژول قرار است در Feature Moduleها استفاده شوند، CommonModule مورد استفاده‌ی در آن‌ها نیز در قسمت exports ذکر شده‌است.

اکنون جهت استفاده‌ی از این قابلیت‌ها، تنها کافی است تعریف SharedModule را به AppModule در فایل app.module.ts اضافه کنیم:
import { CoreModule } from "./core/core.module";
import { SharedModule } from "./shared/shared.module";

@NgModule({
  imports:      [
//...
    CoreModule,
    SharedModule,
//...
    RouterModule.forRoot(appRoutes)
  ],
//...
})
export class AppModule { }


ایجاد Feature Modules

این مورد نکته‌ی ویژه‌ای را به همراه ندارد و همانند ایجاد سایر ماژول‌های برنامه‌است. برای مثال ویژگی مدیریت کاربران، به همراه تمام اجزای آن درون ماژول کاربران قرار می‌گیرد و به همین ترتیب برای سایر ویژگی‌های دیگر برنامه. ایجاد و مدیریت اینگونه ماژول‌ها توسط Angular CLI بسیار ساده‌است:
> ng g m users -m app.module --routing
> ng g c users/users-list
دستور اول ایجاد ماژول جدید users، پوشه‌ی مرتبط با آن و همچنین به روز رسانی فایل app.module را به صورت خودکار انجام می‌دهد.
دستور دوم نیز کامپوننتی را به این ماژول اضافه می‌کند؛ به همراه به روز رسانی تعاریف این ماژول.

فقط در اینجا SharedModule ایی را که پیشتر اضافه کردیم، به قسمت imports آن اضافه می‌کنیم:
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

import { SharedModule } from '../shared/shared.module';
import { UsersListComponent } from './users-list.component';

@NgModule({
  imports: [ RouterModule, SharedModule ],
  declarations: [ UsersListComponent ],
  exports: [  ],
  providers: [ ]
})
export class UsersModule { };