‫۵ سال و ۱ ماه قبل، چهارشنبه ۲۳ مرداد ۱۳۹۸، ساعت ۱۶:۱۵
ارتقاء به ASP.NET Core Identity 3.0  

امضای سازنده‌ی تعدادی از سرویس‌های توکار ASP.NET Core Identity 3.0 تغییر کرده و شامل پارامترهای جدیدی به صورت زیر هستند:
    public class ApplicationSignInManager :
        SignInManager<User>,
        IApplicationSignInManager
    {
   // ...

        public ApplicationSignInManager(
            IApplicationUserManager userManager,
            IHttpContextAccessor contextAccessor,
            IUserClaimsPrincipalFactory<User> claimsFactory,
            IOptions<IdentityOptions> optionsAccessor,
            ILogger<ApplicationSignInManager> logger,
            IAuthenticationSchemeProvider schemes,
            IUserConfirmation<User> confirmation)
            : base((UserManager<User>)userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation)
        {

    public class ApplicationUserManager :
        UserManager<User>,
        IApplicationUserManager
    {
   // ...

        public ApplicationUserManager(
            IApplicationUserStore store,
            IOptions<IdentityOptions> optionsAccessor,
            IPasswordHasher<User> passwordHasher,
            IEnumerable<IUserValidator<User>> userValidators,
            IEnumerable<IPasswordValidator<User>> passwordValidators,
            ILookupNormalizer keyNormalizer,
            IdentityErrorDescriber errors,
            IServiceProvider services,
            ILogger<ApplicationUserManager> logger,
            IHttpContextAccessor contextAccessor,
            IUnitOfWork uow,
            IUsedPasswordsService usedPasswordsService)
            : base(
                (UserStore<User, Role, ApplicationDbContext, int, UserClaim, UserRole, UserLogin, UserToken, RoleClaim>)store,
                  optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
        {

    public class ConfirmEmailDataProtectorTokenProvider<TUser> : DataProtectorTokenProvider<TUser> where TUser : class
    {
        public ConfirmEmailDataProtectorTokenProvider(
            IDataProtectionProvider dataProtectionProvider,
            IOptions<ConfirmEmailDataProtectionTokenProviderOptions> options,
            ILogger<DataProtectorTokenProvider<TUser>> logger)
            : base(dataProtectionProvider, options, logger)
        {

    public class CustomSecurityStampValidator : SecurityStampValidator<User>
    {
   // ...
   
        public CustomSecurityStampValidator(
            IOptions<SecurityStampValidatorOptions> options,
            IApplicationSignInManager signInManager,
            ISystemClock clock,
            ISiteStatService siteStatService,
            ILoggerFactory logger)
            : base(options, (SignInManager<User>)signInManager, clock, logger)
        {
‫۵ سال و ۱ ماه قبل، چهارشنبه ۲۳ مرداد ۱۳۹۸، ساعت ۱۶:۰۹
ارتقاء به ASP.NET Core Identity 3.0

امضای اینترفیس ILookupNormalizer، از حالت کلی زیر، که هم ایمیل و هم نام را شامل می‌شد:
    public interface ILookupNormalizer
    {
        string Normalize(string key);
    }
به حالت اختصاصی‌تر زیر تغییر کرده‌است:
    public interface ILookupNormalizer
    {
        string NormalizeEmail(string email);
        string NormalizeName(string name);
    }
‫۵ سال و ۱ ماه قبل، چهارشنبه ۲۳ مرداد ۱۳۹۸، ساعت ۱۵:۵۲
یک نکته‌ی تکمیلی

در ASP.NET Core 3.0 دیگر شرط زیر برقرار نیست:
‫۵ سال و ۱ ماه قبل، چهارشنبه ۲۳ مرداد ۱۳۹۸، ساعت ۱۵:۴۹
ارتقاء به ASP.NET Core 3.0: دریافت مقادیر Routing پس از فعالسازی Endpoint routing

تا پیش از معرفی Endpoint routing، اطلاعات مسیریابی جاری را می‌شد از طریق یکی از روش‌های زیر به دست آورد:
  // services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
    private readonly IActionContextAccessor _actionContext;

public MyClass(IActionContextAccessor actionContext)
    {
        _actionContext = actionContext;
    }

    public string GetData()
    {
        var routes = _actionContext.ActionContext.RouteData;
        var val = routes.Values["action"]?.ToString() as string;
        return val;
    }
در اینجا سرویس IActionContextAccessor امکان دسترسی به Context اکشن متد در حال اجرا را در قسمت‌های مختلف برنامه میسر می‌کرد و یا شبیه به آن در یک AuthorizationHandler سفارشی، context آن از نوع AuthorizationFilterContext بود که آن نیز دسترسی به اطلاعات context اکشن متد در حال اجرا را در اختیار برنامه قرار می‌داد:
protected override async Task HandleRequirementAsync(
   AuthorizationHandlerContext context,
   DynamicPermissionRequirement requirement)
{
    if (!(context.Resource is AuthorizationFilterContext mvcContext))
    {
      return;
    }

    var actionDescriptor = mvcContext.ActionDescriptor;
    actionDescriptor.RouteValues.TryGetValue("area", out var areaName);
    var area = string.IsNullOrWhiteSpace(areaName) ? string.Empty : areaName;
این روش‌ها دیگر در ASP.NET Core 3.0 کار نمی‌کنند. در اینجا پس از تزریق IHttpContextAccessor به سازنده‌ی کلاس مدنظر، می‌توان توسط متد الحاقی ()HttpContext.GetRouteData به اطلاعات مسیریابی دسترسی داشت:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;

namespace ASPNETCoreIdentitySample.Services.Identity
{
    public class DynamicPermissionsAuthorizationHandler : AuthorizationHandler<DynamicPermissionRequirement>
    {
        private readonly IHttpContextAccessor _httpContextAccessor;

        public DynamicPermissionsAuthorizationHandler(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
        }

        protected override async Task HandleRequirementAsync(
             AuthorizationHandlerContext context,
             DynamicPermissionRequirement requirement)
        {
            var routeData = _httpContextAccessor.HttpContext.GetRouteData();

            var areaName = routeData?.Values["area"]?.ToString();
            var area = string.IsNullOrWhiteSpace(areaName) ? string.Empty : areaName;
‫۵ سال و ۱ ماه قبل، دوشنبه ۲۱ مرداد ۱۳۹۸، ساعت ۲۳:۵۳
- بجای اینکار (اضافه و حذف کردن سرویس‌ها در زمان اجرای برنامه که با ری‌استارت برنامه در سمت سرور غیرمعتبر می‌شود)، بهتر است با توجه به اینکه این وظایف به صورت یک سرویس ثبت می‌شوند، یک سرویس سفارشی فعال یا غیرفعالسازی را تعریف کنید و آن‌را به سازنده‌ی این وظایف تزریق و استفاده کنید. سپس زمانیکه حلقه‌ی انجام وظایف به RunAsync رسید، در اینجا فرصت خواهید داشت تا سرویس سفارشی جدید تزریق شده را بررسی کرده و از فعال بودن یا نبودن این وظیفه مطلع شوید (برای مثال این سرویس بر اساس نامی که به آن ارسال می‌کنید، به بانک اطلاعاتی مراجعه کرده و روشن و یا خاموش بودن آن‌را بررسی کند. تنظیم بانک اطلاعاتی آن‌را هم واگذار کنید به قسمت مدیریتی برنامه).  
+ این نوع Taskهای پویا را باید در ابتدای کار برنامه و در کلاس آغازین آن، به صورت زیر معرفی کنید:
services.AddTransient<DoEnableProductTasks>();
‫۵ سال و ۱ ماه قبل، دوشنبه ۲۱ مرداد ۱۳۹۸، ساعت ۱۵:۴۹
ارتقاء به ASP.NET Core 3.0: تغییرات نام متدهای تعاریف مسیریابی

در اینجا نگاشت کنترلرها داخل متد UseEndpoints انجام می‌شود:
- اگر از attribute routing استفاده می‌کنید، متد MapControllers را فراخوانی کنید که البته به صورت ضمنی هم فراخوانی می‌شود.
- متد MapRoute پیشین به MapControllerRoute تغییر نام یافته‌است.
- متد MapAreaRoute پیشین به MapAreaControllerRoute تغییر نام یافته‌است.
علت این نوع نامگذاری‌های صریح، این است که اکنون سیستم مسیریابی، فراتر از سیستم MVC را پشتیبانی می‌کند.
- همانند سابق متدهای MapControllerRoute/MapAreaControllerRoute/MapDefaultControllerRoute به ترتیبی که تعریف می‌شوند، تاثیرگذار خواهند بود.

در مثال زیر:
public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapAreaControllerRoute(
            "admin", 
            "admin", 
            "Admin/{controller=Home}/{action=Index}/{id?}");
        endpoints.MapControllerRoute(
            "default", "{controller=Home}/{action=Index}/{id?}");
    });
}
- متد MapControllers، کار پشتیبانی از کنترلرهای attribute-routed را انجام می‌دهد.
- متد MapAreaControllerRoute، مسیریابی سنتی کنترلرهای درون یک Area را تعریف می‌کند.
- متد MapControllerRoute، مسیریابی سنتی کنترلرها را تعریف می‌کند.

اگر از Razor pages استفاده می‌کنید، در اینجا باید متد MapRazorPages را نیز فراخوانی کنید:
public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
‫۵ سال و ۱ ماه قبل، دوشنبه ۲۱ مرداد ۱۳۹۸، ساعت ۱۴:۴۹
- این روش با مدل‌های تو در تو هم کار می‌کند. یک مثال: viewModel ، View و همچنین اکشن متد مرتبط
- این روش برای شما مناسب نیست؟ خودتان مستقیما متد Ajax جی‌کوئری یا حتی متد fetch توکار مرورگرها را فراخوانی کنید: