- مطلب و نظرات «امن سازی درخواستهای ایجکسی برنامههای ASP.NET MVC 5.x در مقابل حملات CSRF» را در مورد نحوهی ارسال RequestVerificationToken در برنامههای Ajax ایی مطالعه کنید.
- روش JWT عموما برای برنامههای تمام SPA (تمام تک صفحهای وب مانند Angular) استفاده میشود (پیشنیاز بحث را که در ابتدای آن عنوان شده، مطالعه کنید). اگر برنامهی شما تمام MVC است و از صفحات Razor استفاده میکنید، بهتر است از روش «اعمال تزریق وابستگیها به مثال رسمی ASP.NET Identity» استفاده کنید.
IdentityServer از زمان ارائهی نگارش 5 آن دیگر رایگان نیست و پیشتر مایکروسافت از نگارش 4 آن در قالبهای استاندارد پروژههای Blazor استفاده کرده بود. نگارش قبلی آن تنها در پروژههای NET 5x. پشتیبانی خواهد شد. نگارش 5 آن در پروژههای NET 6x. به همراه ذکر دقیق مجوز آن هنوز هم حضور خواهد داشت. از نگارش 7 دات نت، فکر دیگری خواهند کرد.
Blazor 5x - قسمت 25 - تهیه API مخصوص Blazor WASM - بخش 2 - تامین پایهی اعتبارسنجی و احراز هویت
- فیلترها در MVC
- ASP.NET MVC #15
فیلترها در ASP.NET MVC، امکان اجرای کدهایی را پیش و یا پس از مرحلهی خاصی از طول اجرای pipeline آن فراهم میکنند. کلیات فیلترها در ASP.NET Core با نگارشهای قبلی ASP.NET MVC (پیشنیازهای فوق) تفاوت چندانی را ندارد و بیشتر تغییراتی مانند نحوهی معرفی سراسری آنها، اکشن فیلترهای Async و یا تزریق وابستگیها در آنها، جدید هستند.
امکان تعریف فیلترهای Async در ASP.NET Core
حالت کلی تعریف یک فیلتر در ASP.NET MVC که در ASP.NET Core نیز همچنان معتبر است، پیاده سازی اینترفیس کلی IActionFilter میباشد که توسط آن میتوان به مراحل پیش و پس از اجرای قطعهای از کدهای برنامه دسترسی پیدا کرد:
namespace FiltersSample.Filters { public class SampleActionFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { // انجام کاری پیش از اجرای اکشن متد } public void OnActionExecuted(ActionExecutedContext context) { // انجام کاری پس از اجرای اکشن متد } } }
namespace FiltersSample.Filters { public class SampleAsyncActionFilter : IAsyncActionFilter { public async Task OnActionExecutionAsync( ActionExecutingContext context, ActionExecutionDelegate next) { // انجام کاری پیش از اجرای اکشن متد await next(); // انجام کاری پس از اجرای اکشن متد } } }
یک نکته: توصیه شدهاست که تنها یکی از حالتهای همزمان و یا غیرهمزمان را پیاده سازی کنید و نه هر دوی آنها را. اگر هر دوی اینها را در طی یک کلاس پیاده سازی کنید (تک کلاسی که هر دوی اینترفیسهای IActionFilter و IAsyncActionFilter را با هم پیاده سازی میکند)، تنها نگارش Async آن توسط ASP.NET Core فراخوانی و استفاده خواهد شد. همچنین مهم نیست که اکشن متد شما Async هست یا خیر؛ برای هر دو حالت میتوان از فیلترهای async نیز استفاده کرد.
ساده سازی تعریف فیلترها
اگر مدتی با ASP.NET MVC کار کرده باشید، میدانید که عموما کسی از این اینترفیسهای کلی برای پیاده سازی فیلترها استفاده نمیکند. روش کار با ارث بری از یکی از فیلترهای از پیش تعریف شدهی ASP.NET MVC صورت میگیرد؛ از این جهت که این فیلترها که در اصل همین اینترفیسها را پیاده سازی کردهاند، یک سری جزئیات توکار protected را نیز به همراه دارند که با ارث بری از آنها میتوان به امکانات بیشتری دسترسی پیدا کرد و کدهای سادهتر و کم حجمتری را تولید نمود:
ActionFilterAttribute
ExceptionFilterAttribute
ResultFilterAttribute
FormatFilterAttribute
ServiceFilterAttribute
TypeFilterAttribute
برای مثال در اینجا فیلتری را مشاهده میکنید که با ارث بری از فیلتر توکار ResultFilterAttribute، سعی در تغییر Response برنامه و افزودن هدری به آن کردهاست:
using Microsoft.AspNetCore.Mvc.Filters; namespace FiltersSample.Filters { public class AddHeaderAttribute : ResultFilterAttribute { private readonly string _name; private readonly string _value; public AddHeaderAttribute(string name, string value) { _name = name; _value = value; } public override void OnResultExecuting(ResultExecutingContext context) { context.HttpContext.Response.Headers.Add( _name, new string[] { _value }); base.OnResultExecuting(context); } } }
[AddHeader("Author", "DNT")] public class SampleController : Controller { public IActionResult Index() { return Content("با فایرباگ هدر خروجی را بررسی کنید"); } }
نحوهی تعریف میدان دید فیلترها
نحوهی دید فیلترها در اینجا نیز همانند سابق، سه حالت را میتواند داشته باشد:
الف) اعمال شدهی به یک اکشن متد.
ب) اعمال شدهی به یک کنترلر که به تمام اکشن متدهای آن کنترلر اعمال خواهد شد.
ج) حالت تعریف سراسری و این مورد محل تعریف آن به کلاس آغازین برنامه منتقل شدهاست:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { options.Filters.Add(typeof(SampleActionFilter)); // by type options.Filters.Add(new SampleGlobalActionFilter()); // an instance }); }
الف) اگر توسط ارائهی new ClassName معرفی شوند، یعنی وهله سازی را خودتان قرار است مدیریت کنید و در این حالت تزریق وابستگیهایی صورت نخواهند گرفت.
ب) اگر توسط typeof معرفی شوند، یعنی این وهله سازی توسط IoC Container توکار ASP.NET Core انجام خواهد شد و طول عمر آن Transient است. یعنی به ازای هربار نیاز به آن، یکبار وهله سازی خواهد شد.
ترتیب اجرای فیلترها
توسط خاصیت Order میتوان ترتیب اجرای چندین فیلتر اجرا شدهی به یک اکشن متد را مشخص کرد. اگر این مقدار منفی وارد شود:
[MyFilter(Name = "Method Level Attribute", Order=-1)]
تزریق وابستگیها در فیلترها
فیلترهایی که به صورت ویژگیها یا Attributes تعریف میشوند و قرار است به کنترلرها و یا اکشن متدها به صورت مستقیم اعمال شوند، نمیتوانند دارای وابستگیهای تزریق شدهی در سازندهی خود باشند. این محدودیتی است که توسط زبانهای برنامه نویسی اعمال میشود و نه ASP.NET Core. اگر ویژگی قرار است پارامتری در سازندهی خود داشته باشد، هنگام تعریف و اعمال آن، این پارامترها باید مشخص بوده و تعریف شوند. به همین جهت آنچنان با تزریق وابستگیهای از طریق سازندهی کلاس قابل مدیریت نیستند. برای رفع این نقصیه، راهحلهای متفاوتی در ASP.NET Core پیشنهاد و طراحی شدهاند:
الف) استفادهی از ServiceFilterAttribute
[ServiceFilter(typeof(AddHeaderFilterWithDi))] public IActionResult Index() { return View(); }
همچنین باید دقت داشت که در این حالت ثبت کلاس فیلتر در متد ConfigureServices کلاس آغازین برنامه الزامی است.
services.AddScoped<AddHeaderFilterWithDi>();
System.InvalidOperationException: No service for type 'FiltersSample.Filters.AddHeaderFilterWithDI' has been registered.
ب) استفاده از TypeFilterAttribute
[TypeFilter(typeof(AddHeaderAttribute), Arguments = new object[] { "Author", "DNT" })] public IActionResult Hi(string name) { return Content($"Hi {name}"); }
- نیازی نیست تا وابستگی آنرا در متد ConfigureServices ثبت کرد (هرچند وابستگیهای خود را از DI Container دریافت میکنند).
- امکان دریافت پارامترهای اضافی سازندهی کلاس مدنظر را نیز دارند.
یک مثال تکمیلی: لاگ کردن تمام استثناءهای مدیریت نشدهی یک برنامهی ASP.NET Core 1.0
میتوان با سفارشی سازی فیلتر توکار ExceptionFilterAttribute، امکان ثبت وقایع را توسط فریم ورک توکار Logging اضافه کرد:
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; namespace Core1RtmEmptyTest.StartupCustomizations { public class CustomExceptionLoggingFilterAttribute : ExceptionFilterAttribute { private readonly ILogger<CustomExceptionLoggingFilterAttribute> _logger; public CustomExceptionLoggingFilterAttribute(ILogger<CustomExceptionLoggingFilterAttribute> logger) { _logger = logger; } public override void OnException(ExceptionContext context) { _logger.LogInformation($"OnException: {context.Exception}"); base.OnException(context); } } }
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { options.Filters.Add(typeof(CustomExceptionLoggingFilterAttribute));
در ادامه با این فرض که پیشتر تنظیمات ثبت وقایع صورت گرفتهاست:
public void Configure(ILoggerFactory loggerFactory) { loggerFactory.AddDebug(minLevel: LogLevel.Debug);
public IActionResult GetData() { throw new Exception("throwing an exception!"); }
در Asp.net دو چرخهی حیات مهم
وجود دارند که اساس چارچوب MVC را تشکیل میدهند
:
- چرخهی حیات برنامه (Application)؛ از لحظهای که برنامه برای اولین بار اجرا میشود و تا لحظهی خاتمهی آن را شامل میشود.
- چرخهی حیات یک درخواست ( Request )؛ مسیری که یک درخواست طی میکند، اصطلاحا PipeLine نامیده میشود که همان چرخهی حیات یک درخواست نیز هست و از لحظهای که درخواست تحویل asp.net شده، تا زمانیکه درخواست ارسال میشود را شامل میشود.
تمرکز بنده بیشتر بر روی روند و مسیری است که یک درخواست طی میکند و قصد دارم با بهره گیری از کتاب Pro Asp.net Mvc 5 و دیگر منابع، چرخهی حیات درخواست را در برنامههای Mvc بررسی کرده و در مقالات آتی ماژولها و هندلرها را بررسی کنم.
در asp.net ، برنامه global فایلهای شامل دو فایل Global.asax , Global.asax.cs است.
فایل Global.asax که هیچ گاه نیاز به ویرایش آن نداریم محتویاتی مانند زیر دارد:
<%@ Application Codebehind="Global.asax.cs" Inherits="YourAppName.MvcApplication" Language="C#" %>
در این مقاله منظور از فایل global فایل Global.asax.cs است که مشتق شده از کلاس System.Web.HttpApplication است:
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { ...// } }
Asp.net برای پاسخگویی به درخواستهای واصله، وهلههایی از کلاس MvcApplication را میسازد ولی این دو متد صرفا در نقاط شروع و پایان برنامه فراخوانی شده و عملا در وهلههای یاد شده صدا زده نخواهند شد و به جای آنها رویدادهایی را که در ذیل آنها را معرفی میکنیم، فراخوانی شده و چرخهی حیات درخواست را برای ما مشخص میسازند .
BeginRequest : به عنوان اولین رویداد، به محض وصول یک درخواست جدید رخ خواهد داد.AuthenticateRequest ,PostAuthenticateRequest : رویداد AuthenticateRequest برای شناسایی کاربر ارسال کننده درخواست، کاربرد دارد و پس از پردازش کلیهی توابع، رویداد PostAuthenticateRequest صدا زده میشود.
AuthorizeRequest :بههنگام صدور مجوزهای یک درخواست رخ میدهد و مشابه رویداد بالا پس از پردازش کلیهی توابع، رویداد PostAuthorizeRequest صدا زده خواهد شد.ResolveRequestCache : پس از صدور مجوزهای یک درخواست در رویداد authorization زمانیکه ماژولهای کش میخواهند اطلاعاتی را از کش سرور مطالبه کنند، رخ میدهد و به مانند دو رخداد قبلی، PostResolveRequestCache نیز پس از اتمام پردازش توابع رویداد رخ میدهد.
MapRequestHandler : زمانی که Asp.net میخواهد هندلری را برای پاسخگویی به درخواست واصله انتخاب کند رخ میدهد و PostMapRequestHandler نیز پس از این انتخاب، تریگر میشود.AcquireRequestState : جهت بدست آوردن دادههایی نظیر سشن و ... مرتبط با درخواست جاری کاربرد داشته و PostAcquireRequestState نیز پس از پردازش توابع رویداد رخ خواهد داد.
PreRequestHandlerExecute : بالافاصله قبل و همچنین بلافاصله بعد از این که یک هندلر بخواهد درخواستی را پردازش کند، رخ میدهد. PostRequestHandlerExecute نیز همانند دیگر رویدادهای گذشته، پس از اتمام پردازش توابع، این رویداد رخ خواهد داد.ReleaseRequestState : زمانی رخ میدهد که دادههای مرتبط با درخواست جاری، در ادامهی روند پردازش درخواست مورد نیاز نباشند و پس از پردازش توابع رویداد، PostReleaseRequestState رخ خواهد داد .
UpdateRequestCache : به جهت اینکه ماژولهای مسئول کش، توانایی به روز رسانی دادههای خود، برای پاسخگویی به درخواستهای بعدی را داشته باشند، این رویداد رخ میدهد.
LogRequest : قبل از انجام عملیات لاگین برای درخواست جاری رخ میدهد و پس از پردازش توابع رویداد نیز PostLogRequest تریگر میشود.EndRequest : پس از پایان کار پردازش درخواست جاری و مهیا شدن پاسخ مرتبط جهت ارسال به مرورگر تریگر خواهد شد.
PreSendRequestHeaders : قبل از ارسال HTTP headers به مرورگر این رویداد رخ خواهد داد.
PreSendRequestContent : بعد از ارسال شدن هدرها و قبل از ارسال محتوای صفحه به مرورگر رخ میدهد.Error : هر زمان و در هر مرحله از پردازش درخواست، چنانچه خطایی صورت پذیرد این رویداد رخ خواهد داد.
فریم ورک Asp.net جهت مدیریت بهتر یک درخواست، در تمام مسیر پردازش، رویدادهای بالا را مهیا کرده است. در ادامه نحوهی هندل کردن رویدادهای چرخهی حیات درخواست را در فایل global توضیح میدهم. هر چند که استفاده از این فایل بدین منظور، صرفا برای مدیریت مسائل ابتدایی مناسب بوده و در یک پروژهی بزرگ موجب به هم ریختگی فایل global با کدهای زیاد و خوانایی پایین بوده که قابلیت استفاده مجدد در دیگر پروژهها را نیز ندارد.
Asp.net این مشکل را با معرفی ماژولها که در مقالات آتی توضیح خواهم داد، مرتفع کرده است.
در فایل global هر گاه متدی را با پیشوند Application_ و نام یکی از رویدادهای بالا بنویسید Asp.net آن را به عنوان هندلری برای رویداد مذکور میشناسد. به عنوان مثال متدی با نام Application_BeginRequest متد رویداد BeginRequest میباشد.
ابتدا یک پروژهی MVC جدید را به نام SimpleApp ایجاد کرده و فایل global آن را مطابق ذیل تغییر میدهیم:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace SimpleApp { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); } protected void Application_BeginRequest() { RecordEvent("BeginRequest"); } protected void Application_AuthenticateRequest() { RecordEvent("AuthenticateRequest"); } protected void Application_PostAuthenticateRequest() { RecordEvent("PostAuthenticateRequest"); } private void RecordEvent(string name) { List<string> eventList = Application["events"] as List<string>; if (eventList == null) { Application["events"] = eventList = new List<string>(); } eventList.Add(name); } } }
در اینجا متدی به نام RecordEvent را در کدهای ذکر شده مشاهده میکنید که نام یک رویداد را دریافت و جهت در دسترس قرار دادن در کل برنامه به خاصیت Application از کلاس HttpApplication نسبت داده و متد مذکور را از سه متد دیگر فراخوانی کردهایم. این متدها در زمان رخ دادن رویدادهای BeginRequest, AuthenticateRequest, PostAuthenticateRequest صدا زده خواهند شد.
حال جهت نمایش اطلاعات رویداد نیاز است تغییراتی مشابه ذیل در کنترلر Home ایجاد نماییم.
using System.Web.Mvc; namespace SimpleApp.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(HttpContext.Application["events"]); } } }
ویوی مرتبط با اکشن متد index را مطابق کدهای ذیل بازنویسی میکنیم:
@model List<string> @{ ViewBag.Title = "Events List"; } <h5>Events</h5> <table> @foreach (string eventName in Model) { <tr> <td>@eventName</td> </tr> } </table>
در این مقاله سعی کردیم ابتدا چرخهی حیات یک Request را فرا گرفته و سپس از طریق فایل global و توسط متدهایی با پیشوند Application_ +نام رویداد (اصطلاحا متدهای ویژه نامیده میشوند) چرخه حیات یک درخواست را مدیریت کنیم.
حدود 8 سال از ارائه اولین نگارش دات نت فریم ورک میگذرد و در ادامه مرور سریعی خواهیم داشت بر عناوین کتابخانههای اضافه شده به این مجموعه:
دات نت فریم ورک 1.0
اولین ارائه عمومی آزمایشی آن در PDC 2000 صورت گرفت و در اوایل 2002 به عموم عرضه شد (2/13/2002).
عبارت کد مدیریت شده را به دنیا معرفی کرد (managed code) و شامل اجزای زیر بود:
• GC, JIT
• C#
• Coherent Framework
• XSP….ASP+…ASP.NET!
• WinForms
در اوایل 2003 به همراه ویندوز سرور 2003 و VS 2003 ارائه شد.
• Mobile ASP.NET controls
• Built-in support for ODBC and Oracle databases.
• IPv6 support.
در اواخر 2005 ارائه شد (11/07/2005) و شامل تازههای زیر بود:
• ASP.NET for the Masses
○ Application Building Blocks
§ Parts, Authentication, Role Management, etc
○ Visual Web Developer
• Client Development
• ClickOnce!
در اواخر 2006 ارائه شد (11/06/2006) و موارد زیر را به این فریم ورک افزود:
• Windows CardSpace - Digital identity interface.
• Windows Presentation Foundation : WPF
○ Vector Graphics, Media and UI
○ Enters the age of UX
• Windows Communication Foundation : WCF
○ Unified messaging model
• Windows Workflow Foundation : WF
○ Coordinating work with durable applications
در پایان 2007 ارائه شد (11/19/2007) و تازههای زیر را به همراه داشت:
• Linq
• Expression Trees and Lamda Methods
• Extension Methods
• Paging Support for ADO.NET
• Managed Wrappers for WMI and AD
• Enhancements to WCF and WF
• System.CodeDom namespace
• ASP.NET AJAX
• WCF/WF
○ REST Services
○ Workflow Services
• Client
○ Sync
○ Client app services
سرویس پک یک دات نت فریم ورک 3.5
در اواسط 2008 ارائه شد (8/11/2008) و به همراه تغییرات زیر بود:
• ASP.NET Dynamic Data
• ADO.NET
○ Entity Framework
○ Data Services (Astoria)
• WCF
○ AtomPub ServiceDocuments
• Client
○ Client Profile
○ Performance
§ Working set and startup time
• Silverlight 2
○ RTM end of 2008
○ Brings power of .NET to the web client
○ Media and RIA .NET platform
دات نت فریم ورک 4.0
نگارش بتای آن در دسترس است و احتمالا نگارش نهایی آن در سال آیندهی میلادی به همراه VS2010 ارائه میشود. این مجموعه تازههای زیر را به همراه خواهد داشت:
• Base Class Library Improvements
○ Managed Extensibility Framework
○ More Core Data Structures
○ I/O Improvements
• Parallel Computing
○ Task Parallel Library
○ Parallel Linq (PLINQ)
○ Coordination Data Structures (CDS)
• Client
○ WPF
§ Client Profile
§ Business Focused Controls
§ Win7 Advances (Multi-touch, etc)
○ ADO.NET
§ Entity Framework v2
□ Code-First Development
□ TDD Support
□ Foreign-Key Support
○ ASP.NET
§ ASP.NET Dynamic Data Improvements
§ ASP.NET MVC
§ ASP.NET Dynamic Data for MVC
§ Extensible Caching Framework
○ WF & WCF
§ Fully Declarative Services
§ Workflow Enhancements
□ New flowchart modeling
□ Workflow Rules Integration
□ … much more…
§ WCF Enhancements
□ Durable Duplex
□ WS-Discovery & UDP Channel
□ In-Process Channel
§ RIA (Silverlight)
□ Simplified N-tier development
□ Business-focused framework
this.Clients.Client(this.Context.ConnectionId).SendAsync("method", "message")
ASP.NET MVC #5
«به روز رسانی غیرهمزمان قسمتی از صفحه به کمک jQuery در ASP.NET MVC »
+ مباحث کش کردن اطلاعات را هم مدنظر داشته باشید.
در مورد نحوه نصب پیشنیازهای ASP.NET MVC 3 پیشتر توضیح داده شد. یک روش دیگر هم برای اینکار مهیا است؛ اگر به مشکل برخوردید حین نصب.
- دریافت ASP.NET MVC 3 RTM (نگارش RTM یعنی نگارش نهایی ارائه شده به صنعت)
- دریافت ASP.NET MVC 3 Tools Update (این هم شامل یک سری به روز رسانی است؛ مثلا قالب اینترانت به آن اضافه شده و غیره)
اگر حین نصب ASP.NET MVC 3 Tools Update، کارها خوب پیش نرفت و دست آخر زمانیکه فایل log خطا را باز کردید در پایان آن ذکر شده بود « Installation failed with error code: 0x80070643» باید این مراحل را طی کنید:
الف) فایل نصاب را با استفاده از برنامه 7-zip آنپک کنید (فایلهای داخلی آنرا استخراج کنید).
ب) فایل VS10-KB*.msp یا vs10-kb*.msi را یافته و بر روی آن کلیک راست کنید. گزینه install را از منوی باز شده انتخاب نمائید تا کار نصب شروع شود.
ج) در حین نصب این پیغام را دریافت خواهید کرد: «can't find vs_setup.msi». در این حالت بر روی دکمه browse کلیک کرده و این فایل vs_setup.msi را که در DVD نصب خود VS 2010 اصلی وجود دارد به آن معرفی کنید. علت هم به این بر میگردد که پروسه نصب VS 2010 شما از ابتدا ناقص بوده است و نیاز است یک سری فایل دیگر در ابتدا بر روی سیستم نصب گردند.
اکنون کار نصب بدون مشکل پیش خواهد رفت. لازم به ذکر است که این پیغام خطا را حین عملیات نصب معمولی MVC3 «دریافت نخواهید کرد».
د) سپس یکبار دیگر هم فایل setup.exe اصلی را بدون مراحل فوق اجرا کنید تا خیالتان از این بابت راحت شود و تمام موارد نصب نشده نیز نصب گردند (مهم!).
این مراحل باید مشکل را حل کنند، در غیراینصورت یک سری راه حل دیگر هم در اینجا ذکر شده است: http://support.microsoft.com/kb/2531566
و خلاصه آن این است که فایل C:\Windows\Microsoft.NET\Framework\v4.0.30319\web.config را پیش از نصب rename کنید و اجازه دهید تا نصاب یک نمونه جدید را ایجاد کند.