مطالب
Blazor 5x - قسمت 24 - تهیه API مخصوص Blazor WASM - بخش 1 - ایجاد تنظیمات ابتدایی
تا اینجا با اصول توسعه‌ی برنامه‌های مبتنی بر Blazor Server آشنا شدیم. در ادامه‌ی این سری، روش توسعه برنامه‌های مبتنی بر Blazor WASM را بررسی خواهیم کرد و پیش از شروع آن، باید بتوان امکانات سمت سرور مورد نیاز این نوع برنامه‌های سمت کلاینت را از طریق یک Web API تامین کرد که شامل دریافت و ارائه‌ی اطلاعات و همچنین اعتبارسنجی و احراز هویت مبتنی بر JWT یکپارچه‌ی با ASP.NET Core Identity است.


ایجاد پروژه‌ی ASP.NET Core Web API

برای تامین اطلاعات برنامه‌ی سمت کلاینت Blazor WASM و همچنین فراهم آوردن زیرساخت اعتبارسنجی کاربران آن، نیاز به یک پروژه‌ی ASP.NET Core Web API داریم که آن‌را با اجرای دستور dotnet new webapi در یک پوشه‌ی خالی، برای مثال به نام BlazorWasm.WebApi ایجاد می‌کنیم.
البته این پروژه، از زیرساختی که در برنامه‌ی Blazor Server بررسی شده‌ی تا این قسمت، ایجاد کردیم نیز استفاده خواهد کرد. همانطور که پیشتر نیز عنوان شد، هدف از قسمت Blazor Server مثال این سری، آشنایی با مدل برنامه نویسی خاص آن بود؛ وگرنه می‌توان کل این پروژه را با Blazor Server و یا کل آن‌را با Web API + Blazor WASM نیز پیاده سازی کرد. در این مثال، قسمت‌های مدیریتی برنامه‌ی مدیریت هتل را توسط Blazor Server (مانند قسمت‌های تعریف اتاق‌ها و امکانات رفاهی هتل) و قسمت مخصوص کاربران آن‌را مانند رزرو کردن اتاق‌ها، توسط Blazor WASM پیاده سازی می‌کنیم. به همین جهت قسمت‌هایی از این دو پروژه، مانند سرویس‌های استفاده شده‌ی در پروژه‌ی Blazor server، در پروژه‌ی Web API مکمل Blazor WASM، قابلیت استفاده‌ی مجدد را دارند.


افزودن سرویس‌های آغازین مورد نیاز، به پروژه‌ی Web API

در فایل آغازین BlazorWasm\BlazorWasm.WebApi\Startup.cs، برای شروع به تکمیل Web API، نیاز به این سرویس‌ها را داریم:
namespace BlazorWasm.WebApi
{
    public class Startup
    {
        //...

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAutoMapper(typeof(MappingProfile).Assembly);

            services.AddScoped<IHotelRoomService, HotelRoomService>();
            services.AddScoped<IAmenityService, AmenityService>();
            services.AddScoped<IHotelRoomImageService, HotelRoomImageService>();

            var connectionString = Configuration.GetConnectionString("DefaultConnection");
            services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));

            services.AddIdentity<IdentityUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            //...
در اینجا سرویس‌های AutoMapper، تنظیمات ابتدایی DbContext برنامه، به همراه سرویس‌های Identity (بدون UI آن) و افزودن سرویس‌های اتاق‌ها و امکانات رفاهی هتل را نیاز داریم. به همین جهت ارجاعات و وابستگی‌های زیر را به فایل csproj جاری اضافه می‌کنیم تا پروژه‌های DataAccess ،Services و Mappings قابل دسترسی و استفاده شوند:
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\..\BlazorServer\BlazorServer.DataAccess\BlazorServer.DataAccess.csproj" />
    <ProjectReference Include="..\..\BlazorServer\BlazorServer.Services\BlazorServer.Services.csproj" />
    <ProjectReference Include="..\..\BlazorServer\BlazorServer.Models.Mappings\BlazorServer.Models.Mappings.csproj" />
  </ItemGroup>
</Project>
همچنین در این پروژه نیز از همان بانک اطلاعاتی پروژه‌ی Blazor Server که تاکنون تکمیل کردیم، استفاده می‌کنیم. بنابراین محتوای فایل BlazorWasm\BlazorWasm.WebApi\appsettings.json آن نیز مشابه‌است:
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=HotelManagement;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}


تعریف کنترلر HotelRoom

در ادامه کدهای اولین کنترلر Web API را مشاهده می‌کنید که مرتبط است با بازگشت اطلاعات تمام اتاق‌های ثبت شده و یا بازگشت اطلاعات یک اتاق ثبت شده:
using BlazorServer.Models;
using BlazorServer.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace BlazorWasm.WebApi.Controllers
{
    [Route("api/[controller]")]
    public class HotelRoomController : ControllerBase
    {
        private readonly IHotelRoomService _hotelRoomService;

        public HotelRoomController(IHotelRoomService hotelRoomService)
        {
            _hotelRoomService = hotelRoomService;
        }

        [HttpGet]
        public IAsyncEnumerable<HotelRoomDTO> GetHotelRooms()
        {
            return _hotelRoomService.GetAllHotelRoomsAsync();
        }

        [HttpGet("{roomId}")]
        public async Task<IActionResult> GetHotelRoom(int? roomId)
        {
            if (roomId == null)
            {
                return BadRequest(new ErrorModel
                {
                    Title = "",
                    ErrorMessage = "Invalid Room Id",
                    StatusCode = StatusCodes.Status400BadRequest
                });
            }

            var roomDetails = await _hotelRoomService.GetHotelRoomAsync(roomId.Value);
            if (roomDetails == null)
            {
                return BadRequest(new ErrorModel
                {
                    Title = "",
                    ErrorMessage = "Invalid Room Id",
                    StatusCode = StatusCodes.Status404NotFound
                });
            }

            return Ok(roomDetails);
        }
    }
}
- این کنترلر، از سرویس IHotelRoomService که در قسمت‌های قبل تکمیل کردیم، استفاده می‌کند.
- ErrorModel آن‌را در همان پروژه‌ی قبلی مدل‌ها، در فایل BlazorServer\BlazorServer.Models\ErrorModel.cs به صورت زیر ایجاد کرده‌ایم:
namespace BlazorServer.Models
{
    public class ErrorModel
    {
        public string Title { get; set; }

        public int StatusCode { get; set; }

        public string ErrorMessage { get; set; }
    }
}
در این حالت اگر برنامه‌ی Web API را اجرا کنیم، به خروجی Swagger زیر می‌رسیم که جزئیات این فناوری را در سری «مستند سازی ASP.NET Core 2x API توسط OpenAPI Swagger» پیشتر بررسی کردیم:


یکی از مزایای آن، امکان آزمایش API تهیه شده، بدون نیاز به تهیه‌ی هیچ نوع کلاینت خاصی است. برای مثال اگر بر روی api​/hotelroom آن کلیک کنیم، گزینه‌ی «try it out» آن ظاهر شده و با کلیک بر روی آن، اینبار دکمه‌ی execute ظاهر می‌شود. در ادامه با کلیک بر روی دکمه‌ی اجرای آن، اکشن متد GetHotelRooms اجرا شده و خروجی زیر ظاهر می‌شود:


