ترجمه کد به کمک هوش مصنوعی
آموزش Delegate
<Button Text="This is a test button" />
Tabbed Page نیز چندین Tab را نمایش میدهد که هر Tab خود یک Content Page است. Carousel Page نیز همانند Tabbed Page است، ولی با Swipe کردن به چپ و راست میشود بین صفحات چرخید. هر دوی اینها Multi Page محسوب میشوند. MasterDetail نیز این امکان را میدهد که از بغل منویی برای Swipe کردن وجود داشته باشد. در نهایت Navigation Page محتوای یک Content Page را نمایش میدهد، ولی در بالای آن Navigation Bar دارد؛ شامل دکمه بازگشت به صفحه قبل و Title صفحه جاری و ...
علاوه بر Page ها، Layoutها نیز وجود دارند. برای مثال، Stack Layout برای چینش خطی (افقی یا عمودی) استفاده میشود. Grid برای ساختار شبکهای استفاده میشود و Flex Layout عملکردی مشابه با Flex در وب دارد.
برای مثال، در صورتی که بخواهید چهار دکمه را هم اندازه با هم نمایش دهید، دارید:
<Grid> <Button Text="1" Grid.Row="0" Grid.Column="0" /> <Button Text="2" Grid.Row="0" Grid.Column="1" /> <Button Text="3" Grid.Row="1" Grid.Column="0" /> <Button Text="4" Grid.Row="1" Grid.Column="1" /> </Grid>
در نهایت کنترلها را داریم. برای مثال Label، Button و ... هر کدام از اینها نقشی را ایفا میکنند و امکاناتی دارند.
پس Page داریم، داخل Page از Layout استفاده میکنیم برای چینش کلی صفحه و در نهایت از کنترلهای Image، ListView، Button و ... استفاده میکنیم تا ظاهر فرم تکمیل شود.
هر Page علاوه بر ظاهر خود، دارای یک منطق نیز هست. منطق، کاری است که آن فرم انجام میدهد. برای مثال فرم لاگین میتواند یک Stack Layout عمودی باشد، شامل یک Entry برای گرفتن نام کاربری، یک Entry برای گرفتن رمز عبور، که IsPassword آن True است و در نهایت یک دکمه که برای انجام عمل لاگین است.
در قسمت منطق که با CSharp نوشته میشود، ما یک Property از جنس string برای نگه داشتن نام کاربری داریم. یک Property از جنس string برای نگه داشتن رمز عبور و یک Command که عمل لاگین را انجام دهد. Property اول با نام UserName به Text آن Entry اول وصل میشود (به اصطلاح Bind میشود) و همین طور Property دوم با نام Password نیز به Text آن Entry دوم که IsPassword اش True بود وصل میشود و در نهایت Command لاگین به دکمه لاگین وصل میشود.
برای زدن ظاهر فرم لاگین، در پروژه XamApp روی فولدر Views راست کلیک نموده و از منوی Add به New Item رفته و Content Page را میزنیم. نام آن را LoginView.xaml میگذاریم که داخل تگ Content Page خواهیم داشت:
<StackLayout Orientation="Vertical"> <Entry Placeholder="User name" Text="{Binding UserName}" /> <Entry IsPassword="True" Placeholder="Password" Text="{Binding Password}" /> <Button Command="{Binding LoginCommand}" Text="Login" /> </StackLayout>
برای زدن منطق، در پروژه XamApp روی فولدر ViewModels راست کلیک نموده و از منوی Add گزینه Class را انتخاب کرده و نام آن را LoginViewModel.cs میگذاریم که در داخل آن خواهیم داشت:
public class LoginViewModel : BitViewModelBase { public string UserName { get; set; } public string Password { get; set; } public BitDelegateCommand LoginCommand { get; set; } public LoginViewModel() { LoginCommand = new BitDelegateCommand(Login); } public async Task Login() { // Login implementation ... } }
BitDelegateCommand در این مثال، وظیفه اجرای متد Login را به عهده دارد و آن را اجرا میکند؛ زمانیکه کاربر روی دکمه لاگین Click یا Tap کند.
برای این که Content Page جدید، یعنی LoginView به همراه منطق آن، یعنی LoginViewModel در برنامه نشان داده شوند، لازم است با Navigation به آن صفحه برویم. برای این کار، ابتدا باید این زوج را رجیستر کنیم. برای این کار به متد RegisterTypes در کلاس App رفته (زیر فایل App.xaml یک فایل App.xaml.cs است) و خط زیر را به آن اضافه میکنیم:
containerRegistry.RegisterForNav<LoginView, LoginViewModel>("Login");
حال در متد OnInitializedAsync در چند خط بالاتر داریم:
await NavigationService.NavigateAsync("/Login", animated: false);
این سطر باعث میشود که Navigation Service که همان طور که از اسمش بر میآید، کارش Navigation بین صفحات است، صفحه لاگین را باز کند.
هم اکنون پروژه XamApp بروز شده و دارای این مثال است. در صورتی که آن را الآن Clone کنید و یا در صورتی که از قبل گرفته بودید، دستور git pull را برای گرفتن آخرین تغییرات بزنید، میتوانید این کدها رو داخل پروژه داشته باشید.
برنامه را اجرا کنید و در متد Login، یک Break point بگذارید. سپس برنامه را اجرا کنید. User Name و Password را پر کنید و بر روی دکمه لاگین بزنید. خواهید دید که متد لاگین اجرا میشود و User Name و Password با مقادیری که نوشته بودید، پر شدهاند.
هنوز موارد زیادی برای آموزش باقی مانده، اما با این توضیحات میتوانید در محیط توسعهای که آماده کردهاید، فرمهایی ساده را پیاده سازی کنید و برایشان منطقهایی ساده را بنویسید و به برنامه بگویید که در ابتدای اجرا آن، صفحه را برای شما باز کند. در قسمت بعدی، به صورت عمیقتر وارد UI میشویم.
- ایجاد صورت حساب پرداخت با استفاده از InvoiceBuilder
- درگاه مجازی
- استفاده از پروکسی
- توکن پرداخت
- تزریق وابستگی
- Logging
var result = _onlinePayment.Request(Gateways.Mellat, 123, 25000, "http://www.mywebsite.com/foo/bar/");
var result = _onlinePayment.Request(invoice => { invoice .SetTrackingNumber(123) .SetAmount(25000) .SetCallbackUrl("http://www.mywebsite.com/foo/bar/") .UseGateway(Gateways.Mellat); });
- تولید اتوماتیک کد رهگیری به صورت افزایشی
- تولید اتوماتیک کد رهگیری به صورت تصادفی
- ایجاد یک تولید کننده کد رهگیری توسط شما
- صورت حساب سفارشی برای امکانات اختصاصی درگاههای بانکی
var result = _onlinePayment.Request(invoice => { invoice .UseAutoIncrementTrackingNumber() .SetAmount(25000) .SetCallbackUrl("http://www.mywebsite.com/foo/bar/") .UseGateway(Gateways.Mellat); });
var result = _onlinePayment.Request(invoice => { invoice .UseAutoRandomTrackingNumber() .SetAmount(25000) .SetCallbackUrl("http://www.mywebsite.com/foo/bar/") .UseGateway(Gateways.Mellat); });
public class MyTrackingNumberProvider : ITrackingNumberProvider { public Task<long> ProvideAsync(CancellationToken cancellationToken = new CancellationToken()) { // تولید و برگشت کد در اینجا } }
var result = _onlinePayment.Request(invoice => { invoice .UseTrackingNumberProvider<MyTrackingNumberProvider>() // یا .UseTrackingNumberProvider(new MyTrackingNumberProvider()) // یا .UseTrackingNumberProvider(services => new MyTrackingNumberProvider()) });
services.AddParbad() .ConfigureGateways(gateways => { gateways .AddParbadVirtual() .WithOptions(options => options.GatewayPath = "/MyVirtualGateway"); });
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); // ثبت درگاه مجازی app.UseParbadVirtualGateway(); }
public void Configuration(IAppBuilder app) { var parbad = ParbadBuilder.CreateDefaultBuilder() .ConfigureGateways(gateways => { gateways .AddParbadVirtual() .WithOptions(options => options.GatewayPath = "/MyVirtualGateway"); }) .Build(); app.UseParbadVirtualGateway(parbad.Services); }
var result = _onlinePayment.Request(Gateways.ParbadVirtualGateway, 123, 25000, "http://www.mywebsite.com/foo/bar/");
services.AddParbad() .ConfigureGateways(gateways => { gateways .AddMellat() .WithOptions(options => { options.TerminalId = 123; options.UserName = "abc"; options.UserPassword = "xyz; ) .WithProxy(new Uri("Proxy Server URL"), "UserName", "Password"); });
public class MyTokenProvider : IPaymentTokenProvider { public Task<string> ProvideTokenAsync(Invoice invoice, CancellationToken cancellationToken = new CancellationToken()) { // تولید و برگرداندن توکن در اینجا } public Task<string> RetrieveTokenAsync(CancellationToken cancellationToken = new CancellationToken()) { // خواندن و برگرداندن توکن در اینجا } }
services.AddParbad() .ConfigurePaymentToken(builder => builder.AddPaymentTokenProvider<MyTokenProvider>(ServiceLifetime.Transient));
ما در تولید محتوای فنی (در زمینه کاری خودمون و به زبان فارسی) به شکلی صحیح، مولفین انگشت شماری داریم. به نظر من برخی از مهمترین دلائل این مساله عبارت است از:
1. برخی از افراد انگل هستن - تمام! (به کتاب Harley Hahn در این زمینه مراجعه کنید).
2. بعضی ها فکر میکنن که اگر فلان مطلب رو به اشتراک بذارم، ممکنه همکارم، دوستم و ... با خوندن اون مطلب، فاصله دانسته هاشو با من کم کنه، و به این ترتیب منو با زحمت مواجه کنه (متاسفانه این خصیصه در بسیاری از شرکت های خصوصی، و تقریبا تمامی سازمان های دولتی دیده میشه).
3. وقتی گوگل و بسیاری از شرکت های شناخته شده در صنعت آگهی های Online بر اساس ضوابط کاری کشورشون، اجازه سرویس دهی به سایت هایی با مطالب فارسی رو ندارن، من نوعی از چه طریقی می تونم از نوشتن، انتفاع حاصل کنم؟ چه کنم که به شرکتهای ایرانی فعال در زمینه Ads نیز اعتمادی ندارم؟ جدا از اینکه تبلیغات این شرکت ها، اکثرا Animation هستش و من دوست دارم خواننده مطالب من، هنگام مطالعه یه مطلب فنی، احساس آرامش کنه، نه اینکه چشم هاش مدام به خاطر وجود یه آگهی َ«ـِ»ً]ٌٍ,\[]!,@# پر پر بزنه.
4. نبود قانون Copyright از دیگر دلائل عمده ای هستش که باعث شده در این زمینه ما پیشرفتی نکنیم. وقتی یکی از مطالب فارسی ای که نوشته بودم (در سال 1996 (یا 1994)، دقیق خاطرم نیست)، کپی و در یکی از جرائد کشور به اسم فرد دیگه ای منتشر شد، در همون ابتدای راه تصمیم گرفتم دیگه فارسی ننویسم. متاسفانه هنوز که هنوزه، کم و بیش شاهد این اتفاقات هستیم.
5. ...
اما در مورد مطلبی که در مورد بلاگ من فرمودید. حقیقتش بعد از اینکه فردی چند سال پیش، منو به دلیل مطالبی که به اشتراک میذاشتم به سخره گرفت و ازم پرسید که "تو اصلا میدونی معمار کیه؟"، به خودم اومدم و تصمیم گرفتم مثل وبلاگ های دیگه، به مطالب بزن و برو اکتفا نکنم. به همین دلیل، از 2/1/2010 به بعد، مطالب ارسالیم شکل مقاله به خودشون گرفتن که طبیعتا، نوشتنشون در مقایسه با نوشتن یکی دو وجب مطلب فنی، بسیار دشوارتر و زمان بر تر هست. من از March 2008 تا February 20110 در واقع برای Search Engine گوگل می نوشتم، نه برای خوانندگان. اما از اون تاریخ به بعد، مطالبی که در وبلاگم گذاشتم، توجه بسیاری از افراد رو بخودش جلب کرد و ... (بی ارتباط با موضوع گفتگو هستش، بنابراین بیش از این در این مورد توضیح نمیدم).
در هر حال، بنظر من، عدم ارائه مطالب فنی یه وبلاگ بصورت رایگان (در فرهنگ ما)، موفقیتی در پی نداره (امیدوارم برای آقای نصیری اینطور نباشه، البته اگر این وبلاگ رو از حالت رایگان در آوردن). من هنوز یادم نرفته افرادیکه برای شرکت در کنفرانس کذایی ای که بهروز راد، من و یکی دو نفر دیگه قرار بود در مورد HTML5، JavaScript Performance و ... مطلب ارائه بدیم، ابراز خرسندی کردن، اما وقت پول دادن که شد، تعداد افراد ثبت نام کننده به حداقل تعداد مورد نیاز نرسید و اون جلسه Cancel شد. جای تاسفه اگر بدونید برای یه جلسه 1 ساعته، هر نفر فقط باید 5-6 هزارتومان پرداخت می کرد...
- لیست زبانهای برنامه نویسی محبوب در ماه آوریل 2009؛ سی شارپ یک پله صعود نسبت به سال قبل، زبان برنامه نویسی MATLAB مجددا وارد لیست شده
- اولین محصول نگارش 2010 مایکروسافت برای دریافت، exchange server 2010 beta (میل سرور)
سایر اولین سری محصولات 2010 ، شامل Microsoft Office 2010 ، Microsoft Visio 2010 و Microsoft Project 2010 خواهند بود.
- مجموعه انتشارات مایکروسافت 25 امین سالگرد تاسیس خود را جشن میگیرد. به همین منظور دو کتاب زیر را به رایگان برای دریافت قرار دادهاند:
عنوانی رو که براش انتخاب کردن جالب است "the world's most advanced open source database"
ASP.NET MVC #21
آشنایی با تکنیکهای Ajax در ASP.NET MVC
اهمیت آشنایی با Ajax، ارائه تجربه کاربری بهتری از برنامههای وب، به مصرف کنندگان نهایی آن میباشد. به این ترتیب میتوان درخواستهای غیرهمزمانی (asynchronous) را با فرمت XML یا Json به سرور ارسال کرد و سپس نتیجه نهایی را که حجم آن نسبت به یک صفحه کامل بسیار کمتر است، به کاربر ارائه داد. غیرهمزمان بودن درخواستها سبب میشود تا ترد اصلی رابط کاربری برنامه قفل نشده و کاربر در این بین میتواند به سایر امور خود بپردازد. به این ترتیب میتوان برنامههای وبی را که شبیه به برنامههای دسکتاپ هستند تولید نمود؛ کل صفحه مرتبا به سرور ارسال نمیشود، flickering و چشمک زدن صفحه کاهش خواهد یافت (چون نیازی به ترسیم مجدد کل صفحه نخواهد بود و عموما قسمتی جزئی از یک صفحه به روز میشود) یا بدون نیاز به ارسال کل صفحه به سرور، به کاربری خواهیم گفت که آیا اطلاعاتی که وارد کرده است معتبر میباشد یا نه (نمونهای از آن را در قسمت Remote validation اعتبار سنجی اطلاعات ملاحظه نمودید).
مروری بر محتویات پوشه Scripts یک پروژه جدید ASP.NET MVC در ویژوال استودیو
با ایجاد هر پروژه ASP.NET MVC جدیدی در ویژوال استودیو، یک سری اسکریپت هم به صورت خودکار در پوشه Scripts آن اضافه میشوند. تعدادی از این فایلها توسط مایکروسافت پیاده سازی شدهاند. برای مثال:
MicrosoftAjax.debug.js
MicrosoftAjax.js
MicrosoftMvcAjax.debug.js
MicrosoftMvcAjax.js
MicrosoftMvcValidation.debug.js
MicrosoftMvcValidation.js
این فایلها از ASP.NET MVC 3 به بعد، صرفا جهت سازگاری با نگارشهای قبلی قرار دارند و استفاده از آنها اختیاری است. بنابراین با خیال راحت آنها را delete کنید! روش توصیه شده جهت پیاده سازی ویژگیهای Ajax ایی، استفاده از کتابخانههای مرتبط با jQuery میباشد؛ از این جهت که 100ها افزونه برای کار با آن توسط گروه وسیعی از برنامه نویسها در سراسر دنیا تاکنون تهیه شده است. به علاوه فریم ورک jQuery تنها منحصر به اعمال Ajax ایی نیست و از آن جهت دستکاری DOM (document object model) و CSS صفحه نیز میتوان استفاده کرد. همچنین حجم کمی نیز داشته، با انواع و اقسام مرورگرها سازگار است و مرتبا هم به روز میشود.
در این پوشه سه فایل دیگر پایه کتابخانه jQuery نیز قرار دارند:
jquery-xyz-vsdoc.js
jquery-xyz.js
jquery-xyz.min.js
فایل vsdoc برای ارائه نهایی برنامه طراحی نشده است. هدف از آن ارائه Intellisense بهتری از jQuery در VS.NET میباشد. فایلی که باید به کلاینت ارائه شود، فایل min یا فشرده شده آن است. اگر به آن نگاهی بیندازیم به نظر obfuscated مشاهده میشود. علت آن هم حذف فواصل، توضیحات و همچنین کاهش طول متغیرها است تا اندازه فایل نهایی به حداقل خود کاهش پیدا کند. البته این فایل از دیدگاه مفسر جاوا اسکریپت یک مرورگر، فایل بینقصی است!
اگر علاقمند هستید که سورس اصلی jQuery را مطالعه کنید، به فایل jquery-xyz.js مراجعه نمائید.
محل الحاق اسکریپتهای عمومی مورد نیاز برنامه نیز بهتر است در فایل master page یا layout برنامه باشد که به صورت پیش فرض اینکار انجام شده است.
سایر فایلهای اسکریپتی که در این پوشه مشاهده میشوند، یک سری افزونه عمومی یا نوشته شده توسط تیم ASP.NET MVC برفراز jQuery هستند.
به چهار نکته نیز حین استفاده از اسکریپتهای موجود باید دقت داشت:
الف) همیشه از متد Url.Content همانند تعاریفی که در فایل Views\Shared\_Layout.cshtml مشاهده میکنید، برای مشخص سازی مسیر ریشه سایت، استفاده نمائید. به این ترتیب صرفنظر از آدرس جاری صفحه، همواره آدرس صحیح قرارگیری پوشه اسکریپتها در صفحه ذکر خواهد شد.
ب) ترتیب فایلهای js مهم هستند. ابتدا باید کتابخانه اصلی jQuery ذکر شود و سپس افزونههای آنها.
ج) اگر اسکریپتهای jQuery در فایل layout سایت تعریف شدهاند؛ نیازی به تعریف مجدد آنها در Viewهای سایت نیست.
د) اگر View ایی به اسکریپت ویژهای جهت اجرا نیاز دارد، بهتر است آنرا به شکل یک section داخل view تعریف کرد و سپس به کمک متد RenderSection این قسمت را در layout سایت مقدار دهی نمود. مثالی از آنرا در قسمت 20 این سری مشاهده نمودید (افزودن نمایش جمع هر ستون گزارش).
یک نکته
اگر آخرین به روز رسانیهای ASP.NET MVC را نیز نصب کرده باشید، فایلی به نام packages.config به صورت پیش فرض به هر پروژه جدید ASP.NET MVC اضافه میشود. به این ترتیب VS.NET به کمک NuGet این امکان را خواهد یافت تا شما را از آخرین به روز رسانیهای این کتابخانهها مطلع کند.
آشنایی با Ajax Helpers توکار ASP.NET MVC
اگر به تعاریف خواص و متدهای کلاس WebViewPage دقت کنیم:
using System;
namespace System.Web.Mvc
{
public abstract class WebViewPage<TModel> : WebViewPage
{
protected WebViewPage();
public AjaxHelper<TModel> Ajax { get; set; }
public HtmlHelper<TModel> Html { get; set; }
public TModel Model { get; }
public ViewDataDictionary<TModel> ViewData { get; set; }
public override void InitHelpers();
protected override void SetViewData(ViewDataDictionary viewData);
}
}
علاوه بر خاصیت Html که وهلهای از آن امکان دسترسی به Html helpers توکار ASP.NET MVC را در یک View فراهم میکند، خاصیتی به نام Ajax نیز وجود دارد که توسط آن میتوان به تعدادی متد AjaxHelper توکار دسترسی داشت. برای مثال توسط متد Ajax.ActionLink میتوان قسمتی از صفحه را به کمک ویژگیهای Ajax، به روز رسانی کرد.
مثالی در مورد به روز رسانی قسمتی از صفحه به کمک متد Ajax.ActionLink
ابتدا نیاز است فایل Views\Shared\_Layout.cshtml را اندکی ویرایش کرد. برای این منظور سطر الحاق jquery.unobtrusive-ajax.min.js را به فایل layout برنامه اضافه نمائید (اگر این سطر اضافه نشود، متد Ajax.ActionLink همانند یک لینک معمولی رفتار خواهد کرد):
<head>
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
</head>
سپس مدل ساده و منبع داده زیر را نیز به پروژه اضافه کنید:
namespace MvcApplication18.Models
{
public class Employee
{
public int Id { set; get; }
public string Name { set; get; }
}
}
using System.Collections.Generic;
namespace MvcApplication18.Models
{
public static class EmployeeDataSource
{
public static IList<Employee> CreateEmployees()
{
var list = new List<Employee>();
for (int i = 0; i < 1000; i++)
{
list.Add(new Employee { Id = i + 1, Name = "name " + i });
}
return list;
}
}
}
در ادامه کنترلر جدیدی را به برنامه با محتوای زیر اضافه کنید:
using System.Linq;
using System.Web.Mvc;
using MvcApplication18.Models;
namespace MvcApplication18.Controllers
{
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost] //for IE-8
public ActionResult EmployeeInfo(int? id)
{
if (!Request.IsAjaxRequest())
return View("Error");
if (!id.HasValue)
return View("Error");
var list = EmployeeDataSource.CreateEmployees();
var data = list.Where(x => x.Id == id.Value).FirstOrDefault();
if (data == null)
return View("Error");
return PartialView(viewName: "_EmployeeInfo", model: data);
}
}
}
بر روی متد Index کلیک راست کرده و گزینه Add view را انتخاب کنید. یک View خالی را به آن اضافه نمائید. همچنین بر روی متد EmployeeInfo کلیک راست کرده و با انتخاب گزینه Add view در صفحه ظاهر شده یک partial view را اضافه نمائید. جهت تمایز بین partial view و view هم بهتر است نام partial view با یک underline شروع شود.
کدهای partial view مورد نظر را به نحو زیر تغییر دهید:
@model MvcApplication18.Models.Employee
<strong>Name:</strong> @Model.Name
سپس کدهای View متناظر با متد Index را نیز به صورت زیر اعمال کنید:
@{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
<div id="EmployeeInfo">
@Ajax.ActionLink(
linkText: "Get Employee-1 info",
actionName: "EmployeeInfo",
controllerName: "Home",
routeValues: new { id = 1 },
ajaxOptions: new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "EmployeeInfo",
LoadingElementId = "Progress"
})
</div>
<div id="Progress" style="display: none">
<img src="@Url.Content("~/Content/images/loading.gif")" alt="loading..." />
</div>
توضیحات جزئیات کدهای فوق
متد Ajax.ActionLink لینکی را تولید میکند که با کلیک کاربر بر روی آن، اطلاعات اکشن متد واقع در کنترلری مشخص، به کمک ویژگیهای jQuery Ajax دریافت شده و سپس در مقصدی که توسط UpdateTargetId مشخص میگردد، بر اساس مقدار InsertionMode، درج خواهد شد (میتواند قبل از آن درج شود یا پس از آن و یا اینکه کل محتوای مقصد را بازنویسی کند). HttpMethod آن هم به POST تنظیم شده تا با IE مشکلی نباشد. از این جهت که IE پیغامهای GET را کش میکند و مساله ساز خواهد شد. توسط پارامتر routeValues، آرگومان مورد نظر به متد EmployeeInfo ارسال خواهد شد.
به علاوه یکی دیگر از خواص کلاس AjaxOptions، برای معرفی حالت بروز خطایی در سمت سرور به نام OnFailure در نظر گرفته شده است. در اینجا میتوان نام یک متد JavaScript ایی را مشخص کرده و پیغام خطای عمومی را در صورت فراخوانی آن به کاربر نمایش داد. یا توسط خاصیت Confirm آن میتوان یک پیغام را پیش از ارسال اطلاعات به سرور به کاربر نمایش داد.
به این ترتیب در مثال فوق، id=1 به متد EmployeeInfo به صورت غیرهمزمان ارسال میگردد. سپس کارمندی بر این اساس یافت شده و در ادامه partial view مورد نظر بر اساس اطلاعات کاربر مذکور، رندر خواهد شد. نتیجه کار، در یک div با id مساوی EmployeeInfo درج میگردد (InsertionMode.Replace). متد Ajax.ActionLink از این جهت داخل div تعریف شدهاست که پس از کلیک کاربر و جایگزینی محتوا، محو شود. اگر نیازی به محو آن نبود، آنرا خارج از div تعریف کنید.
عملیات دریافت اطلاعات از سرور ممکن است مدتی طول بکشد (برای مثال دریافت اطلاعات از بانک اطلاعاتی). به همین جهت بهتر است در این بین از تصاویری که نمایش دهنده انجام عملیات است، استفاده شود. برای این منظور یک div با id مساوی Progress تعریف شده و id آن به LoadingElementId انتساب داده شده است. این div با توجه به display: none آن، در ابتدای امر به کاربر نمایش داده نخواهد شد؛ در آغاز کار دریافت اطلاعات از سرور توسط متد Ajax.ActionLink نمایان شده و پس از خاتمه کار مجددا مخفی خواهد شد.
به علاوه اگر به کدهای فوق دقت کرده باشید، از متد Request.IsAjaxRequest نیز استفاده شده است. به این ترتیب میتوان تشخیص داد که آیا درخواست رسیده از طرف jQuery Ajax صادر شده است یا خیر. البته آنچنان روش قابل ملاحظهای نیست؛ چون امکان دستکاری Http Headers همیشه وجود دارد؛ اما بررسی آن ضرری ندارد. البته این نوع بررسیها را در ASP.NET MVC بهتر است تبدیل به یک فیلتر سفارشی نمود؛ به این ترتیب حجم if و else نویسی در متدهای کنترلرها به حداقل خواهد رسید. برای مثال:
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
public class AjaxOnlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
base.OnActionExecuting(filterContext);
}
else
{
throw new InvalidOperationException("This operation can only be accessed via Ajax requests");
}
}
}
و برای استفاده از آن خواهیم داشت:
[AjaxOnly]
public ActionResult SomeAjaxAction()
{
return Content("Hello!");
}
در مورد کلمه unobtrusive در قسمت بررسی نحوه اعتبار سنجی اطلاعات، توضیحاتی را ملاحظه نمودهاید. در اینجا نیز از ویژگیهای data-* برای معرفی پارامترهای مورد نیاز حین ارسال اطلاعات به سرور، استفاده میگردد. برای مثال خروجی متد Ajax.ActionLink به شکل زیر است. به این ترتیب امکان حذف کدهای جاوا اسکریپت از صفحه فراهم میشود و توسط یک فایل jquery.unobtrusive-ajax.min.js که توسط تیم ASP.NET MVC تهیه شده، اطلاعات مورد نیاز به سرور ارسال خواهد گردید:
<a data-ajax="true" data-ajax-loading="#Progress" data-ajax-method="POST"
data-ajax-mode="replace" data-ajax-update="#EmployeeInfo"
href="/Home/EmployeeInfo/1">Get Employee-1 info</a>
در کل این روش قابلیت نگهداری بهتری نسبت به روش اسکریپت نویسی مستقیم داخل صفحات را به همراه دارد. به علاوه جدا سازی افزونه اسکریپت وفق دهنده این اطلاعات با متد jQuery.Ajax از صفحه جاری، که امکان کش شدن آنرا به سادگی میسر میسازد.
به روز رسانی اطلاعات قسمتی از صفحه بدون استفاده از متد Ajax.ActionLink
الزامی به استفاده از متد Ajax.ActionLink و فایل jquery.unobtrusive-ajax.min.js وجود ندارد. اینکار را مستقیما به کمک jQuery نیز میتوان به نحو زیر انجام داد:
<a href="#" onclick="LoadEmployeeInfo()">Get Employee-1 info</a>
@section javascript
{
<script type="text/javascript">
function LoadEmployeeInfo() {
showProgress();
$.ajax({
type: "POST",
url: "/Home/EmployeeInfo",
data: JSON.stringify({ id: 1 }),
contentType: "application/json; charset=utf-8",
dataType: "json",
// controller is returning a simple text, not json
complete: function (xhr, status) {
var data = xhr.responseText;
if (status === 'error' || !data) {
//handleError
}
else {
$('#EmployeeInfo').html(data);
}
hideProgress();
}
});
}
function showProgress() {
$('#Progress').css("display", "block");
}
function hideProgress() {
$('#Progress').css("display", "none");
}
</script>
}
توضیحات:
توسط متد jQuery.Ajax نیز میتوان درخواستهای Ajax ایی خود را به سرور ارسال کرد. در اینجا type نوع http verb مورد نظر را مشخص میکند که به POST تنظیم شده است. Url آدرس کنترلر را دریافت میکند. البته حین استفاده از متد توکار Ajax.ActionLink، این لینک به صورت خودکار بر اساس تعاریف مسیریابی برنامه تنظیم میشود. اما در صورت استفاده مستقیم از jQuery.Ajax باید دقت داشت که با تغییر تعاریف مسیریابی برنامه نیاز است تا این Url نیز به روز شود.
سه سطر بعدی نوع اطلاعاتی را که باید به سرور POST شوند مشخص میکند. نوع json است و همچنین contentType آن برای ارسال اطلاعات یونیکد ضروری است. از متد JSON.stringify برای تبدیل اشیاء به رشته کمک گرفتهایم. این متد در تمام مرورگرهای امروزی به صورت توکار پشتیبانی میشود و استفاده از آن سبب خواهد شد تا اطلاعات به نحو صحیحی encode شده و به سرور ارسال شوند. بنابراین این رشته ارسالی اطلاعات را به صورت دستی تهیه نکنید؛ چون کاراکترهای زیادی هستند که ممکن است مشکل ساز شده و باید پیش از ارسال به سرور اصطلاحا escape یا encode شوند.
متداول است از پارامتر success برای دریافت نتیجه عملیات متد jQuery.Ajax استفاده شود. اما در اینجا از پارامتر complete آن استفاده شده است. علت هم اینجا است که return PartialView یک رشته را بر میگرداند. پارامتر success انتظار دریافت خروجی از نوع json را دارد. به همین جهت در این مثال خاص باید از پارامتر complete استفاده کرد تا بتوان به رشته بدون فرمت خروجی بدون مشکل دسترسی پیدا کرد.
به علاوه چون از یک section برای تعریف اسکریپتهای مورد نیاز استفاده کردهایم، برای درج خودکار آن در هدر صفحه باید قسمت هدر فایل layout برنامه را به صورت زیر مقدار دهی کرد:
@RenderSection("javascript", required: false)
دسترسی به اطلاعات یک مدل در View، به کمک jQuery Ajax
اگر جزئی از صفحه که قرار است به روز شود، پیچیده است، روش استفاده از partial viewها توصیه میشود؛ برای مثال میتوان اطلاعات یک مدل را به همراه یک گرید کامل از اطلاعات، رندر کرد و سپس در صفحه درج نمود. اما اگر تنها به اطلاعات چند خاصیت از مدلی نیاز داشتیم، میتوان از روشهایی با سربار کمتر نیز استفاده کرد. برای مثال متد جدید زیر را به کنترلر Home اضافه کنید:
[HttpPost] //for IE-8
public ActionResult EmployeeInfoData(int? id)
{
if (!Request.IsAjaxRequest())
return Json(false);
if (!id.HasValue)
return Json(false);
var list = EmployeeDataSource.CreateEmployees();
var data = list.Where(x => x.Id == id.Value).FirstOrDefault();
if (data == null)
return Json(false);
return Json(data);
}
سپس View برنامه را نیز به نحو زیر تغییر دهید:
<a href="#" onclick="LoadEmployeeInfoData()">Get Employee-2 info</a>
@section javascript
{
<script type="text/javascript">
function LoadEmployeeInfoData() {
showProgress();
$.ajax({
type: "POST",
url: "/Home/EmployeeInfoData",
data: JSON.stringify({ id: 1 }),
contentType: "application/json; charset=utf-8",
dataType: "json",
// controller is returning the json data
success: function (result) {
if (result) {
alert(result.Id + ' - ' + result.Name);
}
hideProgress();
},
error: function (result) {
alert(result.status + ' ' + result.statusText);
hideProgress();
}
});
}
function showProgress() {
$('#Progress').css("display", "block");
}
function hideProgress() {
$('#Progress').css("display", "none");
}
</script>
}
در این مثال، کنترلر برنامه، اطلاعات مدل را تبدیل به Json کرده و بازگشت خواهد داد. سپس میتوان به اطلاعات این مدل و خواص آن در View برنامه، در پارامتر success متد jQuery.Ajax، مطابق کدهای فوق دسترسی یافت. اینبار چون خروجی کنترلر تعریف شده از نوع Json است، امکان استفاده از پارامتر success فراهم شده است. همه چیز هم در اینجا خودکار است؛ تبدیل یک شیء به Json و برعکس.
یک نکته: اگر نوع متد کنترلر، HttpGet باشد، نیاز خواهد بود تا پارامتر دوم متد بازگشت Json، مساوی JsonRequestBehavior.AllowGet قرار داده شود.
ارسال اطلاعات فرمها به سرور، به کمک ویژگیهای Ajax
متد کمکی توکار دیگری به نام Ajax.BeginForm در ASP.NET MVC وجود دارد که کار ارسال غیرهمزمان اطلاعات یک فرم را به سرور انجام داده و سپس اطلاعاتی را از سرور دریافت و قسمتی از صفحه را به روز خواهد کرد. مکانیزم کاری کلی آن بسیار شبیه به متد Ajax.ActionLink میباشد. در ادامه با تکمیل مثال قسمت جاری، به بررسی این ویژگی خواهیم پرداخت.
ابتدا متد جستجوی زیر را به کنترلر برنامه اضافه کنید:
[HttpPost] //for IE-8
public ActionResult SearchEmployeeInfo(string data)
{
if (!Request.IsAjaxRequest())
return Content(string.Empty);
if (string.IsNullOrWhiteSpace(data))
return Content(string.Empty);
var employeesList = EmployeeDataSource.CreateEmployees();
var list = employeesList.Where(x => x.Name.Contains(data)).ToList();
if (list == null || !list.Any())
return Content(string.Empty);
return PartialView(viewName: "_SearchEmployeeInfo", model: list);
}
سپس بر روی نام متد کلیک راست کرده و گزینه add view را انتخاب کنید. در صفحه باز شده، گزینه create a stronlgly typed view را انتخاب کرده و قالب scaffolding را هم بر روی list قرار دهید. سپس گزینه ایجاد partial view را نیز انتخاب کنید. نام آنرا هم _SearchEmployeeInfo وارد نمائید. برای نمونه خروجی حاصل به نحو زیر خواهد بود:
@model IEnumerable<MvcApplication18.Models.Employee>
<table>
<tr>
<th>
Name
</th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
</tr>
}
</table>
تا اینجا یک متد جستجو را ایجاد کردهایم که میتواند لیستی از رکوردهای کارمندان را بر اساس قسمتی از نام آنها که توسط کاربری جستجو شده است، بازگشت دهد. سپس این اطلاعات را به partial view مورد نظر ارسال کرده و یک جدول را بر اساس آن تولید خواهیم نمود.
اکنون به فایل Index.cshtml مراجعه کرده و فرم Ajax ایی زیر را اضافه نمائید:
@using (Ajax.BeginForm(actionName: "SearchEmployeeInfo",
controllerName: "Home",
ajaxOptions: new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "EmployeeInfo",
LoadingElementId = "Progress"
}))
{
@Html.TextBox("data")
<input type="submit" value="Search" />
}
اینبار بجای استفاده از متد Html.BeginForm از متد Ajax.BeginForm استفاده شده است. به کمک آن اطلاعات Html.TextBox تعریف شده، به کنترلر Home و متد SearchEmployeeInfo آن، بر اساس HttpMethod تعریف شده، ارسال گردیده و نتیجه آن در یک div با id مساوی EmployeeInfo درج میگردد. همچنین اگر اطلاعاتی یافت نشد، به کمک متد return Content یک رشته خالی بازگشت داده میشود.
متد Ajax.BeginForm نیز از ویژگیهای data-* برای تعریف اطلاعات مورد نیاز ارسالی به سرور استفاده میکند. بنابراین نیاز به سطر الحاق jquery.unobtrusive-ajax.min.js در فایل layout برنامه جهت وفق دادن این اطلاعات unobtrusive به اطلاعات مورد نیاز متد jQuery.Ajax وجود دارد.
<form action="/Home/SearchEmployeeInfo" data-ajax="true"
data-ajax-loading="#Progress" data-ajax-method="POST"
data-ajax-mode="replace" data-ajax-update="#EmployeeInfo"
id="form0" method="post">
<input id="data" name="data" type="text" value="" />
<input type="submit" value="Search" />
</form>
کتابخانه کمکی «ASP.net MVC Awesome - jQuery Ajax Helpers»
علاوه بر متدهای توکار Ajax همراه با ASP.NET MVC، سایر علاقمندان نیز یک سری Ajax helper را بر اساس افزونههای jQuery تدارک دیدهاند که از آدرس زیر قابل دریافت هستند:
http://awesome.codeplex.com/
افزودن فرمها به کمک jQuery.Ajax و فعال سازی اعتبار سنجی سمت کلاینت
در ASP.NET MVC چون ViewState حذف شده است، امکان تزریق فرمهای جدید به صفحه یا به روز رسانی قسمتی از صفحه توسط jQuery Ajax به سهولت و بدون دریافت پیغام «viewstate is corrupted» در حین ارسال اطلاعات به سرور، میسر است.
در این حالت باید به یک نکته مهم نیز دقت داشت: «اعتبار سنجی سمت کلاینت دیگر کار نمیکند». علت اینجا است که در حین بارگذاری متداول یک صفحه، متد زیر به صورت خودکار فراخوانی میگردد:
$.validator.unobtrusive.parse("#{form-id}");
اما با به روز رسانی قسمتی از صفحه، دیگر اینچنین نخواهد بود و نیاز است این فراخوانی را دستی انجام دهیم. برای مثال:
$.ajax
({
url: "/{controller}/{action}/{id}",
type: "get",
success: function(data)
{
$.validator.unobtrusive.parse("#{form-id}");
}
});
//or
$.get('/{controller}/{action}/{id}', function (data) { $.validator.unobtrusive.parse("#{form-id}"); });
شبیه به همین مساله را حین استفاده از Ajax.BeginForm نیز باید مد نظر داشت:
@using (Ajax.BeginForm(
"Action1",
"Controller",
null,
new AjaxOptions {
OnSuccess = "onSuccess",
UpdateTargetId = "result"
},
null)
)
{
<input type="submit" value="Save" />
}
var onSuccess = function(result) {
// enable unobtrusive validation for the contents
// that was injected into the <div id="result"></div> node
$.validator.unobtrusive.parse("#result");
};
در این مثال در پارامتر UpdateTargetId، مجددا یک فرم رندر میشود. بنابراین اعتبار سنجی سمت کلاینت آن دیگر کار نخواهد کرد مگر اینکه با مقدار دهی خاصیت OnSuccess، مجددا متد unobtrusive.parse را فراخوانی کنیم.
- استفاده از T4MVC اجباری است. به هیچ عنوان نباید از رشتهها برای مشخص سازی نام کنترلرها یا اکشن متدها در قسمتهای مختلف برنامه استفاده شود.
- تا حد امکان از ViewBag ، ViewData و امثال آن استفاده نشده و به ازای هر View یک مدل متناظر (ViewModel) ایجاد شود.
- فایل پروژه برنامه توسط یک ادیتور متنی ویرایش شده و MvcBuildViews آن به True تنظیم شود.
- مدلهای متناظر با جداول بانک اطلاعاتی نباید مستقیما در Viewهای برنامه استفاده شوند.
- پوشه Models، از پروژه اصلی حذف شود. یک پروژه class library جدید به نام MyProjectName.Models برای نگهداری ViewModels ایجاد گردد.
- یک پروژه Class library دیگر به نام MyProjectName.DomainClasses برای نگهداری کلاسهای متناظر با جداول بانک اطلاعاتی ایجاد شود.
- از سیستم minification و bundling، برای یکی سازی اسکریپتها و CSSهای برنامه استفاده شود.
- قسمت custom errors فایل web.config برنامه به نحو صحیحی مقدار دهی شود.
- تمام فرمهای عمومی برنامه باید دارای AntiForgeryToken باشند.
- تمام فرمهای عمومی برنامه باید captcha داشته باشند.
- پوشههای Content و Scripts از سیستم مسیریابی تعریف شده در Global.asax خارج شوند.
- MvcHandler.DisableMvcResponseHeader = true به Application_Start اضافه شود.
- اگر فقط از Razor به عنوان ViewEngine استفاده میشود، در Application_Start، باید سایر ViewEngineهای مورد استفاده، حذف شوند.
- فیلتر پیش فرض مدیریت خطاها حذف و بجای آن از ELMAH استفاده شود.
- در web.config، مقادیر executionTimeout و maxRequestLength مرتبط با httpRuntime تنظیم شوند. همچنین enableVersionHeader آن نیز خاموش گردد.
- استفاده از سشنها کلا باید حذف شود. ماژول توکار آن از قسمت httpModules حذف گردد تا پردازش موازی صفحات فعال گردد. (سشن مربوط است به دوران ASP کلاسیک دهه نود و هیچ نیازی به استفاده از آن در MVC نیست)
- در هیچ کنترلری نباید جزئیات پیاده سازی متدی مشاهده شود. تمام پیاده سازیها باید به لایه سرویسهای مختلف برنامه منتقل و از طریق تزریق وابستگیها در دسترس باشند.
- اگر نیاز به مشخص سازی آدرسی در سایت است (خصوصا در اسکریپتها) باید از Url.Action استفاده شود و نه رشتهها.
- بهتر است بومی سازی برنامه از روز اول آن درنظر گرفته شده و تمام عبارات مورد استفاده در فایلهای Resource درج شوند.
- برای مدیریت سادهتر بستههای مورد استفاده (وابستگیهای برنامه) بهتر است از NuGet استفاده شود.
- از یک ماژول HTTP compression مستقل و با کیفیت استفاده شود (برای سازگاری بهتر با نگارشهای مختلف IIS).
- برای معرفی HTTP modules و سادگی تعریف و فعال سازی آنها در انواع و اقسام IISها بهتر است از کتابخانه WebActivator استفاده شود.
- امکان دوبار کلیک کردن بر روی تمام دکمهها نباید وجود داشته باشد.
- از هشهای ترکیبی استفاده شود. مستقیما از MD5 یا SHA1 استفاده نشود.
- با اسکریپتهای anti IE6,7، این مرورگرها به رحمت ایزدی واصل شوند.
- اگر کاربری JavaScript را در مرورگر خود غیرفعال کرد، نباید بتواند از سایت استفاده کند.
- کلیه تغییرات تنظیمات و محتوای مهم سایت باید برای مدیر سایت بلافاصله ایمیل شوند.
- یک سری کارهای متداول مانند تهیه فایلهای favicon.ico، apple-touch-icon-XxY.png، crossdomain.xml، robots.txt و sitemap.xml (ترجیحا پویا) فراموش نشود.
- در web.config و در زمان ارائه، compilation debug=false تنظیم شود.
- در تمام قسمتهایی که AlllowHtml فعال شده باید از پاکسازی Html دریافتی جهت مقابله با XSS مطمئن شد.
- جهت سهولت طراحی table less از یک فریم ورک CSS ایی استفاده شود.
- در تمام قسمتهایی که فایلی آپلود میشود باید بررسی شود فایلهای نا امن (فایلهای اجرایی ASP.NET) قابل آپلود نباشند.
- حین کار با بانکهای اطلاعاتی یا از ORM استفاده شود و یا از کوئریهای پارامتری.
- هر برنامه ASP.NET باید داری یک Application pool مجزا به همراه تنظیمات حافظه مشخصی باشد.
- تمام صفحات باید عنوان داشته باشند. به همین منظور مقدار دهی پیش فرض آن در فایل ViewStart صورت گیرد.
- در صفحه لاگین سایت، autocomplete خاموش شود.
- تمام deleteهای برنامه باید به HttpPost محدود شوند. تمام گزارشات و نمایش اطلاعات غیرعمومی برنامه به HttpGet محدود شوند.
- تعداد رفت و برگشتهای به بانک اطلاعاتی در یک صفحه توسط پروفایلرها بررسی شده و اطلاعات عمومی پرمصرف کش شوند.
- در هیچکدام از کلاسهای ASP.NET MVC نباید از HttpContext مستقیما استفاده شود. کلاس پایه جدید آن باید مورد استفاده قرار گیرد یا از Action Result صحیحی استفاده گردد.
- کش کردن فایلهای استاتیک درنظر گرفته شود.
- تمام درخواستهای jQuery Ajax باید بررسی شوند. آیا واقعا مرتبط هستند به سایت جاری و آیا واقعا Ajax ایی هستند.
یک نکته:
امکان تهیه قالبهای سفارشی VS.NET و لحاظ موارد فوق در آن جهت استفادههای بعدی نیز وجود دارد:
Create Reusable Project And Item Templates For Your Development Team
Write Templates for Visual Studio 2010
Building a Custom Project Wizard in Visual Studio .NET