‫۵ سال و ۶ ماه قبل، چهارشنبه ۸ اسفند ۱۳۹۷، ساعت ۱۰:۵۰
1 و 2: مفهوم و هدف از refresh token را در مطلب «پیاده سازی JSON Web Token با ASP.NET Web API 2.x» قسمت «پیاده سازی قسمت صدور Refresh token » آن مطالعه کنید.
3: مطلب «غیرمعتبر شدن کوکی‌های برنامه‌های ASP.NET Core هاست شده‌ی در IIS پس از ری‌استارت آن» را مطالعه کنید و در اینجا هم تفاوتی نمی‌کند.
‫۵ سال و ۶ ماه قبل، چهارشنبه ۸ اسفند ۱۳۹۷، ساعت ۰۱:۱۱
- مساله‌ای که با یک متد الحاقی قابل فراخوانی در فایل‌های Razor قابل حل است، نیازی به اینکار ندارد.
- روشی که برای تولید Url استفاده کردید باید اصلاح شود: «نحوه صحیح تولید Url در ASP.NET MVC» و در اینجا UrlHelper به صورت زیر قابل دریافت است:
var urlHelper = ViewContext.HttpContext.Items.Values.OfType<IUrlHelper>().FirstOrDefault();
‫۵ سال و ۶ ماه قبل، سه‌شنبه ۷ اسفند ۱۳۹۷، ساعت ۲۳:۰۱
یک نکته‌ی تکمیلی: بهبود کارآیی IOutboundParameterTransformer تهیه شده
با توجه به مطلب « چگونه Regex سریعتری داشته باشیم؟ » بهتر است regex نوشته شده را کامپایل کرد تا به حداکثر کارآیی رسید:
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Routing;

public class CustomUrlTransformer : IOutboundParameterTransformer
{
    private static readonly Regex _camelCasingRegEx = new Regex("([a-z])([A-Z])", RegexOptions.Compiled);

    public string TransformOutbound(object value)
    {
        return value == null ? null : _camelCasingRegEx.Replace(value.ToString(), "$1-$2");
    }
}
‫۵ سال و ۶ ماه قبل، سه‌شنبه ۷ اسفند ۱۳۹۷، ساعت ۲۲:۵۸
- به همین صورت باید باشد؛ در غیر اینصورت مقدار کوئری استرینگ دریافتی، encoding صحیح خودش را از دست خواهد داد و در برنامه قابلیت پردازش نخواهد داشت. مگر اینکه در اکشن متد مدنظر هم این encoding غیراستاندارد را دستی پردازش کنید.
- موردی که مدنظر شما است احتمالا تولید slug است که در مطلب «بهینه سازی برنامه‌های وب ASP.NET برای موتورهای جستجو (SEO)» متدی برای آن ارائه شده و در برنامه پردازش نمی‌شود؛ فقط جنبه‌ی نمایشی و یا ارائه‌ی به موتورهای جستجو را دارد. نحوه‌ی استفاده‌ی از آن هم در یک View به این صورت است:
@using System.Text;
@using System.Text.RegularExpressions;

@functions
{
   private static string RemoveAccent(string text) { /* defined in https://www.dntips.ir/post/1529*/  }
   public static string GenerateSlug(string title, int maxLenghtSlug = 50) { /* defined in https://www.dntips.ir/post/1529*/   }
}

@{
  var value = GenerateSlug("this is a test");
}
<a asp-controller="Home" asp-action="ViewDetails" asp-route-id="@value">View Details</a>
‫۵ سال و ۶ ماه قبل، سه‌شنبه ۷ اسفند ۱۳۹۷، ساعت ۲۱:۱۶
هدف ComplexType نظم بخشیدن به یک سری خاصیت است که در یک گروه قرار می‌گیرند؛ مثلا گروه اطلاعات تلفن‌های شخص؛ از تلفن منزل تا تلفن محل کار تا شماره موبایل و غیره یک شخص. یک روش نظم بخشیدن به آن‌ها، قرار دادن این خواص در یک ComplexType است. روش دیگر اینکار تعریف یک جدول جداگانه برای آن و اتصال آن به جدول کاربران از طریق یک کلید خارجی است. این نظم بخشیدن ارتباطی به ارث‌بری ندارد و در رده‌ی « بازسازی کد: جایگزینی داده با شیء (Replace data with object) » قرار می‌گیرد.
‫۵ سال و ۶ ماه قبل، دوشنبه ۶ اسفند ۱۳۹۷، ساعت ۱۲:۴۵
یک نکته‌ی تکمیلی: چگونه VSCode را برای NET Core 3.0. و C# 8.0 آماده کنیم؟