و یا اگر بخواهیم متد GetHotelRoom را توسط آن آزمایش کنیم، بر اساس پارامترهای آن، رابط کاربری زیر را تشکیل می‌دهد که امکان دریافت شماره‌ی اتاق را دارد:



انجام تنظیمات ابتدایی CORS و خروجی JSON برنامه

قرار است این API را از طریق پروژه‌ی Blazor سمت کلاینت خود استفاده کنیم که آدرس آن، با آدرس API یکی نیست. به همین جهت نیاز است تنظیمات CORS را به صورت زیر اضافه کنیم:
namespace BlazorWasm.WebApi
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
         // ... 

            services.AddCors(o => o.AddPolicy("HotelManagement", builder =>
            {
                builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
            }));

            services.AddControllers()
                    .AddJsonOptions(options =>
                    {
                        options.JsonSerializerOptions.PropertyNamingPolicy = null;
                        // To avoid `JsonSerializationException: Self referencing loop detected error`
                        options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
                    });
         // ... 
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            // ... 

            app.UseCors("HotelManagement");
            app.UseRouting();

            app.UseAuthentication();
            // ...
        }
    }
}
در اینجا علاوه بر تنظیمات CORS، تنظیمات JsonSerializer را هم تغییر داده‌ایم تا خطاهای Self referencing loop را در حین ارائه‌ی خروجی‌های Web API، مشاهده نکنیم (همان نکته‌ی «تهیه خروجی JSON از مدل‌های مرتبط، بدون Stack overflow»).


کدهای کامل این مطلب را از اینجا می‌توانید دریافت کنید: Blazor-5x-Part-24.zip
اشتراک‌ها
دوره کار با Angular 16 توسط Web API و Entity Framework Core

Angular 16 CRUD with .NET 7 Web API using Entity Framework Core - Full Course

📑 Contents:
00:00:00 Video Introduction
00:00:40 Angular and ASP.NET Core Udemy Course Demo
00:03:07 Prerequisites
00:03:37 Setting Up Development Environment
00:15:37 Create ASP.NET Core Web API
00:20:07 Understanding Files and Folder Structure
00:25:37 Understanding REST and HTTP Verbs
00:30:10 Create .NET 6 Web API
00:32:41 Our Project and Domain Models
00:41:16 Installing Nuget Packages For Entity Framework Core
00:43:06 DbContext
00:59:26 Running EF Core Migrations
01:03:26 Create Controllers and Actions
01:23:46 Repository Pattern
01:36:46 Create New Angular Application using Angular CLI
01:50:09 Angular Components
02:13:29 CRUD in Angular and ASP.NET Core Web APIs
02:17:21 Angular Forms
02:26:59 Angular Services
02:38:09 CORS
02:42:09 Unsubscribing
 

دوره کار با Angular 16 توسط Web API و Entity Framework Core
مطالب
آشنایی با ساختار IIS قسمت هفتم

در این قسمت بیشتر یک سری از ماژول‌ها را به شما در قالب جداول گروه بندی شده معرفی خواهیم کرد :

   همانطور که در قسمت‌های قبلی گفتیم سرور IIS آماده خصوصی سازی و کار بر اساس علائق شماست؛ ولی توجه داشته باشید حذف تمامی ماژول‌ها ممکن است اثرات جانبی هم داشته باشد. در اینجا ما ماژول هایی را به شما معرفی می‌کنیم که بدانید کار هر ماژول چیست تا مثلا با حذف ماژولی، امنیت وب سایت خود را به خطر نیندازید :

ماژول‌های سودمند یا utility

نام ماژول:

UriCacheModule

توضیح:

این ماژول نوعی کش برای URLها به شمار می‌رود. موقعی که url درخواست می‌شود، اطلاعات در اولین درخواست خوانده شده و کش می‌شود و اگر دوباره همان url درخواست شود، بدون خواندن تنظیمات و بر اساس تنظیمات قبلی، کار url مربوطه را انجام میدهد تا اطلاعات پیکربندی تغییر کند و بر اساس اطلاعات جدید، خود را به روز کند.

تگ قابل پیکربندی:

لازم ندارد

وابستگی:

ندارد

اثرات حذف آن:

کارایی سیستم کاهش می‌یابد و سیستم مجبور است برای هر درخواست فایل پیکربندی را بخواند.

نام ماژول :

FileCacheModule

توضیح :

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

تگ قابل پیکربندی :

لازم ندارد .

وابستگی :

ندارد.

اثرات حذف آن :

کارایی سیستم کاهش می‌یابد. سیستم در هر اجرای دستور مربوط به فایل‌ها باید فایل هندل را به دست آورد.

نام ماژول :

TokenCacheModule

توضیح :

توکن‌های امنیتی ویندوز که پسوردهایی بر اساس authentication schemes هستند را کش می‌کند (anonymous authentication, basic authentication, IIS client certificate authentication )

تگ قابل پیکربندی :

لازم ندارد

وابستگی :

ندارد

اثرات حذف آن :

کارایی سیستم به شدت پایین می‌آید. کاربر باید با هر درخواستی لاگین کند. یکی از اصلی‌ترین ضربه‌ها با حذف این ماژول این است که اگر مثلا یک پسورد از یک فایل html محافظت می‌کند و این صفحه به 50 تصویر ارجاع دارد، 51 بار باید درخواست لاگین اجرا گردد یا شاید هم بدتر

MANAGED ENGINE: ASP.NET INTEGRATION

نام ماژول :

ManagedEngine

توضیح :

مدیریت ماژول‌های native و مدیریت شده

تگ قابل پیکربندی :


وابستگی :

ندارد

اثرات حذف آن :

مشخصا غیرفعال شدن asp.net integrated و غیر فعال شدن تمامی ماژول‌ها و هندلر‌های تگ وب کانفیگ یا داخل فایل کانفیگ IIS که در مقالات قبلی به تفصیل بیان کرده‌ایم.

IIS 7 NATIVE MODULES

نام ماژول :

HttpCacheModule

توضیح :

مدیریت کش خروجی در htttp.sys بر اساس پیکربندی مثل تعریف سایز کش و ...

تگ قابل پیکربندی :

System.webServer/caching

وابستگی :

ندارد.

اثرات حذف آن :

محتوا دیگر به صورت کرنل مد، کش نمی‌شود و کش پروفایل هم ندید گرفته می‌شود و احتمالا بر کارآیی و استفاده از منابع هم اثر می‌گذارد.

نام ماژول :

DynamicCompressionModule

توضیح :

پیاده سازی in-memory compression در محتوای پویا

تگ قابل پیکربندی :

system.webServer/httpCompression and system.webServer/urlCompression.

وابستگی :

وابستگی ندارد چرا که به طور پیش فرض غیرفعال است.

نام ماژول :

StaticCompressionModule

توضیح :

پیادسازی فشرده سازی در محتوای ایستا و برای فایل‌های سیستمی از نوع in memory

تگ قابل پیکربندی :

