برای انتقال جداول احراز هویت (Identity) از SQL Server به بانک اطلاعاتی
MongoDB و نحوه استفاده از آن در ASP.Net Core از سورس نمونه در لینک بالا استفاده کنید.
همچنین میتوانید از پکیج AspNetCore.Identity.Mongo استفاده کنید.
This is a MongoDB provider for the ASP.NET Core 2 Identity framework
اشتراکها
انتقال به asp.net core
ارتقاء به ASP.NET Core 2.1
در ASP.NET Core 2.1 بجای متدهای Html.Partial vs Html.RenderPartial, sync vs async برای رندر partial views میتوان از Tag helper جدید partial استفاده کرد:
که در اینجا name به فایل ProductPartial.cshtml_ اشاره میکند و مقدار مدل آن نیز مشخص شدهاست.
در ASP.NET Core 2.1 بجای متدهای Html.Partial vs Html.RenderPartial, sync vs async برای رندر partial views میتوان از Tag helper جدید partial استفاده کرد:
<partial name="_ProductPartial" asp-for="@Model[i]" />
در طی چند ماه گذشته، ریز نکاتی که برای ارتقاء به ASP.NET Core 3.0 مورد نیاز هستند، در ذیل مطالب مرتبط با هر کدام، جهت برقراری ارتباط منطقی و امکان مشاهدهی روند تغییرات هرکدام، به صورت مجزا و در طی نظراتی تکمیلی، به آن مطالب اضافه شدهاند. در ادامه برای داشتن یک دید کلی و سهولت دسترسی به آنها، لیست این موارد را نیز مشاهده میکنید:
پیشنیازهای کار با ASP.NET Core 3.0
خلاصه شدن ساختار فایلهای csproj
ارائهی یک Generic Host در نگارش سوم
تغییرات مسیریابی با معرفی endpoint routing
بالا رفتن کارآیی پردازش JSON
نکتهی مهمی در مورد توزیع برنامههای وب در IIS
تغییرات SignalR
تغییرات امنیتی نگارش سوم
تغییرات تنظیمات تعدادی از میانافزارها
تغییر مهم ابزارهای مرتبط با EF Core 3.0
پیشنیازهای کار با ASP.NET Core 3.0
خلاصه شدن ساختار فایلهای csproj
- ارتقاء به ASP.NET Core 3.0 و سرنوشت metapackageهای Microsoft.AspNetCore
- در NET Core 3x. دیگر بستههای نیوگت Shared framework به صورت جداگانه تولید و توزیع نمیشوند
ارائهی یک Generic Host در نگارش سوم
- ارتقاء به ASP.NET Core 3.0 و تغییرات نقطهی آغازین برنامه
- قالبی برای ایجاد سرویسهای پسزمینه به NET Core 3.0. اضافه شدهاست که بر اساس Generic Host کار میکند.
- محدود شدن امکان تزریق وابستگیها در سازندهی کلاس آغازین برنامه در ASP.NET Core 3.0
تغییرات مسیریابی با معرفی endpoint routing
- نام متدهای تعاریف مسیریابی تغییر کردهاند.
- تغییرات مورد نیاز در فایل آغازین برنامه جهت ارتقاء به Endpoint routing
- نحوهی تعریف بررسی سلامت برنامه بر اساس endpoint routing تغییر کردهاست.
- همچنین روش فعالسازی ASP.NET MVC نیز تغییر کردهاست.
بالا رفتن کارآیی پردازش JSON
نکتهی مهمی در مورد توزیع برنامههای وب در IIS
- نام بستهی npm سمت کلاینت مخصوص SignalR Core مجددا تغییر کردهاست.
- UseSignalR منسوخ شده اعلام میشود و با UseEndpoints جانشین خواهد شد.
تغییرات امنیتی نگارش سوم
- میانافزار جدید Authorization در ASP.NET Core 3.0
- امضای سازندهی تعدادی از سرویسهای توکار ASP.NET Core Identity 3.0 تغییر کردهاند.
- امضای اینترفیس ILookupNormalizer، توکار ASP.NET Core Identity 3.0 تغییر کردهاست.
- اگر NET Core 3 SDK. را نصب کنید، امکان ایجاد یک برنامهی Angular مبتنی بر Microsoft.AspNetCore.ApiAuthorization.IdentityServer به قالبهای پیشفرض آن اضافه شدهاست.
- تنظیمات کوکیهای سشن تغییر کردهاند.
- تمام Response.Body.Writeها در Action Resultها ممنوع شدهاند.
- هرجائی در برنامهی خود IHostingEnvironment دارید، باید به IWebHostEnvironment تبدیل شود.
اشتراکها
انتشار پیش از موعد NET Core 2.1.
مدیریت پردازش آپلود فایلها در ASP.NET Core نسبت به ASP.NET MVC 5.x به طور کامل تغییر کردهاست و اینبار بجای ذکر نوع System.Web.HttpPostedFileBase باید از اینترفیس جدید IFormFile واقع در فضای نام Microsoft.AspNetCore.Http کمک گرفت.
مراحل فعال سازی آپلود فایلها در ASP.NET Core
مرحلهی اول فعال سازی آپلود فایلها در ASP.NET Core، شامل افزودن ویژگی "enctype="multipart/form-data به یک فرم تعریف شدهاست:
در اینجا همچنین ذکر ویژگی multiple در input از نوع file، امکان ارسال چندین فایل با هم را نیز میسر میکند.
در سمت سرور، امضای اکشن متد دریافت کنندهی این فایلها به صورت ذیل خواهد بود:
در اینجا نام پارامتر تعریف شده، باید دقیقا مساوی نام input از نوع file باشد. همچنین از آنجائیکه ویژگی multiple را نیز در سمت کلاینت قید کردهایم، این پارامتر سمت سرور از نوع یک لیست، تعریف شدهاست. اگر ویژگی multiple را حذف کنیم میتوان آنرا به صورت سادهی IFormFile files نیز تعریف کرد.
یافتن جایگزینی برای Server.MapPath در ASP.NET Core
زمانیکه فایل ارسالی، در سمت سرور دریافت شد، مرحلهی بعد، ذخیره سازی آن بر روی سرور است و از آنجائیکه ما دقیقا نمیدانیم ریشهی سایت در کدام پوشهی سرور واقع شدهاست، میشد از متد Server.MapPath برای یافتن دقیق آن کمک گرفت. با حذف این متد در ASP.NET Core، روش یافتن ریشهی سایت یا همان پوشهی wwwroot در اینجا شامل مراحل ذیل است:
ابتدا اینترفیس توکار IHostingEnvironment را در سازندهی کلاس تزریق میکنیم. سرویس HostingEnvironment جزو سرویسهای از پیش تعریف شدهی ASP.NET Core است و نیازی به تنظیمات اضافهتری ندارد. همینقدر که ذکر شود، به صورت خودکار توسط ASP.NET Core مقدار دهی و تامین میگردد.
پس از آن خاصیت environment.WebRootPath_ به ریشهی پوشهی wwwroot برنامه، بر روی سرور اشاره میکند. به این ترتیب میتوان مسیر دقیقی را جهت ذخیره سازی فایلهای رسیده، مشخص کرد.
امکان ذخیره سازی async فایلها در ASP.NET Core
عملیات کار با فایلها، عملیاتی است که از مرزهای IO سیستم عبور میکند. به همین جهت یکی از بهترین مثالهای پیاده سازی async، جهت رها سازی تردهای برنامه و بالا بردن میزان پاسخدهی آن با بالا بردن تعداد تردهای آزاد بیشتر است. در ASP.NET Core، نوشتن async محتوای فایل رسیده در یک stream پشتیبانی میشود و این stream میتواند یک FileStream و یا MemoryStream باشد. در ذیل نحوهی کار async با یک FileStream را مشاهده میکنید:
در اینجا کدهای کامل متد دریافت فایلها را در سمت سرور مشاهده میکنید. ابتدا با استفاده از خاصیت environment.WebRootPath_، به مسیر ریشهی wwwroot دسترسی و سپس پوشهی uploads را در آن جهت ذخیره سازی فایلهای دریافتی، تعیین کردهایم.
چون برنامههای ASP.NET Core قابلیت اجرای بر روی لینوکس را نیز دارند، تا حد امکان باید از Path.Combine جهت جمع زدن اجزای مختلف یک میسر، استفاده کرد. از این جهت که در لینوکس، جداکنندهی اجزای مسیرها، / است بجای \ در ویندوز و متد Path.Combine به صورت خودکار این مسایل را لحاظ خواهد کرد.
در آخر با استفاده از متد file.CopyToAsync کار نوشتن غیرهمزمان محتوای فایل دریافتی در یک FileStream انجام میشود؛ به همین جهت در امضای متد فوق، <async Task<IActionResult را نیز ملاحظه میکنید.
پشتیبانی کامل از Model Binding آپلود فایلها در ASP.NET Core
در ASP.NET MVC 5.x اگر ویژگی Required را بر روی یک خاصیت از نوع HttpPostedFileBase قرار دهید ... کار نمیکند و در سمت کلاینت تاثیری را به همراه نخواهد داشت؛ مگر اینکه تنظیمات سمت کلاینت آنرا به صورت دستی انجام دهیم. این مشکلات در ASP.NET Core، کاملا برطرف شدهاند:
در اینجا یک خاصیت از نوع IFormFile، با دو ویژگی Required و DataType خاص آن در یک ViewModel تعریف شدهاند. فرم معادل آن در ASP.NET Core به صورت ذیل خواهد بود:
در اینجا ابتدا نوع مدل View تعیین شدهاست و سپس با استفاده از Tag Helpers، صرفا یک input را به خاصیت Photo مدل View جاری متصل کردهایم. همین اتصال سبب فعال سازی مباحث اعتبارسنجی سمت سرور و کاربر نیز میشود.
اینبار جهت فعال سازی و استفادهی از قابلیتهای Model Binding میتوان از ModelState نیز بهره گرفت:
اگر ModelState معتبر باشد، کار ذخیره سازی تک فایل رسیده را انجام میدهیم. سایر نکات این متد، با اکشن متد Index که پیشتر بررسی شد، یکی هستند.
بررسی پسوند فایلهای رسیدهی به سرور
ASP.NET Core دارای ویژگی است به نام FileExtensions که ... هیچ ارتباطی به خاصیتهایی از نوع IFormFile ندارد:
ویژگی FileExtensions صرفا جهت درج بر روی خواصی از نوع string طراحی شدهاست. بنابراین قرار دادن این ویژگی بر روی خاصیتهایی از نوع IFormFile، سبب فعال سازی اعتبارسنجی سمت سرور پسوندهای فایلهای رسیده، نخواهد شد.
در ادامه جهت بررسی پسوندهای فایلهای رسیده، میتوان یک ویژگی اعتبارسنجی سمت سرور جدید را طراحی کرد:
در اینجا با ارث بری از کلاس پایه ValidationAttribute و بازنویسی متد IsValid آن، کار اعتبارسنجی پسوند فایلها و یا فایل رسیده را انجام دادهایم. این ویژگی جدید اگر بر روی خاصیتی از نوع IFormFile قرار بگیرد، پارامتر object value متد IsValid آن حاوی اطلاعات فایل و یا فایلهای رسیده، خواهد بود. بر این اساس میتوان تصمیم گیری کرد که آیا پسوند این فایل، مجاز است یا خیر.
در اینجا روش استفادهی از این ویژگی اعتبارسنجی جدید را نیز با تکمیل ViewModel کاربر، مشاهده میکنید. پس از آن تنها بررسی if (ModelState.IsValid) در یک اکشن متد، نتیجهی دریافتی از اعتبارسنج جدید UploadFileExtensions را در اختیار ما قرار میدهد و بر این اساس میتوان تصمیمگیری کرد که آیا باید فایل رسیده را ذخیره کرد یا خیر.
مراحل فعال سازی آپلود فایلها در ASP.NET Core
مرحلهی اول فعال سازی آپلود فایلها در ASP.NET Core، شامل افزودن ویژگی "enctype="multipart/form-data به یک فرم تعریف شدهاست:
<form method="post" asp-action="Index" asp-controller="TestFileUpload" enctype="multipart/form-data"> <input type="file" name="files" multiple /> <input type="submit" value="Upload" /> </form>
در سمت سرور، امضای اکشن متد دریافت کنندهی این فایلها به صورت ذیل خواهد بود:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Index(IList<IFormFile> files)
یافتن جایگزینی برای Server.MapPath در ASP.NET Core
زمانیکه فایل ارسالی، در سمت سرور دریافت شد، مرحلهی بعد، ذخیره سازی آن بر روی سرور است و از آنجائیکه ما دقیقا نمیدانیم ریشهی سایت در کدام پوشهی سرور واقع شدهاست، میشد از متد Server.MapPath برای یافتن دقیق آن کمک گرفت. با حذف این متد در ASP.NET Core، روش یافتن ریشهی سایت یا همان پوشهی wwwroot در اینجا شامل مراحل ذیل است:
public class TestFileUploadController : Controller { private readonly IHostingEnvironment _environment; public TestFileUploadController(IHostingEnvironment environment) { _environment = environment; }
پس از آن خاصیت environment.WebRootPath_ به ریشهی پوشهی wwwroot برنامه، بر روی سرور اشاره میکند. به این ترتیب میتوان مسیر دقیقی را جهت ذخیره سازی فایلهای رسیده، مشخص کرد.
امکان ذخیره سازی async فایلها در ASP.NET Core
عملیات کار با فایلها، عملیاتی است که از مرزهای IO سیستم عبور میکند. به همین جهت یکی از بهترین مثالهای پیاده سازی async، جهت رها سازی تردهای برنامه و بالا بردن میزان پاسخدهی آن با بالا بردن تعداد تردهای آزاد بیشتر است. در ASP.NET Core، نوشتن async محتوای فایل رسیده در یک stream پشتیبانی میشود و این stream میتواند یک FileStream و یا MemoryStream باشد. در ذیل نحوهی کار async با یک FileStream را مشاهده میکنید:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Index(IList<IFormFile> files) { var uploadsRootFolder = Path.Combine(_environment.WebRootPath, "uploads"); if (!Directory.Exists(uploadsRootFolder)) { Directory.CreateDirectory(uploadsRootFolder); } foreach (var file in files) { if (file == null || file.Length == 0) { continue; } var filePath = Path.Combine(uploadsRootFolder, file.FileName); using (var fileStream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(fileStream).ConfigureAwait(false); } } return View(); }
چون برنامههای ASP.NET Core قابلیت اجرای بر روی لینوکس را نیز دارند، تا حد امکان باید از Path.Combine جهت جمع زدن اجزای مختلف یک میسر، استفاده کرد. از این جهت که در لینوکس، جداکنندهی اجزای مسیرها، / است بجای \ در ویندوز و متد Path.Combine به صورت خودکار این مسایل را لحاظ خواهد کرد.
در آخر با استفاده از متد file.CopyToAsync کار نوشتن غیرهمزمان محتوای فایل دریافتی در یک FileStream انجام میشود؛ به همین جهت در امضای متد فوق، <async Task<IActionResult را نیز ملاحظه میکنید.
پشتیبانی کامل از Model Binding آپلود فایلها در ASP.NET Core
در ASP.NET MVC 5.x اگر ویژگی Required را بر روی یک خاصیت از نوع HttpPostedFileBase قرار دهید ... کار نمیکند و در سمت کلاینت تاثیری را به همراه نخواهد داشت؛ مگر اینکه تنظیمات سمت کلاینت آنرا به صورت دستی انجام دهیم. این مشکلات در ASP.NET Core، کاملا برطرف شدهاند:
public class UserViewModel { [Required(ErrorMessage = "Please select a file.")] [DataType(DataType.Upload)] public IFormFile Photo { get; set; } }
@model UserViewModel <form method="post" asp-action="UploadPhoto" asp-controller="TestFileUpload" enctype="multipart/form-data"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <input asp-for="Photo" /> <span asp-validation-for="Photo" class="text-danger"></span> <input type="submit" value="Upload"/> </form>
اینبار جهت فعال سازی و استفادهی از قابلیتهای Model Binding میتوان از ModelState نیز بهره گرفت:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> UploadPhoto(UserViewModel userViewModel) { if (ModelState.IsValid) { var formFile = userViewModel.Photo; if (formFile == null || formFile.Length == 0) { ModelState.AddModelError("", "Uploaded file is empty or null."); return View(viewName: "Index"); } var uploadsRootFolder = Path.Combine(_environment.WebRootPath, "uploads"); if (!Directory.Exists(uploadsRootFolder)) { Directory.CreateDirectory(uploadsRootFolder); } var filePath = Path.Combine(uploadsRootFolder, formFile.FileName); using (var fileStream = new FileStream(filePath, FileMode.Create)) { await formFile.CopyToAsync(fileStream).ConfigureAwait(false); } RedirectToAction("Index"); } return View(viewName: "Index"); }
بررسی پسوند فایلهای رسیدهی به سرور
ASP.NET Core دارای ویژگی است به نام FileExtensions که ... هیچ ارتباطی به خاصیتهایی از نوع IFormFile ندارد:
[FileExtensions(Extensions = ".png,.jpg,.jpeg,.gif", ErrorMessage = "Please upload an image file.")]
در ادامه جهت بررسی پسوندهای فایلهای رسیده، میتوان یک ویژگی اعتبارسنجی سمت سرور جدید را طراحی کرد:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class UploadFileExtensionsAttribute : ValidationAttribute { private readonly IList<string> _allowedExtensions; public UploadFileExtensionsAttribute(string fileExtensions) { _allowedExtensions = fileExtensions.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); } public override bool IsValid(object value) { var file = value as IFormFile; if (file != null) { return isValidFile(file); } var files = value as IList<IFormFile>; if (files == null) { return false; } foreach (var postedFile in files) { if (!isValidFile(postedFile)) return false; } return true; } private bool isValidFile(IFormFile file) { if (file == null || file.Length == 0) { return false; } var fileExtension = Path.GetExtension(file.FileName); return !string.IsNullOrWhiteSpace(fileExtension) && _allowedExtensions.Any(ext => fileExtension.Equals(ext, StringComparison.OrdinalIgnoreCase)); } }
public class UserViewModel { [Required(ErrorMessage = "Please select a file.")] //`FileExtensions` needs to be applied to a string property. It doesn't work on IFormFile properties, and definitely not on IEnumerable<IFormFile> properties. //[FileExtensions(Extensions = ".png,.jpg,.jpeg,.gif", ErrorMessage = "Please upload an image file.")] [UploadFileExtensions(".png,.jpg,.jpeg,.gif", ErrorMessage = "Please upload an image file.")] [DataType(DataType.Upload)] public IFormFile Photo { get; set; } }