مرحله‌ی اول: نصب SDK مربوطه
در این تاریخ، این SDK در مرحله‌ی پیش‌نمایش است و نگارش نهایی آن قرار است صرفا با VS 2019 سازگار و هماهنگ باشد (و با VS 2017 کار نمی‌کند)؛ اما هم اکنون در VSCode قابل استفاده‌است. برای این منظور SDK آن‌را از آدرس https://dotnet.microsoft.com/download/dotnet-core/3.0 دریافت و نصب کنید. پس از نصب، یک چنین خروجی را در خط فرمان مشاهده خواهید کرد:
> dotnet --version
3.0.100-preview-010184


مشکل: پس از نصب نگارش 3، ممکن است برنامه‌هایی که از SDK نگارش 2 استفاده می‌کنند، به مشکل بر بخورند.
راه حل: برنامه‌های مبتنی بر NET Core.، شماره نگارش SDK خود را از فایل ویژه‌ای به نام global.json دریافت می‌کنند. اگر این فایل در ریشه‌ی پروژه‌ی شما وجود نداشته باشد، یعنی همواره از آخرین شماره‌ی SDK نصب شده استفاده شود. بنابراین ابتدا لیست SDKهای نصب شده را با دستور زیر پیدا کنید:
> dotnet --list-sdks
سپس برای پروژه‌های قدیمی خود که فعلا قصد به روز رسانی آن‌ها را ندارید، یک فایل global.json را به صورت زیر‌، در ریشه‌ی پروژه تولید کنید:
> dotnet new globaljson --sdk-version 2.2.100
> type global.json
در اینجا 2.2.100 یکی از شماره‌هایی است که توسط دستور dotnet --list-sdks یافته‌اید و پروژه‌ی قبلی شما بر اساس آن کار می‌کند.


مرحله‌ی دوم: نصب افزونه‌ی پیش‌نمایش VSCode مخصوص C# 8.0
در این تاریخ هنوز این افزونه در نگارش بتای آن قرار دارد. بنابراین در لیست دریافت‌های خودکار VSCode قرار نمی‌گیرد و باید دستی نصب شود. برای این منظور به آدرس https://github.com/OmniSharp/omnisharp-vscode/releases مراجعه کرده و آخرین نگارش بتای آن‌را دریافت کنید.
در VSCode، قسمتی‌که افزونه‌ها را نمایش می‌دهد، یک دکمه‌ی ... مانند وجود دارد. بر روی آن که کلیک کنید. در منوی باز شده، گزینه‌ی install from vsix نیز موجود است که دقیقا برای نصب دستی یک چنین افزونه‌هایی پیش‌بینی شده‌است. پس از نصب فایل vsix دریافت شده‌ی از GitHub، شماره نگارش 1.18.0-beta7 در قسمت افزونه‌های VSCode قابل مشاهده خواهد بود.


مرحله‌ی آخر: ایجاد یک پروژه‌ی جدید مخصوص NET Core 3x. با پشتیبانی از C# 8.0
اکنون یک پوشه‌ی جدید را ایجاد کرده و در خط فرمان دستور dotnet new console را صادر کنید. سپس فایل csproj آن‌را به صورت زیر تغییر دهید تا از NET Core 3x. و C# 8.0 و قابلیت جدید Nullable Reference Types آن پشتیبانی کند:
<Project Sdk="Microsoft.NET.Sdk"> 
 
  <PropertyGroup> 
    <OutputType>Exe</OutputType> 
    <TargetFramework>netcoreapp3.0</TargetFramework> 
    <LangVersion>8.0</LangVersion> 
    <NullableContextOptions>enable</NullableContextOptions> 
  </PropertyGroup> 
 
</Project>
اکنون یک چنین پروژه‌ای قابلیت کار و دیباگ در VSCode را پیدا می‌کند.
 