system.webServer/httpCompression and system.webServer/urlCompression

وابستگی :

ندارد.

اثرات حذف آن :

در صورت عدم فشرده سازی بر مصرف ترافیک تاثیر گذار است.

نام ماژول :

DefaultDocumentModule

توضیح :

پیاده سازی یک لیست سند پیش فرض. درخواست‌ها مدام پشت سر هم می‌آیند و این درخواست‌های پشت سرهم، به سند پیش فرض هدایت می‌شوند. همان پنجره ای که شما به ترتیب فایل‌های index.htm,index.asp,default.aspx و... را تعیین می‌کنید.

تگ قابل پیکربندی :

system.webServer/defaultDocument

وابستگی :

ندارد.

اثرات حذف آن :

درخواست را به ریشه هدایت می‌کند. مثلا برای localhost صفحه 404 باز میگرداند و اگر directoryBrowsing فعال باشد لیستی از دایرکتوری ریشه را باز میگرداند.

نام ماژول :

DirectoryListingModule

توضیح :

پیادی سازی لیستی از محتویات یک دایرکتوری

تگ قابل پیکربندی :

system.webServer/directoryBrowse

وابستگی :

ندارد.

اثرات حذف آن :

اگر این ماژول و ماژول قبلی غیرفعال باشند response نهایی خالی است.

نام ماژول :

ProtocolSupportModule

توضیح :

پیاده سازی اختصاصی از response header

پیاده سازی تنظیمات trace و HTTP verbs.

پیاده سازی تنظیمات مربوطه به keep-alive بر اساس پیکربندی

تگ قابل پیکربندی :

system.webServer/httpProtocol

وابستگی :

ندارد.

اثرات حذف آن :

بازگرداندن پیام خطای "405 Method not allowed".

نام ماژول :

HttpRedirectionModule

توضیح :

پیاده سازی عملیات انتقال یا redirect

تگ قابل پیکربندی :

system.webServer/httpRedirect

وابستگی :

ندارد.

اثرات حذف آن :

خطر امنیتی: اگر منابعی با redirect کردن محافظت می‌شوند، از این پس در دسترسند.

نام ماژول :

ServerSideIncludeModule

توضیح :

حمایت از فایل shtm یا shtml و ...

تگ قابل پیکربندی :

system.webServer/serverSideInclude

وابستگی :

ندارد.

اثرات حذف آن :

این فایل‌ها به صورت متنی نمایش داده می‌شوند

نام ماژول :

StaticFileModule

توضیح :

فایل‌های ایستا را به همراه پسوند ارسال می‌کند. مثل jpg,html و نوع محتوا را بر اساس staticContent/mimeMap پیکربندی می‌کند.

تگ قابل پیکربندی :

system.webServer/staticContent

وابستگی :

ندارد.

اثرات حذف آن :

فایل‌های ایستا دیگر ارائه نشده و به جای آن خطای 404 بازگشت داده می‌شود.

نام ماژول :

AnonymousAuthenticationModule

توضیح :

پیاده سازی سیستم شناسایی افراد ناشناس. همانطور که میدانید در یک وب سایت حداقل محتوایی برای افرادی بدون داشتن اکانت هم وجود دارد. برای اینکار یک شیء httpuser ایجاد می‌کند.

تگ قابل پیکربندی :

system.webServer/security/authentication/anonymousAuthentication

وابستگی :

ندارد.

اثرات حذف آن :

حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS می‌باشد و در صورت نبودن هیچ سیستم شناسایی وجود نداشته و در نبود شیء httpuser سیستم خطای 401.2 را تولید می‌کند.

نام ماژول :

CertificateMappingAuthenticationModule

توضیح :

مجوز SSL را به Active Directory نگاشت می‌کند.

تگ قابل پیکربندی :

system.webServer/security/authentication/clientCertificateMappingAuthentication

وابستگی :

برای اینکه این ماژول وظیفه خود را انجام دهد باید تنظیمات SSL انجام شود و همچنین سیستم IIS جزئی از دامنه Active directory باشد

اثرات حذف آن :

درخواست‌ها، نرمال رسیدگی میشوند انگار SSL وجود ندارد.

نام ماژول :

BasicAuthenticationModule

توضیح :

پیاده سازی پایه‌ای و روتین شناسایی کاربران بر اساس آن چیزی که در استانداد زیر آمده است

RFC 2617.

تگ قابل پیکربندی :

system.webServer/security/authentication/basicAuthentication

وابستگی :

None.

اثرات حذف آن :

حداقل باید یک سیستم امنیتی برای شناساسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده‌ای در IIS می‌باشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء  httpuser در سیستم، خطای 401.2 را تولید می‌کند.

نام ماژول :

WindowsAuthenticationModule

توضیح :

