‫۴ سال و ۴ ماه قبل، دوشنبه ۲۲ اردیبهشت ۱۳۹۹، ساعت ۰۴:۰۰
- این پروژه برای سازگاری با آخرین نگارش موجود، بارها به روز رسانی شده. متن مطلب فوق را تغییر ندادم، ولی کدهای مخزن کد آن کاملا به روز هست.
- برای درک این مورد باید ساختار پروژه‌ی اصلی Identity را بررسی کنید. در یک طرف آن تعدادی کلاس سطح بالا و abstraction هست و در طرف دیگر پوشه‌ای به نام EntityFrameworkCore که پیاده سازی مخصوص EF-Core این abstraction‌ها است. هستند پروژه‌های دیگری که بجای EntityFrameworkCore از NHibernate و یا MongoDB استفاده کرده باشند.
‫۴ سال و ۴ ماه قبل، پنجشنبه ۱۸ اردیبهشت ۱۳۹۹، ساعت ۱۱:۴۸
دستور npm run build نام فایل‌های نهایی را به همراه هش محتوای آن‌ها تولید می‌کند:

این روشی هست که در Angular هم برای cache busting مورد استفاده قرار می‌گیرد. به همین جهت فایل‌های تغییر یافته، دارای هش جدیدی خواهند بود که به عنوان یک فایل js جدید، حتما مجددا توسط مرورگر از سایت دریافت خواهند شد و کش نمی‌شوند.

‫۴ سال و ۴ ماه قبل، شنبه ۱۳ اردیبهشت ۱۳۹۹، ساعت ۰۵:۵۵
مرورگرهای جدید با استفاده از ویژگی webkitdirectory، امکان انتخاب یک پوشه و تمام زیر پوشه‌های آن‌را دارند:
<form method="post" asp-action="UploadFiles" asp-controller="Home" enctype="multipart/form-data">
    <input type="file" name="files" webkitdirectory />
    <input type="submit" value="Upload" />
</form>
در این حالت کدهای سمت سرور آن به صورت زیر تغییر می‌کند:
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace UploadFolderASPNETCore.Controllers
{
    public class HomeController : Controller
    {
        private readonly IWebHostEnvironment _environment;
        private const int MaxBufferSize = 0x10000;

        public HomeController(IWebHostEnvironment environment)
        {
            _environment = environment;
        }

        public IActionResult Index()
        {
            return View();
        }

        [HttpPost("[action]")]
        public async Task<IActionResult> UploadFiles(IList<IFormFile> files)
        {
            var uploadsRootFolder = Path.Combine(_environment.WebRootPath, "uploads");
            CreateDir(uploadsRootFolder);

            foreach (var file in files)
            {
                var dirPath = Path.GetDirectoryName(file.FileName);
                CreateDir(Path.Combine(uploadsRootFolder, dirPath));

                var filePath = Path.Combine(uploadsRootFolder, file.FileName);
                using (var fileStream = new FileStream(filePath, FileMode.Create,
                                                        FileAccess.Write,
                                                        FileShare.None,
                                                        MaxBufferSize,
                                                        useAsync: true
                                                        ))
                {
                    await file.CopyToAsync(fileStream);
                }
            }

            return RedirectToAction("Index");
        }

        private void CreateDir(string path)
        {
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
        }
    }
}
‫۴ سال و ۴ ماه قبل، دوشنبه ۸ اردیبهشت ۱۳۹۹، ساعت ۱۷:۵۸
یک نکته‌ی تکمیلی: تبدیل enum در سمت سرور
اگر توسط درخواست‌های Ajax ای مقدار یک enum را به صورت رشته‌ای ارسال می‌کنید، در سمت سرور چنین خطایی را دریافت خواهید کرد:
{"$.language":["The JSON value could not be converted to DNTCaptcha.Core.Providers.Language. Path: $.language | LineNumber: 0 | BytePositionInLine: 99."]}
این خطا را هم با فعالسازی ویژگی [ApiController] بر روی کنترلر خود می‌توانید مشاهده کنید و یا توسط بازگشت ModelState در اکشن متد خود به صورت زیر:
if (model == null || !ModelState.IsValid)
{
  return BadRequest(ModelState);
}
برای رفع این مشکل باید تنظیم زیر را به کلاس آغازین برنامه اضافه کرد:
services.AddControllers().AddJsonOptions(opt =>
{
   opt.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
تبدیلگر آن نیز توکار بوده و در فضای نام System.Text.Json تعریف شده‌است.
‫۴ سال و ۴ ماه قبل، یکشنبه ۷ اردیبهشت ۱۳۹۹، ساعت ۰۵:۴۶
- می‌توان دسترسی داشت. پس از لاگین، برنامه را در چند برگه‌ی مجزا باز کنید، باز هم کار می‌کند و کاربر جاری تشخیص داده می‌شود. این محدودیت دسترسی مربوط به دومین جاری برنامه است و نه برگه‌های آن (مفهوم پیاده سازی sand box یا قرنطینه‌ی امنیتی).
- در مورد جزئیات محل‌های ذخیره سازی:
- در مورد علت استفاده‌ی از local storage و مزایا و معایب آن (نگاهی به محل ذخیره سازی JWT و نکات مرتبط با آن ) در اینجا : معرفی JSON Web Token