- QueueBackgroundWorkItem to reliably schedule and run long background processes in ASP.NET
- Fire and Forget on ASP.NET
- Using QueueBackgroundWorkItem to Schedule Background Jobs from an ASP.NET Application in .NET 4.5.2
- Exploring QueueBackgroundWorkItem in ASP.NET and Framework 4.5.2
- An update on background tasks in ASP.NET
Resume Management project with React18, ASP.NET Core7 WebAPI, TypeScript and Entity Framework Core
In this video, we will create a Fullstack Resume Management project using React18, ASP.NET Core WebAPI (.NET 7),TypeScript and Entity Framework Core. The focus of this project is to show you how you can build a Fullstack project from 0 to 100 and build a simple CRUD application with ASP.NET Core WebAPI .
Pet Store Fullstack project with React18, ASP.NET Core7 WebAPI, TypeScript and Entity Framework Core
In this video, we will create a Fullstack Pet Store project using React18, ASP.NET Core WebAPI (.NET 7),TypeScript and Entity Framework Core. The focus of this project is to show you how you can build a Fullstack project from 0 to 100 and build a simple CRUD application with ASP.NET Core WebAPI .
ASP.NET MVC #10
آشنایی با روشهای مختلف ارسال اطلاعات یک درخواست به کنترلر
تا اینجا با روشهای مختلف ارسال اطلاعات از یک کنترلر به View متناظر آن آشنا شدیم. اما حالت عکس آن چطور؟ مثلا در ASP.NET Web forms، دوبار بر روی یک دکمه کلیک میکردیم و در روال رویدادگردان کلیک آن، همانند برنامههای ویندوزی، دسترسی به اطلاعات اشیاء قرار گرفته بر روی فرم را داشتیم. در ASP.NET MVC که کلا مفهوم Events را حذف کرده و وب را همانگونه که هست ارائه میدهد و به علاوه کنترلرهای آن، ارجاع مستقیمی را به هیچکدام از اشیاء بصری در خود ندارند (برای مثال کنترلر و متدی در آن نمیدانند که الان بر روی View آن، یک گرید قرار دارد یا یک دکمه یا اصلا هیچی)، چگونه میتوان اطلاعاتی را از کاربر دریافت کرد؟
در اینجا حداقل سه روش برای دریافت اطلاعات از کاربر وجود دارد:
الف) استفاده از اشیاء Context مانند HttpContext، Request، RouteData و غیره
ب) به کمک پارامترهای اکشن متدها
ج) با استفاده از ویژگی جدیدی به نام Data Model Binding
یک مثال کاربردی
قصد داریم یک صفحه لاگین ساده را طراحی کنیم تا بتوانیم هر سه حالت ذکر شده فوق را در عمل بررسی نمائیم. بحث HTML Helpers استاندارد ASP.NET MVC را هم که در قسمت قبل شروع کردیم، لابلای توضیحات قسمت جاری و قسمتهای بعدی با مثالهای کاربردی دنبال خواهند شد.
بنابراین یک پروژه جدید خالی ASP.NET MVC را شروع کرده و مدلی را به نام Account با محتوای زیر به پوشه Models برنامه اضافه کنید:
namespace MvcApplication6.Models
{
public class Account
{
public string Name { get; set; }
public string Password { get; set; }
}
}
یک کنترلر جدید را هم به نام LoginController به پوشه کنترلرهای برنامه اضافه کنید. بر روی متد Index پیش فرض آن کلیک راست نمائید و یک View خالی را اضافه نمائید.
در ادامه به فایل Global.asax.cs مراجعه کرده و نام کنترلر پیشفرض را به Login تغییر دهید تا به محض شروع برنامه در VS.NET، صفحه لاگین ظاهر شود.
کدهای کامل کنترلر لاگین را در ادامه ملاحظه میکنید:
using System.Web.Mvc;
using MvcApplication6.Models;
namespace MvcApplication6.Controllers
{
public class LoginController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View(); //Shows the login page
}
[HttpPost]
public ActionResult LoginResult()
{
string name = Request.Form["name"];
string password = Request.Form["password"];
if (name == "Vahid" && password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";
return View("Result");
}
[HttpPost]
[ActionName("LoginResultWithParams")]
public ActionResult LoginResult(string name, string password)
{
if (name == "Vahid" && password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";
return View("Result");
}
[HttpPost]
public ActionResult Login(Account account)
{
if (account.Name == "Vahid" && account.Password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";
return View("Result");
}
}
}
همچنین Viewهای متناظر با این کنترلر هم به شرح زیر هستند:
فایل index.cshtml به نحو زیر تعریف خواهد شد:
@model MvcApplication6.Models.Account
@{
ViewBag.Title = "Index";
}
<h2>
Login</h2>
@using (Html.BeginForm(actionName: "LoginResult", controllerName: "Login"))
{
<fieldset>
<legend>Test LoginResult()</legend>
<p>
Name: @Html.TextBoxFor(m => m.Name)</p>
<p>
Password: @Html.PasswordFor(m => m.Password)</p>
<input type="submit" value="Login" />
</fieldset>
}
@using (Html.BeginForm(actionName: "LoginResultWithParams", controllerName: "Login"))
{
<fieldset>
<legend>Test LoginResult(string name, string password)</legend>
<p>
Name: @Html.TextBoxFor(m => m.Name)</p>
<p>
Password: @Html.PasswordFor(m => m.Password)</p>
<input type="submit" value="Login" />
</fieldset>
}
@using (Html.BeginForm(actionName: "Login", controllerName: "Login"))
{
<fieldset>
<legend>Test Login(Account acc)</legend>
<p>
Name: @Html.TextBoxFor(m => m.Name)</p>
<p>
Password: @Html.PasswordFor(m => m.Password)</p>
<input type="submit" value="Login" />
</fieldset>
}
و فایل result.cshtml هم محتوای زیر را دارد:
@{
ViewBag.Title = "Result";
}
<fieldset>
<legend>Login Result</legend>
<p>
@ViewBag.Message</p>
</fieldset>
توضیحاتی در مورد View لاگین برنامه:
در View صفحه لاگین سه فرم را مشاهده میکنید. در برنامههای ASP.NET Web forms در هر صفحه، تنها یک فرم را میتوان تعریف کرد؛ اما در ASP.NET MVC این محدودیت برداشته شده است.
تعریف یک فرم هم با متد کمکی Html.BeginForm انجام میشود. در اینجا برای مثال میشود یک فرم را به کنترلری خاص و متدی مشخص در آن نگاشت نمائیم.
از عبارت using هم برای درج خودکار تگ بسته شدن فرم، در حین dispose شیء MvcForm کمک گرفته شده است.
برای نمونه خروجی HTML اولین فرم تعریف شده به صورت زیر است:
<form action="/Login/LoginResult" method="post">
<fieldset>
<legend>Test LoginResult()</legend>
<p>
Name: <input id="Name" name="Name" type="text" value="" /></p>
<p>
Password: <input id="Password" name="Password" type="password" /></p>
<input type="submit" value="Login" />
</fieldset>
</form>
توسط متدهای کمکی Html.TextBoxFor و Html.PasswordFor یک TextBox و یک PasswordBox به صفحه اضافه میشوند، اما این For آنها و همچنین lambda expression ایی که بکارگرفته شده برای چیست؟
متدهای کمکی Html.TextBox و Html.Password از نگارشهای اولیه ASP.NET MVC وجود داشتند. این متدها نام خاصیتها و پارامترهایی را که قرار است به آنها بایند شوند، به صورت رشته میپذیرند. اما با توجه به اینکه در اینجا میتوان یک strongly typed view را تعریف کرد، تیم ASP.NET MVC بهتر دیده است که این رشتهها را حذف کرده و از قابلیتی به نام Static reflection استفاده کند (^ و ^).
با این توضیحات، اطلاعات سه فرم تعریف شده در View لاگین برنامه، به سه متد متفاوت قرار گرفته در کنترلری به نام Login ارسال خواهند شد. همچنین با توجه به مشخص بودن نوع model که در ابتدای فایل تعریف شده، خاصیتهایی را که قرار است اطلاعات ارسالی به آنها بایند شوند نیز به نحو strongly typed تعریف شدهاند و تحت نظر کامپایلر خواهند بود.
توضیحاتی در مورد نحوه عملکرد کنترلر لاگین برنامه:
در این کنترلر صرفنظر از محتوای متدهای آنها، دو نکته جدید را میتوان مشاهده کرد. استفاده از ویژگیهای HttpPost، HttpGet و ActionName. در اینجا به کمک ویژگیهای HttpGet و HttpPost در مورد نحوه دسترسی به این متدها، محدودیت قائل شدهایم. به این معنا که تنها در حالت Post است که متد LoginResult در دسترس خواهد بود و اگر شخصی نام این متدها را مستقیما در مرورگر وارد کند (یا همان HttpGet پیش فرض که نیازی هم به ذکر صریح آن نیست)، با پیغام «یافت نشد» مواجه میگردد.
البته در نگارشهای اولیه ASP.NET MVC از ویژگی دیگری به نام AcceptVerbs برای مشخص سازی نوع محدودیت فراخوانی یک اکشن متد استفاده میشد که هنوز هم معتبر است. برای مثال:
[AcceptVerbs(HttpVerbs.Get)]
یک نکته امنیتی:
همیشه متدهای Delete خود را به HttpPost محدود کنید. به این علت که ممکن است در طی مثلا یک ایمیل، آدرسی به شکل http://localhost/blog/delete/10 برای شما ارسال شود و همچنین سشن کار با قسمت مدیریتی بلاگ شما نیز در همان حال فعال باشد. URL ایی به این شکل، در حالت پیش فرض، محدودیت اجرایی HttpGet را دارد. بنابراین احتمال اجرا شدن آن بالا است. اما زمانیکه متد delete را به HttpPost محدود کردید، دیگر این نوع حملات جواب نخواهند داد و حتما نیاز خواهد بود تا اطلاعاتی به سرور Post شود و نه یک Get ساده (مثلا کلیک بر روی یک لینک معمولی)، کار حذف را انجام دهد.
توسط ActionName میتوان نام دیگری را صرفنظر از نام متد تعریف شده در کنترلر، به آن متد انتساب داد که توسط فریم ورک در حین پردازش نهایی مورد استفاده قرار خواهد گرفت. برای مثال در اینجا به متد LoginResult دوم، نام LoginResultWithParams را انتساب دادهایم که در فرم دوم تعریف شده در View لاگین برنامه مورد استفاده قرار گرفته است.
وجود این ActionName هم در مثال فوق ضروری است. از آنجائیکه دو متد هم نام را معرفی کردهایم و فریم ورک نمیداند که کدامیک را باید پردازش کند. در این حالت (بدون وجود ActionName معرفی شده)، برنامه با خطای زیر مواجه میگردد:
The current request for action 'LoginResult' on controller type 'LoginController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult LoginResult() on type MvcApplication6.Controllers.LoginController
System.Web.Mvc.ActionResult LoginResult(System.String, System.String) on type MvcApplication6.Controllers.LoginController
برای اینکه بتوانید نحوه نگاشت فرمها به متدها را بهتر درک کنید، بر روی چهار return View موجود در کنترلر لاگین برنامه، چهار breakpoint را تعریف کنید. سپس برنامه را در حالت دیباگ اجرا نمائید و تک تک فرمها را یکبار با کلیک بر روی دکمه لاگین، به سرور ارسال نمائید.
بررسی سه روش دریافت اطلاعات از کاربر در ASP.NET MVC
الف) استفاده از اشیاء Context
در ویژوال استودیو، در کنترلر لاگین برنامه، بر روی کلمه Controller کلیک راست کرده و گزینه Go to definition را انتخاب کنید. در اینجا بهتر میتوان به خواصی که در یک کنترلر به آنها دسترسی داریم، نگاهی انداخت:
public HttpContextBase HttpContext { get; }
public HttpRequestBase Request { get; }
public HttpResponseBase Response { get; }
public RouteData RouteData { get; }
در بین این خواص و اشیاء مهیا، Request و RouteData بیشتر مد نظر ما هستند. در مورد RouteData در قسمت ششم این سری، توضیحاتی ارائه شد. اگر مجددا Go to definition مربوط به HttpRequestBase خاصیت Request را بررسی کنیم، موارد ذیل جالب توجه خواهند بود:
public virtual NameValueCollection QueryString { get; } // GET variables
public NameValueCollection Form { get; } // POST variables
public HttpCookieCollection Cookies { get; }
public NameValueCollection Headers { get; }
public string HttpMethod { get; }
توسط خاصیت Form شیء Request میتوان به مقادیر ارسالی به سرور در یک کنترلر دسترسی یافت که نمونهای از آنرا در اولین متد LoginResult میتوانید مشاهده کنید. این روش در ASP.NET Web forms هم کار میکند. جهت اطلاع این روش با ASP کلاسیک دهه نود هم سازگار است!
البته این روش آنچنان مرسوم نیست؛ چون NameValueCollection مورد استفاده، ایندکسی عددی یا رشتهای را میپذیرد که هر دو با پیشرفتهایی که در زبانهای دات نتی صورت گرفتهاند، دیگر آنچنان مطلوب و روش مرجح به حساب نمیآیند. اما ... هنوز هم قابل استفاده است.
به علاوه اگر دقت کرده باشید در اینجا HttpContextBase داریم بجای HttpContext. تمام این کلاسهای پایه هم به جهت سهولت انجام آزمونهای واحد در ASP.NET MVC ایجاد شدهاند. کار کردن مستقیم با HttpContext مشکل بوده و نیاز به شبیه سازی فرآیندهای رخ داده در یک وب سرور را دارد. اما این کلاسهای پایه جدید، مشکلات یاد شده را به همراه ندارند.
ب) استفاده از پارامترهای اکشن متدها
نکتهای در مورد نامگذاری پارامترهای یک اکشن متد به صورت توکار اعمال میشود که باید به آن دقت داشت:
اگر نام یک پارامتر، با نام کلید یکی از رکوردهای موجود در مجموعههای زیر یکی باشد، آنگاه به صورت خودکار اطلاعات دریافتی به این پارامتر نگاشت خواهد شد (پارامتر هم نام، به صورت خودکار مقدار دهی میشود). این مجموعهها شامل موارد زیرهستند:
Request.Form
Request.QueryString
Request.Files
RouteData.Values
برای نمونه در متدی که با نام LoginResultWithParams مشخص شده، چون نامهای دو پارامتر آن، با نامهای بکارگرفته شده در Html.TextBoxFor و Html.PasswordFor یکی هستند، با مقادیر ارسالی آنها مقدار دهی شده و سپس در متد قابل استفاده خواهند بود. در پشت صحنه هم از همان رکوردهای موجود در Request.Form (یا سایر موارد ذکر شده)، استفاده میشود. در اینجا هر رکورد مثلا مجموعه Request.Form، کلیدی مساوی نام ارسالی به سرور را داشته و مقدار آن هم، مقداری است که کاربر وارد کرده است.
اگر همانندی یافت نشد، آن پارامتر با نال مقدار دهی میگردد. بنابراین اگر برای مثال یک پارامتر از نوع int را معرفی کرده باشید و چون نوع int، نال نمیپذیرد، یک استثناء بروز خواهد کرد. برای حل این مشکل هم میتوان از Nullable types استفاده نمود (مثلا بجای int id نوشت int? id تا مشکلی جهت انتساب مقدار نال وجود نداشته باشد).
همچنین باید دقت داشت که این بررسی تطابقهای بین نام عناصر HTML و نام پارامترهای متدها، case insensitive است و به کوچکی و بزرگی حروف حساس نیست. برای مثال، پارامتر معرفی شده در متد LoginResult مساوی string name است، اما نام خاصیت تعریف شده در کلاس Account مساوی Name بود.
ج) استفاده از ویژگی جدیدی به نام Data Model Binding
در ASP.NET MVC چون میتوان با یک Strongly typed view کار کرد، خود فریم ورک این قابلیت را دارد که اطلاعات ارسالی یکی فرم را به صورت خودکار به یک وهله از یک شیء نگاشت کند. در اینجا model binder وارد عمل میشود، مقادیر ارسالی را استخراج کرده (اطلاعات دریافتی از Form یا کوئری استرینگها یا اطلاعات مسیریابی و غیره) و به خاصیتهای یک شیء نگاشت میکند. بدیهی است در اینجا این خواص باید عمومی باشند و هم نام عناصر HTML ارسالی به سرور. همچنین model binder پیش فرض ASP.NET MVC را نیز میتوان کاملا تعویض کرد و محدود به استفاده از model binder توکار آن نیستیم.
وجود این Model binder، کار با ORMها را بسیار لذت بخش میکند؛ از آنجائیکه خود فریم ورک ASP.NET MVC میتواند عناصر شیءایی را که قرار است به بانک اطلاعاتی اضافه شود، یا در آن به روز شود، به صورت خودکار ایجاد کرده یا به روز رسانی نماید.
نحوه کار با model binder را در متد Login کنترلر فوق میتوانید مشاهده کنید. بر روی return View آن یک breakpoint قرار دهید. فرم سوم را به سرور ارسال کنید و سپس در VS.NET خواص شیء ساخته شده را در حین دیباگ برنامه، بررسی نمائید.
بنابراین تفاوتی نمیکند که از چندین پارامتر استفاده کنید یا اینکه کلا یک شیء را به عنوان پارامتر معرفی نمائید. فریم ورک سعی میکند اندکی هوش به خرج داده و مقادیر ارسالی به سرور را به پارامترهای تعریفی، حتی به خواص اشیاء این پارامترهای تعریف شده، نگاشت کند.
در ASP.NET MVC سه نوع Model binder وجود دارند:
1) Model binder پیش فرض که توضیحات آن به همراه مثالی ارائه شد.
2) Form collection model binder که در ادامه توضیحات آنرا مشاهده خواهید نمود.
3) HTTP posted file base model binder که توضیحات آن به قسمت بعدی موکول میشود.
یک نکته:
اولین متد LoginResult کنترلر را به نحو زیر نیز میتوان بازنویسی کرد:
[HttpPost]
[ActionName("LoginResultWithFormCollection")]
public ActionResult LoginResult(FormCollection collection)
{
string name = collection["name"];
string password = collection["password"];
if (name == "Vahid" && password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";
return View("Result");
}
در اینجا FormCollection به صورت خودکار بر اساس مقادیر ارسالی به سرور توسط فریم ورک تشکیل میشود (FormCollection هم یک نوع model binder ساده است) و اساسا یک NameValueCollection میباشد.
بدیهی است در این حالت باید نگاشت مقادیر دریافتی، به متغیرهای متناظر با آنها، دستی انجام شود (مانند مثال فوق) یا اینکه میتوان از متد UpdateModel کلاس Controller هم استفاده کرد:
[HttpPost]
public ActionResult LoginResultUpdateFormCollection(FormCollection collection)
{
var account = new Account();
this.UpdateModel(account, collection.ToValueProvider());
if (account.Name == "Vahid" && account.Password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";
return View("Result");
}
متد توکار UpdateModel، به صورت خودکار اطلاعات FormCollection دریافتی را به شیء مورد نظر، نگاشت میکند.
همچنین باید عنوان کرد که متد UpdateModel، در پشت صحنه از اطلاعات Model binder پیش فرض و هر نوع Model binder سفارشی که ایجاد کنیم استفاده میکند. به این ترتیب زمانیکه از این متد استفاده میکنیم، اصلا نیازی به استفاده از FormCollection نیست و متد بدون آرگومان زیر هم به خوبی کار خواهد کرد:
[HttpPost]
public ActionResult LoginResultUpdateModel()
{
var account = new Account();
this.UpdateModel(account);
if (account.Name == "Vahid" && account.Password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";
return View("Result");
}
استفاده از model binderها همینجا به پایان نمیرسد. نکات تکمیلی آنها در قسمت بعدی بررسی خواهند شد.
public class UserModel { [MaxLength(200)] [Display(Name = "Full name")] [Required] public string Name { get; set; } } public class UserModalViewModel { public UserModel Model { get; set; } public bool IsAdmin { get; set; } public IReadonlyList<lookupitem> Roles { get; set; } }
[HttpGet] public async Task<IActionResult> Edit(int id) { var user = await _service.FindAsync(id); //return Maybe<UserModel> if (!user.HasValue) { return NotFound(); } // prepare model var model = new UserModalViewModel { Model = user.Value, IsAdmin = true, Roles = await _lookupService.ReadRolesAsync() }; return View(model); }
[HttPost] public async Task<IActionResult> Edit([Bind(Prefix = "Model")] UserModel model) { //todo: check ModelState and save model await _service.EditAsync(model); }
لازم به ذکر است که انواع دادهای در جاوا اسکریپت شامل 2 نوع میباشند:
1- نوع داده اولیه (Primitive) که شامل Boolean ، Number و Strings میباشند.
2- نوع داده Object که طبق تعریف هر Object مجموعهای از خواص و متدها است.
نوع دادهای اولیه، از نوع Value Type و نوع داده ای Object، از نوع Refrence Type میباشد.
برای تعریف یک شیء (Object) در جاوا اسکریپت، 3 راه وجود دارد:
1 - تعریف و ایجاد یک نمونه مستقیم از یک شیء ( direct instance of an object )
2 – استفاده از function برای تعریف و سپس نمونه سازی از یک شیء ( Object Constructor )
3 – استفاده از متد Object.Create
روش اول :
در روش اول دو راه برای ایجاد اشیاء استفاده میگردد که با استفاده از دو مثال ذیل، این دو روش توضیح داده شدهاند:
مثال اول : (استفاده از new )
<script type=”text/javascript”> var person = new Object(); person.firstname = “John”; person.lastname = “Doe”; person.age = 50; person.eyecolor = “blue”; document.write(person.firstname + “ is “ + person.age + “ years old.”); </script>
result : John is 50 years old.
مثال دوم (استفاده از literal notation )
<script type=”text/javascript”> var obj = { var1: “text1”, var2: 5, Method: function () { alert(this.var1); } }; obj.Method(); </script>
Result : text1
هر دو مثالهای 1 و 2 در روش اول برای ایجاد اشیاء بکار میروند. امکان گسترش دادن اشیاء در این روش و اضافه کردن خواص و متد در آینده نیز وجود دارد. بعنوان مثال میتوان نوشت :
Obj.var3 = “text3”;
حال در این مثال اگر مقدار شی obj را برابر یک شیء دیگر قرار دهیم به نحو زیر :
var newobj = obj; newobj.var1 = "other text"; alert(obj.var1);// other text alert(newobj.var1);// other text
میبینیم که مقدار هر دو متغیر در خروجی یکسان میباشد و این موضوع با ماهیت شیء گرایی که در آن همهی اشیایی که از روی یک الگو نمونه سازی میگردند مشخصههایی یکسان، ولی مقادیر متفاوتی دارند، متفاوت است. البته این موضوع از آنجا ناشی میگردد که اشیاء ایجاد شده در جاوا اسکریپت ذاتا type refrence هستند و به همین منظور برای پیاده سازی الگویی (کلاسی) که بتوان رفتار شیء گرایی را از آن انتظار داشت از روش زیر استفاده میکنیم. برای درک بهتر اسم این الگو را کلاس مینامیم که در روش دوم به آن اشاره میکنیم.
روش دوم :
<script type=”text/javascript”> function Person(firstname, lastname, age, eyecolor) { this.firstname = firstname; this.lastname = lastname; this.age = age; this.eyecolor = eyecolor; } var myFather = new Person("John", "Doe", 50, "blue"); document.write(myFather.firstname + " is " + myFather.age + " years old."); result : John is 50 years old. var myMother=new person("Sally","Rally",48,"green"); document.write(myMother.firstname + " is " + myFather.age + " years old."); result : Sally is 48 years old. </script>
var Person = function (firstname, lastname, age, eyecolor) { this.firstname = firstname; this.lastname = lastname; this.age = age; this.eyecolor = eyecolor; } var myFather = new Person("John", "Doe", 50, "blue"); document.write(myFather.firstname + " is " + myFather.age + " years old."); result : John is 50 years old. var myMother=new person("Sally","Rally",48,"green"); document.write(myMother.firstname + " is " + myFather.age + " years old."); result : Sally is 48 years old.
در اینجا با استفاده از کلمه کلیدی function و در داخل {} کلیه خواص و متدهای لازم را به شیء مورد نظر اضافه میکنیم. استفاده از کلمه this در داخل function به این معنی است که هر کدام از نمونههای object مورد نظر، مقادیر متفاوتی خواهند داشت .
یک مثال دیگر :
<script type="text/javascript"> function cat(name) { this.name = name; this.talk = function() { alert( this.name + " say meeow!" ) } } cat1 = new cat("felix") cat1.talk() //alerts "felix says meeow!" cat2 = new cat("ginger") cat2.talk() //alerts "ginger says meeow!" </Script>
روش سوم :استفاده از متد Object.Create
var myObjectLiteral = { property1: "one", property2: "two", method1: function() { alert("Hello world!"); }} var myChild = Object.create(myObjectLiteral); myChild.method1(); // will alert "Hello world!"
حال برای اضافه کردن متدها و خاصیتهایی به کلاس جاوا اسکریپتی مورد نظر، به طوریکه همهی نمونههایی که از این کلاس ایجاد میشوند بتوانند به این متدها و خاصیتها دسترسی داشته باشند، از مفهومی به اسم prototype استفاده میکنیم. برای مثال کلاس زیر را در نظر بگیرید:
این کلاس یک سیستم ساده امتحانی (quiz ) را پیاده میکند که در آن اطلاعات شخص که شامل نام و ایمیل میباشد گرفته شده و سه تابع، شامل ذخیره نمرات، تغییر ایمیل و نمایش اطلاعات شخص به همراه نمرات نیز به آن اضافه میشود.
function User (theName, theEmail) { this.name = theName; this.email = theEmail; this.quizScores = []; this.currentScore = 0; }
User.prototype = { saveScore:function (theScoreToAdd) { this.quizScores.push(theScoreToAdd) }, showNameAndScores:function () { var scores = this.quizScores.length > 0 ? this.quizScores.join(",") : "No Scores Yet"; return this.name + " Scores: " + scores; }, changeEmail:function (newEmail) { this.email = newEmail; return "New Email Saved: " + this.email; } }
// A User firstUser = new User("Richard", "Richard@examnple.com"); firstUser.changeEmail("RichardB@examnple.com"); firstUser.saveScore(15); firstUser.saveScore(10); document.write(firstUser.showNameAndScores()); //Richard Scores: 15,10 document.write('<br/>'); // Another User secondUser = new User("Peter", "Peter@examnple.com"); secondUser.saveScore(18); document.write(secondUser.showNameAndScores()); //Peter Scores: 18
وراثت (Inheritance) در جاوا اسکریپت :
در بسیاری از مواقع لازم است عملکردی (Functionality) که در یک کلاس تعریف میگردد، در کلاسهای دیگر نیز در دسترس باشد. بدین منظور از مفهوم وراثت استفاده میشود. در نتیجه کلاسها میتوانند از توابع خود و همچنین توابعی که کلاسهای والد در اختیار آنها میگذارند استفاده کنند. برای این منظور چندین راه حل توسط توسعه دهندگان ایجاد شده است که در ادامه به چند نمونه از آنها اشاره میکنیم.
سادهترین حالت ممکن از الگویی شبیه زیر است:
<script type="text/javascript"> function Base() { this.color = "blue"; } function Sub() { } Sub.prototype = new Base(); Sub.prototype.showColor = function () { alert(this.color); } var instance = new Sub(); instance.showColor(); //"blue" </Script>
راه حل دیگری نیز برای اینکار وجود دارد که الگویی است بنام Parasitic Combination :
در این الگو براحتی و با استفاده از متد Object.create که در بالا توضیح داده شد، هر کلاسی که ایجاد میکنیم، با انتساب آن به یک شیء جدید، کلیه خواص و متدهای آن نیز توسط شیء جدید قابل استفاده میشود.
<script language="javascript" type="text/javascript"> if (typeof Object.create !== 'function') { Object.create = function (o) { ایجاد یک کلاس خالی که قرار است خواص کلاس دریافتی توسط آرگومان کلاس پایه را به ارث ببرد// function F() { } با ارث برده شود F باعث میشویم کلیه خواص و متدهای دریافتی توسط Prototype توسط خصوصیت F با انتساب آرگومان دریافتی که یک شی است به کلاس F.prototype = o; return new F(); }; } var cars = { type: "sedan", wheels: 4 }; // We want to inherit from the cars object, so we do: var toyota = Object.create(cars); // now toyota inherits the properties from cars document.write(toyota.type); </script> output :sedan
برای مطالعه بیشتر :
http://eloquentjavascript.net/chapter8.html
http://phrogz.net/JS/classes/OOPinJS2.html
تغییرات Web API در دات نت 8
Preview 3 of .NET 8 includes a new project templates to create an API with a TODO service instead of the weather forecast . Looking into the generated code of this template, there are a lot more changes going on such as a slim builder and using a JSON source generator which helps when using AOT to create native .NET binaries. This article looks into the changes coming.
کار با یک مخزن کد GitHub از طریق VSCode
git config --global user.email "you@example.com" git config --global user.name "Your Name"
, What Every JavaScript Developer Should Know About ECMAScript 2015 is the book I'd like to read about the new features in the JavaScript language. The book isn't a reference manual or an exhaustive list of everything in the ES2015 specification. Instead, I purposefully selected what I think are the important features we will use in everyday programming.
PdfRpt-1.9.zip
- Updated the project to use iTextSharp 5.4.1.0. - Updated the project to use EPPlus 3.1.3. EPPlus 3.1.3 has a reference to System.Web for Uri decoding. So to use PdfReport from now on you need to change your project's target framework to full profile instead of the client profile. - Added FlushType parameter to FlushInBrowser method. FlushType.Inline displays PDF in the browser instead of showing the download popup. - Added EFCodeFirstMvc4Sample. - Added PdfFilePrinter sample. - Fixed `StartIndex cannot be less than zero` exception when parameter values are defined without defining the actual parameters in SQL data sources.