((windows Authentication (NTLM or Negotiate (Kerberos

تگ قابل پیکربندی :

system.webServer/security/authentication/windowsAuthentication

وابستگی :

ندارد.

اثرات حذف آن :

حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS می‌باشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید می‌کند.

نام ماژول :

DigestAuthenticationModule

توضیح :

پیاده سازی سیستم شناسایی دیاجست بر اساس

RFC 2617 .

تگ قابل پیکربندی :

system.webServer/security/authentication/digestAuthentication

وابستگی :

IIS باید بخشی از دامنه Active Directory باشد.

اثرات حذف آن :

حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS می‌باشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید می‌کند.

نام ماژول :

IISCertificateMappingAuthenticationModule

توضیح :

پیاده سازی نگاشت مجوزهای IIS، نگهداری و ذخیره اطلاعات همه نگاشت‌ها و مجوزهای کاربری چون SSL client certificates  

تگ قابل پیکربندی :

system.webServer/iisClientCertificateMappingAuthentication

وابستگی :

اطلاعات SSL به همراه دریافت client certificates جهت پیکربندی این ماژول

اثرات حذف آن :

حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS می‌باشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید می‌کند.

نام ماژول :

UrlAuthorizationModule

توضیح :

پیاده سازی authorization بر اساس قوانین پیکربندی شده

تگ قابل پیکربندی :

system.webServer/security/authorization

وابستگی :

ندارد.

اثرات حذف آن :

محتواهای محافظت شده توسط authorization دیگر محافظت نمی‌شوند.

نام ماژول :

IsapiModule

توضیح :

پیاده سازی ISAPI Extension 

تگ قابل پیکربندی :

system.webServer/isapiCgiRestriction

وابستگی :

ندارد.

اثرات حذف آن :

هندلر‌های معرفی شده در بخش IsapiModule و تگ handlers دیگر اجرا نمی‌شوند

نام ماژول :

IsapiFilterModule

توضیح :

پیاده سازی ISAPI filter 

تگ قابل پیکربندی :

system.webServer/isapiFilters

وابستگی :

ندارد.

اثرات حذف آن :

اگر برنامه ای از ISAPI filter استفاده می‌کند، در اجرا دچار مشکل خواهد شد.

نام ماژول :

IpRestrictionModule

توضیح :

یک سیستم تشخیص دسترسی  بر اساس آی پی‌های ورژن4

تگ قابل پیکربندی :

system.webServer/security/ipSecurity

وابستگی :

IPv4 stack باید نصب شود.

اثرات حذف آن :

کلاینت هایی که IP هایشان در IPsecurity لیست شده‌اند ندید گرفته میشوند

نام ماژول :

RequestFilteringModule

توضیح :

پیاده سازی یک مجموعه قدرتمند از قوانین امنیتی که درخواست‌های مشکوک را پس می‌زند.

تگ قابل پیکربندی :

system.webServer/security/requestFiltering

وابستگی :

ندارد.

اثرات حذف آن :

دیگر قوانین امنیتی اجرا نخواهند شد و سبب وجود مشکلات امنیتی میشود.

نام ماژول :

CustomLoggingModule

توضیح :

پیاده سازی اینترفیس ILogPlugin در سمت IIS، به مشتریان اجازه میدهد تا لاگ‌های خود را توسعه دهند. هر چند این روش توصیه نمی‌شود و توصیه کارشناس مایکروسافت استفاده از یک ماژول دست نویس از نوع RQ_LOG_REQUEST می باشد.

Implements the ILogPlugin interface on top of IIS. ILogPlugin is a previous COM implementation that allowed customers to extend IIS logging. We do not not recommend extending IIS using this interface. Instead, customers should write a module and subscribe to the RQ_LOG_REQUEST notification.

تگ قابل پیکربندی :

system.webServer/httpLogging and system.applicationhost/sites/site/logFile/customLogPluginClsid

وابستگی :

ندارد.

اثرات حذف آن :

مسلما پلاگین‌های‌های این اینترفیس از کار می‌‌افتند که سیستم ODBC Logging هم جز آن است.

نام ماژول :

CustomErrorModule

توضیح :

پیاده سازی مدیریت خطاهای ویژه

تگ قابل پیکبرندی :

system.webServer/httpErrors

وابستگی :

None.

اثرات حذف آن :

در صورتی که خطایی از هسته باشد، نتیجه یک صفحه، با توضیح مختصری از خطا خواهد بود. در غیر این صورت اگر خطا از برنامه یا کامپوننتی باشد جزئیات خطا فاش خواهد شد

نام ماژول :

HttpLoggingModule

توضیح :

پیاده سازی سیستم logging استاندارد http.sys

تگ قابل پیکربندی :

system.applicationHost/log and system.webServer/httpLogging

وابستگی :

ندارد.

اثرات حذف آن :

از کار افتادن سیستم لاگ

نام ماژول :

FailedRequestsTracingModule

توضیح :

پیاده سازی سیستم ردیابی درخواست‌های ناموفق و اجرای قوانین، طبق پیکربندی

تگ قابل پیکربندی :

system.webServer/tracing and system.webServer/httpTracing

وابستگی :

ندارد.

اثرات حذف آن :

Tracing http requests will no longer work.

نام ماژول :

RequestMonitorModule

توضیح :

پیاده سازی IIS Run-time State and Control Interface یا به اختصار RSCA . به کاربران اجازه می‌دهد از اطلاعات، حین اجرا، کوئری بگیرند. مثل درخواست درحال اجرای جاری، آغاز به کار یا توقف وب سایت و دامنه‌های اپلیکیشن در حال اجرای جاری

تگ قابل پیکربندی :

ندارد.

وابستگی :

ندارد.

اثرات حذف آن :

ابزارهای مرتبط با این موضوع از کار می‌افتند

نام ماژول :

CgiModule

توضیح :

پیاده سازی CGI در سمت IIS

تگ قابل پیکبرندی :

system.webServer/cgi and system.webServer/isapiCgiRestriction

وابستگی :

ندارد.

اثرات حذف آن :

برنامه‌های CGI متوقف می‌شوند

نام ماژول :

TracingModule

توضیح :

پیاده سازی سیستم ردیابی ETW

تگ قابل پیکربندی :

system.webServer/httpTracing

وابستگی :

ندارد.

اثرات حذف آن :

باعث از کار افتادن سیستم مربوطه می‌شود

نام ماژول :

ConfigurationValidationModule

توضیح :

اعتبارسنجی تنظیمات برنامه ASP.Net که به حالت integrate انتقال یافته است

تگ قابل پیکربندی :

system.webServer/Validation

وابستگی :

ندارد.

اثرات حذف آن :

عدم اعتبارسنجی و در نتیجه عدم نمایش خطاها

MANAGED MODULES:

نام ماژول :

OutputCache

توضیح :

پیاده سازی output caching

تگ قابل پیکربندی :

system.web/caching/outputCache

وابستگی :

نیاز به ManagedEngine .

اثرات حذف آن :

عدم اجرای output cache

نام ماژول :

Session

توضیح :

مدیریت سشن ها

تگ قابل پیکربندی :

system.web/sessionState

وابستگی :

نیاز به ManagedEngine . 

اثرات حذف آن :

سشن‌ها از دسترس خارج می‌شوند.

نام ماژول :

WindowsAuthentication

توضیح :

اینجا 

تگ قابل پیکربندی :

system.web/authentication

وابستگی :

نیاز به ManagedEngine .

اثرات حذف آن :

این حالت قابل اجرا نخواهد بود

نام ماژول :

FormsAuthentication

توضیح :

اینجا 

تگ قابل پیکربندی :

system.web/authentication

وابستگی :

نیاز به ManagedEngine .

اثرات حذف آن :

این حالت قابل اجرا نیست و کاربران مجوز دار هم نمی‌توانند به منابع محافظت شده دسترسی داشته باشند.

نام ماژول :

DefaultAuthentication

توضیح :

اطمینان از وجود شی Authentication در context مربوطه 

تگ قابل پیکربندی :

system.web/authentication

وابستگی :

نیاز به ManagedEngine .  

اثرات حذف آن :

اگر مد Forms authentication انتخاب شده باشد بر روی بعضی از کاربران ناشناس کار نخواهد کرد و رویداد DefaultAuthentication.OnAuthenticate اجرا نخواهد شد.

نام ماژول :

RoleManager

توضیح :

اینجا 

تگ قابل پیکربندی :


وابستگی :

نیاز به ManagedEngine .

اثرات حذف آن :

این قابلیت در دسترس نمی‌باشد

نام ماژول :

UrlAuthorization

توضیح :

اینجا 

تگ قابل پیکربندی :

system.web/authorization.

وابستگی :

نیاز به ManagedEngine .  

اثرات حذف آن :

باعث از کار افتادن asp.net authorization و فاش شدن بعضی اطلاعات و همچنین دیگر تهدیدات امنیتی

نام ماژول :

AnonymousIdentification

توضیح :

اینجا 

تگ قابل پیکربندی :


وابستگی :

نیاز به ManagedEngine . 

اثرات حذف آن :

The anonymous identification feature used by the ASP.NET Profile will not work.

نام ماژول :

Profile

توضیح :

اینجا 

تگ قابل پیکربندی :


وابستگی :

ManagedEngine module must be installed.

اثرات حذف آن :

ASP.Net Profile از کار خواهد افتاد

نام ماژول :

UrlMappingsModule

توضیح :

 تبدیل یک Url واقعی به یک Url کاربرپسند 

تگ قابل پیکبرندی :


وابستگی :

نیاز به ManagedEngine .

اثرات حذف آن :

نگاشت Url‌ها صورت نمی‌گیرد

مطالب
امکان استفاده‌ی مستقیم از کتابخانه‌های Full .NET Framework در NET Core 2.0.
یکی از مواردی که به همراه NET Core 1.x. وجود دارد، کمبود کتابخانه‌های ثالث مخصوص آن است. برای مثال کتابخانه‌ی log4net در اوایل ارائه‌ی NET Core. نگارش مخصوص به آن‌را نداشت (البته هم اکنون دارد). باید درنظر داشت، این مورد صرفا در حالت توزیع چندسکویی برنامه‌های مبتنی بر NET Core. مشکل ایجاد می‌کرد. از این جهت که می‌توان full .NET framework را به عنوان Target Framework برنامه‌های NET Core. معرفی کرد و در این حالت برنامه بدون هیچگونه مشکلی تنها بر روی ویندوز و سرورهای ویندوزی اجرا می‌شود (و امکان دسترسی به تمامی کتابخانه‌های مخصوص full .NET framework را نیز دارا خواهد بود)؛ اما قابلیت توزیع بر روی لینوکس و مک را از دست خواهد داد.
در NET Core 2.0. از یک اصطلاحا «compatibility shim» مخصوص استفاده می‌شود که امکان افزودن ارجاعات به full framework library‌ها را بدون نیاز به تغییر target framework برنامه میسر می‌کند. یعنی در اینجا می‌توان یک کتابخانه‌ی قدیمی دات نتی را در برنامه‌های مبتنی بر NET Core. بر روی لینوکس نیز اجرا کرد و در این حالت نیازی به تبدیل اجباری این کتابخانه به نسخه‌ی NET Core. آن نیست.


NET Core 2.0. پیاده سازی کننده‌ی NET Standard 2.0. است

NET Standard‌. در حقیقت یک قرار داد است که سکوهای کاری مختلف دات نتی مانند Full .NET Framework ، Xamarin ، Mono ، UWP و غیره می‌توانند آن‌را پیاده سازی کنند. یک نمونه‌ی دیگر این پیاده سازی‌ها نیز NET Core. است. برای مثال دات نت 4.6.1، استاندارد و قرار داد شماره‌ی 2 دات نت را پیاده سازی می‌کند. به همین صورت NET Core 2.0. نیز پیاده سازی کننده‌ی این استاندارد شماره 2 است.
 با تغییرات اخیر، اکنون NuGet می‌تواند کتابخانه‌های مبتنی بر NET Standard 2. را در برنامه‌های مبتنی بر سکوهای کاری که آن‌را پیاده سازی می‌کنند، بدون مشکل اضافه کند. برای مثال می‌توان اسمبلی‌های دات نت 4.6.1 را به برنامه‌های ASP.NET Core 2.0 اضافه کرد (کاری که در نگارش 1x آن به صورت مستقیم میسر نیست) و یا می‌توان اسمبلی‌های کامپایل شده‌ی برای دات نت استاندارد 2 را به برنامه‌های مبتنی بر دات نت 4.6.1 اضافه کرد.


آیا واقعا کتابخانه‌های قدیمی دات نتی توسط برنامه‌های NET Core 2.0. در لینوکس نیز اجرا خواهند شد؟

دات نت استاندارد، بیش از یک قرار داد چیزی نیست و پیاده سازی کنندگان آن می‌توانند سطح بیشتری را نسبت به این قرار داد نیز لحاظ کنند. برای مثال دات نت 4.6.1 شامل سطح API بیشتری از دات نت استاندارد 2 است.
 به همین جهت باید درنظر داشت که امکان اضافه کردن یک بسته‌ی نیوگت از یک کتابخانه‌ی نوشته شده‌ی برای دات نت کامل در برنامه‌های دات نت Core به معنای تضمینی برای کار کردن آن در زمان اجرا نخواهد بود. از این جهت که دات نت کامل، به همراه قسمت‌هایی است که در NET Standard. وجود خارجی ندارند. بنابراین اگر کتابخانه‌ی استفاده شده صرفا این API مشترک را هدف قرار داده‌است، هم قابلیت اتصال و هم قابلیت اجرا را خواهد داشت؛ اما اگر برای مثال کسی بسته‌ی NServiceBus را به پروژه‌ی ASP.NET Core 2.0 اضافه کند، بدون مشکل کامپایل خواهد شد. اما از آنجائیکه این کتابخانه از MSMQ استفاده می‌کند که خارج از میدان دید این استاندارد است، در زمان اجرا با شکست مواجه خواهد شد.


«compatibility shim» در NET Standard 2.0. چگونه کار می‌کند؟

در NET Core.، پیاده سازی Object در System.Runtime قرار دارد و کد تولید شده‌ی توسط آن یک چنین ارجاعی را [System.Runtime]System.Object تولید می‌کند. اما در دات نت کلاسیک، System.Object در mscorlib قرار دارد. به همین جهت زمانیکه سعی کنید اسمبلی‌های دات نت کلاسیک را در NET Core 1.x. استفاده کنید، پیام یافتن نشدن نوع‌ها را دریافت خواهید کرد. اما در NET Core 2.0. یک پیاده سازی صوری (facade) از mscorlib وجود دارد که کار آن هدایت نوع درخواستی، به نوع واقعی پیاده سازی شده‌ی در NET Core. است.


در این تصویر استفاده‌ی از یک کتابخانه‌ی ثالث را مشاهده می‌کنید که ارجاعی را به [mscorlib]Microsoft.Win32.RegistryKey دارد (مبتنی بر دات نت کلاسیک است).  همچنین یک mscorlib مشخص شده‌ی به صورت facade را نیز مشاهده می‌کنید. کار آن هدایت درخواست نوع واقع شده‌ی در mscorlib، به نوع موجود [Microsoft.Win32.Registry] Microsoft.Win32.RegistryKey است و تنها زمانی کار خواهد کرد که Microsoft.Win32.RegistryKey.dll وجود خارجی داشته باشد. به این معنا که رجیستری، یک مفهوم ویندوزی است و این کتابخانه بر روی ویندوز بدون مشکل کار می‌کند. اما تحت لینوکس، این قسمت خاص با پیام PlatformNotSupportedException خاتمه خواهد یافت. اما اگر قسمت‌هایی از این کتابخانه را استفاده کنید که در تمام سکوهای کاری وجود داشته باشند، بدون مشکل قادر به استفاده‌ی از آن خواهید بود.


یک مثال: استفاده از کتابخانه‌ی رمزنگاری اطلاعات Inferno

آخرین نگارش کتابخانه‌ی رمزنگاری اطلاعات Inferno مربوط به NET 4.5.2. است. مراحل ذیل را پس از نصب SDK جدید NET Core 2.0. در خط فرمان طی می‌کنیم:
الف) ایجاد پوشه‌ی UseNET452InNetCore2 و سپس ایجاد یک پروژه‌ی کنسول جدید
dotnet new console

ب) افزودن بسته‌ی نیوگت Inferno به پروژه
 dotnet add package Inferno
این بسته بدون مشکل اضافه می‌شود؛ البته پیام اخطار ذیل نیز صادر خواهد شد (چون مبتنی بر NET 4.6.1. که پیاده سازی کننده‌ی NET Standard 2.0. است، نیست):
 log  : Installing Inferno 1.4.0.
warn : Package 'Inferno 1.4.0' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This package may not be fully compatible with your project.
info : Package 'Inferno' is compatible with all the specified frameworks in project 'D:\UseNET452InNetCore2\UseNET452InNetCore2.csproj'.
info : PackageReference for package 'Inferno' version '1.4.0' added to file 'D:\UseNET452InNetCore2\UseNET452InNetCore2.csproj'.
ابتدا پیام می‌دهد که این بسته ممکن است با NET Core 2.0. سازگار نباشد. سپس عنوان می‌کند که سازگاری کاملی را با پروژه‌ی جاری دارد و بسته را اضافه می‌کند.

ج) استفاده از کتابخانه‌ی Inferno جهت تولید یک عدد تصادفی thread safe
using System;
using SecurityDriven.Inferno;

namespace UseNET452InNetCore2
{
    class Program
    {
        static CryptoRandom random = new CryptoRandom();
        static void Main(string[] args)
        {
            Console.WriteLine($"rnd: {random.NextLong()}");
        }
    }
}

د) اجرای برنامه
در ادامه اگر دستور dotnet run را صادر کنیم، ابتدا اخطاری را صادر می‌کند که این بسته ممکن است دارای قسمت‌هایی باشد که با NET core 2.0. سازگار نیست و سپس خروجی نهایی را بدون مشکل اجرا کرده و نمایش می‌دهد.
 >dotnet run
warning NU1701:  This package may not be fully compatible with your project.
rnd: 8167886599578111106
اشتراک‌ها
پیاده سازی یک پروژه با ASP.NET Core Web API

Ticketier project | ASP.NET Core Web API CRUD and Search | .NET 7 API | Full Course

Full Course Ticketier project with ASP.NET Core Web API (.NET 7 API ) and  Entity Framework Core covering CRUD and Search step by step
In this video, we will create an ASP.NET Core Web API (.NET 7) project called Ticketier and implement full CRUD and Search functionality into it.
The focus of this project is to show you how you can build new ASP.NET Core Web API (.NET 7) project from 0 to 100 and implement CRUD and Search in it.

we will learn these topics together:
Entities
Dtos
Context
ORM
Http Methods
Swagger
AutoMapper
IQueryable
Where clause 

پیاده سازی یک پروژه با ASP.NET Core Web API
نظرات مطالب
احراز هویت و اعتبارسنجی کاربران در برنامه‌های Angular - قسمت اول - معرفی و ایجاد ساختار برنامه
یک نکته‌ی تکمیلی
اگر NET Core 3 SDK. را نصب کنید، امکان ایجاد یک برنامه‌ی Angular مبتنی بر Microsoft.AspNetCore.ApiAuthorization.IdentityServer به قالب‌های پیش‌فرض آن اضافه شده‌است. روش ایجاد آن توسط دستورات CLI به صورت زیر است:
dotnet new angular --auth Individual