یک نکته: اگر دستور dotnet new classlib را صادر کنید، هنوز TargetFramework آن‌را netstandard2.0 تنظیم می‌کند. فایل csproj آن نیز باید دقیقا مانند مثال فوق تنظیم شود، با این تفاوت که سطر OutputType را ندارد.
‫۵ سال و ۶ ماه قبل، دوشنبه ۶ اسفند ۱۳۹۷، ساعت ۰۰:۲۰
من از ویندوز 10 با VMWare 12 به همراه Hyper-V فعال، بدون مشکل استفاده می‌کنم. فقط Credential-Guard ای که در تصویر خطا ارسال کردید بر روی سیستم من غیرفعال است. برای غیرفعال کردن آن، اسکریپت  Device Guard and Credential Guard hardware readiness tool را دریافت کنید. سپس PowerShell را با دسترسی ادمین اجرا کرده و برای بررسی فعال بودن Credential-Guard، دستور زیر را اجرا کنید:
 ./DG_Readiness_Tool_v3.6.ps1 -Ready
و برای غیرفعال کردن آن:
 ./DG_Readiness_Tool_v3.6.ps1 -Disable
در Identity Server، دسترسی‌های کاربران بر اساس User Claims آن‌ها تعریف می‌شوند؛ مانند مثال ()public static List<TestUser> GetUsers مطلب جاری. بنابراین تعدادی Claims را به نام‌های SuperAdmin1 تا n، به کاربران SuperAdmin ای که مدنظر هستند، انتساب می‌دهید. سپس سایر کاربران زیر مجموعه‌ی آن‌ها هم Claims جدیدی مانند SuperAdmin1_User تا n را خواهند داشت. بعد از تعریف این Claims، نحوه‌ی دادن دسترسی‌ها دقیقا مانند مثال CanOrderFrame مطلب فوق است. یک Policy جدید را مانند SuperAdmin1User_Policy تعریف می‌کنید که policyBuilder.RequireClaim آن بر اساس Claim ای مانند SuperAdmin1_User کار کند. سپس قسمتی که قرار است صرفا با این Policy کار کند، توسط  [Authorize(Policy = " SuperAdmin1User_Policy")] محدود می‌شود.
ASP.NET Core Identity هم چنین طراحی مبتنی بر User Claims «تک» برنامه‌ای هم دارد. بحث جاری در مورد طراحی «چند» برنامه‌ای Identity Server هست.
‫۵ سال و ۶ ماه قبل، یکشنبه ۵ اسفند ۱۳۹۷، ساعت ۰۵:۱۴
دو نوع پیاده سازی سمت کلاینت برای این مطلب تهیه شده؛ مثال صفحه‌ی HTML آن در پوشه‌ی wwwroot و همچنین مثال کامل و جامع Angular آن. مثال صفحه‌ی HTML آن یک مثال ساده‌است برای توضیح مفاهیم و فاقد تایمری برای فعالسازی خودکار refresh token؛ درحالیکه مثال Angular آن دارای تایمر مخصوصی برای اینکار است و پیش از رسیدن به زمان انقضای access token، یک توکن جدید را درخواست می‌کند. همچنین در مثال HTML آن توکن‌ها در local storage مرورگر ذخیره نمی‌شوند و با refresh صفحه، متغیرهای موقتی جاوا اسکریپتی که توکن‌ها را ذخیره کرده بودند، پاک خواهند شد. اما در مثال Angular آن بحث ذخیره سازی در local storage پیاده سازی شده‌است و خیلی جزئیات دیگر.
برای درک این سیستم از قسمت آخر آن شروع نکنید. در قسمت‌های قبل در مورد مفهوم یک سیستم تامین هویت مرکزی، مفهوم کلاینت‌ها و دسترسی دادن به آن‌ها در یک IDP (نه دسترسی دادن به کاربران)، امکان محدود کردن دسترسی کاربران به قسمت‌های مختلف برنامه‌ها و یا Web APIها توسط User Claims آن‌ها و ... مفصل بحث شده‌است.
برای مثال زمانیکه برنامه‌ای (کلاینتی) به IDP گوگل معرفی می‌شود، آیا تمام کاربران گوگل به آن دسترسی پیدا می‌کنند؟ بله. تمام آن‌ها بدون استثناء.
اما آیا تمام آن‌ها می‌توانند با قسمت‌های مختلف برنامه‌ی ما کار کنند؟ خیر. نحوه‌ی مدیریت دسترسی‌های این کاربران، در قسمت‌های قبلی بحث شده‌اند.