توليد خودكار فرمهاي ورود و نمايش اطلاعات در ASP.NET MVC بر اساس اطلاعات مدلها
در الگوي MVC، قسمت M يا مدل آن يك سري ويژگيهاي خاص خودش را دارد:
شما را وادار نميكند كه مدل را به نحو خاصي طراحي كنيد. شما را مجبور نميكند كه كلاسهاي مدل را براي نمونه همانند كلاسهاي كنترلرها، از كلاس خاصي به ارث ببريد. يا حتي در مورد نحوهي دسترسي به دادهها نيز، نظري ندارد. به عبارتي برنامه نويس است كه ميتواند بر اساس امكانات مهياي در كل اكوسيستم دات نت، در اين مورد آزادانه تصميم گيري كند.
بر همين اساس ASP.NET MVC يك سري قرارداد را براي سهولت اعتبار سنجي يا توليد بهتر رابط كاربري بر اساس اطلاعات مدلها، فراهم آورده است. اين قراردادها هم چيزي نيستند جز يك سري metadata كه نحوهي دربرگيري اطلاعات را در مدلها توضيح ميدهند. براي دسترسي به آنها پروژه جاري بايد ارجاعي را به اسمبليهاي System.ComponentModel.DataAnnotations.dll و System.Web.Mvc.dll داشته باشد (كه VS.NET به صورت خودكار در ابتداي ايجاد پروژه اينكار را انجام ميدهد).
يك مثال كاربردي
يك پروژه جديد خالي ASP.NET MVC را آغاز كنيد. در پوشه مدلهاي آن، مدل اوليهاي را با محتواي زير ايجاد نمائيد:
using System; namespace MvcApplication8.Models { public class Employee { public int Id { set; get; } public string Name { set; get; } public decimal Salary { set; get; } public string Address { set; get; } public bool IsMale { set; get; } public DateTime AddDate { set; get; } } }
سپس يك كنترلر جديد را هم به نام EmployeeController با محتواي زير به پروژه اضافه نمائيد:
using System; using System.Web.Mvc; using MvcApplication8.Models; namespace MvcApplication8.Controllers { public class EmployeeController : Controller { public ActionResult Create() { var employee = new Employee { AddDate = DateTime.Now }; return View(employee); } } }
بر روي متد Create كليك راست كرده و يك View ساده را براي آن ايجاد نمائيد. سپس محتواي اين View را به صورت زير تغيير دهيد:
@model MvcApplication8.Models.Employee @{ ViewBag.Title = "Create"; } <h2>Create An Employee</h2> @using (Html.BeginForm(actionName: "Create", controllerName: "Employee")) { @Html.EditorForModel() <input type="submit" value="Save" /> }
اكنون اگر پروژه را اجرا كرده و مسير http://localhost/employee/create را وارد نمائيد، يك صفحه ورود اطلاعات توليد شده به صورت خودكار را مشاهده خواهيد كرد. متد Html.EditorForModel بر اساس اطلاعات خواص عمومي مدل، يك فرم خودكار را تشكيل ميدهد.
البته فرم توليدي به اين شكل شايد آنچنان مطلوب نباشد، از اين جهت كه براي مثال Id را هم لحاظ كرده، در صورتيكه قرار است اين Id توسط بانك اطلاعاتي انتساب داده شود و نيازي نيست تا كاربر آنرا وارد نمايد. يا مثلا برچسب AddDate نبايد به اين شكل صرفا بر اساس نام خاصيت متناظر با آن توليد شود و مواردي از اين دست. به عبارتي نياز به سفارشي سازي كار اين فرم ساز توكار ASP.NET MVC وجود دارد كه ادامه بحث جاري را تشكيل خواهد داد.
سفارشي سازي فرم ساز توكار ASP.NET MVC با كمك Metadata خواص
براي اينكه بتوان نحوه نمايش فرم خودكار توليد شده را سفارشي كرد، ميتوان از يك سري attribute و data annotations توكار دات نت و ASP.NET MVC استفاده كرد و نهايتا اين metadata توسط فريم ورك، مورد استفاده قرار خواهند گرفت. براي مثال:
using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Web.Mvc; namespace MvcApplication8.Models { public class Employee { //[ScaffoldColumn(false)] [HiddenInput(DisplayValue=false)] public int Id { set; get; } public string Name { set; get; } [DisplayName("Annual Salary ($)")] public decimal Salary { set; get; } public string Address { set; get; } [DisplayName("Is Male?")] public bool IsMale { set; get; } [DisplayName("Start Date")] [DataType(DataType.Date)] public DateTime AddDate { set; get; } } }
در اينجا به كمك ويژگي HiddenInput از نمايش عمومي خاصيت Id جلوگيري خواهيم كرد يا توسط ويژگي DisplayName، برچسب دلخواه خود را به عناصر فرم تشكيل شده، انتساب خواهيم داد. اگر نياز باشد تا خاصيتي كلا از رابط كاربري حذف شود ميتوان از ويژگي ScaffoldColumn با مقدار false استفاده كرد. يا توسط DataType، مشخص كردهايم كه نوع ورودي فقط قرار است Date باشد و نيازي به قسمت Time آن نداريم.
DataType شامل نوعهاي از پيش تعريف شده ديگري نيز هست. براي مثال اگر نياز به نمايش TextArea بود از مقدار MultilineText، استفاده كنيد:
[DataType(DataType.MultilineText)]
يا براي نمايش PasswordBox از مقدار Password ميتوان كمك گرفت. اگر نياز داريد تا آدرس ايميلي به شكل يك لينك mailto نمايش داده شود از مقدار EmailAddress استفاده كنيد. به كمك مقدار Url، متن خروجي به صورت خودكار تبديل به يك آدرس قابل كليك خواهد شد.
اكنون اگر پروژه را مجددا كامپايل كنيم و به آدرس ايجاد يك كارمند جديد مراجعه نمائيم، با رابط كاربري بهتري مواجه خواهيم شد.
سفارشي سازي ظاهر فرم ساز توكار ASP.NET MVC
در ادامه اگر بخواهيم ظاهر اين فرم را اندكي سفارشيتر كنيم، بهتر است به سورس صفحه توليدي در مرورگر مراجعه كنيم. در اينجا يك سري عناصر HTML محصور شده با div را خواهيم يافت. هر كدام از اينها هم با classهاي css خاص خود تعريف شدهاند. بنابراين اگر علاقمند باشيم كه رنگ و قلم و غيره اين موارد تغيير دهيم، تنها كافي است فايل css برنامه را ويرايش كنيم و نيازي به دستكاري مستقيم كدهاي برنامه نيست.
انتساب قالبهاي سفارشي به خواص يك شيء
تا اينجا در مورد نحوه سفارشي سازي رنگ، قلم، برچسب و نوع دادههاي هر كدام از عناصر نهايي نمايش داده شده، توضيحاتي را ملاحظه نموديد.
در فرم توليدي نهايي، خاصيت bool تعريف شده به صورت خودكار به يك checkbox تبديل شده است. چقدر خوب ميشد اگر امكان تبديل آن مثلا به RadioButton انتخاب مرد يا زن بودن كارمند ثبت شده در سيستم وجود داشت. براي اصلاح يا تغيير اين مورد، باز هم ميتوان از متاديتاي خواص، جهت تعريف قالبي خاص براي هر كدام از خواص مدل استفاده كرد.
به پوشه Views/Shared مراجعه كرده و يك پوشه جديد به نام EditorTemplates را ايجاد نمائيد. بر روي اين پوشه كليك راست كرده و گزينه Add view را انتخاب كنيد. در صفحه باز شده، گزينه «Create as a partial view» را انتخاب نمائيد و نام آنرا هم مثلا GenderOptions وارد كنيد. همچنين گزينه «Create a strongly typed view» را نيز انتخاب كنيد. مقدار Model class را مساوي bool وارد نمائيد. فعلا يك hello داخل اين صفحه جديد وارد كرده و سپس خاصيت IsMale را به نحو زير تغيير دهيد:
[DisplayName("Gender")] [UIHint("GenderOptions")] public bool IsMale { set; get; }
توسط ويژگي UIHint، ميتوان يك خاصيت را به يك partial view متصل كرد. در اينجا خاصيت IsMale به partial view ايي به نام GenderOptions متصل شده است. اكنون اگر برنامه را كامپايل و اجرا كرده و آدرس ايجاد يك كارمند جديد را ملاحظه كنيد، بجاي Checkbox بايد يك hello نمايش داده شود.
محتويات اين Partial view هم نهايتا به شكل زير خواهند بود:
@model bool <p>@Html.RadioButton("", false, !Model) Female</p> <p>@Html.RadioButton("", true, Model) Male</p>
در اينجا Model كه از نوع bool تعريف شده، به خاصيت IsMale اشاره خواهد كرد. دو RadioButton هم براي انتخاب بين حالت زن و مرد تعريف شدهاند.
يا يك مثال جالب ديگر در اين زمينه ميتواند تبديل enum به يك Dropdownlist باشد. در اين حالت partial view ما شكل زير را خواهد يافت:
@model Enum @Html.DropDownListFor(m => m, Enum.GetValues(Model.GetType()) .Cast<Enum>() .Select(m => { string enumVal = Enum.GetName(Model.GetType(), m); return new SelectListItem() { Selected = (Model.ToString() == enumVal), Text = enumVal, Value = enumVal }; }))
و براي استفاده از آن، از ويژگي زير ميتوان كمك گرفت (مزين كردن خاصيتي از نوع يك enum دلخواه، جهت تبديل خودكار آن به يك دراپ داون ليست):
[UIHint("Enum")]
ساير متدهاي كمكي توليد و نمايش خودكار اطلاعات از روي اطلاعات مدلهاي برنامه
متدهاي ديگري نيز در ردهي Templated helpers قرار ميگيرند. اگر از متد Html.EditorFor استفاده كنيم، از تمام اين اطلاعات متاديتاي تعريف شده نيز استفاده خواهد كرد. همانطور كه در قسمت قبل (قسمت 11) نيز توضيح داده شد، صفحه استاندارد Add view در VS.NET به همراه يك سري قالب توليد فرمهاي Create و Edit هم هست كه دقيقا كد نهايي توليدي را بر اساس همين متد توليد ميكند.
استفاده از Html.EditorFor انعطاف پذيري بيشتري را به همراه دارد. براي مثال اگر يك طراح وب، طرح ويژهاي را در مورد ظاهر فرمهاي سايت به شما ارائه دهد، بهتر است از اين روش استفاده كنيد. اما خروجي نهايي Html.EditorForModel به كمك تعدادي متاديتا و اندكي دستكاري CSS، از ديدگاه يك برنامه نويس بي نقص است!
به علاوه، متد Html.DisplayForModel نيز مهيا است. بجاي اينكه كار توليد رابط كاربري اطلاعات نمايش جزئيات يك شيء را انجام دهيد، اجازه دهيد تا متد Html.DisplayForModel اينكار را انجام دهد. سفارشي سازي آن نيز همانند قبل است و بر اساس متاديتاي خواص انجام ميشود. در اين حالت، مسير پيش فرض جستجوي قالبهاي UIHint آن، Views/Shared/DisplayTemplates ميباشد. همچنين Html.DisplayFor نيز جهت كار با يك خاصيت مدل تدارك ديده شده است. البته بايد درنظر داشت كه استفاده از پوشه Views/Shared اجباري نيست. براي مثال اگر از پوشه Views/Home/DisplayTemplates استفاده كنيم، قالبهاي سفارشي تهيه شده تنها جهت Viewهاي كنترلر home قابل استفاده خواهند بود.
يكي ديگر از ويژگيهايي كه جهت سفارشي سازي نحوه نمايش خودكار اطلاعات ميتواند مورد استفاده قرار گيرد، DisplayFormat است. براي مثال اگر مقدار خاصيت در حال نمايش نال بود، ميتوان مقدار ديگري را نمايش داد:
[DisplayFormat(NullDisplayText = "-")]
يا اگر علاقمند بوديم كه فرمت اطلاعات در حال نمايش را تغيير دهيم، به نحو زير ميتوان عمل كرد:
[DisplayFormat(DataFormatString = "{0:n}")]
مقدار DataFormatString در پشت صحنه در متد string.Format مورد استفاده قرار ميگيرد.
و اگر بخواهيم كه اين ويژگي در حالت توليد فرم ويرايش نيز درنظر گرفته شود، ميتوان خاصيت ApplyFormatInEditMode را نيز مقدار دهي كرد:
[DisplayFormat(DataFormatString = "{0:n}", ApplyFormatInEditMode = true)]
بازنويسي قالبهاي پيش فرض توليد فرم يا نمايش اطلاعات خودكار ASP.NET MVC
يكي ديگر از قرارداهاي بكارگرفته شده در حين استفاده از قالبهاي سفارشي، استفاده از نام اشياء ميباشد. مثلا در پوشه Views/Shared/DisplayTemplates، اگر يك Partial view به نام String.cshtml وجود داشته باشد، از اين پس نحوه رندر كليه خواص رشتهاي تمام مدلها، بر اساس محتواي فايل String.cshtml مشخص ميشود؛ به همين ترتيب در مورد datetime و ساير انواع مهيا.
براي مثال اگر خواستيد تمام تاريخهاي ميلادي دريافتي از بانك اطلاعاتي را شمسي نمايش دهيد، فقط كافي است يك فايل datetime.cshtml سفارشي را توليد كنيد كه Model آن تاريخ ميلادي دريافتي است و نهايتا كار اين Partial view، رندر تاريخ تبديل شده به همراه تگهاي سفارشي مورد نظر ميباشد. در اين حالت نيازي به ذكر ويژگي UIHint نيز نخواهد بود و همه چيز خودكار است.
به همين ترتيب اگر نام مدل ما Employee باشد و فايل Partial view ايي به نام Employee.cshtml در پوشه Views/Shared/DisplayTemplates قرار گيرد، متد Html.DisplayForModel به صورت پيش فرض از محتواي اين فايل جهت رندر اطلاعات نمايش جزئيات شيء Employee استفاده خواهد كرد.
داخل Partial viewهاي سفارشي تعريف شده به كمك خاصيت ViewData.TemplateInfo.FormattedModelValue مقدار نهايي فرمت شده قابل استفاده را فراهم ميكند. اين مورد هم از اين جهت حائز اهميت است كه نيازي نباشد تا ويژگي DisplayFormat را به صورت دستي پردازش كنيم. همچنين اطلاعات ViewData.ModelMetadata نيز دراينجا قابل دسترسي هستند.
سؤال: Partial View چيست؟
همانطور كه از نام Partial view برميآيد، هدف آن رندر كردن قسمتي از صفحه است به همراه استفاده مجدد از كدهاي توليد رابط كاربري در چندين و چند View؛ چيزي شبيه به User controls در ASP.NET Web forms البته با اين تفاوت كه Page life cycle و Code behind و ساير موارد مشابه آن در اينجا حذف شدهاند. همچنين از Partial viewها براي به روز رساني قسمتي از صفحه حين فراخوانيهاي Ajaxايي نيز استفاده ميشود. مهمترين كاربرد Partial views علاوه بر استفاده مجدد از كدها، خلوت كردن Viewهاي شلوغ است جهت سادهتر سازي نگهداري آنها در طول زمان (يك نوع Refactoring فايلهاي View محسوب ميشوند).
پسوند اين فايلها نيز بسته به موتور View مورد استفاده تعيين ميشود. براي مثال حين استفاده از Razor، پسوند Partial views همان cshtml يا vbhtml ميباشد. يا اگر از web forms view engine استفاده شود، پسوند آنها ascx است (همانند User controls در وب فرمها).
البته چون در حالت استفاده از موتور Razor، پسوند View و Partial viewها يكي است، مرسوم شده است كه نام Partial viewها را با يك underline شروع كنيم تا بتوان بين اين دو تمايز قائل شد.
اگر اين فايلها را در پوشه Views/Shared تعريف كنيم، در تمام Viewها قابل استفاده خواهند بود. اما اگر مثلا در پوشه Views/Home آنهارا قرار دهيم، تنها در Viewهاي متعلق به كنترلر Home، قابل بكارگيري ميباشند.
Partial views را نيز ميتوان strongly typed تعريف كرد و به اين ترتيب با مشخص سازي دقيق نوع model آن، علاوه بر بهرهمندي از Intellisense خودكار، رندر آنرا نيز تحت كنترل كامپايلر قرار داد.
مقدار Model در يك View بر اساس اطلاعات مدلي كه به آن ارسال شده است تعيين ميگردد. اما در يك Partial view كه جزئي از يك View را نهايتا تشكيل خواهد داد، بر اساس مقدار ارسالي از طريق View معين ميگردد.
يك مثال
در ادامه قصد داريم كد حلقه نمايش ليستي از عناصر توليد شده توسط VS.NET را به يك Partial view منتقل و Refactor كنيم.
ابتدا يك منبع داده فرضي زير را در نظر بگيريد:
using System; using System.Collections.Generic; namespace MvcApplication8.Models { public class Employees { public IList<Employee> CreateEmployees() { return new[] { new Employee { Id = 1, AddDate = DateTime.Now.AddYears(-3), Name = "Emp-01", Salary = 3000}, new Employee { Id = 2, AddDate = DateTime.Now.AddYears(-2), Name = "Emp-02", Salary = 2000}, new Employee { Id = 3, AddDate = DateTime.Now.AddYears(-1), Name = "Emp-03", Salary = 1000} }; } } }
سپس از آن در يك كنترلر براي بازگشت ليستي از كاركنان استفاده خواهيم كرد:
public ActionResult EmployeeList() { var list = new Employees().CreateEmployees(); return View(list); }
View متناظر با اين متد را هم با كليك راست بر روي متد، انتخاب گزينه Add view و سپس ايجاد يك strongly typed view از نوع كلاس Employee، ايجاد خواهيم كرد.
در ادامه قصد داريم بدنه حلقه زير را refactor كنيم و آنرا به يك Parial view منتقل نمائيم تا View ما اندكي خلوتتر و مفهومتر شود:
@foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Name) </td> <td> @Html.DisplayFor(modelItem => item.Salary) </td> <td> @Html.DisplayFor(modelItem => item.Address) </td> <td> @Html.DisplayFor(modelItem => item.IsMale) </td> <td> @Html.DisplayFor(modelItem => item.AddDate) </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> }
سپس بر روي پوشه Views/Employee كليك راست كرده و گزينه Add|View را انتخاب كنيد. در اينجا نام _EmployeeItem را وارد كرده و همچنين گزينه Create as a partial view و create a strongly typed view را نيز انتخاب كنيد. نوع مدل هم Employee خواهد بود. به اين ترتيب فايل زير تشكيل خواهد شد:
\Views\Employee\_EmployeeItem.cshtml
ابتداي نام فايلرا با underline شروع كردهايم تا بتوان بين Viewها و Partial views تفاوت قائل شد. همچنين اين Partial view چون داخل پوشه Employee تعريف شده، فقط در Viewهاي كنترلر Employee در دسترس خواهد بود.
در ادامه كل بدنه حلقه فوق را cut كرده و در اين فايل جديد paste نمائيد. مرحله اول refactoring يك view به همين نحو آغاز ميشود. البته در اين حالت قادر به استفاده از Partial view نخواهيم بود چون اطلاعاتي كه به اين فايل ارسال ميگردد و مدلي كه در دسترس آن است از نوع Employee است و نه ليستي از كارمندان. به همين جهت بايد item را با Model جايگزين كرد:
@model MvcApplication8.Models.Employee <tr> <td> @Html.DisplayFor(x => x.Name) </td> <td> @Html.DisplayFor(x => x.Salary) </td> <td> @Html.DisplayFor(x => x.Address) </td> <td> @Html.DisplayFor(x => x.IsMale) </td> <td> @Html.DisplayFor(x => x.AddDate) </td> <td> @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) | @Html.ActionLink("Details", "Details", new { id = Model.Id }) | @Html.ActionLink("Delete", "Delete", new { id = Model.Id }) </td> </tr>
سپس براي استفاده از اين Partial view در صفحه نمايش ليست كارمندان خواهيم داشت:
@foreach (var item in Model) { @Html.Partial("_EmployeeItem", item) }
متد Html.Partial، اطلاعات يك Partial view را پردازش و تبديل به يك رشته كرده و در اختيار Razor قرار ميدهد تا در صفحه نمايش داده شود. پارامتر اول آن نام Partial view مورد نظر است (نيازي به ذكر پسوند فايل نيست) و پارامتر دوم، اطلاعاتي است كه به آن ارسال خواهد شد.
متد ديگري هم وجود دارد به نام Html.RenderPartial. كار اين متد نوشتن مستقيم در Response است، برخلاف Html.Partial كه فقط يك رشته را بر ميگرداند.
نمايش اطلاعات از كنترلرهاي مختلف در يك صفحه
Html.Partial بر اساس اطلاعات مدل ارسالي از يك كنترلر، كار رندر قسمتي از آنرا در يك View خاص عهده دار خواهد شد. اما اگر بخواهيم مثلا در يك صفحه يك قسمت را به نمايش آخرين اخبار و يك قسمت را به نمايش آخرين وضعيت آب و هوا اختصاص دهيم، از روش ديگري به نام RenderAction ميتوان كمك گرفت. در اينجا هم دو متد Html.Action و Html.RenderAction وجود دارند. اولي يك رشته را بر ميگرداند و دومي اطلاعات را مستقيما در Response درج ميكند.
يك مثال:
كنترلر جديدي را به نام MenuController به پروژه اضافه كنيد:
using System.Web.Mvc; namespace MvcApplication8.Controllers { public class MenuController : Controller { [ChildActionOnly] public ActionResult ShowMenu(string options) { return PartialView(viewName: "_ShowMenu", model: options); } } }
سپس بر روي نام متد كليك راست كرده و گزينه Add view را انتخاب كنيد. در اينجا قصد داريم يك partial view كه نامش با underline شروع ميشود را اضافه كنيم. مثلا با محتواي زير ( با توجه به اينكه مدل ارسالي از نوع رشتهاي است):
@model string <ul> <li> @Model </li> </ul>
حين فراخواني متد Html.Action، يك متد در يك كنترلر فراخواني خواهد شد (كه شامل ارائه درخواست و طي سيكل كامل پردازشي آن كنترلر نيز خواهد بود). سپس آن متد با بازگشت دادن يك PartialView، اطلاعات پردازش شده يك partial view را به فراخوان بازگشت ميدهد. اگر نامي ذكر نشود، همان نام متد در نظر گرفته خواهد شد. البته از آنجائيكه در اين مثال در ابتداي نام Partial view يك underline قرار داديم، نياز خواهد بود تا اين نام صريحا ذكر گردد (چون ديگر هم نام متد يا ActionName آن نيست). ويژگي ChildActionOnly سبب ميشود تا اين متد ويژه تنها از طريق فراخواني Html.Action در دسترس باشد.
براي استفاده از آن هم در Viewايي ديگر خواهيم داشت:
@Html.Action(actionName: "ShowMenu", controllerName: "Menu", routeValues: new { options = "some data..." })
در اينجا هم پارامتر ارسالي به كمك anonymously typed objects مشخص و مقدار دهي شده است.
سؤال مهم: چه تفاوتي بين RenderPartial و RenderAction وجود دارد؟ به نظر هر دو يك كار را انجام ميدهند، هر دو مقداري HTML را پس از پرداش به صفحه تزريق ميكنند.
پاسخ: اگر View والد، داراي كليه اطلاعات لازم جهت نمايش اطلاعات Partial view است، از RenderPartial استفاده كنيد. به اين ترتيب برخلاف حالت RenderAction درخواست جديدي به ASP.NET Pipeline صادر نشده و كارآيي نهايي بهتر خواهد بود. صرفا يك الحاق ساده به صفحه انجام خواهد شد.
اما اگر براي رندر كردن اين قسمت از صفحه كه قرار است اضافه شود، نياز به دريافت اطلاعات ديگري خارج از اطلاعات مهيا ميباشد، از روش RenderAction استفاده كنيد. براي مثال اگر در صفحه جاري قرار است ليست پروژهها نمايش داده شود و در كنار صفحه مثلا منوي خاصي بايد قرار گيرد، اطلاعات اين منو در View جاري فراهم نيست (و همچنين مرتبط به آن هم نيست). بنابراين از روش RenderAction براي حل اين مساله ميتوان كمك گرفت.
به صورت خلاصه براي نمايش اطلاعات تكراري در صفحات مختلف سايت در حالتيكه اين اطلاعات از قسمتهاي ديگر صفحه ايزوله است (مثلا نمايش چند ويجت مختلف در صفحه)، روش RenderAction ارجحيت دارد.
يك نكته
فراخواني متدهاي RenderAction و RenderPartial در حين كار با Razor بايد به شكل فراخواني يك متد داخل {} باشند:
@{ Html.RenderAction("About"); } And not @Html.RenderAction("About")
علت اين است كه @ به تنهايي به معناي نوشتن در Response است. متد RenderAction هم خروجي ندارد و مستقيما در Response اطلاعات خودش را درج ميكند. بنابراين اين دو با هم همخواني ندارند و بايد به شكل يك متد معمولي با آن رفتار كرد.
اگر حجم اطلاعاتي كه قرار است در صفحه درج شود بالا است، متدهاي RenderAction و RenderPartial نسبت به Html.Action و Html.Partial كارآيي بهتري دارند؛ چون يك مرحله تبديل كل اطلاعات به رشته و سپس درج نتيجه در Response، در آنها حذف شده است.