همین مورد برای برنامه‌های React نیز پیش بینی شده‌است:
dotnet new react --auth Individual
//or
dotnet new reactredux --auth Individual
نظرات مطالب
سازماندهی برنامه‌های Angular توسط ماژول‌ها
ارتقاء به Angular 6: ساده سازی قسمت providers در CoreModule

ویژگی جدیدی به Angular 6 به نام tree-shakable providers اضافه شده‌است که نمونه‌ای از کاربرد آن به صورت پیش‌فرض در حین «ایجاد پروژه‌ی «کتابخانه» توسط Angular CLI 6.0» ارائه می‌شود. به این معنا که با استفاده‌ی از آن دیگر نیازی نیست تا سرویس‌های سراسری برنامه را در قسمت providers مربوط به CoreModule ثبت کرد. همینقدر که یک سرویس سراسری را به صورت ذیل تعریف کنید:
import { Injectable } from '@angular/core';
@Injectable({
    providedIn: 'root'
})
export class MyCoreService { }
خاصیت providedIn آن کار ثبت این سرویس را به صورت خودکار انجام می‌دهد. تفاوت آن با حالت قبل این است که اگر این سرویس جایی در برنامه استفاده نشده باشد، tree-shakable خواهد بود. یعنی به صورت کد مرده در نظر گرفته شده و به prod bundle اضافه نمی‌شود که سبب کاهش حجم نهایی برنامه می‌گردد.
در این حالت تزریق وابستگی‌هایی که در مطلب «تزریق وابستگی‌ها فراتر از کلاس‌ها در برنامه‌های Angular» نیز بحث شدند، پشتیبانی می‌شود:
@Injectable({
    providedIn: 'root',
    useClass: LazyFlightCancellingService,
    deps: [NgModuleFactoryLoader, Injector] 
})
export class FlightCancellingService { }
فقط مواردی مانند ثبت interceptors و حالت‌هایی که به همراه InjectionToken هستند، هنوز هم باید از طریق قسمت providers صورت گیرد.

به عنوان مثال کدهای مخزن کد «اعتبارسنجی کاربران در برنامه‌های Angular» جهت استفاده‌ی از این قابلیت به روز شد.
مطالب
امن سازی برنامه‌های ASP.NET Core توسط IdentityServer 4x - قسمت یازدهم- استفاده از تامین کننده‌های هویت خارجی
همیشه نمی‌توان کاربران را وادار به استفاده‌ی از صفحه‌ی لاگین برنامه‌ی IDP کرد. ممکن است کاربران بخواهند توسط سطوح دسترسی خود در یک شبکه‌ی ویندوزی به سیستم وارد شوند و یا از Social identity providers مانند تلگرام، گوگل، فیس‌بوک، توئیتر و امثال آن‌ها برای ورود به سیستم استفاده کنند. برای مثال شاید کاربری بخواهد توسط اکانت گوگل خود به سیستم وارد شود. همچنین مباحث two-factor authentication را نیز باید مدنظر داشت؛ برای مثال ارسال یک کد موقت از طریق ایمیل و یا SMS و ترکیب آن با روش فعلی ورود به سیستم جهت بالا بردن میزان امنیت برنامه.
در این مطلب نحوه‌ی یکپارچه سازی Windows Authentication دومین‌های ویندوزی را با IdentityServer بررسی می‌کنیم.


کار با تامین کننده‌های هویت خارجی

اغلب کاربران، دارای اکانت ثبت شده‌ای در جای دیگری نیز هستند و شاید آنچنان نسبت به ایجاد اکانت جدیدی در IDP ما رضایت نداشته باشند. برای چنین حالتی، امکان یکپارچه سازی IdentityServer با انواع و اقسام IDP‌های دیگر نیز پیش بینی شده‌است. در اینجا تمام این‌ها، روش‌های مختلفی برای ورود به سیستم، توسط یک کاربر هستند. کاربر ممکن است توسط اکانت خود در شبکه‌ی ویندوزی به سیستم وارد شود و یا توسط اکانت خود در گوگل، اما در نهایت از دیدگاه سیستم ما، یک کاربر مشخص بیشتر نیست.


