آموزش جامع و کاربردی ASP.NET MVC5

آموزش ASP.NET MVC5 – فصل1 – بخش1
درباره معماری MVC و معرفی کنترولر و اکشن
مقدمه معماری ASP.NET-MVC:
سلام دوستان . در این سری آموزشی قصد داریم شما را با دنیای بی انتهای Asp.net MVC 5 آشنا کنیم . در این سری آموزشی سعی داریم تمامی مطالب مهم و کاربردی این مبحث را بیان کنیم .
مفهوم معماری MVC :
MVC مخفف کلمات Model-View-Controller می باشد . ما قبلا فقط asp.net webform داشتیم ولی با آمدن mvc به دنیای دات نت asp.net به دو بخش webform و mvc تقسیم می شود .
ASP.NET webform بصورت Event Driven است مانند windows application ها . یعنی بعنوان مثال با کلیک روی button به رویداد onClick دکمه می رویم . ولی نحوه کار کردن mvc بر اساس معاری Model-View-Controller می باشد .
معماری mvc مفهوم جدیدی در دنیای برنامه نویسی نیست . بلکه از سال 1956 بوجود آمد . اولین بار نیز در زبان برنامه نویسی جاوا بحث mvc مطرح شد (Spring mvc) سپس در PHP بیان شد و چند سالی است که مایکروسافت مفهوم mvc را به دنیای دات نت وارد کرده است .
معماری MVVM:
معماری دیگری وجود دارد بنام MVVM که مخفف کلمات Model-View-View-Model می باشد که معماری برنامه های تحت ویندوز یا دسکتاپی می باشد .
مقایسه معماری ها از لحاظ آدرس سایت در مرورگر :
اگر بخواهیم از لحاظ آدرس وب سات در مروگر نیز مقایسه کنیم بدین صورت می باشد که اگر آدرس مرورگر به نام صفحه ختم شود معماری کلاسیک دارد و اگر بصورت مثلا www.EhsanSafari.com/product/cat/12 ختم شود از معماری mvc بهره می برد . ولی مشخص نیست با چه زبان برنامه نویسی نوشته شده است (PHP یا ASP Classic یا ASP.NET یا Java)
مثلا :
- اگر url مرورگر به asp ختم شود تکنولوژی asp کلاسیک دارد
- اگر به php ختم شود php classic
- اگر به jsp ختم شود جاوا کلاسیک
مفهوم Controller و Action :
دو مفهوم مهم کنترلر و اکشن را با یک مثال توضیح می دهیم :
به آدرس www.EhsanSafari.com/user/list دقت کنید . user نام controller است و list نیز action می باشد . (یعنی میخواهم در کنترلر user اکشن یا تابع list را فراخوانی کنی)
کنترلر یک کلاس است که از System.web.MVC.Controller ارث می برد . مانند page در asp.net webform که از کتابخانه System.web.UI.page ارث می برد(inherit) .
در mvc به توابع داخل کلاس Controller اکشن می گویند (یک function است) .
اگر علاوه بر دو پارامتر فوق در url پارامتر دیگری داشتیم ID می باشد . در مثال فوق داریم : www.EhsanSafari.com/user/list/12
بدین صورت تفسیر میشود که برو از اکشن list واقع در کنترلر user اطلاعات کاربری را که آیدی آن 12 می باشد را استخراج کن .
اکنون نوبت آنست که نرم افزار قدرتمند ویژوال استودیو را نصب کرده و اولین پروژه mvc5 را ایجاد کنیم.
نصب ویژوال استودیو و ایجاد اولین پروژه MVC
نصب ویژوال استودیو 2013:
برای شروع کار ابتدا باید نرم افزار ویژوال استودیو 2013 (Visual Studio 2013) را نصب کنید .
نکته : همانطور که در بخش قبل دیدیم قصد داریم در این سری آموزشی ، MVC5 را یاد بگیریم . بنابراین باید ویژوال استودیو 2013 را نصب کنیم . اگر نسخه 2012 را از قبل نصب داریم می توانیم آنرا پاک کرده و نسخه 2013 را نصب کنیم . ویژوال استودیو 2012 معماری mvc4 را ساپورت میکند .
ایجاد پروژه MVC5:
سپس به منوی file رفته و از منوی new گزینه project را انتخاب میکنیم (File>New>Project) . در پنجره ای که ظاهر می شود در منوی Visual c# و زیر منوی web کلیک کرده (دقت کنید که وارد زیرمنوی web نمی شویم) و Asp.net Web Application را انتخاب مینماییم و همچنین ورژن .net framework را از لیست بازشوی بالا روی net 4.5 انتخاب کرده و سپس مسیر ذخیره پروژه را بیان میکنیم و در نهایت دکمه OK را میزنیم . (مطابق تصویر زیر)
اکنون در پنجره جدید (تصویر زیر) گزینه Empty را انتخاب کرده و در قسمت پایین گزینه MVC را تیک زده و نهایتا ok میکنیم .(برای شروع کار Empty بهترین گزینه است)
در بخش بعد میخواهیم یک کنترولر بسازیم و یک اکشن تعریف کنیم و آنرا بدون پارامتر ورودی و خروجی صدا بزنیم.
تعریف کنترولر و اکشن در پروژه ASP.NET-MVC
تا بدین جا با مفهوم معماری MVC آشنا شده ایم و سپس ویژوال استودیو را نصب کردیم و اولین پروژه MVC را ایجاد کردیم . اکنون با تصویر زیر مواجه هستیم :
کنترولر یک کلاس می باشد که باید حتما در فولدر Controllers ایجاد شود .
قوانین ایجاد کنترولر:
همانطور که ذکر شد کنترولر باید در فولدر Controllers ساخته شود و همچنین باید به نام Controller ختم شود یعنی اگر ما کنترولری میخواهیم با نام Home باید نام کلاس آن را HomeController قرار دهیم . برای شروع کار ابتدا روی فولدر Controllers راست کلیک کرده و زیرمنوی Add و سپس Controller را میزینیم . در پنجره ای که ظاهر می شود نام کنترولر را میدهیم . چون اولین کنترولر پروژه است باید نام آنرا HomeController قرار دهیم . هم اکنون یک کلاس ایجاد شده است که میتوانیم اکشن های دلخواه خود را در آن تعریف کنیم . اکشن Index پیش فرض است و با ایجاد هر کنترولر یک اکشن Index نیز اتوماتیک ساخته می شود .
نکته: لطفا توجه داشته باشید که نام Home در کنترولرها نیز پیش فرض است یعنی با اجرای برنامه-زدن کلید F5 پروژه با اکشن ایندکس از کنترولر Home شروع بکار میکند. بعنوان مثال : http://localhost:7538/Home/Index
اکنون کنترولر Home بصورت تصویر زیر می باشد :
همانطور که مشاهده می کنید اکشن Index نه پارامتری میگیرد (void) نه پارامتری ارسال میکند .
در بخش چهارم از این بخش، اکشن هایی تعریف میکنیم که پارامتر ورودی میگیرند.
تعریف اکشن با پارامتر ورودی در ASP.NET-MVC
1- ارسال عدد int بعنوان پارامتر:
در اکشن Learn1010 پارامتر id بصورت int عددی تعریف شده است .بصورت زیر :
public void Learn1010(int id) { // Do Something }
با توجه به اینکه Primitive type است نمیتواند خالی یا null باشد پس اگر در مرورگر بنویسیم http://localhost:30847/Home/Learn1010 با خطا روبرو میشویم .
نام id پیش فرض است یعنی اگر نام پارامتر ورودی را id قرار دهیم میتوانیم در هنگام فراخوانی نام id را ننویسیم و فقط با یک / مقدار id را وارد کنیم ولی اگر نام دیگری داشته باشد باید حتما نام پارامتر را وارد کنیم .
2- ارسال پارامتر عددی بنام number:
اکشن دیگری تعریف می کنیم بنام Learn1020 و نام پارامتر آنرا number میگذاریم .
public void Learn1020(int number)
{
// Do Something
}
روشهای فراخوانی اکشن Learn1020:
اگر آدرس را به دو صورت زیر بنویسیم با خطا مواجه می شویم :
http://localhost:30847/Home/Learn1020 http://localhost:30847/Home/Learn1020/15
ولی دو آدرس زیر صحیح (Valid) می باشد :
http://localhost:30847/Home/Learn1020?number=15 http://localhost:30847/Home/Learn1020?Number=15
نکته آدرس دوم : نام پارامتر حساس به حروف بزرگ و کوچک نیست (Case Sensitive) مثلا number همان Number است .
3- ارسال دو پارامتر عددی در اکشن:
اکشن دیگری بنام Learn1030 تعریف میکنیم و دو پارامتر عددی num1 و num2 را ارسال میکنیم :
public void Learn1030(int num1, int num2) { // Do Something… }
روشهای فراخوانی اکشن Learn1030:
در صورتی که آدرس بصورت زیر باشد Error میدهد :
http://localhost:30847/Home/Learn1030 http://localhost:30847/Home/Learn1030/15 http://localhost:30847/Home/Learn1030?firstNumber=15
علت غلط بودن آدرسهای اول و دوم که در بالا گفته شد . در آدرس سوم هم چون فقط یکی از دو پارامتر مقداردهی شده است ارور میدهد . ولی آدرسهای زیر معتبر هستند :
http://localhost:30847/Home/Learn1030?firstNumber=15&secondNumber=20 http://localhost:30847/Home/Learn1030?secondNumber=20&firstNumber=15
نکته : ترتیب مقدار دادن به پارامترها اهمیت ندارد (روش دوم)
4- ارسال دو پارامتر عددی بنامهای id و number:
اکشن بعدی Learn1040 است که بصورت زیر تعریف شده است :
public void Learn1040(int id, int number) { // Do Something… }
روشهای فراخوانی اکشن Learn1040:
اگر به روشهای زیر اکشن فوق را فراخوانی کنیم با error روبرو می شویم :
http://localhost:30847/Home/Learn1040 http://localhost:30847/Home/Learn1040/15
و روشهای زیر درست است :
http://localhost:30847/Home/Learn1040/15?number=20 http://localhost:30847/Home/Learn1040?id=15&number=20 http://localhost:30847/Home/Learn1040?number=20&id=15
روش اول شیکتر است ! با توجه به اینکه نام یکی از پارامترها id می باشد میتوان آنرا ننوشت و فقط نام پارامتر بعدی را قید کرد .
5- ارسال پارامتر عددی بصورت Nullable:
اکشن Learn1050 بصورت زیر است:
public void Learn1050(int? number) { // Do Something… }
روشهای فراخوانی اکشن Learn1050:
پارامتر عددی این اکشن بصورت Nullable تعریف شده است (?int) پس می توانیم به آن عددی نسبت دهیم میتوانیم ندهیم . تمام روشهای زیر درست می باشند :
http://localhost:30847/Home/Learn1050 http://localhost:30847/Home/Learn1050?number=15 http://localhost:30847/Home/Learn1050/15
6- ارسال پارامتر رشتهای (string):
اکشن Learn1060 پارامتر رشته ای می گیرد :
public void Learn1060(string name) { // Do Something… }
روشهای فراخوانی اکشن Learn1060:
http://localhost:30847/Home/Learn1060 http://localhost:30847/Home/Learn1060/Something http://localhost:30847/Home/Learn1060?name=Something
چون رشته می تواند null باشد (Reference Type است) به مشکلی برخورد نمیکنیم .
7- ارسال پارامتر رشته ای بنام id:
در اکشن بعدی (Learn1070) پارامتر رشته ای بنام id تعریف شده است . پس می توان نام آنرا در آدرس ننوشت :
public void Learn1070(string id) { // Do Something… }
روشهای فراخوانی اکشن Learn1070:
http://localhost:30847/Home/Learn1070 http://localhost:30847/Home/Learn1070/Something http://localhost:30847/Home/Learn1070?id=Something
مشخص است که روش دوم شیک تر است !
8- ارسال پارامتر رشته ای با مقدار پیشفرض:
اکشن آخر هم نکته جالبی دارد . اگر به پارامتر name مقداری اختصاص داده نشود مقدار پیش فرض مثلا * را در name میریزد :
public void Learn1080(string name = "*") { // Do Something… }
روشهای فراخوانی اکشن Learn1080:
روشهای زیر همگی درست می باشند و error نمیدهند :
http://localhost:30847/Home/Learn1080 -> name = “*” http://localhost:30847/Home/Learn1080/Something -> name = "*" http://localhost:30847/Home/Learn1080?name=Something -> name = "Something"
در روش اول چون مقداری داده نشده name مقدار پیش فرض * را میگیرد .
در روش دوم چون نام پارامتر ذکر نشده ، دنبال id میگردد و چون نام پارامتر id نمی باشد name مجددا * میشود
در روش سوم که مقدار name صراحتا تعیین شده است .
امیدوارم استفاده لازم را از این مقاله برده باشید . برای اطلاعات بیشتر در این زمینه به وبلاگ asp.net مراجعه کنید .
با بخش دوم از جلسه اول آموزش MVC همراه ما باشید…!
آموزش ASP.NET MVC5 – فصل1 – بخش2
در بخش قبل با معماری قدرتمند MVC آشنا شدیم و مفهوم کنترولر و اکشن را یاد گرفتیم و آنها را با پارامترهای ورودی عددی (INT) و رشته ای (String) فراخوانی کردیم.
در این مقاله قصد داریم اکشن در MVC را بیشتر مورد بررسی و تحلیل قرار دهیم و مثال های دیگری در این زمینه مشاهده کنیم.
شرایط اکشن بودن تابعی در کنترولر
تعریف Access Modifier:
لزوما هر تابعی در کنترولر ، اکشن نیست . بعنوان مثال اگر Access Modifier تابع را private یا protected یا internal تعریف کنیم آن تابع دیگر اکشن نیست . مانند توابع زیر :
private void NonAction1() { // Do Something… } protected void NonAction2() { // Do Something… } internal void NonAction3() { // Do Something… } protected internal void NonAction4() { // Do Something… }
تعریف اتریبیوت NonAction:
ممکنه گاهی خود تابع اکشن باشد و public باشد ولی در بالای آن ، attribute NonAction تعریف کنیم . بنابراین آن تابع هم اکشن نیست . مانند تابع زیر :
[System.Web.Mvc.NonAction] public void NonAction5() { // Do Something… }
نکته کلی : تابعی اکشن است که اولا public باشد و دوما اتریبیوت NonAction هم نداشته باشد .
تغییر نام اکشن :
اگر بخواهیم نام اکشن را توسط اتریبیوت تغییر دهیم داریم :
[System.Web.Mvc.ActionName(“SafariAction”)] public void Learn1100() { // Do Something… }
از این پس نام اکشن Learn1100 به SafariAction تغییر کرده است . مفهوم Routing یا Mapping نیز همین است . برای اطلاعات بیشتر به وب سایت asp.net مراجعه شود .
در بخش بالا دیدیم که چگونه می توان یک تابعی را به اکشن تبدیل کرد و یا تابعی را از حالت اکشن بودن خارج کرد و نیز چگونه نام اکشن را تغییر دهیم . در بخش بعدی می خواهیم خروجی رشته را برای یک اکشن تعریف کنیم.
خروجی رشته (string) برای اکشن (action)
تعریف string بجای void:
در این بخش قصد داریم برای اکشن ها خروجی رشته تعریف کنیم . پس دیگر قبل از نام تابع void نداریم و string مینویسیم :
public string Learn1110() { return ("Mohtavaban.com Website is provided by Safari"); }
تعریف ContentResult بعنوان خروجی اکشن:
توصیه : برای تعریف خروجی رشته بهتر است نوع خروجی را string نگذاریم و System.Web.Mvc.ContentResult قرار دهیم :
public System.Web.Mvc.ContentResult Learn1120() { return (Content("Mohtavaban.com Website is provided by Safari")); }
خروجی هر دو اکشن یکی است . اگر مطمئن باشیم خروجی تابع ، رشته است میتوان از مثال فوق استفاده کرد وگرنه در صورتی که خروجی تابع مشخصا رشته نباشد یعنی شاید نوع دیگری باشد باید خروجی اکشن را بصورت System.Web.Mvc.ActionResult تعریف کنیم .
تگ html بعنوان خروجی اکشن:
در ضمن می توانیم در رشته خروجی تگ html نیز بنویسیم :
public System.Web.Mvc.ContentResult Learn1140() { return (Content("EhsanSafari.com")); }
پیام خطایی نمی دهد ولی از لحاظ امنیتی وب سایت را دچار تهدید می کند . برای جلوگیری از این مشکل امنیتی باید از Server.HtmlEncode استفاده کنیم :
public System.Web.Mvc.ContentResult Learn1150() { string strContent = Server.HtmlEncode("EhsanSafari.com"); return (Content(strContent)); }
شایان ذکر است که HtmlEncode مختص MVC نیست . بلکه در ASP.NET webform نیز وجود داشت.
در بخش بعدی بیان می کنیم که چگونه می توان از یک اکشن به اکشن دیگری ریدایرکت کنیم (مانند Response.Redirect که در webform وجود داشت).
ریدایرکت از اکشنی به اکشن دیگر
استفاده از RedirectToAction:
اگر بخواهیم به یک اکشن در کنترولر جاری برویم فقط لازم است نام اکشن را بنویسیم :
RedirectToAction(actionName: "Action1")
ولی اگر اکشن مقصد در کنترولر دیگری باشد باید نام کنترولر را نیز بنویسیم :
RedirectToAction(controllerName: "Home", actionName: "Action2")
مثال ریدایرکت اکشن:
اکشن کلی بصورت زیر است :
public System.Web.Mvc.ActionResult Learn1160(int id) { switch (id) { case 1: { return (RedirectToAction(actionName: "Action1")); } case 2: { // Solution (1) // ی در همین کنترلر برویم Action اگر بخواهیم به return (RedirectToAction(actionName: "Action2")); // /Solution (1) // Solution (2) // ی در کنترلر دیگری برویم Action اگر بخواهیم به return (RedirectToAction(actionName: "Action2", controllerName: "Home")); // /Solution (2) // Solution (3) return (RedirectToAction(controllerName: "Home", actionName: "Action2")); // /Solution (3) } default: { string strContent = "Id value is not valid!"; return (Content(strContent)); } } }
در اکشن فوق id ورودی را بررسی می کنیم . با شرایطی خاص به Action1 میرویم و با شرایطی دیگر به Action2 .
ریدایرکت اکشن بدون ذکر نام پارامتر:
میتوانستیم دستور فوق را بدون ذکر نام پارامتر بنویسیم (بصورت زیر) :
RedirectToAction("Home","Action2")
پیش فرض تابع ، اولین پارامتر ActionName است و دومی ControllerName . ولی اگر نام پارامترها را هم بنویسیم بهتر است . چرا که می توانیم جای آن دو را با هم جابجا کنیم .
کاربرد دستور RedirectPermanent برای ریدایرکت:
علاوه بر دستور RedirectToAction دستور دیگری داریم بنام RedirectPermanent که در مبحث سئو کاربرد دارد . برای جا افتادن مطلب به مثال زیر دقت کنید : فرض کنید یک اکشن ای داریم بنام AboutUs که مثلا 6 ماه است که طراحی شده و تمام موتورهای جستجو آنرا ایندکس کرده اند . اکنون تصمیم گرفته ایم نام آنرا تغییر دهیم به نام About . برای اینکه مثلا گوگل صفحه قبلی من را گم نکند باید یک اکشنی بسازیم بنام About و در اکشن قبلی یعنی AboutUs دستور زیر را بنویسیم تا هر وقت ربات های جستجوی گوگل به این اکشن رسیدند اتوماتیک و برای همیشه به اکشن About ریدایرکت شوند :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ActionResult AboutUs() { return (RedirectPermanent(url: "About")); } }
در بخش بعد میخواهیم وقتی به اکشنی ریدایرکت میکنیم به آن اکشن پارامتر نیز ارسال کنیم .
ارسال پارامتر ورودی بهنگام ریدایرکت اکشن
پارامتر ورودی در اکشن مقصد:
اگر اکشن مقصد (اکشنی که میخواهیم به آن ریدایرکت شویم) دارای پارامتر ورودی باشد باید بصورت زیر عمل کنیم :
اکشن ما در این مثال دارای دو پارامتر firstNumber و secondNumber است . برای ریدایرکت شدن به این اکشن باید از anonymous object استفاده کنیم .
اینگونه تعریف میشود :
routeValues: new { param1 = x1 , param2 = x2 }
اکشن مبدا و مقصد برای ریدایرکت:
پس اکشن مبدا ما بصورت زیر تعریف می شود :
public System.Web.Mvc.ActionResult Learn1170() { return (RedirectToAction(actionName: "Action3", routeValues: new { firstNumber = 10, secondNumber = 20 })); }
و اکشن مقصد نیز بصورت زیر است :
public System.Web.Mvc.ActionResult Action3(int firstNumber, int secondNumber) { string strResult = string.Format("First Number: {0}, Second Number: {1}", firstNumber, secondNumber); return (Content(strResult)); }
نکته : اگر هنگام ریدایرکت شدن به اکشن مقصد دقیقا تعداد پارامترها و نام آنها مشخص نباشد(بعنوان مثال بخواهیم از اکشن های مختلف ، اکشن مقصد را با پارامترهای مختلف صدا بزنیم) باید از متغیر TempData استفاده کنیم . در بخش بعد با TempData آشنا خواهیم شد.
معرفی و استفاده از TempData در MVC
کاربرد متغیر TempData:
در بخش قبل ، نحوه ریدایرکت به اکشن بهمراه ارسال پارامتر را یاد گرفتیم . با توجه به سناریوی گفته شده در بخش نهایی از این مقاله میخواهیم پارامترهای مختلفی را با نام های گوناگون به اکشن مقصد بفرستیم .
TempData مانند Session در ASP.NET webform عمل میکند . در اکشن مبدا داریم :
public System.Web.Mvc.ActionResult Learn1180() { TempData[“MyNumber”] = 10; return (RedirectToAction(actionName: "Action4")); }
در اکشن Learn1180 اکشن مقصد را با پارامتر MyNumber صدا زدیم و ریدایرکت شدیم . ممکن است در اکشنی دیگر (Learn1190 ) بخواهیم اکشن مقصد را با متغیر دیگری مانند MyName صدا بزنیم :
public System.Web.Mvc.ActionResult Learn1190() { TempData[“MyName”] = "Ehsan Safari"; return (RedirectToAction(actionName: "Action4")); }
و در اکشن مقصد (Action4) پارامترهای فوق را بررسی میکنیم . اگر خالی نبودند آنرا چاپ میکنیم :
public System.Web.Mvc.ActionResult Action4() { string strResult = string.Empty; if (TempData[“MyNumber”] != null) { int intMyNumber = System.Convert.ToInt32(TempData[“MyNumber”]); strResult = string.Format("My Number is {0}", intMyNumber); } if (TempData[“MyName”] != null) { string strMyName = TempData[“MyName”].ToString(); strResult = string.Format("My Name is {0}", strMyName); } return (Content(strResult)); }
نکته : متغیر TempData عمر محدودی دارد یعنی مثلا متغیر MyNumber تا وقتی که خروجی به کاربر نمایش داده نشده است زنده می ماند ! بعد از آن null می شود.
نگهداری مقدار TempData توسط دستور Keep :
برای نگهداری مقدار قبلی tempdata از دستور keep استفاده میکنیم . برای روشن شدن مطلب به مثال زیر توجه کنید :
دو اکشن به نامهای Learn 1190 و Learn1200 داریم که در اولی از keep استفاده نکردیم :
public System.Web.Mvc.ContentResult Learn1190() { if (TempData[“MyNumber”] == null) { TempData[“MyNumber”] = 10; } else { TempData[“MyNumber”] = (int)TempData[“MyNumber”] + 1; } return (Content(TempData[“MyNumber”].ToString())); }
با هر بار refresh شدن صحه مروگر مقدار MyNumber برابر با null می شود و دوباره مقدار 10 میگیرد . در اکشن دومی یعنی Learn1200 از دستور keep استفاده کرده ایم :
public System.Web.Mvc.ContentResult Learn1200() { if (TempData[“MyNumber”] == null) { TempData[“MyNumber”] = 10; } else { TempData[“MyNumber”] = (int)TempData[“MyNumber”] + 1; } //TempData.Keep(); TempData.Keep("MyNumber"); return (Content(TempData[“MyNumber”].ToString())); }
بنابراین با هر بار بارگذاری صفحه مقدار قبلی در MyNumber می ماند و هر بار یکواحد به مقدار قبلیش اضافه می شود .
نکته : می توان بعنوان مثال یک متغیر بنام age در اکشنی تعریف کنیم و آنرا keep کنیم و در اکشن دیگری از آن استفاده کنیم . به مثال زیر توجه کنید :
در اکشن Learn1210 متغیر age را در TempData تعریف کرده و آنرا keep میکنیم :
public System.Web.Mvc.ContentResult Learn1210() { TempData[“Age”] = 10; TempData.Keep("Age"); return (Content(TempData[“Age”].ToString())); }
و در اکشن دوم Learn1220 آن متغیر نگهداری شده یعنی Age را چاپ میکنیم :
public System.Web.Mvc.ContentResult Learn1220() { if (TempData[“Age”] == null) { return (Content("Undefined!")); } else { return (Content(TempData[“Age”].ToString())); } }
در بار اولی که این اکشن اجرا می شود شرط if برابر false است و اجرا نمیشود و به else میرود . در بار دوم به بعد چون آن متغیر را keep نکرده ایم مقدارش null میشود و شرط if برابر true میشود . برای کسب اطلاعات بیشتر به وب سایت asp.net مراجعه شود .
آموزش ASP.NET MVC5 – فصل1 – بخش3
در بخش دوم از فصل اول مواردی مانند: شرایط اکشن بودن یک تابع، نحوه تغییر نام یک اکشن، تعریف خروجی رشته (string) برای اکشن، ریدایرکت از اکشنی به اکشن دیگر و غیره را بررسی کردیم. در این بخش ارسال درخواست Http به سرور توسط متدهای Get و Post، تعریف دو اکشن با نام یکسان در یک کنترولر و … را آموزش می دهیم.
ارسال درخواست Http به سرور توسط متدهای Get و Post
ورژن قبلی HTTP 1.0 بود که دو مدل مهم Request به سمت سرور داشت که Get و Post بود . ورژن حال حاضر HTTP 1.1 است که معروفترین Request های آن از سمت server عبارتند از : Get-Post-Put-Delete
ارسال Request به سرور به صورت Get:
چه مواقعی بصورت Get به سرور درخواست میفرستیم ؟
- در مواقعی که آدرس سایت را بصورت دستی در نوار آدرس مرورگر وارد کرده و Enter را میزنیم .
- وقتی روی یک لینک کلیک میکنیم و به سایت دیگری میرویم .
- وقتی در تگ Form متد آنرا Get تعریف کنیم (بصورت پیش فرض Post می باشد) .
در مواقعی که در تگ فرم (Form) متد را بصورت پیش فرض Post قراردهیم و یک دکمه Submit داشته باشد و روی ان کلیک کنیم . اطلاعات فرم بصورت متد post به سرور ارسال میشود .
ویژگیهای متد Get:
در HTTP 1.0 متد get دارای محدودیت 255 کاراکتر دارد و بیش از 255 کاراکتر را نمیتوان به سرور فرستاد .
در HTTP 1.1 محدودیت get به 2048 کاراکتر افزایش یافت ولی با اینحال توصیه نمیشود متد فرم (مثلا ثبت نام کاربران) را get قرار دهیم .
اگر متد فرمی را get قرار دهیم پس از submit کردن فرم و ارسال به سرور ، در آدرس بار مروگر تمام اطلاعات و فیلدهای پر شده کاربر نمایش داده می شود(بعنوان مثال http://mohtavaban.com/username=ehsan&password=12345)
از این پس در این مقاله آموزشی ، در بالای هر اکشن متد ارسالی را به صراحت بیان میکنیم (بصورت Attribute)
اکنون به دو اکشن زیر دقت کنید :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ContentResult Learn1230() { return (Content("Hello World!")); } [System.Web.Mvc.HttpPost] public System.Web.Mvc.ContentResult Learn1240() { return (Content("Hello World!")); }
در اکشن اول متد را get تعریف کرده ایم پس میتوان این اکشن را در آدرس بار مرورگر تایپ کنیم و نتیجه را ببینیم .
ارسال درخواست توسط متد Post:
در اکشن دوم متد بصورت post تعریف شده است بنابراین اگر آدرس آنرا (مثلا بصورت http://mohtavaban.com/Home/Learn1240) در آدرس بار تایپ کنیم با خطای Http Not Found مواجه می شویم . و برای اجرای این اکشن و تست آن باید حتما یک فرم طراحی کنیم که متد آن post باشد که بعد از submit کردن فرم به این اکشن بیاییم .
نکته : نوشتن هر دوی متدهای post و get بی معنی است . اگر Attribute را در بالای اکشن تعریف نکنیم ، پیش فرض آن get است .برای آشنایی بیشتر با متدهای get و post به وب سایت mvc4beginner مراجعه شود .
در بخش بعد خواهیم دید که چگونه میتوان دو اکشن با نام های یکسان در یک کنترولر تعریف کرد .
تعریف دو اکشن با نام یکسان در یک کنترولر
دو تابع با نام یکسان و پارامتر ورودی متفاوت:
در مبحث Object Oriented میتوان دو تابع تعریف کرد با نام یکسان و Signature (پارامتر ورودی) متفاوت . اما در MVC اگر دو اکشن زیر را تعریف و اجرا کنیم پیغام خطا میدهد :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ActionResult Learn1270() { return (Content("Hello World!")); } [System.Web.Mvc.HttpGet] public System.Web.Mvc.ActionResult Learn1270(string name) { return (Content("Hello World!")); }
با اینکه اکشن دوم پارامتر ورودی میگیرد و اکشن اول پارامتری ندارد اگر در مرورگر آدرس زیر را وارد کنیم خطا میدهد چون مشخص نیست اکشن اول را صدا زدیم یا دوم را !
http://Mohtavaban.com/Home/Learn1270
تعریف اکشن ها بصورت Get و Post:
برای حل این مشکل یک روش اینست که یکی از اکشن ها را بصورت get تعریف کنیم یکی را post . بنابراین دو اکشن Learn1280 که در ذیل آمده با خطایی روبرو نمیشوند :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ActionResult Learn1280() { return (Content("[GET] Hello World!")); } [System.Web.Mvc.HttpPost] public System.Web.Mvc.ActionResult Learn1280(string name) { return (Content("[POST] Hello World!")); }
استفاده از اتریبیوت ActionName:
روش دیگر اینست که با اتریبیوت ActionName نام اکشن دوم را تغییر بدهیم . در مثال زیر هم نام اکشن ها یکیست هم متدهای آنان . ولی با اتریبیوت مذکور مشکل را حل کرده ایم :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ActionResult Learn1290() { return (Content("[GET] Hello Ehsan !")); } [System.Web.Mvc.HttpGet] [System.Web.Mvc.ActionName(“Learn_Mohtava”)] public System.Web.Mvc.ActionResult Learn1290(string name) { return (Content("[GET] Hello Safari !")); }
برای کسب اطلاعات بیشتر به وب سایت asp.net مراجعه شود . در بخش بعد با مفهوم کش cache آشنا می شویم .
مفهوم کش (Cache) در ASP.NET MVC5
کاربرد Cache در وب سایت:
سناریو : فرض کنید شما یک وب سایتی طراحی کرده اید که در صفحه آن تیتر روزنامه های کشور را نمایش میدهید و نیز وب سایت شما روزی یک میلیون نفر بازدیدکننده دارد . یعنی روزی یک میلیون بار باید به دیتابیس جهت بازیابی داده مراجعه شود . با توجه به اینکه تیتر روزنامه ها هر صبح به صبح تغییر میکند و نیازی نیست که هر ثانیه آپدیت شود باید دستوری بنویسیم که هر روز صبح به دیتابیس مراجعه کند و دیتای لازم را fetch کند . در اینگونه موارد از مفهوم کش(caching) استفاده میکنیم .
افزودن Cache به اکشن در MVC :
بدین منظور باید یک اتریبیوت(Attribute) به بالای اکشن اضافه کنیم :
[System.Web.Mvc.OutputCache(Duration = 10)]
پارامتر Duration مدت زمان کش شدن به واحد ثانیه است . مثلا اگر میخواهیم هر یکساعت یکبار اطلاعات از دیتابیس خوانده شود باید 24*60*60 ثانیه نوشته شود .
در مثال زیر هر ده ثانیه یکبار زمان نمایش داده شده در صفحه تغییر میکند(با refresh کاربر) یعنی در طول ده ثانیه ، کاربر هر چقدر صفحه را لود کند همان زمان قبلی را نشان میدهد :
[System.Web.Mvc.HttpGet] [System.Web.Mvc.OutputCache(Duration = 10)] public System.Web.Mvc.ContentResult Learn1330() { string strContent = System.DateTime.Now.ToString("yyyy/MM/dd – HH:mm:ss"); return (Content(strContent)); }
در صورتی که اکشن کش شده دارای پارامتر ورودی باشد ، به ازای هر پارامتر کش مجزا صورت میگیرد . مثال زیر را داریم :
[System.Web.Mvc.HttpGet] [System.Web.Mvc.OutputCache(Duration = 120)] public System.Web.Mvc.ContentResult Learn1340(int id) { switch (id) { case 1: { return (Content("Hello World (1)!")); } case 2: { return (Content("Hello World (2)!")); } default: { return (Content("Hello World!")); } } }
اگر اکشن بالا را با پارامتر 1 صدا بزنیم تا دو دقیقه کش میشود و اگر با 2 صدا بزنیم دو دقیقه جدا محاسبه میشود . بنابراین توصیه میشود اکشن هایی را کش کنیم که تعداد پارامتر محدودی دارند .
پاک کردن کش یک اکشن خاص :
در مثالی که زده شد ، فرض میکنیم در وسط یک روز خاص ، یک روزنامه به نشریات کشور اضافه شود . اگر با همان کش قبلی کار کند تا فردای آنروز تیتر آن روزنامه در وب سایت ما نمایش داده نمیشود . روش ناقص و پر خطر برای حل این مشکل اینست که کش IIS را پاک کنیم . این روش کار/امد نیست چون در لحظه پاک شدن کش IIS هر کاربری که لاگین است و در حال کار با سایت است را LogOut میکند و نیز تمام کش های اکشن های دیگر را هم از بین میبرد . پس اصلا توصیه نمیشود . روش موثر و مفید برای پاک کردن کش اینست که فقط کش آن اکشن مربرط به نمایش تیتر روزنامه های کشور را پاک کنیم تا همان لحظه به دیتابیس برود و اطلاعات روزنامه جدید را نیز بخواند و نمایش دهد .
استفاده از دستور RemoveOutputCacheItem:
این روش در اکشن زیر نشان داده شده است :
[System.Web.Mvc.HttpGet] public void Learn1360() { string strUrl = Url.Action(actionName: "Learn1350"); Response.RemoveOutputCacheItem(strUrl); }
دستور RemoveOutputCacheItem باید در تمام متدهای Insert , Update , Delete مربوط به روزنامه ها نوشته شود .
برای تکمیل آموخته های خود درباره cashing in MVC به سایت مایکروسافت مراجعه نمایید .
در بخش بعد، با مبحثی بنام Authorize آشنا میشویم.
تشخیص هویت کاربران توسط اتریبیوت Authorize
کاربرد اتریبیوت Authorize:
اگر بخواهیم دسترسی به یک اکشن را برای کاربر یا کاربرانی محدود کنیم (پیام Access Denied بدهیم) باید از اتریبیوت Authorize استفاده کنیم . مثلا هنگامی که میخواهیم دسترسی کاربر را به صفحه مدیریت ببندیم . در اکشن زیر وقتی کاربر لاگین کرده باشد وارد اکشن میشود وگرنه او را به فرم لاگین هدایت میکند :
[System.Web.Mvc.HttpGet] [System.Web.Mvc.Authorize] public System.Web.Mvc.ContentResult Learn1380() { return (Content("Hello World!")); }
برای تعریف فرمی که کاربر به آن ریدایرکت میشود باید به فایل Web.config برویم و دستور زیر را در زیرمجموعه system.web بنویسیم :
<authentication mode="Forms"> <forms loginUrl="~/Account/Login"/> </authentication>
در loginUrl میتوان آدرس فرم موردنظر خود را بنویسیم .
بررسی نقش کاربر توسط Roles:
علاوه بر اتریبیوت Authorize مورد دیگری داریم بنام Roles که نقش کاربر را بررسی میکند . این مفهوم با مثال زیر واضح تر میشود :
[System.Web.Mvc.HttpGet] [System.Web.Mvc.Authorize(Roles = "Supervisor,Manager")] public System.Web.Mvc.ContentResult Learn1390() { return (Content("Hello World!")); }
به این معنی است که نه تنها کاربر باید برای دیدم اکشن Learn1390 لاگین کرده باشد بلکه باید رول یا نقش او هم یا Supervisor باشد یا Manager .
برای کسب اطلاعات بیشتر درباره Authorize Attribute به این وب سایت مراجعه کنید .
در بخش بعد با نوع داده ای Json آشنا می شویم .
نوع دادهای JSON بعنوان خروجی اکشن
تعریف فرمت Json در اکشن:
اگر بخواهیم نوع خروجی اکشن ما بصورت Json باشد یا باید بصورت دستی داده های موردنظرمان را به فرمت json در بیاوریم :
[System.Web.Mvc.HttpGet] public string Learn1400() { string strResult = "{\"FullName\":\"Ehsan Safari\",\"Age\":28}"; return (strResult); }
تعریف JsonResult قبل از نام اکشن:
بدین منظور باید بجای ActionResult یا ContentResult یا هر چیز دیگری ، قبل از نام اکشن بنویسیم JsonResult و در هنگام بازگرداندن خروجی (return) بعد از کلمه return کلمه Json و سپس پرانتز باز و بسته را مینویسیم و سپس داده یا داده هایی که میخواهیم بفرستیم را بصورت شئ مینویسیم :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.JsonResult Learn1410() { return (Json(new { FullName = "Ehsan Safari", Age = 28}, System.Web.Mvc.JsonRequestBehavior.AllowGet)); }
برای تکمیل اطلاعات خود درباره نوع داده ای Json به این وب سایت مراجعه کنید .
در بخش بعد با نحوه چگونگی دانلود فایل در MVC آشنا می شویم.
چگونگی دانلود فایل در MVC
قرار دادن لینک دانلود یک فایل در ASP.NET MVC:
به منظور قرار دادن لینک دانلود یک فایل روش اول اینست که میتوانیم آدرس فایل را مستقیما با لینک بدهیم و کاربر با کلیک کردن روی آن ، آنرا دانلود کند . بعنوان مثال فایل مربوطه در فولدر Uploads قرار دارد و نام فایل هم myFile.pdf می باشد :
http://Mohtavaban.com/Uploads/myFile.pdf
کاربر با نوشتن این آدرس در مرورگر میتواند آنرا بطور مستقیم دانلود کند و این امر از لحاظ امنیتی اصلا جالب نیست .
برقراری امنیت فایل دانلودی در MVC:
بنابراین باید فایلهای مهم (اعم ازعکس-داکیومنت-ویدیو یا غیره) را که کاربرعادی نباید آنها را ببیند و یا بابت آنها باید هزینه ای پرداخت کند را داخل فولدر App_Data بریزیم (چرا که فولدر مذکور یک فولدر امن است و دات نت Security محافظ آن است )
بعنوان مثال در اکشن زیر داریم :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.FileResult Learn1420() { // شرایط دریافت فایل string strRootRelativePathName = "~/App_Data/Images/EhsanSafari.jpg"; string strPathName = Server.MapPath(strRootRelativePathName); return (File(strPathName, contentType: "image/jpeg")); }
در این اکشن میتوانیم ابتدا شرایط هر کاربر را جهت دانلود فایل بررسی کنیم و سپس اجازه دانلود به او بدهیم .
تعریف File بعنوان خروجی اکشن:
خروجی اکشن باید File باشد و قبل از نام اکشن نیز باید FileResult بنویسیم . در هنگام return دستور زیر را داریم :
return (File(strPathName, contentType: "image/jpeg"));
پارامتر اول آدرس فیزیکی فایل مربوطه است و پارامتر دوم نیز نوع داده فایل دانلودی است .
با اجرای اکشن فوق ، تصویر مربوطه در مرورگر نمایش داده میشود ولی اگر بخواهیم پس از اجرای اکشن مذکور پنجره Save As ظاهر شود باید contentType آنرا مقداری بنویسیم که نا مفهوم باشد از نظر دات نت !
[System.Web.Mvc.HttpGet] public System.Web.Mvc.FileResult Learn1440() { // شرایط دریافت فایل string strRootRelativePathName = "~/App_Data/Images/Ehsan.jpg"; string strPathName = Server.MapPath(strRootRelativePathName); return (File(strPathName, contentType: "salam/chetori")); }
تعریف پارامتر fileDownloadName:
در این حالت فایل با موفقیت دانلود میشود ولی نام فایل دانلود شده همان نام اکشن میشود . برای رفع این مشکل باید به پارامتر fileDownloadName نیز مقدار بدهیم :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.FileResult Learn1450() { // شرایط دریافت فایل string strRootRelativePathName = "~/App_Data/Images/Safari.jpg"; string strPathName = Server.MapPath(strRootRelativePathName); return (File(strPathName, contentType: "googooli/magooli", fileDownloadName: "EhsanSafari.jpg")); }
این اکشن تقریبا کامل است و می توانید برای قرار دادن امکان دانلود فایل ها در وب سایتتان از آن استفاده کنید .
آموزش ASP.NET MVC5 – فصل2 – بخش1
با سلام خدمت شما عزیزان . به فصل دوم از مقالات آموزشی MVC خوش آمدید . در فصل اول که شامل 3 سرفصل بود با معماری قدرتمند MVC و نیز کنترولر و اکشن در mvc آشنا شدیم.
در فصل دوم، قصد داریم مبحث View در MVC را آموزش دهیم که این جلسه شامل دو بخش است.
آشنایی با Razor View در ASP.NET MVC
ایجاد یک پروژه MVC در ویژوال استودیو:
برای ادامه آموزش ، برنامه ویژوال استودیو را باز کنید و به منوی FILE و زیرمنوی NEW–>Project بروید و به مسیر Web–>ASP.NET WebApplication میرویم و ورژن دات نت فریمورک را 4.5 انتخاب میکنیم و سپس از منوی بالا Empty را انتخاب کرده و از منوی پایین گزینه MVC را تیک بزنید . در نهایت نام پروژه و آدرس ذخیره سازی آنرا تعیین کرده و OK کنید .
اکنون اولین کنترولر را بنام HomeController ایجاد میکنیم (یک کنترولر میسازیم بنام Home که اسم کلاسش HomeController است)
خروجی ViewResult در اکشن:
در جلسه اول سری آموزشی MVC، با انواع خروجی ActionResult و ContentResult و JsonResult و … آشنا شدیم . در این بخش میخواهیم با خروجی مهم ViewResult آشنا شویم . در اکشن ها اگر مطمئنیم خروجی ما از چه نوعی است بهتر است آنرا بنویسیم مثلا اگر میدانیم اکشن ما خروجی View میدهد باید قبل از نام اکشن ViewResult بنویسیم .
نکته : برای یادگیری بیشتر میتوانید به مرجع اصلی آموزش View در mvc مراجعه کنید .
ایجاد کنترولر HomeController:
هنگامی که کنترولر را میسازیم ، در فولدر Views بنام کنترولر یک فولدر بطور اتوماتیک ساخته می شود . مثلا با ایجاد HomeController ، بلافاصله یک زیر فولدر در فولدر Views ساخته می شود بنام Home که می بایست View های مربوط به کنترولر Home را در آن ایجاد کنیم .
ایجاد View برای اکشن در MVC:
برای ایجاد View برای یک اکشن باید روی فولدر ویوی مربوطه مثلا Home راست کلیک کرده و سپس Add–>View را میزنیم . حالا نوبت آن رسیده است که نام ویو را بنویسیم که همان نام اکشن می باشد . مثلا برای اکشن Index باید نام ویوی آن نیز Index باشد . سپس در پنجره باز شده هیچ تیکی را نمیزنیم و در نهایت Add را میزنیم . یک فایل بنام Index.cshtml ایجاد میشود که یک فایل ساده HTML بنظر میرسد ولی در جلسات آینده یاد میگیریم که داخل این صفحه ، کدهای سی شارپ نیز بنویسیم . سپس تایتل یا عنوان صفحه را مینویسیم .
روش دیگر برای ایجاد ویو برای اکشن اینست که در کنترولر روی نام اکشن راست کلیک کنیم و گزینه Add View را انتخاب کنیم . حالا در پنجره ای که ظاهر شده است نام ویو بطور خودکار نام اکشن ست شده است و add را میزنیم .
معمولا در اکثر موارد نام اکشن با نام ویو یکی می باشد ولی اگر بخواهیم نام آنها با هم فرق داشته باشد باید بصورت اکشن زیر عمل کنیم:
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1010() { return (View(viewName: "Learn1000")); }
در این مثال نام اکشن Learn1010 است و نام ویو آن Learn1000 می باشد .
ویوی بعدی بصورت زیر است :
Mohtavaban.com (1)! Mohtavaban.com (2)! Mohtavaban.com (3)! Mohtavaban.com (4)! Mohtavaban.com (5)!
همانطور که مشاهده میکنید عبارت Mohtavaban.com بارها تکرار شده است پس منطقی است که آنرا در حلقه For بنویسیم .
ویوی بعدی یعنی با حلقه فور پیاده سازی شده است :
@for (int intIndex = 1; intIndex <= 5; intIndex++) { Hello World (@intIndex)! }
دقت کنید که علامت @ باید به for چسبیده باشد .
تعریف متغیر در View :
اگر ویوی ما بصورت زیر باشد با خطا مواجه می شویم که میگوید چنین متغیری در ویو وجود ندارد !
My email address is EhsanSafari@hotmail.com @SomeText
Error: The name ‘SomeText’ does not exist in the current context
نکته کد فوق: اگر بلافاصله قبل از علامت @ چیزی نوشته باشیم اثر @ را از بین برده ایم . در مثال فوق hotmail.com متغیر محسوب نمیشود ولی RazorView عبارت someText را متغیر به حساب آورده و پیام خطا میدهد. برای اینکه بتوانیم قبل از کلمه ای علامت @ چاپ شود باید از دو تا @ پشت سر هم استفاده کنیم . در View زیر داریم :
@@SomeText
خروجی View فوق بصورت زیر است :
@SomeText
نحوه نگارش بلاک کد (Razor Block Code):
در این قسمت ، نوشتن کد در بلاک را خواهیم دید و نحوه کامنت کردن کدهای سی شارپ را یاد می گیریم .
بدین منظور باید بصورت مثال زیر عمل کنیم :
@* Razor Block Comment – به کلاینت ارسال نمی شود *@ @* My strFullName value is: @strFullName *@ @{ C# Code is Here…. }
کامنت کردن کدهای #C در Razor View:
برای کامنت کردن کدهای HTML از <!– و –> استفاده میکنیم و به سمت کلاینت ارسال میشود . برای کامنت کردن کدهای سی شارپ از @* و *@ استفاده میکنیم .
نوشتن کدهای #C در View:
برای نوشتن کد سی شارپ در بلاک از @{ و } استفاده میکنیم . در مواقعی که کدهای سی شارپ ما زیاد است از این بلاک استفاده میکنیم و در عین حال می توان کدهای HTML را نیز بنویسیم .
بعنوان مثال View زیر را تعریف میکنیم :
@{ // Razor Block Code string strFirstName = "Ehsan"; string strLastName = "Safari"; string strFullName = string.Format("{0} {1}", strFirstName, strLastName); strFullName = strFullName.ToLower(); if (strFullName == "Ehsan Safari") { string strMessage = "Something…"; } { string strSomeVariable = "Something…"; } } My strFullName value is: @strFullName
نکته 1: متغیرهایی که در بلاک کد RazorView ساخته می شوند علاوه بر خود بلاک ، تا پایان داکیومنت (ویوی جاری) نیز شناخته می شوند . در مثال فوق با اینکه strFullName در بلاک کد تعریف شده است ولی در کد بعد از بلاک نیز شناخته می شود و قابل دسترسی است .
نکته 2: کلیدهای میانبر برای کامنت کردن کدهای سی شارپ و یا کدهای داخل بلاک کد RazorView عبارتند از : Ctrl+k+c و کلیدهای Ctrl+k+u نیز متن مذکور را از حالت کامنت در میاورد .
به منظور کسب اطلاعات بیشتر درباره Razor View لطفا به وب سایت asp.net مراجعه نمایید .
نحوه نمایش تصویر در ویو (Razor View):
فرض کنید ما تصویری بنام Mohtava در فولدر images داریم . میخواهیم محتویات آنرا در مرورگر به کاربر نمایش دهیم . برای اینکار داریم :
@{ string strFileName = "Mohtava"; } <img src="~/Images/@strFileName.jpg" alt="@strFileName" />
@* Error: 'string' does not contain a definition for 'jpg' and no extension method 'jpg' accepting a first argument of type 'string' could be found *@
@{ string strFileNameWithExtension = string.Format("{0}.jpg", strFileName); } <img src="~/Images/@strFileNameWithExtension" alt="@strFileName" />
@* Success : Our Image is Displayed Successfully…! *@
نکات تعریف آدرس تصویر در ویو:
نکته 1 : اگر بصورت روش اول بنویسیم با خطا مواجه می شویم چون بعد از @ یک متغیر است و شناخته شده است ولی از جنس رشته است . بعد از نام متغیر کلمه jpg آمده است . چون String متدی بنام jpg ندارد !!! اما در روش دوم این مشکل را با استفاده از string.Format حل کرده ایم . ابتدا پسوند عکس را بدین صورت تعریف میکنیم و سپس در تگ img نمایش میدهیم .
نکته 2 : برای نمایش عکس میتوانیم از کد زیر استفاده کنیم:
@{ string strFileNameWithExtension = string.Format("{0}.jpg", strFileName); } <img src="~/Images/@strFileNameWithExtension" alt="@strFileName" />
@* Success : Our Image is Displayed Successfully…! *@
برای یادگیری بیشتر درباره نمایش و نیز آپلود تصاویر در ASP.NET می توانید به وب سایت مرجع دات نت رجوع کنید .
قوانین تعریف کد #C در بین کدهای HTML:
با اینکه میتوان در بین کدهای html کدهای سی شارپ نوشت و بالعکس ، ولی قوانینی نیز دارد . برای مثال نمیتوان کدی بصورت زیر نوشت :
@{ string strFirstName = "Ehsan"; if (strFirstName.StartsWith("E")) { The name starts with "E" character! } else { The name does not start with "E" character! } }
خط آخر خطا دارد . چون باید در تگ html نوشته شود نه همینجوری ! مثال زیر تصحیح شده مثال فوق است :
@{ string strFirstName = "Safari"; if (strFirstName.StartsWith("E")) { The name starts with "E" character! } else { The name does not start with "E" character! } }
کاربرد دستور <text> در Razor:
زمانی که بخواهیم یک متنی را عینا در خروجی چاپ کنیم و نمیخواهیم هیچ تگی اطراف آن باشد (مانند div , span , …) باید از دستور <text> استفاده کنیم . تکست یک تگ html نمی باشد و مختص Razor است . بنابراین در مثال زیر داریم :
@{ string strFirstName = "Mohtava"; if (strFirstName.StartsWith("M")) { The website starts with "M" character! } else { @:The website does not start with "M" character! } }
علاوه بر text میتوانیم از :@ نیز استفاده کنیم ولی این دستور بصورت inline (یک خطی است) .
برای مباحث پیشرفته تر درباره RazorView Engine میتوانید به وب سایت اصلی ASP.net مراجعه کنید .
نحوه ارسال پارامتر از Controller به View:
به اکشن زیر دقت کنید :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1130() { ViewData[“Message”] = "Hello World!"; return (View()); }
تعریف متغیر ViewData:
بدین صورت تعریف میشود که اگر ViewData با نام Message از قبل وجود نداشت آنرا بساز و مقدار اولیه آن را Hello World قرار بده و اگر از قبل وجود داشت ، مقدار آنرا به Hello World تغییر بده . بنابراین ما دستوری برای تعریف متغیر نداریم . View اکشن فوق بصورت زیر است :
@ViewData[“Message”]
تعریف متغیر ViewBag:
ViewBag نیز مانند ViewData عمل میکند فقط با این تفاوت که مقداردهی آنها با هم فرق دارد . به اکشن زیر توجه کنید :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1140() { ViewBag.Message = "Hello World!"; return (View()); }
و View این اکشن بصورت زیر می باشد :
@ViewBag.Message
رابطه بین ViewData و ViewBag:
در مثال بعد خواهیم فهمید که در واقع ViewData و ViewBag یک کالکشن هستند یعنی اگر در ViewData متغیری تعریف کنیم میتوانیم در ویو انرا با ViewBag بخوانیم :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1150() { ViewBag.Message1 = "Hello World (1)!"; ViewData[“Message2”] = "Hello World (2)!"; return (View()); }
و View این اکشن :
@ViewBag.Message1 @ViewData[“Message1”] @ViewBag.Message2 @ViewData[“Message2”]
آموزش ASP.NET MVC5 – فصل2 – بخش2
دوستان در بخش اول از فصل دوم سری آموزشی ASP.NET MVC موارد زیر آموزش داده شد:
- آشنایی با Razor View در ASP.NET MVC
- خروجی ViewResult در اکشن
- ایجاد View برای اکشن
- تعریف متغیر در View
- نحوه نگارش بلاک کد
- کامنت کردن کدهای #C در Razor View
- نمایش تصویر در ویو
- ارسال پارامتر از Controller به View
- متغیرهای ViewData و ViewBag
نحوه ارسال آبجکت به View در MVC
در این مقاله نحوه ارسال شئ به ویو (View) و پارشیال ویو (Partial-View) را خواهیم دید .
نحوه ارسال شئ (Object) به ویو (View):
برای اینکار ابتدا در فولدر Models کلاسی میسازیم بنام Person :
namespace Models { public class Person : System.Object { public Person() { } public int Age { get; set; } public string FullName { get; set; } public string Description { get; set; } } }
نکات تعریف کلاس (Class) در Model:
- معمولا بهتر است nameSpace کلاس با نام فولدر Models یکی باشد .
- بهتر است قید کنیم که کلاس ما از چه چیز ارث می برد مانند System.Object
- بهتر است namespace های اضافی بالای کلاس را پاک کنیم
این کلاس دارای سه property است که public تعریف شده است و یک Default Constructor دارد .
اکشن Learn1160:
اکشن مربوطه بدین صورت است :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1160() { Models.Person oPerson = new Models.Person() { Age = 28, FullName = "Ehsan Safari", }; ViewBag.Person = oPerson; return (View()); }
ایجاد شی از کلاس در اکشن:
دستورات ابتدایی این اکشن کارش اینست که از کلاس Person یک شئ میسازد و همانجا به property هایش مقدار میدهد .
ارسال آبجکت به ویو توسط ViewBag:
روش نسبتا اشتباه اینست که مانند اکشن بالا ، شئ تولید شده را بهمراه مقادیرش داخل ViewBag بریزیم و به view پاس کنیم . و در view این اکشن از ViewBag تولید شده استفاده می کنیم:
Age: @ViewBag.Person.Age Full Name: @ViewBag.Person.FullName
یکی از ایرادات روش فوق اینست که intellisence ندارد یعنی در view با نوشتن ViewBag.Person ، لیست property ها نشان داده نمیشود . برای مثال اگر دستور فوق را بصورت ViewBag.Person.Ageee بنویسیم ، خطایی در view نمی بینیم و تنها در زمان کامپایل پروژه خطای کد فوق نمایان می شود .
ارسال شی بعنوان پارامتر view بهنگام return:
راه حل توسعه یافته روش فوق این است که شئ ساخته شده را بعنوان پارامتر View در هنگام return بفرستیم :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1190() { Models.Person oPerson = new Models.Person() { Age = 20, FullName = "Ehsan Safari", }; return (View(model: oPerson)); }
و در View میتوان شئ ارسال شده را توسط Model بگیریم :
Age: @Model.Age Full Name: @Model.FullName
ولی مشکل روش فوق باز هم اینست که اولا intellisence ندارد دوما اگر غلط املایی در property ها داشته باشیم ارور نمیدهد و در زمان کامپایل خطا مشخص می شود .
بهترین روش ارسال آبجکت از View به Controller:
بهترین روش برای ارسال و دریافت شئ از کنترولر به ویو روش زیر است :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1220() { Models.Person oPerson = new Models.Person() { Age = 20, FullName = "Ehsan Safari", }; return (View(model: oPerson)); }
و view متناظر آن :
@model Models.Person Age: @Model.Age Full Name: @Model.FullName
با نوشتن دستور خط اول یعنی model Models,Person مشکل intellisence و خطا ندادن حل می شود .
ارسال ViewModel از کنترولر به view:
سناریو : فرض کنید می خواهیم دو موجودیت را به سمت ویو بفرستیم . مثلا یک شئ person و یک factoryName . روش اول و کلاسیک اینست که بخش مهمتر را بصورت model به view بفرستیم و بخش کوچکتر را توسط viewBag . در این مثال شئ person را توسط model و factoryName را بوسیله ViewBag یا ViewData به سمت view ارسال می کنیم . اکشن مورد نظر به این صورت می شود :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1230() { ViewBag.FactoryName = "Iran Khodro Co."; Models.Person oPerson = new Models.Person() { Age = 28, FullName = "Ehsan Safari" }; return (View(model: oPerson)); }
استفاده از ViewModel برای ارسال چند شئ به View :
راه حل هوشمندانه استفاده از ViewModel است . مورد استفاده ViewModel وقتی است که می خواهیم کنار شئی که میخواهیم ارسال کنیم ، اشیاء دیگر و یا property های دیگر قرار دهیم (مانند مثال فوق) . مثال ملموس تر برای استفاده از ViewModel را میتوان در فرم ثبت نام کاربران ببینیم . در این فرم ، کاربران باید username , password , confirmPassword ,email , confirmEmail را وارد کنند . کلاس user فقط فیلدهای username , password, email دارد . پس برای اینکه بتوان فیلدهای تایید را نیز به آن استفاده کنیم میتوان یک ViewModel ایجاد میکنیم و تمام فیلدهای confirmPassword , confirmEmail را بهمراه خود کلاس user در آن تعریف میکنیم . برای ایجاد ViewModel در پروژه خود ، باید به اینصورت عمل کنیم :
نحوه ایجاد ViewModel :
روی پروژه راست کلیک کرده و سپس Add–>NewFoler را انتخاب میکنیم . نام فولدر را ViewModels قرار میدهیم و روی آن راست کلیک کرده و زیر فولدری بنام کنترولر جاری (در این مثال Home) میسازیم و سپس روی فولدر Home راست کلیک کرده و Add–>Class را انتخاب کرده و بخش اول نام کلاس را همان نام اکشن و بخش دوم را به کلمه ViewModel ختم می کنیم . بعنوان مثال نام ViewModel برای ارسال در اکشن Learn1240 برابر Learn1240ViewModel.cs می باشد .
کد Learn1240ViewModel.cs:
namespace ViewModels.Home { public class Learn1240ViewModel : System.Object { public Learn1240ViewModel() { } public string FactoryName { get; set; } public Models.Person Person { get; set; } } }
اکشن Learn1240:
و در اکشن باید یک شئ از کلاس فوق بسازیم و سپس مقداردهی کنیم :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1240() { ViewModels.Home.Learn1240ViewModel oViewModel = new ViewModels.Home.Learn1240ViewModel(); oViewModel.FactoryName = "Iran Khodro Co."; Models.Person oPerson = new Models.Person() { Age = 28, FullName = "Ehsan Safari", }; oViewModel.Person = oPerson; return (View(model: oViewModel)); }
نحوه ارسال ویومدل از اکشن به کنترولر:
همانطور که مشاهده می کنید ابتدا باید از کلاس Person یک شئ بسازیم و مقداردهی را انجام دهیم (Age,FullName) و سپس این شئ تولید شده را به شئ ViewModel خود نسبت دهیم و در نهایت آنرا به view ارسال کنیم .
در سمت view ، ویومدل ارسالی از کنترولر را به این صورت باید بگیریم :
@model ViewModels.Home.Learn1240ViewModel
با تعریف دستور اول ، میگوییم که منظور ما از Model که داخل view استفاده شده است ، همان ViewModel است . در این حالت intellisence نیز داریم .
به منظور تکمیل آموخته های خود در زمینه ViewModel میتوانید به مرجع اصلی آموزش viewModel در mvc مراجعه کنید .
ارسال لیستی از اشیاء به ویو (View):
سناریو : اگر بخواهیم آرایه ای از person را به view ارسال کنیم و در view توسط یک حلقه for اطلاعات ارسالی را نمایش دهیم .
یادآوری : فرق ArrayList با Generic.List اینست که در ArrayList هنگام add کردن خانه ای به آرایه ، میتوان هر object ای را به آن افزود و از لحاظ امنیتی خطرناک است ولی Generic بدین گونه است که در هنگام ایجاد آن به صراحت میگوییم که لیست Generic ما مثلا از جنس person است .
اکشن Learn1250:
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1250() { System.Collections.Generic.List oPeople = new System.Collections.Generic.List(); for (int intIndex = 1; intIndex <= 10; intIndex++) { Models.Person oPerson = new Models.Person() { Age = 20 + intIndex, FullName = string.Format("Full Name ({0})", intIndex), }; oPeople.Add(oPerson); } return (View(model: oPeople)); }
ارسال لیست افراد بصورت شئ به ویو:
در دستور اول این اکشن ابتدا لیستی از person ها ایجاد کردیم و سپس در حلقه for به تعداد 10 نفر ، اطلاعات نمونه وارد کرده ایم ( در هر بار اجرای این حلقه توسط دستور oPeople.Add اطلاعات یک نفر به لیست اضافه میشود ) در نهایت هم لیست افراد را بصورت شئ به ویو ارسال کردیم .
در سمت view نیز model بالای ویو نیز میتواند به سه صورت تعریف شود :
@model System.Collections.Generic.List @model System.Collections.Generic.IEnumerable @model IEnumerable
هر سه روش درست است ولی مایکروسافت روش سوم را توصیه می کند .
پس view ما بطور کلی بصورت زیر است :
@model IEnumerable @foreach (Models.Person oPerson in Model) { <div style="color: blue; background-color: khaki; margin: 4px; padding: 4px; border: thin outset;">I'm @oPerson.FullName, and @oPerson.Age years old.</div> }
توسط حلقه foreach ، روی اطلاعات افراد ارسال از کنترولر ، یک لوپ زدیم و آنها را در یک div که توسط css استایل داده شده است ، نمایش میدهیم .
لزوم تعریف Partial-View در MVC:
فرض کنیم در صد جای پروژه میخواهیم از اطلاعات لیست افراد استفاده کنیم مشکل پیش رو اینست که علاوه بر اینکه باید در هر صد جا ، کدهای فوق را کپی کنیم ، اگر یک روزی بخواهیم به فیلدهای افراد ، مثلا ایمیل را اضافه کنیم باید برویم و در صد جای قبل ، ایمیل را اضافه کنیم و این زمان بر و پر اشتباه است . روشی که برای حل اینگونه موارد ارائه می شود استفاده از PartialView می باشد .
تعریف PartialView در MVC:
مفهوم PartialView مانند userControl در ASP.NET webform می باشد . کاربرد آن بطور مثال اینگونه است : فرض کنید میخواهیم در چند جای پروژه خود ، تاریخ شمسی را با یک استایل خاصی به کاربر نمایش دهیم . می توان یکبار آنرا در یک نوع ویو بنام PartialView تعریف کنیم و در جاهایی که میخواهیم ، آنرا فراخوانی کنیم .
محل ایجاد PartialView :
اگر PartialView تعریف شده بعنوان مثال فقط بدرد Home میخورد ، آنرا در فولدر Home داخل فولدر Views ایجاد میکنیم ولی اگر بدانیم ممکن است از این PartialView در کنترولرها و view های دیگر نیز استفاده شود ، باید آنرا در داخل فولدر Shared تعریف کنیم . برای ایجاد این فولدر باید روی فولدر Views راست کلیک کرده و Add–>New Folder را انتخاب کنیم . نام فولدر را نیز Shared قرار میدهیم .
نحوه ایجاد PartialView :
روی فولدری که میخواهیم PartialView در آن قرار بگیرد راست کلیک کرده و Add–>View را انتخاب میکنیم . در پنجره باز شده ، تیک گزینه create as a partialview را میزنیم و add میکنیم . توصیه مایکروسافت اینست که نام PartialView ما با یک underline و سپس کلمه Partial آغاز شود .
تعریف تاریخ شمسی در PartialView:
مثالی که میخواهیم انجام دهیم تعریف تاریخ شمسی در PartialView است :
_Partial_DisplayCurrentPersianDate : @{ System.DateTime dtmNow = System.DateTime.Now; System.Globalization.PersianCalendar oPersianCalendar = new System.Globalization.PersianCalendar(); int intYear = oPersianCalendar.GetYear(dtmNow); int intMonth = oPersianCalendar.GetMonth(dtmNow); int intDay = oPersianCalendar.GetDayOfMonth(dtmNow); } <div dir="ltr" style="color: blue; background-color: khaki; margin: 4px; padding: 4px; border: thin outset;">@intYear / @intMonth / @intDay </div>
ابتدا تاریخ سیستم را به شمسی تبدیل کرده و متغیر های سال و ماه و روز را مقداردهی میکنیم و در نهایت در تگ div با استایل خاصی نمایش میدهیم .
در view ای که قصد استفاده از این PartialView را داریم بصورت زیر عمل میکنیم :
نکته 1) : روش اول اشتباه است یعنی بعد از نام PartialView خود نباید پسوند آنرا نیز بنویسیم .
نکته 2) : همانطور که می بینید ، آدرس PartialView ذکر نشده است . پیش فرض مایکروسافت این است که ابتدا در فولدر کنترولر مربوطه واقع در فولدر view میگردد . اگر چنین PartialView ای پیدا نکرد ، سراغ فولدر Shared می رود . (بنابراین در این مثال اولویت با فولدر Home است)
نکته 3) : در ASP.NET webform هنگام استفاده از TextBox در واقع یک شئ ایجاد می کردیم از کلاس TextBox ولی در معماری MVC ، در هنگام استفاده از Textbox در واقع یک متد صدا زده می شود که دارای پارامترهای مختلفی است . در واقع یک HtmlHelper است .
نکته 4) : بصورت runTime نیز میتوان به View یک یا چند PartialView اضافه کنیم مثلا پس از بررسی دیتابیس ، اگر شرط خاصی True بود فلان Partial را نمایش دهد .
ارسال پارامتر به پارشیال ویو:
همانند view به partialView نیز میتوان شئ ارسال کرد (چون partialView نوعی view است) . پس در مثال بعدی میخواهیم شئ person را به partial ارسال کنیم .
اکشن مثال بعد بصورت زیر است :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1280() { System.Collections.Generic.List oPeople = new System.Collections.Generic.List(); for (int intIndex = 1; intIndex <= 10; intIndex++) { Models.Person oPerson = new Models.Person() { Age = 20 + intIndex, FullName = string.Format("Full Name ({0})", intIndex), }; oPeople.Add(oPerson); } return (View(model: oPeople)); }
کد view مربوطه نیز بدین صورت است :
@model IEnumerable<models.person> <!DOCTYPE html> <head> <meta name="viewport" content="width=device-width" /> <title>Learn 1280</title> </head> <body> @foreach (Models.Person oPerson in Model) { @Html.Partial("_Partial_DisplayPerson1", model: oPerson) } </body> </html>
کد PartialView بصورت زیر است :
_Partial_DisplayPerson1 : @model Models.Person @if (Model == null) { return; } <div dir="ltr" style="color: blue; background-color: khaki; margin: 4px; padding: 4px; border: thin outset;">I'm @Model.FullName and @Model.Age years old.</div>
استفاده از دستور Html.Raw:
گر فیلدی از کلاس person دارای تگ html باشد مثلا Description ، برای نمایش محتویات آن بصورت صحیح در view باید از دستور Html.Raw استفاده کنیم (یک HtmlHelper می باشد) فرض کنید اکشن ما بصورت زیر است :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.ViewResult Learn1340() { Models.Person oPerson = new Models.Person() { Age = 28, FullName = "Ehsan Safari", Description = "Nothing!", }; return (View(model: oPerson)); }
همانطور که می بینیم فیلد Description دارای تگ <b> می باشد . پس باید در هنگام نمایش ، Render شود . بنابراین در view کد ما بصورت زیر است :
بنابراین با اجرای اکشن فوق در مرورگر ، فیلد توضیحات بصورت بولد نمایش داده می شود .
امیدوارم این مقاله مورد استفاده شما کاربران عزیز قرار گرفته باشد .
لطفا ما را از دیدگاه های خود درباره این مقاله بی بهره نگذارید .
برای تکمیل آموزه های خود درباره PartialView به وب سایت اصلی ASP.NET MVC مراجعه کنید .
فصل دوم به پایان رسید . در فصل سوم از سری آموزشی ASP.NET MVC میخواهیم قالب وب سایت خود را توسط فریم ورک Bootstrap طراحی کنیم .
آموزش ASP.NET MVC5 – فصل3 – بخش1
با سلام خدمت دوستان و علاقه مندان به دنیای وب . به فصل سوم از مقالات آموزشی MVC خوش آمدید . در فصل دوم که شامل 2 بخش بود با View در mvc آشنا شدیم.
نصب فریمورک بوتاسترپ توسط نوگت (Nuget)
بوت استرپ یک فریم ورک Grid Base می باشد که واکنش گراست . برای نصب بوت استرپ نیاز به نوگت داریم . در بخش بعدی با Nuget آشنا میشویم .
آشنایی با Nuget :
به منظور نصب فریم ورک Bootstrap در پروژه خود ، نیازمند Nuget هستیم . (وب سایت اصلی Nuget) بدین منظور به مسیری که در تصویر زیر نشان داده شده است می رویم :
مراجعه به Package Manager Console:
مطابق تصویر به مسیر زیر می رویم و کنسول Nuget را باز میکنیم .
Tools > NuGet Package Manager > Package Manager Consoleپیش از نصب بوت استرپ توسط نوگت ، باید Jquery را نصب کنیم . برای اینکار دستور زیر را در خط فرمان(Command Line) کنسول نوگت می نویسیم :
Install-Package jQuery
نصب bootstrap توسط nuget:
سپس سراغ نصب Bootstrap می رویم . برای اینکه بدانیم برای نصب بوت استرپ چه فرمانی را باید بنویسیم ، ابتدا در گوگل عبارت Nuget Bootstrap را سرچ می کنیم (مطابق تصویر زیر)
اولین سایت پیدا شده توسط گوگل را باز میکنیم . در وب سایت NuGet دستور لازم برای نصب را مشاهده می کنیم (مطابق تصویر زیر)
خود سایت نوگت دستور نصب آخرین ورژن بوت استرپ را نمایش می دهد (در تاریخ نگارش این مقاله ، آخرین ورژن 3.3.6 می باشد) .
در خط فرمانی که در قسمت پایین ویژوال استودیو باز شده ، دستور نصب بوت استرپ را تایپ کرده و Enter میزنیم .
Install-Package bootstrap
با اجرای این فرمان ، سه فولدر به پروژه ما افزوده می شود :
Content : شامل فایلهای css است .
Scripts : فایلهای جاوا اسکریپت فریم ورک بوت استرپ را شامل می شود .
fonts : فونتهای مربوط به بوت استرپ در آن قرار دارند .
فریم ورک بوت استرپ محصول کمپانی توییتر (Twitter) می باشد که دو ویژگی مهم ریسپانسیو و Grid Base بودن را دارد .
شروع کار با فریم ورک بوت استرپ:
برای شروع کار ، ابتدا یک صفحه Html به پروژه خود Add میکنیم . سپس در برنامه ویژوال استودیو ، فولدر Content را از نوار Solution Explorer باز میکنیم و فایل Bootstrap.min.css را داخل صفحه html خود در تگ head وبعد از تایتل ، drag & drop میکنیم . باید چنین خطی به کد ما اضافه شده باشد :
<link href="Content/bootstrap.min.css" rel="stylesheet">
تگهای پرکاربرد در بوت استرپ:
در مرحله بعد ، وارد بدنه صفحه html یعنی تگ body میشویم . بعد از تگ <body> یک تگ div تعریف میکنیم بصورت زیر :
<div class="container">
دقت کنید که در یک صفحه میتوان چند div با کلاس container داشته باشیم ولی والد یا parent تمام آنها باید تگ body باشد .
برای شروع هر سطر در طراحی بوت استرپ ، از تگ div بصورت زیر استفاده میکنیم :
<div class="row">
و هر ستون در فریمورک بوت استرپ با div ای با کلاس col مشخص می شود :
<div class="col-md-6">
اندازه اسکرینهای مختلف در بوت استرپ :
نکته : بدلیل واکنش گرا بودن این فریمورک ، باید برای هر ستون مشخص کنیم که در هر یک از دستگاه های رایج در بازار ، چند ستون از صفحه را به خود اختصاص دهد . اندازه Device های مختلف بصورت زیر تعریف شده است :
Extra small devices : Phones (<768px) (xs) --> .col-xs- Small devices : Tablets (≥768px) (sm) --> .col-sm- Medium devices : Desktops (≥992px) (md) --> .col-md- Large devices : large Desktops (≥1200px) (lg) --> .col-lg-
توضیح : به هر کدام از اندازه های فوق Break Point میگویند.
معرفی نقاط شکست (break points) بوت استرپ:
- دستگاه های خیلی کوچک با xs مشخص میشوند مانند موبایل ها که عرض آنها کوچکتر از 768 پیکسل معین شده است .
- دستگاه های کوچک با sm مشخص میشوند مانند تبلت ها که عرض آنها بزرگتر یا مساوی 768 پیکسل معین شده است .
- دستگاه های متوسط با md مشخص میشوند مانند دسکتاپ ها که عرض آنها بزرگتر یا مساوی 992 پیکسل معین شده است .
- دستگاه های بزرگ با lg مشخص میشوند مانند دسکتاپ های عریض که عرض آنها بزرگتر یا مساوی 1200 پیکسل معین شده است .
نکته 1: مرجع مطالب فوق ، وب سایت بوت استرپ است .
نکته 2: هر بخش از صفحه از دید بوت استرپ میتواند به 12 قسمت تقسیم شود (علت عدد 12 اینست که کوچکترین عددی است که بیشترین اعداد بخش پذیر می باشد)
طراحی دو ستون با عرض یکسان در بوت استرپ:
بنابراین اگر بخواهیم در سطری ، دو بخش داشته باشیم که عرض آنها با هم برابر باشند ، باید اندازه هر دو را 6 در نظر بگیریم(6+6=12)
بعنوان مثال داریم :
<div class="container"> <div class="row"> <div class="col-md-6"> <p> Godard consequat plaid, deserunt fixie craft beer Cosby sweater Bushwick skateboard </p> <p> </p> </div> <div class="col-md-6"> <p> Actually polaroid synth jean shorts Portland, street art nihil fixie bicycle rights </p> <p> </p> </div> </div>
ایجاد سه ستون با عرض یکسان در bootstrap:
اگر بخواهیم سطری به 24 قسمت تقسیم شود ، می توان ابتدا آنرا به 2 قسمت تقسیم کنیم و سپس هر کدام را به 12 بخش تقسیم کنیم . یا اگر بخواهیم سطری به سه قسمت تقسیم شود ، اندازه هر کدام را 4 در نظر میگیریم (12=4*3) :
<div class="row"> <div class="col-md-4"> <p> Godard consequat plaid, deserunt fixie craft beer Cosby sweater Bushwick skateboard </p> </div> <div class="col-md-4"> <p> Actually polaroid synth jean shorts Portland, street art nihil fixie bicycle rights </p> </div> <div class="col-md-4"> <p> single-origin coffee. Brunch forage fixie banh mi adipisicing, freegan mumblecore </p> </div> </div>
کاربرد کلاسهای container و container-fluid:
اگر div با کلاس container را ننویسیم ، بعد از اجرا میبینیم که محتویات داخل row به کناره های صفحه چسبیده اند و ظاهر جالبی ندارد .
برای اینکه یک طراحی بینابین داشته باشیم یعنی نه مانند کلاس container از لبه های صفحه فاصله داشته باشیم و نه مانند چسبیدن بهنگام حذف container ، میتوان از کلاس container-fluid بجای container استفاده کنیم .
همانطور که در بخش قبل دیدیم ، بوت استرپ برای اندازه دستگاه های مختلف موجود در بازار ، breakPoint تعریف کرده است :
نکته : در صورتی که برای هر کدام از break point های بوت استرپ خصوصیتی تعریف کنیم ، برای اندازه های بزرگتر از آن نیز اعمال می شود مثلا اگر داشته باشیم :
<div class="row"> <div class="col-sm-6"> <p> Godard consequat plaid, deserunt fixie craft beer Cosby sweater Bushwick skateboard single-origin coffee. Brunch forage fixie banh mi adipisicing, freegan mumblecore </p> </div> <div class="col-sm-6"> <p> Actually polaroid synth jean shorts Portland, street art nihil fixie bicycle rights ugh cornhole organic selvage. Wayfarers Shoreditch nesciunt fap Vice. Tumblr master </p> </div> </div>
کد بالا بدین صورت تفسیر می شود که در دستگاه های با اندازه sm و بزرگتر از آن ، سطر مذکور به دو بخش با اندازه یکسان تقسیم میشود (col-sm-6)
نکته : قسمت جالب قضیه اینجاست که میتوان در مثلا اندازه موبایل ، سطر مورد نظرمان تمام صفحه را پوشش دهد و در اندازه تبلت ، مثلا 8 قسمت از 12 قسمت را مال خود کند . به مثال زیر دقت کنید :
<div class="row"> <div class="col-md-6 col-sm-4"> <p> Godard consequat plaid, deserunt fixie craft beer Cosby sweater Bushwick skateboard single-origin coffee. Brunch forage fixie banh mi adipisicing, freegan mumblecore </p> </div> <div class="col-md-6 col-sm-8"> <p> Actually polaroid synth jean shorts Portland, street art nihil fixie bicycle rights ugh cornhole organic selvage. Wayfarers Shoreditch nesciunt fap Vice. Tumblr master </p> </div> </div>
توضیح : در مثال فوق می گوییم که پاراگراف ها در اندازه تبلت ، هر کدام نیمی از صفحه را بپوشانند و در اندازه sm پاراگراف اول در یک سوم صفحه و پاراگراف دوم نیز در دو سوم صفحه نمایش داده شود .
برای انجام تمرینات بیشتر در این زمینه میتوانید به این وب سایت مراجعه کنید .
نحوه تعریف سلکتور css و تفسیر آن:
p.x { color: red; }
- هر پاراگرافی که کلاس x دارد را انتخاب کن (select کن) و رنگ متن آنرا قرمز کن .
.x { color: red; }
- هر تگی که کلاس x دارد را انتخاب کن و رنگ متن آنرا قرمز کن .
p#x { color: red; }
- پاراگرافی که id آن x است را انتخاب کن و رنگ متن آنرا قرمز کن .
#x { color: red; }
- تگی که id آن x است را انتخاب کن و رنگ متن آنرا قرمز کن.
p a { color: red; }
- هر لینکی که داخل پاراگراف است را انتخاب کن و رنگ متن آنرا قرمز کن .
body div[class]
- تمام div هایی که داخل body می باشند و دارای اتریبیوتی بنام class هستند را انتخاب کن .
body div[class="col"]
- تمام div هایی که داخل body می باشند و دارای اتریبیوتی بنام class هستند که مقدار class برابر col باشد را انتخاب کن.
body div[class^="col-"]
- تمام div هایی که داخل body می باشند و دارای اتریبیوتی بنام class هستند که مقدار class با -col شروع شود را انتخاب کن .
بعد از فراگیری مطالب فوق ، حالا میخواهیم کلاس زیر را در بخش head صفحه خود و داخل <style> بنویسیم :
body div[class^="col-"] { padding-top: 10px; padding-bottom: 10px; border: 1px solid rgba(86, 61, 124, 0.2); background-color: rgba(86, 61, 124, 0.15); }
در اینصورت ، ما می توانیم به تمامی تگ های بوت استرپی که کلاس آنها با -col شروع می شوند استایل گفته شده را بدهیم.
سطرهای تو در تو (Nested Row):
میخواهیم صفحه ای مطابق شکل زیر طراحی کنیم :
ابتدا استایل زیر را در بخش مربوطه می نویسیم :
body div[class^="col-"] { padding-top: 10px; padding-bottom: 10px; border: 1px solid rgba(86, 61, 124, 0.2); background-color: rgba(86, 61, 124, 0.15); }
سپس div ای با کلاس container مینویسیم :
<div class="container">
و در این div یک row با دوبخش 3 تایی و 9 تایی تعریف میکنیم که خود این بخش 9 تایی شامل دو row است که هر کدام از این سطرها به دو بخش 6 تایی تقسیم شده اند:
<div class="row"> <div class="col-md-3"> <p> Asymmetrical YOLO banjo lomo fanny pack, shoreditch flexitarian dreamcatcher ethnic </p> </div> <div class="col-md-9"> <div class="row"> <div class="col-md-6"> <p> Consectetur art party Tonx culpa semiotics. Pinterest assumenda minim organic quis. </p> </div> <div class="col-md-6"> <p> Consectetur art party Tonx culpa semiotics. Pinterest assumenda minim organic quis. </p> </div> </div> <div class="row"> <div class="col-md-6"> <p> Wayfarers selvage YOLO, commodo assumenda eu est bespoke mlkshk. Helvetica reprehenderit </p> </div> <div class="col-md-6"> <p> iPhone, aesthetic 90's literally chambray bicycle rights viral blog voluptate. Occupy </p> </div> </div> </div> </div>
بدین ترتیب به طرح مورد نظرمان می رسیم .
کاربرد کلاسهای offset و push در بوت استرپ:
کار offset اینست که به تعداد دلخواه ، یک ستون را به چپ یا راست شیفت (shift) می دهیم . یکی از کاربردهای offset ، وسط قرار دادن یک div است . مثلا میخواهیم یک div با 6 واحد را دقیقا وسط صفحه بندازیم . بدین منظور ، آنرا سه واحد به راست شیفت میدهیم :
<div class="row"> <div class="col-md-6 col-md-offset-3"> <p> Mohtavaban.com | Web Development Articles ; </p> </div> </div>
کار push نیز شیفت دادن است و میتوان از آن برای وسط انداختن div استفاده کرد ولی فرق آن با offset اینست که در صورت push دادن یک div ، روی div های پیش روی خود ، overlap میشود ولی offset در واقع div های بعد از خود را هل می دهد !
مثالی با push و pull :
در این مثال ، با اعمال push و pull ، جای دو div عوض می شود :
<div class="row"> <div class="col-md-9 col-md-push-3"> (11,1) </div> <div class="col-md-3 col-md-pull-9"> (11,2) </div> </div>
به منظور تکمیل اطلاعات خود درباره مبحث این مقاله میتوانید به وب سایت مرجع بوت استرپ و یا وب سایت w3Schools مراجعه کنید .
آموزش ASP.NET MVC5 – فصل3 – بخش2
در بخش اول از فصل سوم سری آموزشی MVC نحوه نصب فریم ورک بوت استرپ را بوسیله نوگت (Nuget) ویژوال استودیو آموزش دادیم و طراحی قالب (view در MVC) را توسط بوت استرپ آغاز کردیم. نقاط شکست (Break points) آنرا بیان کردیم و چند سلکتور (selector) نسبتا پیچیده و تو در تو را نیز شرح دادیم. در بخش دوم از فصل سوم، می خواهیم مباحث کاربردی دیگری در زمینه bootstrap را آموزش دهیم. مانند: پنل (Panel)، دکمه (Button)، جدول (Table)
پنل در بوت استرپ (Bootstrap Panel):
پنل ها ناحیه ای هستند که دارای گوشه های خمیده و شامل سه بخش می باشند : Heading , Body , Footer . هم می توان هر سه بخش را در یک پنل داشت و هم یک یا دو تا از آنها را ، ولی ترتیب آنها مهم است . پنل ها در بوت استرپ بسیار پر کاربرد هستند و یادگیری آن نیز آسان است . برای مثال میخواهیم دو پنل به شکل زیر طراحی کنیم :
برای رسیدن به پنل اول (پنل پیش فرض) باید به شکل زیر عمل کنیم :
<div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title"> Panel Heading (Default) </h3> </div> <div class="panel-body"> Panel Body </div> <div class="panel-footer"> Panel Footer </div> </div>
انواع پنلها در فریم ورک Bootstrap:
همانطور که مشاهده می کنید ابتدا باید یک div با کلاس panel تعریف کنیم (اگر panel-default را ننویسیم فرقی نمیکند ، زیرا همان پیش فرض را نمایش میدهد) سپس یک یا دو یا هر سه بخش Heading-Body-Footer را تعریف میکنیم . بخش Heading با کلاس panel-heading و بخش بدنه پنل با panel-body و بخش فوتر آن با panel-footer تعریف می شود . برای بخش ابتدایی پنل ، کلاسهای زیر را میتوان تعریف کرد :
<div class="panel panel-primary">...</div> <div class="panel panel-success">...</div> <div class="panel panel-info">...</div> <div class="panel panel-warning">...</div> <div class="panel panel-danger">...</div>
در داخل heading نیز معمولا یک تگ heading (مانند h3) تعریف میکنیم و به آن کلاس panel-title میدهیم .
استایلدهی به پنل بوت استرپ:
برای استایل دادن به پنل می توان از css ای که خودمان مینویسیم استفاده کنیم . بطور مثال اگر بخواهیم قسمت فوتر تمام پنلهای سایت استایل خاصی داشته باشند باید کد css را به این صورت تعریف کنیم :
div.panel div.panel-footer { background-color: red; }
مثال بعد : میخواهیم هدر پنلهایی که danger هستند به رنگ قرمز در بیایند :
div.panel-danger div.panel-heading { color: white; font-weight: bold; background-color: red; }
تعریف استایلهای شخصی در فایل جدا:
برای سفارشی سازی استایل های بوت استرپ نباید به هیچ وجه روی فایل اصلی bootstrap.min.css تغییراتمان را اعمال کنیم . بلکه باید فایلی بنام دلخواه مثلا myStyle.css را در فولدر content ایجاد کنیم و به پروژه خود اضافه کنیم . این استایل روی استایل پیش فرض بوت استرپ Override می شود . بنابراین باید css ها را بصورت زیر در تگ head تعریف کنیم :
<link href="Content/bootstrap.min.css" rel="stylesheet" /> <link href="Content/myStyle.css" rel="stylesheet" />
نکته : برای تکمیل آموخته های خود درباره موضوع مهم پنل ، میتوانید به وب سایت مرجع بوت استرپ و یا وب سایت W3Schools مراجعه کنید .
دکمه در بوت استرپ (Bootstrap Button):
تعریف دکمه توسط تگ input:
در html دکمه را با تگ input تعریف میکردیم و انعطاف پذیری گرافیکی زیادی نداشت :
<input type="submit" value="My Button 1 (Submit)" /> <input type="reset" value="My Button 2 (Reset)" /> <input type="button" value="My Button 3 (Button)" />
تعریف دکمه توسط تگ button:
ولی در فریمورک بوت استرپ باید از تگ button استفاده کرد که بسیار شیک تر از دکمه های سابق می باشد :
<button type="submit">My Button 4 (Submit)</button> <button type="reset">My Button 5 (Reset)</button> <button type="button">My Button 6 (Button)</button>
استایل دهی به دکمه های بوت استرپی:
دکمه های بالا هنوز استایل بوت استرپی ندارند . برای اعمال این استایل باید مانند زیر کلاس css را به آن اضافه کنیم :
<!--– Standard button –--><button class="btn btn-default" type="button">Default</button>
رنگی کردن دکمه ها:
دکمه فوق پیش فرض bootstrap است یعنی هیچ گونه رنگ و استایلی ندارد و به رنگ طوسی است . برای رنگی کردن دکمه داریم :
<button class="btn btn-primary" type="button">Primary</button> <!--– Indicates a successful or positive action –--> <button class="btn btn-success" type="button">Success</button> <!--– Contextual button for informational alert messages –--> <button class="btn btn-info" type="button">Info</button> <!--– Indicates caution should be taken with this action –--> <button class="btn btn-warning" type="button">Warning</button> <!--– Indicates a dangerous or potentially negative action –--> <button class="btn btn-danger" type="button">Danger</button>
مشاهده می شود که مانند پنل ها ، دکمه ها نیز شامل 5 رنگ هساتند که میتوانیم با توجه به موقعیت ، از آنها استفاده کنیم .
طراحی دکمه لینکی در بوت استرپ:
اگر بخواهیم دکمه ای بصورت لینک نمایش داده شود باید بصورت زیر انجام دهیم :
<button class="btn btn-link" type="button">Link</button>
طراحی لینک بصورت دکمه:
نکته 2) : اگر بخواهیم لینکی شبیه دکمه نمایش داده شود باید بصورت زیر انجام دهیم:
<a class="btn btn-primary" href="http://www.Mohtavaban.com">Link</a>
تغییر اندازه دکمه بوت استرپی :
به منظور تغییر سایز دکمه ها باید از کلاسهای زیر استفاده کنیم :
<button class="btn btn-primary btn-xs" type="button">Extra small button</button> <button class="btn btn-info btn-sm" type="button">Small button</button> <button class="btn btn-warning btn-md" type="button">Medium button</button> <button class="btn btn-danger btn-lg" type="button">Large button</button>
خروجی بصورت زیر می شود :
اگر بخواهیم دکمه ای ، تا جایی که جا دارد بزرگ شود (مانند شکل فوق-دکمه بالا) باید به آن کلاس btn-block بدهیم :
<div class="row"> <div class="col-sm-6"> <button class="btn btn-primary btn-sm btn-block" type="button">Small Block Primary Button</button> </div> </div>
نکته : با افزودن فایل bootstrap-theme.min.css به head صفحه خود ، مشاهده می کنیم که به تمامی المان های موجود در صفحه ، گرافیک بهتری اعمال می شود (مثلا دکمه ها حالت برجسته و دارای gradient می شوند) .
نکته : برای یادگیری بیشتر درباره button و button group میتوانید به وب سایت مرجع بوت استرپ مراجعه کنید .
جدول در بوت استرپ (Bootstrap Table):
اعمال کلاس table به تگ <table>:
جدول در html با تگ <table> مشخص میشود . با افزودن کلاس table به این تگ ، میتوان یک جدول بوت استرپی پیش فرض داشت ولی کلاس های زیادی برای جدول وجود دارند که به هر چه زیباتر شدن جداول در بوت استرپ کمک میکنند:
<table class="table"> <tbody> <tr> <td> Content Here...! </td> </tr> </tbody> </table>
کلاس table-responsive برای اعمال واکنش گرایی:
برای افزودن قابلیت واکنش گرایی به جدول ، باید در تگ والد تگ table کلاس table-responsive را اضافه کنیم :
<div class="row"> <div class="col-sm-12 table-responsive"> <table class="table"> <tbody> <tr> <td> Content Here </td> </tr> </tbody> </table> </div> </div>
با اینکار ، وقتی وب سایت خود را در دستگاه های مختلف مانند تبلت و یا موبایل می بینیم ، جدول بهم نمیریزد و اسکرول افقی نمیخورد .
کلاسهای table-condensed و table-bordered:
با افزودن کلاس table-bordered جدول دارای حاشیه می شود . توسط کلاس table-condensed جدول کمی فشرده تر نمایش داده میشود .
کلاسهای table-striped و table-hover:
توسط کلاس table-striped سطرهای جدول بصورت یکی در میان به رنگ کم رنگ و پررنگ در می آید . با کلاس table-hover با رفتن موس به روی هر سطر از جدول ، رنگ آن سطر پررنگ تر می شود .
بطور کلی داریم :
<div class=”row”> <div class=”col-sm-12 table-responsive”> <table class=”table table-bordered table-condensed table-striped table-hover”> <tbody> <tr> <th> # </th> <th> First Name </th> <th> Last Name </th> <th> Phone Number </th> </tr> <tr> <td> 1 </td> <td> Ehsan </td> <td> Safari </td> <td> 09026660220 </td> </tr> </tbody> </table> </div> </div>
خروجی بصورت شکل زیر است :
شخصی سازی استایل های جدول بوت استرپ:
حالا میخواهیم به جدول بالا ، استایل دلخواه خود را اعمال کنیم (مثلا رنگ نوشته های جدول زرد شود) بدین منظور می بایست در بخش head صفحه استایل زیر را بدهیم :
div .table > tbody{ color:yellow; }
و نیز میخواهیم رنگ سطرهای جدول بصورت یکی در میان بنفش کم رنگ و پررنگ شوند (توسط css3 امکان پذیر است) :
.table-striped > tbody > tr:nth-of-type(odd) { background-color: #9d6cc3; } .table-striped > tbody > tr:nth-of-type(even) { background-color: #7f39b5; }
نکته : برای تکمیل اطلاعات درباره جداول در بوت استرپ ، به وب سایت مرجع بوت استرپ و یا وب سایت W3schools مراجعه شود .
طراحی فرم لاگین واکنشگرا در بوت استرپ:
در این بخش میخواهیم یک فرم لاگین واکنش گرا مطابق شکل زیر طراحی کنیم :
طراحی یک div با کلاس container:
ابتدا یک div با کلاس container در خط اول بعد از تگ body تعریف میکنیم و سپس به آن margin-top میدهیم :
div.container { margin-top: 20px; }
ایجاد یک پنل برای طراحی فرم لاگین یا رجیستر:
سپس یک پنل تعریف میکنیم که هم heading دارد هم body هم footer . در بخش heading عنوان فرم را مینویسیم مانند Login یا Register که کد آن بصورت زیر است :
<div class="panel panel-primary"> <div class="panel-heading"> <h4 class="panel-title"> Login </h4> </div> </div>
در داخل فوتر پنل ورود دو تا لینک داریم که یکی برای فراموشی رمز عبور است و دیگری برای هدایت به فرم ثبت نام :
<div class="panel-footer"> <a href="#">Forgot Password</a> | <a href="#">Register for free</a> </div>
و اما قسمت اصلی فرم لاگین ، بخش body آن است . باید تمام المانهای فرم را از قبیل TextBox و Button و CheckBox را داخل تگ form قرار بدهیم .
خصوصیات تگ فرم در HTML :
یکی از خصوصیاتی که باید در تگ فرم مقداردهی شود action می باشد که باید آدرس اکشنی را بنویسیم که میخواهیم اطلاعات ورودی کاربر را به آن ارسال کنیم . این ارسال میتواند بصورت post باشد یا get (برای فرمهای ورود اطلاعات معمولا post است) بنابراین خاصیت method را نیز post تعریف میکنیم .
یادآوری : در جلسه اول ، بخش سوم، با متدهای post و get و نیز اکشن آشنا شدید .
خاصیت autoComplete:
خاصیت autoComplete را نیز بهتر است off کنیم . به این معنیست که مثلا در فیلد ایمیل ، کاربری ایمیل خود را وارد کرده است (مثلا info@EhsanSafari.com) اگر کاربر دیگری روی همان سیستم بخواهد اطلاعات خود را وارد کند و حرف i را بزند ، ایمیل نفر قبلی را می بیند .
خاصیت spellcheck:
خاصیت spellcheck را نیز false میکنیم بویژه در فرمهای زبان فارسی . اگر فعال باشد غلط دیکته ای میگیرد و کارایی ندارد .
خاصیت translate:
خاصیت translate را نیز برابر no قرار می دهیم . این کار مانع نمایش پیغامهای translate که در پایین سایتها ظاهر می شود ، میگردد .
خاصیت name و id:
خاصیت name و id را نیز معمولا عین هم تعریف میکنند مثلا frmLogin .
خاصیت role:
خاصیت role را نیز form قرار میدهیم که معلوم شود فرم ورود اطلاعات است .
بنابراین تگ فرم بصورت زیر در می آید :
<form action="user/login" autocomplete="off" id="frmMain" method="post" name="frmMain" role="form" spellcheck="false" translate="no"> Form Content </form>
کاربرد کلاس form-horizontal:
تمام TextBox ها و button ها و غیره باید درون یک div که کلاس آن form-horizontal است قرار گیرند :
<div class="form-horizontal">
برای هر سطر از فرم یک row تعریف میکنیم و برای label هر سطر معمولا 3 ستون و برای textbox متناظرش 9 ستون جا میگذاریم :
<div class="row form-group"> <label class="col-sm-3 control-label" for="txtEmailAddress">Email Address</label> <div class="col-sm-9"> <input class="form-control" id="txtEmail" name="txtEmail" placeholder="Sample: info@Mohtavaban.com" /> </div> </div>
نکات ایجاد فرم در بوت استرپ:
- در هر سطر که با row مشخص می شوند باید کلاس دیگری بنام form-group را اضافه کنیم .
- به input ها و یا button ها باید کلاسی بنام form-control بدهیم .
- معمولا نام و آیدی هر المان را نیز برابر هم قرار میدهند (مانند تگ فرم) .
طراحی سطر رمز عبور در فرم لاگین:
برای سطر رمزعبور نیز داریم :
<div class="row form-group"> <label class="col-sm-3 control-label" for="txtPassword">Password</label> <div class="col-sm-9"> <input class="form-control" id="txtPass" name="txtPass" placeholder="Hello12345" type="password" /> </div> </div>
تنها تفاوت اساسی آن با سطر ایمیل اینست که type برای input پسورد برابر password است . چون میخواهیم رمز عبور را بصورت ستاره یا دایره نمایش دهد.
سطرهای دکمه Login و Reset:
در نهایت ، سطر مربوط به دکمه های Login و Reset را نیز بصورت زیر تعریف میکنیم :
<div class="row form-group"> <div class="col-sm-9 col-sm-offset-3"> <button accesskey="L" class="btn btn-primary" type="submit">(L)ogin</button><button accesskey="R" class="btn btn-default" type="reset">(R)eset</button> </div> </div>
همانطور که مشاهده می کنید ، به دو دکمه Login و Reset تعداد 9 ستون اختصاص دادیم و نیز گفتیم که به اندازه 3 واحد به سمت راست شیفت شوند تا هم تراز بقیه المانها قرار گیرند .
نکته : برای تمرین بیشتر به وب سایت getBootstrap و یا w3schools مراجعه شود .
فارسی سازی بوت استرپ:
برای فارسی سازی بوت استرپ (راست چین کردن) می بایست در یک فایل مجزا ، استایلهای مختص فارسی سازی را اعمال کنیم و سپس در صفحه خود و بعد از فایل اصلی استایل بوت استرپ آنرا include کنیم .
راستچین کردن فریمورک بوتاسترپ:
خوشبختانه نیازی به این نیست که خودمان اینکار را انجام دهیم . آقای مرتضی انصاری نیا زحمت انجام این فرآیند را کشیده است و بوت استرپ ورژن 3.3.1 را فارسی کرده است که بنده نیز این فایل را در آخر همین مقاله بصورت رایگان برای دانلود شما عزیزان قرار داده ام .
بعد از دانلود فایل مذکور باید بصورت زیر آنرا به صفحه خود اضافه کنیم :
<link href="Content/bootstrap.min.css" rel="stylesheet" /> <link href="Content/bootstrap-rtl.min.css" rel="stylesheet" />
در فرم لاگینی که در مقاله قبل آموختیم برخی جاها را باید ltr تعریف کنیم (یعنی بصورت پیش فرض چپ به راست) مانند آدرس ایمیل . پس استایل زیر را به ابتدای صفحه اضافه میکنیم :
.ltr { direction: ltr; text-align: left; font-family: Verdana; }
کد فرم لاگین بصورت زیر می شود :
<div class="panel panel-primary"> <div class="panel-heading"> <h4 class="panel-title"> ورود به پایگاه </h4> </div> <div class="panel-body form-horizontal"> <form action="نشانی جایی که می خواهیم اطلاعات به آنجا ارسال شود" autocomplete="off" id="frmMain" method="post" name="frmMain" role="form" spellcheck="false" translate="no"> <div class="row form-group"> <label class="col-sm-3 control-label" for="txtEmailAddress">نشانی پست الکترونیکی</label> <div class="col-sm-9"> <input class="form-control ltr" id="txtEmailAddress" name="txtEmailAddress" placeholder="نمونه: info@EhsanSafari.com" type="search" /> </div> </div> <div class="row form-group"> <label class="col-sm-3 control-label" for="txtPassword">گذرواژه</label> <div class="col-sm-9"> <input class="form-control ltr" id="txtPassword" name="txtPassword" placeholder="نمونه: Hello12345" type="password" /> </div> </div> <div class="row form-group"> <div class="col-sm-9 col-sm-offset-3"> <button accesskey="S" class="btn btn-primary" type="submit">ورود</button><button accesskey="R" class="btn btn-default" type="reset">حالت اولیه</button> </div> </div> </form> </div> <div class="panel-footer"> <a href="#">کلمه عبور را فراموش کرده‌ام</a> | <a href="#">رایگان ثبت نام کنید</a> </div> </div>
همانطور که میبینیم تنها کاری که ما برای فارسی سازی انجام داده ایم افزودن استایل فارسی بود و تغییر عناوین فرم از انگلیسی به فارسی . همین
خروجی فرم فوق به شکل زیر است :
دانلود فایل فارسیساز بوت استرپ:
برای دانلود فایل css مربوط به فارسی سازی بوت استرپ bootstrap-rtl.min را کلیک کنید .
آموزش ASP.NET MVC5 – فصل4
امیدوارم تا بدین جای مقالات آموزشی ASP.NET MVC5 بخوبی توانسته باشیم شما را با دنیای MVC آشنا کرده باشیم و قدمی کوچک در یادگیری شما در این زمینه برداشته باشیم . لطفا ما را از دیدگاه های خود درباره این مقاله آموزشی با خبر سازید .
آموزش طراحی Layout در ASP.NET MVC5
تفاوت MasterPage و Layout :
Layout در MVC دقیقا شبیه مفهوم MasterPage در ASP.NET webform می باشد . برای دوستانی که با Masterpage آشنایی ندارند عرض میکنم که وقتی Masterpage تعریف میکنیم ، یک یا چند بخش دارد بنام ContentPlaceHolder . در هر صفحه ای که از این فایل ارث می برد ، مطالب داخل ContentPlaceHolder داینامیک می شود یعنی صفحه به صفحه مطلبش تغییر می کند ولی کدها و منوهای بیرون ContentPlaceHolder ثابت هستند و در هر صفحه عینا تکرار می شوند .
نکته : در معماری ASP.NET MVC بجای Masterpage مفهوم Layout را داریم و بجای Page ها View داریم و بجای ContentPlaceHolder عبارت RenderBody .
محل ذخیره سازی Layout ها :
مکان تعریف Layout در فولدر Shared در زیر فولدر Views می باشد . برخلاف PartialView ها که باید در روت root فولدر shared باشند ، Layout را می توانیم هم در روت تعریف کنیم و هم در فولدر دلخواه خود داخل فولدر Shared .
توصیه ما اینست که داخل فولدر shared فولدری بنام Layouts تعریف کنیم و Layout ها را آنجا ایجاد کنیم تا با partialview ها قاطی نشوند .
نحوه ایجاد Layout :
در برنامه ویژوال استودیو ، فولدر Shared را در زیر فولدر views ایجاد میکنیم و سپس فولدر Layouts را در زیر فولدر Shared ایجاد میکنیم. حالا روی فولدر Layouts راست کلیک کرده و Add–>New Item را انتخاب میکنیم . از منوی سمت چپ باید web انتخاب شده باشد و در لیست سمت راست ، گزینه MVC5 Layout Page را انتخاب میکنیم . نام آنرا نیز بنابر توصیه مایکروسافت ، با یک underline و سپس کلمه Layout تعریف میکنیم .
بعد از ایجاد Layout صفحه ای با کد زیر نمایش داده می شود :
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> </head> <body> <div> @RenderBody() </div> </body> </html>
افزودن فایل CSS سفارشی:
در بخش head باید css سفارشی خود را add کنیم :
<link href="~/Content/Site.css" rel="stylesheet" />
و در ابتدا کد بدنه layout را بصورت زیر تعریف میکنیم :
<div id="layout"> <div id="header"> </div> <div id="subHeader"> </div> <div id="main"> @RenderBody() </div> <div id="subFooter"> </div> <div id="footer"> </div> </div>
تمام بخشهای هدر و فوتر static و بخش main داینامیک است یعنی در هر view محتویات داخل آن تغییر میکند .
تعریف View برای استفاده از Layout:
حالا در این مرحله میخواهیم یک View تعریف کنیم که از Layout فوق خوراک بگیرد . برای اینکار مانند قبل روی فولدر Views و زیرفولدر مثلا Home راست کلیک کرده و گزینه Add–>View را انتخاب میکنیم . در پنجره باز شده ، مطابق شکل زیر ، باید تیک گزینه Use a layout or masterpage را بزنیم و آدرس Layout فوق را در محل مربوطه وارد کنیم :
فرآیند نمایش خروجی به کاربر :
زمانی که کاربر یک اکشن از کنترولر را صدا میکند ، ابتدا وارد Default Constructor کنترولر میشود بعد به اکشن میرود . سپس به view مربوط به اکشن میرود و در view کد html آن ساخته میشود و میبیند که view از layout استفاده میکند ، این کد html ساخته شده را داخل layout قسمت renderBody قرار میدهد و در نهایت HTML نهایی را بصورت یکپارچه به سمت کلاینت (مرورگر کاربر) میفرستد .
خروجی ما در صورت استفاده از view و layout این مقاله به شکل زیر می شود :
مطالبی که تا اینجا در زمینه Layout یاد گرفتیم ، مانند MasterPage در ASP.NET webform بود . ولی تا انتهای این مقاله، با امکانات جالب و کارآمد Layout آشنا خواهیم شد.
کاربرد RenderBody و RenderSection در Layout:
در ASP.net webform اگر بخواهیم چند بخش از صفحه را داینامیک اعلام کنیم یعنی در صفحات مختلف محتویات متفاوتی داشته باشد ، باید در MasterPage چند تا contentPlaceHolder تعریف کنیم . ولی در MVC قضیه متفاوت است . بدین صورت که در Layout یک بخش اصلی داریم بنام RenderBody و قسمتهای اضافی (که میخواهیم علاوه بر بدنه اصلی ، داینامیک باشد) با RenderSection تعریف می شوند . بنابر این ما باید در فایل Layout یک و فقط یک RenderBody داشته باشیم و هیچ یا چند تا RenderSection .
نحوه تعریف دستور RenderSection:
دستور RenderSection پارامتر ورودی بنام name میگیرد که مثلا برای بخش header میتوانیم بدین صورت تعریف کنیم :
@RenderSection(name: "HeaderSection")
نکته : اگر در Layout بخش RenderSection تعریف کنیم ولی در View ای که از این layout خوراک میگیرد renderSection را تعریف نکنیم با خطا مواجه می شویم . پس باید دقیقا به تعداد RenderSection های فایل layout در view نیز RenderSection را تعریف کنیم .
تعریف section در view:
برای تعریف section در view باید بصورت کد زیر عمل کنیم :
@section HeaderSection { <a href="~/Home/Index">Home</a> }
بنابراین در این مثال کد layout ما بصورت زیر است :
<div id="layout"> <div id="header"> @RenderSection(name: "HeaderSection") </div> <div id="main"> @RenderBody() </div> <div id="footer"> </div> </div>
و کد view آن نیز بصورت زیر می باشد :
@{ ViewBag.Title = "Learn 3"; Layout = "~/Views/Shared/Layouts/_Layout3.cshtml"; } @section subHeaderSection { <a href="~/Home/Index">Home</a> } <h2>Learn 3</h2> <p>Hello World!</p>
توضیح : بخش renderSection که در view به رنگ آبی مشخص شده است میرود بجای rendersection فایل layout می نشیند و بقیه کدهای view (تگ h2 و p) داخل renderBody نمایش داده میشوند .
نکته : برای یادگیری بیشتر به وبلاگ asp.net مراجعه شود .
تعریف Section بصورت اختیاری (Optional):
ویژگی جالب و متفاوت Layout ها در mvc (نسبت به masterpage ها در asp.net webform) اینجاست که میتوان section خاصی را optional (اختیاری) کرد یعنی این که اگر در view این section تعریف نشده بود error ندهد . برای اینکار باید پارامتر دیگری به RenderSection در layout بدهیم بنام required . مقدار پیش فرض آن true است . اگر آنرا false کنیم ، دیگر تعریف ان در view اجباری نیست :
@RenderSection(name: "HeaderSection", required: false)
تعریف مقدار پیشفرض برای Section:
امکان دیگری که Layout در اختیار ما قرار میدهد اینست که میتوان محتوای پیش فرض برای section تعریف کنیم . یعنی اگر section خاصی که در layout تعریف شده است ، در view تعریف نشده باشد ، مقدار پیش فرضی که در layout تعیین کردیم نمایش داده می شود :
<div id="Header"> @if (IsSectionDefined(name: "HeaderSection")) { @RenderSection(name: "HeaderSection") } else { <text>Default Header Section!</text> } </div>
فایل ViewStart :
در این فایل میتوان نام layout را تعریف کنیم . نام این فایل رزرو شده است و باید خودمان ایجاد کنیم . برای ساختن این فایل روی پوشه Views راست کلیک کرده و گزینه add–>view را انتخاب میکنیم . در پنجره ظاهر شده ، تیک هیچکدام از گزینه ها را نمیزنیم و نام فایل view را دقیقا بصورت زیر مینویسیم :
_ViewStart
در view باز شده layout ای که قبلا ایجاد کردیم را تعریف میکنیم :
Layout = "~/Views/Shared/Layouts/_Layout7.cshtml";
ایجاد View برای استفاده از Layout واقع در ViewStart:
برای ایجاد view ای که از این layout خوراک بگیرد بصورت زیر عمل میکنیم :
مانند قبل روی پوشه Home (یا هر پوشه دیگری) که داخل پوشه Views است راست کلیک کرده و add—>view را میزنیم . سپس مانند شکل زیر در پنجره باز شده تیک user a layout را میزنیم ولی چیزی در باکس زیر آن نمی نویسیم . همانطور که در ذیل این باکس مشاهده میکنید ، میگوید “اگر نام layout در فایل viewStart ست شده است ، این باکس را خالی بگذارید” و در نهایت add را میزنیم . روش توصیه شده ایجاد view نیز همین روش است (بجای اینکه در بالای view نام layout را به صراحت تعریف کنیم بهتر است آنرا در viewStart ست کنیم)
نکته : با استفاده از فایل viewstart میتوان چند تا layout تعریف کنیم و در مناسبت های گوناگون ، layout متناسب آنرا نمایش دهیم (بصورت runTime) .
برای یادگیری بیشتر ، این تمرین را به خود شما واگذار میکنم در صورتی که سوال یا ابهامی داشتید لطفا به ما اعلام کنید. با تشکر
جلسه چهارم از سری آموزشی MVC در اینجا به پایان میرسد .
آموزش ASP.NET MVC5 – فصل5
با عرض سلام مجدد خدمت علاقه مندان به مقاله آموزشی MVC . در فصل چهارم، با نحوه ایجاد و طراحی Layout در MVC آشنا شدیم. در فصل پنجم میخواهیم با HtmlHelper نویسی در MVC آشنا شویم .
آموزش HtmlHelper نویسی در ASP.NET MVC:
تا کنون با دو نمونه از HtmlHelper ها در MVC کار کرده ایم . یکی Html.Partial و دیگری Html.Raw . حالا میخواهیم با چند نمونه دیگر از htmlhelper ها آشنا شویم و در نهایت خودمان یک HtmlHelper بنویسیم
در ASP.NET webform برای ایجاد تکست باکس ، asp:textbox داشتیم (یک شئ از یک کلاس است) و در MVC ، معادل آن Html.TextBox می باشد (یک متد است)
HtmlHelper برای ایجاد تگ فرم :
@{ Html.BeginForm(); } @{ Html.EndForm(); }
دقیقا در سمت کاربر ، همان تگ فرم form نمایش داده میشود (render می شود) و بطور پیش فرض متد آنرا post و اکشن آنرا نیز همان اکشن جاری انتخاب میکند . بنابراین اگر در سمت کلاینت ، view page source را بزنیم ، کدی مانند زیر میبینیم :
<form action="/Home/Learn02" method="post"></form>
HtmlHelper برای تولید Label :
@Html.Label(expression: "firstName", labelText: "First Name")
همانطور که می بینیم دو پارامتر میگیرد ، یکی expression (مانند for در label های سابق) و دیگری labelText که متن Label را مشخص می کند .
HtmlHelper برای تولید TextBox :
برای ایجاد textbox میتوان به 7 روش پارامترهای آنرا تعریف نمود (7 تا overload دارد) . یک روش آن فقط name میگیرد . روش دیگر name , value میگیرد (مقدار اولیه داخل textbox) مورد بعدی که مهم است htmlAttributes می باشد که باید بصورت anonymous Object تعریف شود . مواردی از قبیل css style و max length و غیره در اینجا تعریف می شوند . برای مثال در textbox زیر داریم :
@Html.TextBox(name: "fName", value: null, htmlAttributes: new { maxlength = 20, title = "Name", @class = "form-control" })
نکته : برای تمرین بیشتر در زمینه HtmlHelpers میتوانید به وب سایت W3Schools و یا وب سایت مرجع asp.net مراجعه کنید .
لزوم استفاده از HtmlHelper ها در MVC:
سناریو : فرض کنید یک پروژه بزرگی دارید که مثلا 1000 تا textbox دارد . روزی تصمیم می گیرید textbox های خود را بوت استرپی کنید (یعنی کلاس form-control را به هر textbox اضافه کنید) . برای اینکار باید 1000 جا را تغییر بدهید و عملا امکان پذیر نیست . ولی اگر textbox های خود را در htmlhelper تعریف کنید ، فقط کافیست کد htmlhelper مربوط به textbox را تغییر دهید و کلاس form-control را به آن اضافه کنید .
انجام تغییرات سراسری در پروژه MVC توسط HtmlHelper:
مثال دیگری که کاربرد htmlHelper ها را بیشتر نمایان میکند اینست که فرض کنید بخواهیم label های یک پروژه را داخل div ای با کلاس caption تعریف کنیم . با استفاده از htmlHelper دیگر نیازی نیست در کل پروژه تغییرات را اعمال کنیم . فقط و فقط htmlhelper مربوط به label را تغییر میدهیم .
تعریف HTMLHelper در MVC:
برای شروع کار ابتدا یک فولدر بنام Infrastructure در روت پروژه میسازیم و روی فولدر راست کلیک کرده و یک کلاس add میکنیم . نام کلاس را TraditionalHtmlHelpers.cs انتخاب میکنیم . سپس در کلاس باز شده ، بصورت زیر عمل میکنیم :
namespace Infrastructure { public static class TraditionalHtmlHelpers { static TraditionalHtmlHelpers() { } } }
کلاس باید از نوع static باشد که برای فراخوانی آن نیاز نباشد که ابتدا از آن کلاس ، شئ تولید کنیم .
پیاده سازی تابع Label توسط htmlhelper:
اکنون در ادامه کلاس ، تابع مربوط به Label را مینویسیم که خروجی آن string است و دو پارامتر ورودی میگیرد : expression , labelText . کد تابع Label بدین صورت است :
public static string Label(string expression, string labelText) { // Solution (1) string strResult = string.Format("{1}", expression, labelText); return (strResult); }
اکنون توانسته ایم htmlHelper ساده ای برای label تعریف کنیم .
فراخوانی HtmlHelper مربوط به Label:
برای فراخوانی این تابع در view بدین صورت عمل می کنیم :
باید نام فولدر (Infrastructure) را بهمراه نام فایل (TraditionalHtmlHelpers) بهمراه نام تابع (Label) را ذکر کنیم :
@Html.Raw(Infrastructure.TraditionalHtmlHelpers.Label(expression: "firstName", labelText: "First Name"))
حالا می خواهیم تمام label هایی که در پروژه خود استفاده کرده ایم را داخل div ای با کلاس caption قراردهیم . متغیر strResult بصورت زیر تعریف می شود :
string strResult = string.Format("<div class="caption"><label for="{0}">{1}</label></div>", expression, labelText);
نکته : برای تکمیل آموخته های خود ، به وب سایت W3Schools مراجعه کنید .
ایرادات احتمالی در HtmlHelper نویسی:
تا کنون به نحوه HTMLHelper نویسی در ASP.NET MVC آشنا شدیم و توانستیم یک label را توسط آن تعریف کنیم. این روش دارای ایراداتی بود مانند اینکه باید مسیر طولانی محل ذخیره سازی htmlHelper را در هر بار فراخوانی ، بیان میکردیم . همچنین باید Html.Raw را نیز صدا میزدیم . در این بخش میخواهیم ایرادات مذکور را برطرف کنیم .
میخواهیم label تعریف شده را بصورت Extension Method تعریف کنیم . یعنی وقتی Html را مینویسیم و دات (نقطه) را میزنیم ، متدی که ما برای label نوشتیم نیز در لیست ظاهر شده وجود داشته باشد و نیازی به تایپ دستی آن نباشد .
نحوه نوشتن Extension Method :
ابتدا روی فولدر Infrastructure راست کلیک کرده و add–>class میکنیم و نام کلاس را HtmlHelpers.cs قرار میدهیم (نام کلاس دلخواه است) .
سپس تابع زیر را بعد از Default Constructor کلاس می نویسیم . هم تابع و هم کلاس htmlhelper ای که مینویسیم باید public و static باشند . نکته مهم و کلیدی در Extension Method نویسی اینست که در هنگام تعریف تابع ، پارامتر اول آن همیشه باید چیزی باشد که بیانگر این است که این تابع به چه چیزی میخواهد Extend شود (که در این مقاله به htmlHelper میخواهیم Extend شود) . پارامترهای بعدی نیز مثلا همان expression و labelText می باشند :
public static string ESLabel (this System.Web.Mvc.HtmlHelper myParam, string expression, string labelText) { string strResult = string.Format("{1}", expression, labelText); return (strResult); }
پارامتری که آبی رنگ است همان نوع Extension می باشد و دو پارامتر دیگر سبز رنگ پارامترهای دلخواه هستند . (نام myParam دلخواه می باشد) .
استفاده از Extension Method :
همانطور که می بینید بدنه تابع مانند قبل است . برای اینکه بتوان از این ExtensionMethod در view خود استفاده کنیم باید در view در بالای صفحه عبارت زیر را بنویسیم تا nameSpace مربوط به ESLabel را اضافه کرده باشیم :
@using Infrastructure
سپس در view در هرجای صفحه که خواستیم میتوان از label خودمان استفاده کنیم :
@Html.Raw(Html.ESLabel("firstName", "First Name"))
مشاهده میکنید که همچنان باید Html.Raw را بنویسیم (برای اینکه تگ های html داخل متغیر strResult تابع ESLabel در مرورگر render شوند) . برای رفع این مشکل باید نوع خروجی تابع ESLabel را عوض کنیم و از نوع زیر قرار دهیم :
public static System.Web.IHtmlString ESxLabel
و در هنگام return کردن خروجی ، Html.Raw را آنجا تعریف کنیم :
return (htmlHelper.Raw(strResult.ToString()));
بنابراین بطور کلی تابع ESxLabel نهایی بصورت زیر می باشد :
public static System.Web.IHtmlString ESLabel (this System.Web.Mvc.HtmlHelper htmlHelper, string expression, string labelText) { string strResult = string.Format("{1}", expression, labelText); return (htmlHelper.Raw(strResult.ToString())); }
برای انجام تمرینات بیشتر در زمینه ExtensionMethodها ، به وب سایت asp.net مراجعه کنید .
خب دوستان عزیز ، فصل پنجم از مقالات آموزشی MVC به پایان رسید . در فصل آینده با Area ها در MVC آشنا می شویم . با ما باشید
آموزش ASP.NET MVC5 – فصل6
آشنایی با Area در MVC و نحوه استفاده از آن در پروژه
لزوم استفاده از Area در پروژههای MVC:
در این جلسه میخواهیم با مبحث Area ها آشنا شویم . برای پروژه های نسبتا بزرگ که مثلا شامل 500 تا کنترولر می باشد ، منطقی نیست که همه آنها را داخل یک فولدری بنام Controllers در روت پروژه بریزیم . برای حل این مشکل ، مایکروسافت در MVC4 مفهومی بنام Area را مطرح کرد .
نحوه افزودن Area به پروژه ASP.NET-MVC:
هر Area تمام امکانات روت پروژه را دارد مانند Models , Views و … برای افزودن یک Area به پروژه خود ، روی نام پروژه در Solution Explorer راست کلیک کرده و سپس Add—>Area را انتخاب میکنیم . در این مرحله نام area موردنظرمان را تایپ کرده مثلا admin و ok میکنیم . اتوماتیک فولدر Area در روت پروژه ایجاد می شود و در فولدر Area ، فولدر admin ساخته می شود .
ActionLink چیست و چه کاربردی دارد؟
برای رفتن از روت پروژه به یک اکشنی در area و یا برعکس ، بهتر است از actionLink استفاده کنیم . اکشن لینک بطور معمول دو پارامتر میگیرد : اولی linkText و دیگری actionName .
تعریف linkText و actionName:
linkText متنی که برای لینک نمایش داده می شود می باشد و actionName نام اکشنی که میخواهیم به آن لینک بدهیم . دقت کنید که در اینصورت ، آن اکشن باید در همین کنترولر باشد . اگر بخواهیم به اکشنی در کنترولر دیگری لینک بدهیم هم controllerName را نیز باید تعریف کنیم :
@Html.ActionLink(linkText: "Help", actionName: "Help") @Html.ActionLink(linkText: "Help", actionName: "Help", controllerName: "Home")
نحوه لینک دادن به اکشن در Area دیگر:
اگر بخواهیم به اکشنی لینک بدهیم که در Area دیگری وجود دارد ، باید actionLink را به روش خاصی تعریف کنیم که شاید یه کمی پیچیده باشد .
فرض کنید Area ما admin است ، روش تعریف actionLink بصورت زیر اشتباه می باشد :
@Html.ActionLink(linkText: "Users List", actionName: "List", controllerName: "User", areaName: "admin")
روش صحیح تعریف actionLink در صورت وجود داشتن area بصورت زیر است :
@Html.ActionLink(linkText: "Users List", actionName: "List", controllerName: "User", routeValues: new { Area = "admin" }, htmlAttributes: null)
لینک به یک اکشن در روت پروژه:
اگر Area برابر null string باشد منظور کنترولر واقع در روت root پروژه است . کاربرد این روش زمانی است که در یک area هستیم و میخواهیم به اکشنی در روت پروژه لینک بدهیم . بنابراین باید actionLink ما باید بصورت زیر تعریف شود :
@Html.ActionLink(linkText: "Home", actionName: "Index", controllerName: "Home", routeValues: new { Area = "" }, htmlAttributes: null)
در صورت تعریف area به آدرس بار مرورگر ما یک پارامتر اضافه می شود یعنی بصورت زیر می شود :
https://mohtavaban.com/areaName/controllerName/actionName/parameters(optional)
برای یادگیری بیشتر در مورد Area به وب سایت asp.net مراجعه کنید .
یکسان بودن نام کنترولر در Area با کنترولر در Root پروژه:
حال این سوال پیش می آید که اگر نام کنترولری در area با نام کنترولری در روت پروژه یکسان باشد ، چه مشکلی رخ میدهد . مثلا اگر علاوه بر HomeController ای که در روت پروژه داریم ، یک HomeController دیگری در area داشته باشیم ، کامپایلر دچار ابهام می شود که کدام HomeController منظور ما است.
لزوم استفاده از Routing در MVC:
برای حل این مشکل می بایست از مبحث routing استفاده کنیم . در روت پروژه فولدری بنام app_start وجود دارد . در این فولدر فایلی بنام RouteConfig وجود دارد که میتوان routing دلخواه را در آن تعریف کرد .
فایل RouteConfig:
تابع RegisterRoutes در فایل RouteConfig بطور پیش فرض بصورت زیر تعریف شده است :
public static void RegisterRoutes (System.Web.Routing.RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = System.Web.Mvc.UrlParameter.Optional } ); }
کنترلر و اکشن پیشفرض در MVC:
در هنگام اجرای پروژه ، کنترولر پیش فرض Home می باشد و اکشن پیش فرض نیز Index . این اسامی در این تابع تعریف شده اند . در صورتی که اسم کنترولر را ذکر نکنیم Home و اگر اکشن را قید نکنیم Index اجرا میشود . در صورت لزوم می توان آنها را تغییر داد مثلا نام کنترولر پیش فرض را Default قرار بدهیم !
روش حل مشکل تداخل اسامی یکسان کنترلرها:
برای حل مشکل تداخل یا conflict نام های یکسان کنترولر ، باید پارامتری بنام nameSpace را به تابع RegisterRoutes اضافه نمود :
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = System.Web.Mvc.UrlParameter.Optional }, namespaces: new[] { "LEARNING_AREA.Controllers" } ); }
توضیح : LEARNING_AREA.Controllers اسم namespace کنترولر Home روت پروژه می باشد . در اینصورت با اجرای پروژه ، اگر نام کنترولر را ننویسیم ، کامپایلر با رجوع به این فایل میفهمد که منظور ما کنترولر واقع در روت پروژه می باشد .
فایل routeConfig در Area:
در هر area نیز فایل routeConfig را داریم . پس به این مسیر می رویم :
Root > Areas > admin > adminAreaRegistration.cs
تابع RegisterArea:
در این فایل تابع RegisterArea کار همان تابع RegisterRoutes را انجام می دهد . nameSpace مربوط به کنترولر Home داخل admin area را باید تعریف کنیم :
public override void RegisterArea(System.Web.Mvc.AreaRegistrationContext context) { context.MapRoute( "Administrator_Default", "Administrator/{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = System.Web.Mvc.UrlParameter.Optional }, namespaces: new[] { "LEARNING_AREA.Areas.Administrator.Controllers" } ); }
نوگت T4MVC چیست و چه کاربردی دارد؟
سناریو : به یاد دارید که در زمان RedirectToAction باید نام اکشن را بصورت دستی می نوشتیم و نیز در ActionLink ها ، نام کنترولر و نام اکشن و سایر پارامترها را بطور دستی تایپ میکردیم . اینکار مشکلاتی بهمراه دارد . یکی اینکه امکان غلط دیکته ای در تایپ وجود دارد . دیگری اینکه باید اول ببینیم در فلان کنترولر چه اکشنی وجود دارد تا از آن استفاده کنیم . برای رفع این مشکل با نوگت (nuget) دیگری آشنا می شویم بنام T4MVC .
نحوه نصب T4MVC در پروژه ASP.NET MVC:
دوستان عزیز ، در مقاله آشنایی با فریم ورک بوت استرپ نحوه استفاده از نوگت را فرا گرفتید . بنابراین به مسیر زیر می رویم :
Tools > NuGet Package Manager > Package Manager Console
مطابق شکل زیر ، دستور نصب T4MVC را تایپ میکنیم :
اجرای دستور install-package T4MVC:
با اجرای این فرمان ، سه فایل و فولدر به پروژه اضافه می شود و تمام area و action و controller ها را stronglyType میکند . هر زمانی که بعنوان مثال کنترولری میسازیم یا آنرا rename میکنیم یا پاک میکنیم ، area میسازیم rename یا پاک میکنیم ، اکشنی add , rename , delete میکنیم و یا signature آنرا تغییر میدهیم ، روی فایل t4mvc.tt دابل کلیک کرده و آنرا باز میکنیم و سپس روی همان فایل راست کلیک کرده (مطابق شکل زیر) و گزینه Run Custom Tool را میزنیم :
استفاده از T4MVC در RedirectToAction :
دیگر از این پس لازم نیست نام اکشن ها و کنترولرهای خود را حفظ کنید و آنها را دستی تایپ کنید ، چرا که توسط T4MVC شما میتوانید با نوشتن کلمه MVC (با حروف بزرگ) و سپس زدن نقطه ، تمام کنترولرهای موجود را ببینید (مانند شکل زیر) :
استفاده از T4MVC در ActionLink :
فرض کنید میخواهیم لینکی در view قرار دهیم که به area Administrator و کنترولر User و اکشن List هدایت شود . سه روش برای اینکار وجود دارد . اول اینکه لینک را بصورت کلاسیک بنویسیم :
<a href="~/Administrator/User/List">Users List</a>
روش دوم اینست که با actionLink و بدون استفاده از T4MVC آنرا بنویسیم :
@Html.ActionLink( "Users List", actionName: "List", controllerName: "User", routeValues: new { Area = "Administrator" }, htmlAttributes: null)
روش سوم و بهترین روش اینست که actionLink را توسط T4MVC بنویسیم :
@Html.ActionLink("Users List", MVC.Administrator.User.List())
همانطور که میبینیم در روش سوم توانستیم با سه کلمه به لینک مورد نظر خود برسیم ولی در روش دوم با دوخط !
امیدوارم جلسه ششم از سری آموزشی ASP.NET-MVC5 مفید بوده باشد . برای تکمیل آموخته های خود درباره نوگت مهم T4MVC ، به وب سایت مرجع T4MVC مراجعه کنید .
در فصل هفتم با Action Filter Attribute آشنا می شویم . همراه ما باشید …
آموزش ASP.NET MVC5 – فصل7
در فصل ششم با مفهوم Area آشنا شدیم و لزوم استفاده از آنها را بیان کردیم. در این جلسه وارد دنیای Action Filter Attribute می شویم.
اکشن فیلتر در MVC چیست و چه کاربردی دارد؟
ما یک سری فولدر در یک پروژه MVC داریم که نام آنها رزرو شده است و نمی توان نام آنها را عوض کرد که عبارتند از : App_Data , Controllers , Views , Shared و یک سری فولدر داریم که نام آنها عرفی هستند یعنی توصیه شده و بهتر است که نامشان همین باشد مانند : Models , ViewModels Infrastructure .
ما در این آموزشها ، کلاسهایی را که پر کاربرد هستند و ممکن است در پروژه های دیگر نیز بدرد ما بخورند را در فولدر Infrastructure تعریف میکنیم .
نکته : Attribute ها کلاسهایی هستند که معمولا در بالای اکشن ها نوشته می شوند مانند دستورات زیر :
[System.Web.Mvc.HttpGet] , [System.Web.Mvc.HttpGet] , [System.Web.Mvc.ActionName(“Learn_Mohtava”)]
ایجاد اتریبیوت سفارشی (Custom Attribute):
در این سری آموزشی ما میخواهیم خودمان یک Attribute بنویسیم . روی فولدر Infrastructure راست کلیک میکنیم و add->class را میزنیم . نام کلاس باید به کلمه Attribute ختم شود مثلا LogAttribute.cs . در بالای این کلاس فقط باید نام namespace یعنی Infrastructure نوشته شده باشد :
namespace Infrastructure
ارث بری از ActionFilterAttribute:
وقتی میخواهیم کلاس ما از کلاس دیگری ارث ببرد ، باید بدین صورت نوشته شود :
public class LogAttribute : System.Web.Mvc.ActionFilterAttribute
با ارث بری از ActionFilterAttribute میتوان 4 متد را override کرد :
OnActionExecuting و OnActionExecuted و OnResultExecuting و OnResultExecuted
سورس کد کلاس LogAttribute:
بنابراین کل کلاس LogAttribute ما بصورت زیر می شود :
namespace Infrastructure { public class LogAttribute : System.Web.Mvc.ActionFilterAttribute { public LogAttribute() { } public override void OnActionExecuting (System.Web.Mvc.ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); } public override void OnActionExecuted (System.Web.Mvc.ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); } public override void OnResultExecuting (System.Web.Mvc.ResultExecutingContext filterContext) { base.OnResultExecuting(filterContext); } public override void OnResultExecuted (System.Web.Mvc.ResultExecutedContext filterContext) { base.OnResultExecuted(filterContext); } } }
استفاده از Attribute سفارشی در پروژه MVC:
برای استفاده از Attribute ای که خودمان نوشتیم در بالای نام اکشن به چند روش میتوان عمل کرد :
[Infrastructure.Log] [Infrastructure.Log()]
اگر میخواهیم پارامتر یا پارامترهایی را به Attribute خود ارسال کنیم باید از روش دوم استفاده کنیم و در داخل پرانتز پارامترها را بیان کنیم ولی اگر مانند این مثال ، پارامتری نمیگیرد بهتر است به روش اول آنرا فراخوانی کنیم (در صورت استفاده از روش دوم ، پیغام خطا نمیدهد) .
ترتیب اجرای پروسه های اکشن فیلتر :
پس از ایجاد Attribute و استفاده از آن ، ترتیب اجرای پروسه ها تا نمایش آن به کاربر بصورت زیر می شود :
- ابتدا وارد Default Constructor کنترولر اکشن می شود .
- سپس وارد Default Constructor کلاس Attribute می شود .
- وارد متد OnActionExecuting می شود .
- وارد اکشنی می شود که Attribute برایش تعریف شده است .
- وارد متد OnActionExecuted می شود .
- وارد متد OnResultExecuting می شود .
- وارد view مربوط به اکشن می شود و آنرا render میکند .
- وارد متد OnResultExecuted می شود .
- در نهایت وارد متد OnResultExecuted می شود و نتیجه بصورت HTML به کلاینت نمایش داده می شود .
اهمیت ایجاد اتریبیوت سفارشی و دانستن ترتیب اجرای پروسه ها:
از کاربردهای بهره بردن از Custom Attribute و دانستن توالی اجرای پروسه ها اینست که میتوان مفاهیمی نظیر Log , Performance , Security , Statistic را در متد OnActionExecuting و سایر متدها بررسی کرد .
بعنوان مثال میتوان در متد فوق :
- بررسی کنیم که آیا کاربری که وارد این مرحله شده است به سایر مراحل میتواند دسترسی داشته باشد و یا لاگین کرده است یا خیر .
- میتوان IP کاربران حاضر در سایت را در دیتابیس ذخیره کنیم .
- میتوان آمار سایت را بدین وسیله بدست بیاوریم .
- میتوان با محاسبه اختلاف زمان متد OnActionExecuting و متد OnActionExecuted متوجه شویم کدام یک از اکشن های ما زمان بیشتری برای اجرا نیاز دارند و یا سنگین تر هستند .
تعریف اتریبیوت لاگ (Log Attribute):
فرض کنید attribute فوق را بالای اکشن Index (بصورت زیر) تعریف کرده ایم :
[Infrastructure.Log] public System.Web.Mvc.ViewResult Index() { return (View()); }
پس با اجرای اکشن Index وارد LogAttribute و متدهای مربوط به آن می شویم . پس اگر اتریبیوت را در بالای هر اکشن بنویسیم فقط روی آن اکشن اعمال می شود . حال اگر بخواهیم اتریبیوت خاصی برای تمام اکشن های یک کنترولر فراخوانی شود ، باید آنرا در بالای نام کلاس Controller نوشت :
[Infrastructure.Log] public class HomeController : System.Web.Mvc.Controller { }
اجرای اتریبیوت سفارشی برای کل پروژه:
برای اینکه Attribute ای که نوشتیم برای کل پروژه اجرا شود ، باید آنرا در فایل FilterConfig.cs واقع در فولدر App_Start رجیستر کنیم :
filters.Add(new Infrastructure.LogAttribute());
بنابراین دستورات تابع RegisterGlobalFilters واقع در فایل FilterConfig بصورت زیر است :
public static void RegisterGlobalFilters (System.Web.Mvc.GlobalFilterCollection filters) { filters.Add(new Infrastructure.LogAttribute()); filters.Add(new System.Web.Mvc.HandleErrorAttribute()); }
با اینکار ، LogAttribute برای تمام area ها ، کنترولرها و اکشن های پروژه اجرا می شود .
تعریف دو اتریبیوت سفارشی در بالای اکشن در MVC:
سناریو : اگر فرض کنیم دو attribute تعریف کرده ایم و میخواهیم هر دو را برای کل پروژه اعمال کنیم ، (اولی LogAttribute و دومی AnotherAttribute)
باید با دستورات زیر آنها را در filterConfig تعریف کنیم :
filters.Add(new Infrastructure.LogAttribute()); filters.Add(new Infrastructure.AnotherAttribute());
ترتیب اجرای پروسههای دو اتریبیوت سفارشی:
ترتیب اجرای پروسه های آن دو بدین صورت می شود :
- ابتدا Default Constructor اولین اتریبیوت یعنی Log اجرا می شود .
- سپس Default Constructor دومین اتریبیوت یعنی Another اجرا می شود .
- در مرحله سوم Default Constructor کنترولر اجرا می شود .
- متد OnActionExecuting اتریبیوت Log
- متد OnActionExecuting اتریبیوت Another
- اکشن اجرا می شود .
- متد OnActionExecuted اتریبیوت دوم یعنی Another
- متد OnActionExecuted اتریبیوت اول یعنی Log
- متد OnResultExecuting اتریبیوت اول یعنی Log
- متد OnResultExecuting اتریبیوت دوم یعنی Another
- به view می رود و render می شود .
- متد OnResultExecuted اتریبیوت دوم یعنی Another
- متد OnResultExecuted اتریبیوت اول یعنی Log
- در نهایت داده بصورت HTML به کلاینت ارسال می شود
اجرای Attribute برای برخی از اکشنها:
در این بخش میخواهیم attribute خاصی را برای کل پروژه به استثنای یک یا چند اکشن اعمال کنیم . باید attribute ای بنویسیم که Ignorable باشد یعنی توسط پارامتر ignore به آن اتریبیوت بگوییم که از فلان اکشن صرف نظر کن . برای اینکار باید ignore را true قرار دهیم . روش انجام اینکار بدین صورت است :
تعریف یک property بنام ignore:
در کلاس attribute مثلا LogAttribute.cs یک property بنام ignore تعریف میکنیم :
public bool Ignore { get; set; }
مقداردهی false در سازنده کلاس:
در سازنده کلاس ، مقدارش را false قرار میدهیم (زیرا بطور پیش فرض نباید صرف نظر کند) :
public LogAttribute() { Ignore = false; }
تعریف سازنده دیگر با پارامتر ورودی ignore:
یک سازنده دیگر میسازیم که ignore را بعنوان پارامتر میگیرد :
public LogAttribute(bool ignore) { Ignore = ignore; }
ویرایش متد OnActionExecuting:
بعد در متد OnActionExecuting میگوییم اگر ignore برابر false بود عملیات Log را انجام دهد :
public override void OnActionExecuting (System.Web.Mvc.ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); if (Ignore == false) { object objAction = filterContext.RouteData.Values[“action”]; object objController = filterContext.RouteData.Values[“controller”]; } }
اجرا نشدن اتریبیوت برای اکشنهای دلخواه:
برای هر اکشنی که میخواهیم این Attribute اجرا نشود ، بصورت زیر ، پارامتر ignore را برابر true قرار میدهیم :
[Infrastructure.Log(ignore: true)] public System.Web.Mvc.ActionResult SomeAction() { return (View()); }
تعریف اتریبیوت Authorize برای تعیین هویت کاربران:
فرض کنید بخواهیم اکشن امن تعریف کنیم یعنی مثلا کاربر باید لاگین کرده باشد تا بتواند وارد این اکشن یا کنترولر بشود . اتریبیوتی بنام Authorize تعریف میکنیم . فرض کنید اکشن SecuredAction را میخواهیم امن کنیم . در متد OnActionExecuting بصورت زیر نام کنترولر و اکشن را پیدا کرده و در شرط if بررسی میکنیم که اگر اکشن SecuredAction فراخوانی شده بود به اکشن AccessDenied هدایت شود :
public override void OnActionExecuting (System.Web.Mvc.ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); string strAction = filterContext.RouteData.Values[“action”].ToString(); string strController = filterContext.RouteData.Values[“controller”].ToString(); if ((string.Compare(strController, "Home", ignoreCase: true) == 0) && (string.Compare(strAction, "SecuredAction", ignoreCase: true) == 0)) { filterContext.Result = new System.Web.Mvc.RedirectToRouteResult( new System.Web.Routing.RouteValueDictionary { { "area", string.Empty }, { "controller", "Home" }, { "action", "AccessDenied" } }); } }
از این طریق میتوان ورود کاربران عادی را به بخش مدیریت سایت کنترل نمود برای تمرین بیشتر و تکمیل اطلاعات خود به وب سایت asp.net مراجعه کنید. جلسه هفتم از مجموعه آموزشی MVC به پایان رسید .
در فصل بعد، آموزش Linq to EF – Code First را خواهیم داشت . همراه ما باشید …
آموزش ASP.NET MVC5 – فصل8
آموزش Entity Framework در ASP.NET-MVC
مبحث Entity Framework یا بطور خلاصه EF به سه بخش تقسیم می شود : Model First , Database First , Code First
نصب نوگت Entity Framework:
برای شروع کار ، باید نوگت Entity Framework را نصب کنیم . بنابراین در گوگل سرچ میکنیم : Entity Framework Nuget و اولین لینکی که یافت می شود را کلیک کرده و وارد سایت www.nuget.org می شویم و دستور زیر را کپی کرده و در کنسول Nuget پیست میکنیم و Enter را می زنیم :
Install-Package EntityFramework
با اجرای این دستور ، آخرین ورژن Entity Framework نصب میشود .
یادآوری :
- در ADO.NET سنتی ، به جمع DataTable ها DataSet میگفتند .
- در Entity Framework ، از مجموعه Model یا Entity ها ، مفهوم DatabaseContext ایجاد می شود .
افزودن کلاس Person به فولدر Models:
روی فولدر Models راست کلیک کرده و add–>class را انتخاب میکنیم . نام کلاس را Person میگذاریم که مطابق شکل زیر دارای 4 فیلد است :
تعریف کلاس DatabaseContext :
کلاس مهمی بنام DatabaseContext باید ایجاد کنیم که اطلاعات مدل های ایجاد شده در پروژه در آن قرار میگیرد . مانند شکل زیر این کلاس را تعریف میکنیم :
همانطور که می بینیم ، این کلاس باید از کلاس DbContext ارث بری کند :
public class DatabaseContext : System.Data.Entity.DbContext
تعریف مدلها در کلاس DatabaseContext:
مدلهایی که مانند Person ایجاد کرده ایم را باید بصورت زیر در کلاس DatabaseContext تعریف کنیم :
public System.Data.Entity.DbSet<Person> People { get; set; }
یعنی به ازای هر مدل ، یک property در کلاس DatabaseContext تعریف میکنیم که از نوع کلاس DbSet می باشند و نام این property را معمولا اسم جمع همان مدل انتخاب میکنیم . مثلا برای Person –>People و برای User –>Users و …..
تعریف رشته اتصال (ConnectionString) به دیتابیس:
در این بخش میخواهیم رشته اتصال به دیتابیس را تعریف کنیم و دستورات لازم برای ایجاد دیتابیس و جدول موردنظر را بنویسیم .
نحوه تعریف ConnectionString :
در فایل web.config تگ ConnectionString باید دقیقا بعد از تگ ConfigSections تعریف شود و به سه صورت زیر تعریف می شود :
<connectionstrings> <add name="DatabaseContext" connectionstring="Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=LEARNING_ADO_NET;Data Source=.\SQLExpress" providername="System.Data.SqlClient" /> <add name="DatabaseContext" connectionstring="Password=1234512345;Persist Security Info=True;User ID=SA;Initial Catalog=LEARNING_ADO_NET;Data Source=.\SQLExpress" providername="System.Data.SqlClient" /> <add name="DatabaseContext" connectionstring="Data Source=|DataDirectory|\MyDatabase.sdf" providername="System.Data.SqlServerCe.4.0" /> </connectionstrings>
- روش اول : رشته اتصالی است به sqlServer به روش Windows Authentication
- روش دوم : رشته اتصالی است به sqlServer به روش sqlServer Authentication
- روش سوم : رشته اتصالی است برای وصل شدن به sqlServer Compact .
نکته مهم : نام رشته اتصال باید با نام کلاس DatabaseContext یکی باشد .
ایجاد دیتابیس در روش Code First :
در EntityFramework Code First ، دیتابیس بصورت زیر ایجاد می شود :
کد بالا در Windows Form Application نوشته شده است ولی در وب اپلیکیشن ها نیز مانند همین روش باید اجرا شود (در اکشن مربوطه) تا دیتابیس ایجاد شود و در نهایت شئ ایجاد شده را dispose میکنیم یعنی از حافظه دور می اندازیم تا به مرور زمان ، برنامه را دچار سنگینی نکند .
توضیح : همانطور که در تصویر فوق میبینیم ، ابتدا باید از هر دوی Person و DatabaseContext یک شئ بسازیم و سپس شئ person را مقداردهی کنیم و به شئ databaseContext نسبت دهیم . در این مرحله db ایجاد شده و جدول people نیز ساخته می شود .
طراحی جدول people:
جدول people بصورت زیر ایجاد شده است :
توضیح : فیلد Id بطور اتوماتیک ایجاد شده است و Primary Key و Auto Increment می باشد . فیلد Age بدلیل اینکه int است نمیتواند null باشد و fullname را nullable تعریف کرده است و isSupervisor نیز چون bit است نمیتواند null باشد .
بعد از اجرای دستور saveChanges ، رکورد مورد نظر در جدول people درج می شود .
به منظور تمرین بیشتر و تست معلومات خود درباره موضوع مهم EntityFramework میتوانید به وب سایت EntityframeworkTutorial مراجعه کنید .
ایجاد کلاس BaseEntity :
روی فولدر Models راست کلیک کرده و کلاسی اضافه میکنیم بنام BaseEntity.cs . این کلاس فیلدی بنام Id از جنس Guid دارد که در سازنده کلاس آنرا new میکنیم :
namespace Models { public abstract class BaseEntity : System.Object { public BaseEntity() { Id = System.Guid.NewGuid(); } public System.Guid Id { get; set; } } }
چون در هر جدول ، فیلد کلید اصلی Id ضروری است ، کلاس فوق را ساختیم تا هر بار هنگام ایجاد مدل ، نیاز نباشد فیلد Id را نیز تعریف کنیم . فقط کافیست در تعریف کلاس مدل ، آنرا از کلاس فوق ارث بری کنیم .
ایجاد جداول Role و User با رابطه یک به چند:
فرض کنید میخواهیم دو جدول بنامهای Role و User بسازیم که باهم رابطه یک به چند دارند . بدین معنی که هر Role میتواند یک یا چند User داشته باشد ولی هر User فقط میتواند یک Role داشته باشد .
ایجاد جدول Role :
فیلدهای جدول Role عبارتند از : نام role و لیستی از user ها (فیلد Id نیز در تمام جداول وجود دارد) .
اجباری کردن فیلد Name:
همانطور که میدانید نوع داده ای رشته (String) میتواند null باشد . ما میتوانیم توسط attribute ها ، فیلد Name را required کنیم (در واقع تیک nullable بودن را از فیلد نام برداریم) :
[System.ComponentModel.DataAnnotations.Required (AllowEmptyStrings = false)]
اتریبیوت AllowEmptyStrings نیز null string بودن Name را چک میکند .
تعیین حداقل-حداکثر طول رشته توسط attribute:
همچنین میتوان طول رشته (حداقل-حداکثر) را توسط attribute ها تعیین کرد :
[System.ComponentModel.DataAnnotations.StringLength (maximumLength: 50)]
بنابراین کلاس Role بصورت زیر می باشد :
namespace Models { public class Role : BaseEntity { public Role(){} [System.ComponentModel.DataAnnotations.Required (AllowEmptyStrings = false)] [System.ComponentModel.DataAnnotations.StringLength (maximumLength: 50)] public string Name { get; set; } public virtual System.Collections.Generic.IList<user> Users { get; set; } } }
با دستور public class Role : BaseEntity میگوییم کلاس Role از کلاس BaseEntity که قبلا نوشتیم ارث ببرد .
ایجاد جدول User :
جدول User دارای فیلدهای متعددی است که بصورت زیر می باشد :
- IsActive از نوع boolean
- Age از نوع int که محدوده سنی بین 25 تا 35 را فقط شامل می شود .
- Username از نوع string که فیلد ضروریست و طولش بین 6 تا 20 کاراکتر است .
- Password از نوع string که فیلد اجباریست و طولش بین 8 تا 20 کاراکتر است .
- FullName از نوع string که طول رشته اش بین 3 تا 50 کاراکتر و اجباریست .
- Description از نوع string که نوشتن آن اجباری نیست و میتواند تگ html داشته باشد (Rich Text) .
سورس کد کلاس User:
کد کامل کلاس User بصورت زیر می باشد :
namespace Models { public class User : BaseEntity { public User() { } public virtual Role Role { get; set; } public System.Guid RoleId { get; set; } // ********** public bool IsActive { get; set; } // ********** // ********** [System.ComponentModel.DataAnnotations.Range (type: typeof(int), minimum: "25", maximum: "35")] public int Age { get; set; } // ********** [System.ComponentModel.DataAnnotations.Required (AllowEmptyStrings = false)] [System.ComponentModel.DataAnnotations.StringLength (maximumLength: 20, MinimumLength = 6)] public string Username { get; set; } // ********** [System.ComponentModel.DataAnnotations.Required (AllowEmptyStrings = false)] [System.ComponentModel.DataAnnotations.StringLength (maximumLength: 20, MinimumLength = 8)] [System.ComponentModel.DataAnnotations.DataType (System.ComponentModel.DataAnnotations.DataType.Password)] public string Password { get; set; } // ********** [System.ComponentModel.DataAnnotations.Required (AllowEmptyStrings = false)] [System.ComponentModel.DataAnnotations.StringLength (maximumLength: 50, MinimumLength = 3)] public string FullName { get; set; } // ********** [System.Web.Mvc.AllowHtml] [System.ComponentModel.DataAnnotations.DataType (System.ComponentModel.DataAnnotations.DataType.MultilineText)] public string Description { get; set; } // ********** } }
دو فیلد Role و RoleId که در ابتدای کلاس تعریف شده اند بدین خاطر می باشند که رابطه یک به چند بین جداول Role و User را پیاده سازی کنند .
کلاس مهم دیگری که باقی می ماند DatabaseContext می باشد . این کلاس باید از DbContext ارث ببرد و دو property برای جداول user , role نیز داشته باشد :
public System.Data.Entity.DbSet<role> Roles { get; set; } public System.Data.Entity.DbSet<user> Users { get; set; }
ایجاد کلاس DatabaseContext :
نکته مهم : در کلاس DatabaseContext دستور مهمی باید در سازنده کلاس بنویسیم که دیتابیس را در هر بار اجرای برنامه بررسی میکند :
static DatabaseContext() { // فقط به درد برنامه نویسان آن هم در زمان پیاده سازی می خورد System.Data.Entity.Database.SetInitializer (new System.Data.Entity.DropCreateDatabaseIfModelChanges<databasecontext>()); // برای تحویل به مشتری مناسب است //System.Data.Entity.Database.SetInitializer // (new System.Data.Entity.CreateDatabaseIfNotExists<databasecontext>()); }
- روش اول میگوید اگر مدلی از دیتابیس تغییر کرد (و یا مدلی حذف یا اضافه شد) دیتابیس را پاک میکند و بعد از اعمال تغییرات دوباره می سازد .
- روش دوم بدین معنیست که اگر دیتابیس وجود نداشت آنرا میسازد وگرنه کاری به دیتابیس ندارد (برای تحویل پروزه به کلاینت مناسب است) .
برای یادگیری و تمرین بیشتر به وب سایت asp.net مراجعه شود .
ایجاد View های لازم جهت 4 عمل اصلی CRUD:
در این بخش میخواهیم view های لازم برای 4 عمل اصلی CRUD را بطور اتوماتیک ایجاد کنیم . برای اینکار روی فولدر Controllers راست کلیک کرده و Add–>Controller را انتخاب میکنیم . در این مرحله با تصویر زیر مواجه می شویم :
ایجاد کنترلر RoleController:
مطابق شکل ، گزینه MVC5 Controller with views Using EntityFramework را انتخاب میکنیم و در مرحله بعد ، مطابق تصویر زیر ، Model Class را Role انتخاب میکنیم و Data Context Class را برابر DatabaseContext قرار میدهیم و تیک Generate views , use layout را میزنیم و در نهایت نام کنترولر را RoleController تایپ میکنیم و Add را می زنیم :
ایجاد View های Index , Edit , Delete , Create , Detail:
با زدن دکمه Add ، کنترولر Role با تمام view های Index , Edit , Delete , Create , Detail و اکشن های مرتبط ، اتوماتیک ایجاد می شوند .
در view های تولید شده با توجه به مدل Role که قبلا تعریف کردیم به Textbox ها validation اختصاص داده می شود ، مثلا اگر فیلدی required باشد هنگام اجرای Create و زدن دکمه Create با پیغام the field is required مواجه می شویم :
نکته : با اینکه کدهای اکشن های مختلف کنترولر RoleController بدرستی کار میکنند و همچنین View های ایجاد شده توسط مایکروسافت بدون خطا کار میکنند ولی ما میخواهیم View های زیباتری داشته باشیم و نیز کدهای cSharp , Linq که در اکشن های مختلف نوشته شده اند هوشمندانه تر شوند یک سری مراحلی باید طی کنیم .
مثال برای View : در View مربوط به create role ، دکمه درج در دیتابیس استایل خاصی ندارد . ما میخواهیم مثلا استایل btn-primary به آن بدهیم .
مثال برای Action : در اکشن مربوط به Index که لیستی از Role ها را نمایش میدهد ، کد موجود به صورت زیر است :
return View(db.Roles.ToList());
ولی آنچه که ما میخواهیم ، مرتب شده رول ها بر اساس نام آنها می باشد .
نکته : برای تمرین بیشتر و مشاهده مثالهای پیشرفته تر به وب سایت codeProject مراجعه شود.
در بخش بعد قصد داریم عملیات مرتب سازی و هوشمندسازی کد ها را شروع کنیم . همراه ما باشید …
در بخش قبل با نحوه تولید اتوماتیک view ها و اکشن های مربوط به یک مدل آشنا شدیم . در این بخش قصد داریم کدهای تولید شده را زیباتر و هوشمندانه تر کنیم .
تعریف کلاس BaseController:
ابتدا یک کلاس بنام BaseController تعریف میکنیم تا از این به بعد تمام کنترولرهای ما از آن ارث ببرند . برای اینکار روی فولدر Infrastructure راست کلیک کرده و add > class را انتخاب میکنیم . نام کلاس را BaseController قرار میدهیم :
namespace Infrastructure { public class BaseController : System.Web.Mvc.Controller { public BaseController() { } private Models.DatabaseContext _databaseContext; protected Models.DatabaseContext DatabaseContext { get { if (_databaseContext == null) { _databaseContext = new Models.DatabaseContext(); } return (_databaseContext); } } protected override void Dispose(bool disposing) { if (disposing) { if (_databaseContext != null) { _databaseContext.Dispose(); _databaseContext = null; } } base.Dispose(disposing); } } }
توضیح کلاس BaseController: ابتدا متغیر private از نوع مدل DatabaseContext تعریف میکنیم و سپس یک property با همان نوع DatabaseContext تعریف میکنیم که readOnly می باشد یعنی فقط متد get دارد . شرط if در property می گوید اگر متغیر null بود آنرا new کن وگرنه همان را return کن .
بنابراین با ایجاد این کلاس ، تمام کنترولرهای ایجاد شده را بصورت زیر از کلاس BaseController ارث بری میکنیم :
public partial class RoleController : BaseController
اکشن Index کنترولر RoleController :
کد اکشن فوق بطور پیش فرض بصورت است :
public ActionResult Index() { return View(db.Roles.ToList()); }
و کد بهینه سازی شده و هوشمندانه بدین صورت :
public ActionResult Index() { var varRoles = DatabaseContext.Roles .OrderBy(current => current.Name) .ToList(); return (View(model: varRoles)); }
همانطور که میبینیم روش دوم قدرت مانور بیشتری نسبت به اولی دارد (می توان از دستورات Where , Orderby در آن استفاده کرد)
سفارشی سازی Index View :
ویوی تولید شده پیش فرض برای اکشن Index (نمایش لیست رول ها) بصورت زیر است :
@model IEnumerable<models.role> @{ViewBag.Title = "Index";} <h2>Index</h2> <p> @Html.ActionLink("Create New", "Create")</p> @foreach (var item in Model) { } <table class="table"> <tbody> <th> @Html.DisplayNameFor(model => model.Name) </th> <tr> <td> @Html.DisplayFor(modelItem => item.Name) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.Id }) | @Html.ActionLink("Details", "Details", new { id=item.Id }) | @Html.ActionLink("Delete", "Delete", new { id=item.Id }) </td> </tr> </tbody> </table>
همانطور که قبلا گفتیم این کد نیز بدرستی کار میکند ولی ما قصد داریم ویوی زیباتری داشته باشیم . پس ویوی فوق را بصورت زیر تغییر میدهیم (که در آن به جدول موجود ، استایل بوت استرپی دادیم واز نوگت T4MVC استفاده کردیم که نام اکشن را StronglyTyped میکند) :
@model IEnumerable<models.role> @{string strTitle = "Roles List";ViewBag.Title = strTitle;} <h2>@strTitle</h2> <div class="links"> @Html.ActionLink("Create New Role", MVC.Role.Create())</div> <div class="table-responsive"> @foreach (Models.Role oCurrentRole in Model) {<table class="table table-bordered table-condensed table-hover table-striped"> <tbody><tr><td> </td></tr></tbody><tbody><tr><td> </td><th> </th><td> </td><th> @Html.DisplayNameFor(model => model.Name)</th><td> </td></tr><tr><td> </td><td> @Html.ActionLink("Details", MVC.Role.Details(oCurrentRole.Id)) | @Html.ActionLink("Edit", MVC.Role.Edit(oCurrentRole.Id)) | @Html.ActionLink("Delete", MVC.Role.Delete(oCurrentRole.Id))</td><td> </td><td> @Html.DisplayFor(modelItem => oCurrentRole.Name)</td><td> </td></tr></tbody></table></div>
توضیح دستور زیر :
@Html.DisplayNameFor(model => model.Name)
برای نمایش نام اختصاص داده شده در مدل بکار میرود . اگر نامی برای این فیلد تعریف نکرده باشیم همان Name را نمایش میدهد . نحوه تعریف کردن نام نمایشی دلخواه برای یک فیلد ، بصورت Attribute در مدل می باشد :
[System.ComponentModel.DataAnnotations.Display (Name="Role Name")] public string Name { get; set; }
تا بدین جا ، اکشن Index بهمراه View متناظرش را سفارشی سازی کردیم . به همین ترتیب می توان اکشن های Delete , Edit , Insert را بهمراه ویوهای آنها ، مرتب و بهینه سازی کنیم . برای تمرین بیشتر ، به وب سایت asp.net مراجعه کنید .
فصل هشتم (آموزش Linq to EF code first) در اینجا به پایان میرسد. در فصل بعد، با Validation ها آشنا می شویم . همراه ما باشید …
آموزش ASP.NET MVC5 – فصل9
آموزش اعتبارسنجی (Validation) در ASP.NET MVC
اجباری کردن فیلد از طریق Required Validator
فرض کنید میخواهیم فیلد FullName در مدل زیر اجباری (required) باشد و کاربر حتما textbox آنرا در فرم پر کند :
namespace Models { public class Learn01 : System.Object { public Learn01() { } public int Age { get; set; } public string FullName { get; set; } } }
اتریبیوت required:
برای اینکار ، باید اتریبیوت required را بصورت زیر به فیلد FullName اعمال کنیم :
[System.ComponentModel.DataAnnotations.Required (AllowEmptyStrings = false)] public string FullName { get; set; }
نکته : همانطور که میدانید نوع داده ای int بصورت پیش فرض nullable نیست یعنی حتما باید توسط کاربر مقداردهی شود . برای اینکه این پیش فرض را تغییر دهیم و نوشتن Age اجباری نباشد ، باید بصورت زیر از علامت سوال استفاده کرد :
public int? Age { get; set; }
تعیین طول رشته توسط StringLength
اگر در یک مدل ، فیلدی را از نوع رشته تعریف کنیم و از تکنولوژی EF Code First استفاده کرده باشیم ، این فیلد در دیتابیس از نوع nVarChar max تعریف میشود . حال اگر بخواهیم طول این رشته را عوض کنیم باید از اتریبیوت StringLength استفاده کنیم :
[System.ComponentModel.DataAnnotations.StringLength (maximumLength: 50, MinimumLength = 3)] public string FullName { get; set; }
در validation فوق ، حداقل و حداکثر طول رشته FullName را تعیین کرده ایم (بین 3 تا 50 کاراکتر) .
اعتبارسنجی فرمت ورودی کاربر توسط RegularExpression
برای اعتبارسنجی فرمت وارد شده توسط کاربر ، بعنوان مثال ایمیل ، از این Validation استفاده می شود که بصورت زیر تعریف می شود :
[System.ComponentModel.DataAnnotations.RegularExpression (pattern: @"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*")] public string EmailAddress { get; set; }
برای سایر Regex ها ، مثلا برای شماره تلفن ، به وب سایت tutsplus مراجعه نمایید .
تعیین محدوده فیلدها توسط Range Validator
برای مشخص کردن محدوه ای برای فیلدها بکار میرود که سه تا پارامتر میگیرد : typeof , minimum , maximum :
[System.ComponentModel.DataAnnotations.Range (type: typeof(int), minimum: "25", maximum: "35")] public int? Age { get; set; }
توضیح : فیلد Age باید عدد صحیحی بین 25 و 35 باشد .
[System.ComponentModel.DataAnnotations.Range (type: typeof(decimal), minimum: "0", maximum: "5000")] public decimal? Price { get; set; }
توضیح : فیلد Price باید عدد اعشاری بین 0 و 5000 باشد .
برای یادگیری و تمرین بیشتر در زمینه Validation ها در ASP.NET MVC به وب سایت asp.net مراجعه نمایید .
تا بدین جا با validator های required , range , stringLength , regularExpression آشنا شدیم . در بخش های بعد، با تعدادی دیگر از اعتبارسنجی های MVC آشنا می شویم .
مقایسه مقادیر دو تکستباکس توسط Compare
به منظور مقایسه دو مقداری که در textbox ها کاربر وارد میکند مانند پسورد و تائید پسورد :
public string Password { get; set; } [System.ComponentModel.DataAnnotations.Compare (otherProperty: "Password")] public string ConfirmPassword { get; set; }
در دستورات فوق برای فیلد ConfirmPassword اتریبیوت Compare تعریف کرده ایم که توسط پارامتر otherProperty با فیلد Password مقایسه میشود .
نکته : در مثال بالا ما دو تا فیلد بنامهای Password , ConfirmPassword داریم . فقط باید برای فیلد پسورد validator تعریف کنیم (مانند regex stringLength , …) و نیازی به تعریف آنها برای فیلد تائید پسورد نیست .
انجام فرآیند ایجکسی توسط Remote
وظیفه این اعتبارسنج اینست که بدون آنکه برنامه نویس ، Ajax بلد باشد میتواند یک فرآیند ajax ای را انجام دهد
بعنوان مثال وقتی کاربر در Textbox نام کاربری شروع به تایپ میکند ، یک اکشن سمت سرور صدا زده می شود که نام کاربری ورودی کاربر را چک میکند که اگر قبلا در دیتابیس موجود است و فرد دیگری انرا انتخاب کرده است ، در همان لحظه بصورت Ajax ای پیغامی مبنی بر تکراری بودن username به کاربر نمایش میدهد .
پارامترهای دستور Remote:
پارامترهایی که دستور Remote میگیرد عبارتست از : controllerName , actionName , area :
[System.Web.Mvc.Remote (action: "CheckUsername", controller: "Home", areaName: "")] public string Username { get; set; }
فرض کنید validator فیلد username را بصورت فوق تعریف کرده ایم . حال اکشن CheckUsername باید تعریف شود . اکشنی که برای اعتبارسنج ریموت نوشته می شود باید دارای خروجی JsonResult باشد و مقداری که در return بر میگرداند از نوع boolean می باشد .
اکشن Remote Validator:
اکشنی که برای Remote Validator نوشته می شود مانند زیر است :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.JsonResult CheckUsername(string username) { bool blnResult = true; if (string.Compare(username, "EhsanSafari", ignoreCase: true) == 0) { blnResult = false; } return (Json(data: blnResult, behavior: System.Web.Mvc.JsonRequestBehavior.AllowGet)); }
توضیح : در اکشن فوق ، گفته ایم که اگر نام کاربری که کاربر وارد میکند برابر با EhsanSafari بود ، خروجی false را برگرداند وگرنه true .
برای تمرین بیشتر درباره remote validation به وب سایت asp.net مراجعه نمایید .
لزوم یکپارچهسازی تمام اعتبارسنجیها:
سناریو : فرض کنید در پروژه خود ، چندین مدل دارید که همگی UserName دارند و validator یکسانی نیز دارند . حال میخواهیم مثلا stringLength آنرا با حداقل 8 کاراکتر تعریف کنیم . باید برویم در تمام model هایی که ساختیم ، اتریبیوت username را تغییر دهیم و اینکار منطقی و مقروم بصرفه بنظر نمی آید . بنابراین بهتر است validator مربوط به نام کاربری را در یک کلاس تعریف کنیم و فقط در مدل آنرا صدا بزنیم
تعریف کلاس RegularExpressions.cs:
خب برای اینکار ، فولدری بنام Infrastructure در روت پروژه میسازیم و در ان یک کلاس بنام RegularExpressions.cs تعریف میکنیم و تمام regEx ها را در این کلاس تعریف میکنیم . بهمین ترتیب میتوان برای stringLength ها و سایر اعتبارسنج ها نیز کلاس مرتبط را ایجاد کرد . کلاسی که ما در مثال زیر ساختیم شامل regex برای فیلدهای Email , username , password می باشد :
namespace Infrastructure { public static class RegularExpressions { static RegularExpressions(){} public const string EmailAddress = @" \w+([-+.’]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"; public const string username=@"[a-zA-Z0-9_]{6,20}"; public const string password=@"[a-zA-Z0-9_]{8,20}"; } }
و در این مرحله باید از این کلاسی که تعریف کردیم در مدل خود استفاده کنیم :
namespace Infrastructure { public static class RegularExpressions { static RegularExpressions(){} public const string EmailAddress [System.ComponentModel.DataAnnotations.RegularExpression(pattern: Infrastructure.RegularExpressions.Username)] public string Username { get; set; } } }
به همین راحتی!
می خواهیم اگر کاربر ، فیلدی را بطور valid وارد نکرد (مثلا فیلدی که required است را خالی رها کند !) پیغام خطای دلخواه ما نمایش داده شود . بدین منظور از دستور ErrorMessage استفاده میکنیم :
namespace Infrastructure{ public static class RegularExpressions{ static RegularExpressions(){} public const string EmailAddress; [System.ComponentModel.DataAnnotations.Required (AllowEmptyStrings = false, ErrorMessage = "You did not specify Username!")] public string Username { get; set; } }
نکته : میتوان از ErrorMessage بصورت پارامتریک استفاده کنیم . توسط دستور string.Format :
namespace Infrastructure{ public static class RegularExpressions{ static RegularExpressions(){} public const string EmailAddress; [System.ComponentModel.DataAnnotations.Required (AllowEmptyStrings = false, ErrorMessage = "You did not specify Username!")] public string Username { get; set; } }
توضیح : در مثال فوق گفتیم که اگر اتریبیوت Display تعریف شده است بجای {0} مقدار Display را قرار بده وگرنه همان نام فیلد را نمایش میدهد . در این مثال در صورت پر نشدن فیلد تائید پسورد توسط کاربر ، با توجه به اینکه Display تعریف شده است ، کاربر پیغام زیر را مشاهده میکند :
!Confirm Password is required
در بخش قبل نحوه نوشتن validator ها را در کلاسی مجزا و نیز نمایش پیام خطای دلخواه را یاد گرفتیم .
لزوم استفاده از Resource:
اکیدا توصیه می شود که پیام ها و سایر متون را بصورت Hard Code در کلاس خود ننویسیم ( در تمام زبانها و محیط های برنامه نویسی نیز این توصیه وجود دارد) و باید آنها را در فایلی بنام Resource تعریف و سپس از آن در مدل یا کلاس خود استفاده کنیم .
نحوه ایجاد Resource :
به این منظور ، روی solution پروژه خود راست کلیک کرده و add > new project را انتخاب می کنیم (مطابق شکل زیر) :
سپس از لیست موجود ، یک Class Library از نوع Visual Csharp انتخاب میکنیم و نام آنرا Resources قرار میدهیم (مطابق شکل زیر) :
در این مرحله روی Resources راست کلیک کرده و یک فولدر جدید به آن اضافه میکنیم و نام آنرا Models میگذاریم . اکنون روی همین فولدر راست کلیک کرده و add>new item را میزنیم . سپس یک Resource File از لیست انتخاب کرده و نام آنرا همان نام مدلی قرار میدهیم که میخواهیم متون داخل آنرا تعریف کنیم (مثلا UserList.resx)
تمام فیلدهایی که در مدل موردنظرمان هستند را در این فایل بهمراه متن آنها وارد میکنیم (مطابق شکل زیر) :
دقت کنید که مقدار Access Modifier را از Internal به Public تغییر دهید . مانند شکل بالا .
نکته : در داخل Name نمیتوان از نقطه یا space استفاده کرد ولی در Value هر چیزی که بخواهیم (حتی تگ html) میتوانیم بنویسیم .
استفاده از Resource File :
برای استفاده از فایل ریسورسی که در بالا ایجاد کردیم ( فرض کنید برای فیلد Username ) بصورت زیر باید عمل کنیم :
[System.ComponentModel.DataAnnotations.Display (ResourceType = typeof(Resources.Models.UserList), Name = " username="">
در مثال فوق بجای اینکه متن اتریبیوت Display را بصورت hard code داخل کلاس بنویسیم ، آدرس ریسورس فایل را داده ایم (Resources.Models.UserList) پارامتر Name آن همان Name واقع در UserList.resx می باشد .
آموزش Validation در ASP.NET MVC در اینجا به پایان میرسد . برای تمرین بیشتر به وب سایت asp.net مراجعه شود .
در فصل بعد ، که فصل آخر از سری آموزشی MVC می باشد ، با نحوه کار با Ajax در MVC آشنا می شویم . پس با ما همراه باشید …
آموزش ASP.NET MVC5 – فصل 10
با جلسه آخر از مجموعه آموزشی MVC در خدمتتان هستیم . لطفا انتقادات و پیشنهادهای خود را از طریق ایمیل EhsanSafari@Hotmail.com با ما در میان بگذارید و یا با مراجعه به فرم ارسال دیدگاه که در انتهای هر مقاله قرار دارد نظرات و سوالات خود را مطرح کنید.
در این فصل قصد داریم شما را با تکنولوژی زیبا و جذاب Ajax آشنا کنیم . همراه ما باشید .
استفاده از تابع ایجکس (Ajax) در MVC
تعریف ایجکس به زبان ساده:
کاربرد اصلی Ajax در وب بدین صورت است که هنگامی که دکمه ای کلیک میشود و میخواهد اطلاعات را بسمت سرور ارسال کند ، دیگر صفحه مرورگر refresh نمی شود . بلکه ارسال فرم به سرور در پشت صحنه انجام می شود و کاربر فقط علامت درحال بارگذاری یا Loading را مشاهده می کند .
معرفی اجمالی JQuery :
برای شروع کار با Ajax نیاز داریم کمی درباره jQuery صحبت کنیم . برای استفاده از دستورات جی کوئری ، باید فایل jQuery.min.js را به صفحه یا ویوی خود اضافه کنیم :
<script src="~/Scripts/jquery-2.1.3.min.js"></script>
بعنوان مثال در view داریم :
<p>Hello World!</p> <button type="button" id="btnDisplayMessage">Click Me!</button> <div id="message"></div> <script src="../Scripts/jquery-2.1.3.min.js"></script>
و دستورات جی کوئری را به صورت زیر نوشتیم :
$(document).ready(function () { $("p").css("color", "red"); //1 $("button#btnDisplayMessage").click(function (e) { $("div#message").html("<p>Hello World!</p>"); //2 }); });
توضیح : دستور شماره 1 کارش اینست که تمام پاراگرافها را قرمز رنگ میکند و دستور شماره 2 کارش اینست که وقتی روی دکمه ای با ID=btnDisplayMessage کلیک می شود ، عبارت Hello World را داخل div ای با ID=message مینویسد .
شروع تعریف تابع Ajax در View:
تا بدین جا با مفهوم و کاربرد Ajax در وب آشنا شدیم و نیز یک مثال از دستورات جی کوئری را با هم بررسی کردیم . در این بخش وارد کدنویسی Ajax در View می شویم .
برای شروع ، ابتدا کد زیر را در تگ head ویوی موردنظر مینویسیم :
$(document).ready(function () { $("button#btnDisplayMessage").click(function () { $("div#message").html(""); // Solution (3) $.ajax({ type: "GET", dataType: "json", data: null, url: "/StepByStep/GetData01", error: function (response) { $("div#message").html("Error on sending or receiving data!"); }, success: function (response) { //$("div#message").html(response); $("div#message").html(response.Message); }, }); }); });
پارامترهای تابع Ajax:
تابع ajax بصورت ()ajax.$ تعریف می شود که پارامترهای آن عبارتند از :
- type : نوع درخواست ما از سرور
- dataType : نوع داده ای که از سرور به سمت ما ارسال می گردد
- data : پارامترهای ورودی که به تابع اکشن ارسال می گردد
- url : نشانی اکشن یا web api در سمت سرور می باشد
- error : اگر request ای که به سرور ارسال می شود با خطا روبرو شود
- success : وقتی درخواست به سمت سرور موفقیت آمیز باشد .
تگ های html ای که در تگ body همین ویو مینویسیم بصورت زیر است :
<button id="btnDisplayMessage" type="button">Click Me!</button> <div id="message"></div>
و اکشن GetData01 نیز بصورت زیر تعریف می شود :
[System.Web.Mvc.HttpGet] public System.Web.Mvc.JsonResult GetData01() { return (Json(data: new { Message = "Hello World!" }, behavior: System.Web.Mvc.JsonRequestBehavior.AllowGet)); }
لطفا اطلاعات بیشتر را در وب سایت jQuery.com دنبال کنید.
نحوه صحیح تعریف پارامتر type و اتریبیوت بالای اکشن:
دقت کنید که اگر پارامتر type تابع ajax را post تعریف کنیم ، در بالای اکشن ، اتریبیوت [System.Web.Mvc.HttpPost] را باید تعریف کنیم . در صورتی که یکی get باشد و دیگری post ، با error مواجه می شویم .
مثالی دیگر از کاربرد تابع Ajax در MVC:
بعنوان مثال دیگر ، فرض کنید دیتا که از سرور به ویو ارسال می شود دو قسمت age , fullname را دارد . در view دو span برای این دو دیتا در نظر میگیریم که وقتی response از سرور ارسال شد ، آنها را داخل این span ها نمایش دهیم .
بخش body فایل view بصورت زیر می باشد :
<div> <div id="message"></div> <button id="btnDisplayUserInformation" type="button">Display User Information</button> Age: Full Name: </div>
سورس کد تابع Ajax این مثال:
تابع ajax آن بدین صورت تعریف شده است :
$(document).ready(function () { $("button#btnDisplayUserInformation").click(function () { $("div#message").html(""); //1 $("span#age").html(""); //1 $("span#fullName").html(""); //1 $("button#btnDisplayUserInformation").hide(); //2 $.ajax({ type: "POST", dataType: "json", data: null, url: "/StepByStep/GetData03", error: function (response) { $("div#message").html("Error on sending or receiving data!"); $("button#btnDisplayUserInformation").show(); }, success: function (response) { $("span#age").html(response.Age); $("span#fullName").html(response.FullName); $("button#btnDisplayUserInformation").show(); }, }); }); });
شرح دستورات فوق:
دستورات فوق با زدن دکمه ای با ID=btnDisplayUserInformation اجرا می شوند :
در دستورات شماره 1 ، محتوای داخل span و div را خالی میکنیم و در خط 2 ، دکمه را مخفی میکنیم تا کاربر نتواند کلیک کند !
اگر فرآیند ارسال و دریافت اطلاعات به سرور با ارور مواجه شد ، در div با ID=message پیغام متناسب نمایش داده می شود وگرنه age , fullname ارسال شده به کاربر نمایش داده می شود و دکمه دوباره show می شود .
سورس کد اکشنGetData03:
کد اکشن نیز بصورت زیر تعریف می شود :
[System.Web.Mvc.HttpPost] public System.Web.Mvc.JsonResult GetData03() { System.Threading.Thread.Sleep(5000); //1 return (Json(data: new { FullName = "Ehsan Safari", Age = 28 }, behavior: System.Web.Mvc.JsonRequestBehavior.AllowGet)); }
دستور شماره 1 برای اینست که کندی سرعت اینترنت را شبیه سازی کنیم . بنابراین بعد از زدن دکمه ، 5 ثانیه طول میکشد تا جواب را کاربر ببیند
برای تمرین بیشتر در حوزه ajax ، به وب سایت w3schools مراجعه شود .
افزودن بخش بارگذاری (لودینگ:Loading):
در این درس میخواهیم بخش لودینگ Loading نیز به view خود اضافه کنیم .
برای دانلود تصویر متحرک Loading با فرمت gif ، می توانید به وب سایت AjaxLoad.info مراجعه نمایید . برای مثال ، بنده تصویر زیر را برای نمایش در view خود انتخاب کرده ام :
سپس باید یک تگ div را برای نمایش این عکس تعریف کنیم :
<div id="loading"> <img alt="Loading" src="~/Images/Loading.gif" title="Loading" /> Loading… Please Wait! </div>
کد تابع ایجکس برای نمایش لودینگ:
کدهای جاوا اسکریپت برای تعریف تابع ajax بصورت زیر می باشد :
$(document).ready(function () { $("button#btnDisplayUserInformation").click(function () { $("div#message").html(""); $("span#age").html(""); $("span#fullName").html(""); $("div#loading").show(); $("button#btnDisplayUserInformation").hide(); $.ajax({ type: "POST", dataType: "json", data: null, url: "/StepByStep/GetData04", error: function (response) { $("div#message").html("Error on sending or receiving data!"); }, success: function (response) { $("span#age").html(response.Age); $("span#fullName").html(response.FullName); }, complete: function (response) { $("div#loading").hide(); $("button#btnDisplayUserInformation").show(); }, }); }); });
تعریف استایل CSS:
و در بخش style ها ، تگ div ای که شامل loading gif می باشد را مخفی میکنیم :
div#loading { display: none; }
با فشردن دکمه ، لودینگ را show میکنیم . در تابع ajax پارامتر دیگری داریم بنام complete که بعد از error و success رخ میدهد . یعنی این فرآیند چه با موفقیت تمام شود چه با شکست ، رویداد complete رخ میدهد .
نحوه فراخوانی اکشن بهمراه پارامتر در تابع Ajax:
در این بخش میخواهیم اطلاعاتی که کاربر در فرم وارد میکند را به تابع ajax و سپس به اکشن مربوطه ارسال کنیم و نتیجه را برگردانیم .
دو textbox بنامهای age , fullname داریم که بصورت زیر تعریف شده اند :
Age: <input id="age" type="search" /> Full Name: <input id="fullName" type="search" /> <button id="btnCreate" type="button">Create</button>
دستورات Javascript مورد نیاز برای پیادهسازی قابلیت ایجکس:
کدهای جاوااسکریپت مربوط به این مثال، بصورت زیر تعریف می شوند :
$(document).ready(function () { $("button#btnCreate").click(function () { $("div#message").html(""); $("div#loading").show(); $("button#btnCreate").hide(); var varData = { age: $("input#age").val(), fullName: $("input#fullName").val(), }; $.ajax({ type: "POST", dataType: "json", data: varData, url: "/StepByStep/GetData05", error: function (response) { $("div#message").html("Error on sending or receiving data!"); }, success: function (response) { $("input#age").val(""); $("input#fullName").val(""); $("div#message").html(response.Message); }, complete: function (response) { $("div#loading").hide(); $("button#btnCreate").show(); }, }); }); });
توضیح : قبل از شروع تابع ajax ، بصورت زیر مقادیر ورودی کاربر را از فرم گرفته و داخل age , fullname قرار میدهیم :
var varData = { age: $("input#age").val(), fullName: $("input#fullName").val(), };
سپس این مقادیر را داخل data قرار میدهیم و به اکشن میفرستیم : data: varData
کد اکشن GetData05:
اکشن GetData05 بصورت زیر تعریف می شود :
[System.Web.Mvc.HttpPost] public System.Web.Mvc.JsonResult GetData05(string FullName, int Age) { System.Threading.Thread.Sleep(5000); string strMessage = string.Format("I'm {0} and {1} years old.", FullName, Age); return (Json(data: new { Message = strMessage }, behavior: System.Web.Mvc.JsonRequestBehavior.AllowGet)); }
توضیح دستورات اکشن فوق:
متد اکشن فوق را POST تعریف کرده ایم . در دستور Sleep بمدت 5 ثانیه تصویر لودینگ نمایش داده می شود و در strMessage ، مقادیری که به اکشن ارسال شده است را میریزیم و آنرا بصورت anonymous Object به ویو ارسال میکنیم .
دوستان و همراهان آکادمی راهکارینو، مجموعه آموزشی ASP.NET MVC 5 در اینجا به پایان می رسد . لطفا با بیان دیدگاه های خود بعد از هر مقاله و نیز ارسال پیشنهادهای خود به ایمیل : EhsanSafari@hotmail.com (و یا فرم ارسال دیدگاه) بنده را در نگارش هر چه بهتر مقالات آموزشی وب ، یاری نمایید.
دیدگاهتان را بنویسید