نگاهی به شیوه‌ی پشتیبانی از تامین کننده‌های هویت خارجی توسط Quick Start UI

Quick Start UI ای را که در «قسمت چهارم - نصب و راه اندازی IdentityServer» به IDP اضافه کردیم، دارای کدهای کار با تامین کننده‌های هویت خارجی نیز می‌باشد. برای بررسی آن، کنترلر DNT.IDP\Controllers\Account\ExternalController.cs را باز کنید:
[HttpGet]
public async Task<IActionResult> Challenge(string provider, string returnUrl)

[HttpGet]
public async Task<IActionResult> Callback()
زمانیکه کاربر بر روی یکی از تامین کننده‌های لاگین خارجی در صفحه‌ی لاگین کلیک می‌کند، اکشن Challenge، نام provider مدنظر را دریافت کرده و پس از آن returnUrl را به اکشن متد Callback به صورت query string ارسال می‌کند. اینجا است که کاربر به تامین کننده‌ی هویت خارجی مانند گوگل منتقل می‌شود. البته مدیریت حالت Windows Authentication و استفاده از اکانت ویندوزی در اینجا متفاوت است؛ از این جهت که از returnUrl پشتیبانی نمی‌کند. در اینجا اطلاعات کاربر از اکانت ویندوزی او به صورت خودکار استخراج شده و به لیست Claims او اضافه می‌شود. سپس یک کوکی رمزنگاری شده از این اطلاعات تولید می‌شود تا در ادامه از محتویات آن استفاده شود.
در اکشن متد Callback، اطلاعات کاربر از کوکی رمزنگاری شده‌ی متد Challenge استخراج می‌شود و بر اساس آن هویت کاربر در سطح IDP شکل می‌گیرد.


فعالسازی Windows Authentication برای ورود به IDP

در ادامه می‌خواهیم برنامه را جهت استفاده‌ی از اکانت ویندوزی کاربران جهت ورود به IDP تنظیم کنیم. برای این منظور باید نکات مطلب «فعالسازی Windows Authentication در برنامه‌های ASP.NET Core 2.0» را پیشتر مطالعه کرده باشید.
پس از فعالسازی Windows Authentication در برنامه، اگر برنامه‌ی IDP را توسط IIS و یا IIS Express و یا HttpSys اجرا کنید، دکمه‌ی جدید Windows را در قسمت External Login مشاهده خواهید کرد:


یک نکته: برچسب این دکمه را در حالت استفاده‌ی از مشتقات IIS، به صورت زیر می‌توان تغییر داد:
namespace DNT.IDP
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<IISOptions>(iis =>
            {
                iis.AuthenticationDisplayName = "Windows Account";
                iis.AutomaticAuthentication = false;
            });

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

سازنده‌ی کنترلر DNT.IDP\Controllers\Account\ExternalController.cs نیز همانند کنترلر Account که آن‌را در قسمت قبل تغییر دادیم، از TestUserStore استفاده می‌کند:
        public ExternalController(
            IIdentityServerInteractionService interaction,
            IClientStore clientStore,
            IEventService events,
            TestUserStore users = null)
        {
            _users = users ?? new TestUserStore(TestUsers.Users);

            _interaction = interaction;
            _clientStore = clientStore;
            _events = events;
        }
بنابراین در ابتدا آن‌را با IUsersService تعویض خواهیم کرد:
        private readonly IUsersService _usersService;
        public ExternalController(
    // ...
            IUsersService usersService)
        {
    // ...
            _usersService = usersService;
        }
و سپس تمام ارجاعات قبلی به users_ را نیز توسط امکانات این سرویس اصلاح می‌کنیم:
الف) در متد FindUserFromExternalProvider
سطر قدیمی
 var user = _users.FindByExternalProvider(provider, providerUserId);
به این صورت تغییر می‌کند:
 var user = await _usersService.GetUserByProviderAsync(provider, providerUserId);
در این حالت امضای این متد نیز باید اصلاح شود تا async شده و همچنین User را بجای TestUser بازگشت دهد:
 private async Task<(User user, string provider, string providerUserId, IEnumerable<Claim> claims)> FindUserFromExternalProvider(AuthenticateResult result)
ب) متد AutoProvisionUser قبلی
private TestUser AutoProvisionUser(string provider, string providerUserId, IEnumerable<Claim> claims)
{
   var user = _users.AutoProvisionUser(provider, providerUserId, claims.ToList());
   return user;
}
نیز باید حذف شود؛ زیرا در ادامه آن‌را با صفحه‌ی ثبت نام کاربر، جایگزین می‌کنیم.
مفهوم «Provisioning a user» در اینجا به معنای درخواست از کاربر، جهت ورود اطلاعاتی مانند نام و نام خانوادگی او است که پیشتر صفحه‌ی ثبت کاربر جدید را برای این منظور در قسمت قبل ایجاد کرده‌ایم و از آن می‌شود در اینجا استفاده‌ی مجدد کرد. بنابراین در ادامه، گردش کاری ورود کاربر از طریق تامین کننده‌ی هویت خارجی را به نحوی اصلاح می‌کنیم که کاربر جدید، ابتدا به صفحه‌ی ثبت نام وارد شود و اطلاعات تکمیلی خود را وارد کند؛ سپس به صورت خودکار به متد Callback بازگشته و ادامه‌ی مراحل را طی نماید:
در اکشن متد نمایش صفحه‌ی ثبت نام کاربر جدید، متد RegisterUser تنها آدرس بازگشت به صفحه‌ی قبلی را دریافت می‌کند:
[HttpGet]
public IActionResult RegisterUser(string returnUrl)
اکنون نیاز است اطلاعات Provider و ProviderUserId را نیز در اینجا دریافت کرد. به همین جهت ViewModel زیر را به برنامه اضافه می‌کنیم:
namespace DNT.IDP.Controllers.UserRegistration
{
    public class RegistrationInputModel
    {
        public string ReturnUrl { get; set; }
        public string Provider { get; set; }
        public string ProviderUserId { get; set; }

        public bool IsProvisioningFromExternal => !string.IsNullOrWhiteSpace(Provider);
    }
}
سپس با داشتن اطلاعات FindUserFromExternalProvider که آن‌را در قسمت الف اصلاح کردیم، اگر خروجی آن null باشد، یعنی کاربری که از سمت تامین کننده‌ی هویت خارجی به برنامه‌ی ما وارد شده‌است، دارای اکانتی در سمت IDP نیست. به همین جهت او را به صفحه‌ی ثبت نام کاربر هدایت می‌کنیم. همچنین پس از پایان کار ثبت نام نیاز است مجددا به همینجا، یعنی متد Callback که فراخوان FindUserFromExternalProvider است، بازگشت:
namespace DNT.IDP.Controllers.Account
{
    [SecurityHeaders]
    [AllowAnonymous]
    public class ExternalController : Controller
    {
        public async Task<IActionResult> Callback()
        {
            var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            var (user, provider, providerUserId, claims) = await FindUserFromExternalProvider(result);
            if (user == null)
            {
                // user = AutoProvisionUser(provider, providerUserId, claims);
                
                var returnUrlAfterRegistration = Url.Action("Callback", new { returnUrl = returnUrl });
                var continueWithUrl = Url.Action("RegisterUser", "UserRegistration" ,
                    new { returnUrl = returnUrlAfterRegistration, provider = provider, providerUserId = providerUserId });
                return Redirect(continueWithUrl);
            }
در اینجا نحوه‌ی اصلاح اکشن متد Callback را جهت هدایت یک کاربر جدید به صفحه‌ی ثبت نام و تکمیل اطلاعات مورد نیاز IDP را مشاهده می‌کنید.
returnUrl ارسالی به اکشن متد RegisterUser، به همین اکشن متد جاری اشاره می‌کند. یعنی کاربر پس از تکمیل اطلاعات و اینبار نال نبودن user او، گردش کاری جاری را ادامه خواهد داد.

در ادامه نیاز است امضای متد نمایش صفحه‌ی ثبت نام را نیز بر این اساس اصلاح کنیم:
namespace DNT.IDP.Controllers.UserRegistration
{
    public class UserRegistrationController : Controller
    {
        [HttpGet]
        public IActionResult RegisterUser(RegistrationInputModel registrationInputModel)
        {
            var vm = new RegisterUserViewModel
            {
                ReturnUrl = registrationInputModel.ReturnUrl,
                Provider = registrationInputModel.Provider,
                ProviderUserId = registrationInputModel.ProviderUserId
            };

            return View(vm);
        }
به این ترتیب اطلاعات provider نیز علاوه بر ReturnUrl در اختیار View آن قرار خواهد گرفت. البته RegisterUserViewModel هنوز شامل این خواص اضافی نیست. به همین جهت با ارث بری از RegistrationInputModel، این خواص در اختیار RegisterUserViewModel نیز قرار می‌گیرند:
namespace DNT.IDP.Controllers.UserRegistration
{
    public class RegisterUserViewModel : RegistrationInputModel
    {

اکنون نیاز است RegisterUser.cshtml را اصلاح کنیم:
- ابتدا دو فیلد مخفی دیگر Provider و ProviderUserId را نیز به این فرم اضافه می‌کنیم؛ از این جهت که در حین postback به سمت سرور به مقادیر آن‌ها نیاز داریم:
<inputtype="hidden"asp-for="ReturnUrl"/>
<inputtype="hidden"asp-for="Provider"/>
<inputtype="hidden"asp-for="ProviderUserId"/>
- با توجه به اینکه کاربر از طریق یک تامین کننده‌ی هویت خارجی وارد شده‌است، دیگر نیازی به ورود کلمه‌ی عبور ندارد. به همین جهت خاصیت آن‌را در ViewModel مربوطه به صورت Required تعریف نکرده‌ایم:
@if (!Model.IsProvisioningFromExternal)
{
    <div>
        <label asp-for="Password"></label>
        <input type="password" placeholder="Password"
               asp-for="Password" autocomplete="off">
    </div>
}
مابقی این فرم ثبت نام مانند قبل خواهد بود.

پس از آن نیاز است اطلاعات اکانت خارجی این کاربر را در حین postback و ارسال اطلاعات به اکشن متد RegisterUser، ثبت کنیم:
namespace DNT.IDP.Controllers.UserRegistration
{
    public class UserRegistrationController : Controller
    {
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> RegisterUser(RegisterUserViewModel model)
        {
    // ...
            
            if (model.IsProvisioningFromExternal)
            {
                userToCreate.UserLogins.Add(new UserLogin
                {
                    LoginProvider = model.Provider,
                    ProviderKey = model.ProviderUserId
                });
            }

            // add it through the repository
            await _usersService.AddUserAsync(userToCreate);

// ...
        }
    }
که اینکار را با مقدار دهی UserLogins کاربر در حال ثبت، انجام داده‌ایم.
همچنین در ادامه‌ی این اکشن متد، کار لاگین خودکار کاربر نیز انجام می‌شود. با توجه به اینکه پس از ثبت اطلاعات کاربر نیاز است مجددا گردش کاری اکشن متد Callback طی شود، این لاگین خودکار را نیز برای حالت ورود از طریق تامین کننده‌ی خارجی، غیرفعال می‌کنیم:
if (!model.IsProvisioningFromExternal)
{
    // log the user in
    // issue authentication cookie with subject ID and username
    var props = new AuthenticationProperties
    {
        IsPersistent = false,
        ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
    };
    await HttpContext.SignInAsync(userToCreate.SubjectId, userToCreate.Username, props);
}

بررسی ورود به سیستم توسط دکمه‌ی External Login -> Windows

پس از این تغییرات، اکنون در حین ورود به سیستم (تصویر ابتدای بحث در قسمت فعالسازی اعتبارسنجی ویندوزی)، گزینه‌ی External Login -> Windows را انتخاب می‌کنیم. بلافاصله به صفحه‌ی ثبت‌نام کاربر هدایت خواهیم شد:


همانطور که مشاهده می‌کنید، IDP اکانت ویندوزی جاری را تشخیص داده و فعال کرده‌است. همچنین در اینجا خبری از ورود کلمه‌ی عبور هم نیست.
پس از تکمیل این فرم، بلافاصله کار ثبت اطلاعات کاربر و هدایت خودکار به برنامه‌ی MVC Client انجام می‌شود.
در ادامه از برنامه‌ی کلاینت logout کنید. اکنون در صفحه‌ی login مجددا بر روی دکمه‌ی Windows کلیک نمائید. اینبار بدون پرسیدن سؤالی، لاگین شده و وارد برنامه‌ی کلاینت خواهید شد؛ چون پیشتر کار اتصال اکانت ویندوزی به اکانتی در سمت IDP انجام شده‌است.



کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید.
برای اجرای برنامه:
- ابتدا به پوشه‌ی src\WebApi\ImageGallery.WebApi.WebApp وارد شده و dotnet_run.bat آن‌را اجرا کنید تا WebAPI برنامه راه اندازی شود.
- سپس به پوشه‌ی src\IDP\DNT.IDP مراجعه کرده و و dotnet_run.bat آن‌را اجرا کنید تا برنامه‌ی IDP راه اندازی شود.
- در آخر به پوشه‌ی src\MvcClient\ImageGallery.MvcClient.WebApp وارد شده و dotnet_run.bat آن‌را اجرا کنید تا MVC Client راه اندازی شود.
اکنون که هر سه برنامه در حال اجرا هستند، مرورگر را گشوده و مسیر https://localhost:5001 را درخواست کنید. در صفحه‌ی login نام کاربری را User 1 و کلمه‌ی عبور آن‌را password وارد کنید.

یک نکته: برای آزمایش برنامه جهت فعالسازی Windows Authentication بهتر است برنامه‌ی IDP را توسط IIS Express اجرا کنید و یا اگر از IIS Express استفاده نمی‌کنید، نیاز است UseHttpSys فایل program.cs را مطابق توضیحات «یک نکته‌ی تکمیلی: UseHttpSys و استفاده‌ی از HTTPS»  فعال کنید.