اشتراک‌ها
آموزش Delegate
می‌توان گفت که Delegate یکی از ویژگی‌های جذاب زبان برنامه نویسی سی‌شارپ بوده که امکانات بالقوه فوق‌العاده‌ای را به این زبان می‌افزاید.   
آموزش Delegate
مطالب
توسعه برنامه های Cross Platform با Xamarin Forms & Bit Framework - قسمت ششم
در پنج قسمت گذشته به نحوه نصب و راه اندازی Xamarin برای توسعه هر سه پلتفرم Android / iOS / Windows پرداختیم. حال با داشتن محیطی آماده برای کد زدن و تست، می‌توانیم به آموزش کد نویسی بپردازیم.
ابتدا بد نیست نگاهی به ساختار XamApp بیاندازیم. این پروژه‌ی مثال، خود از چهار قسمت تشکیل شده‌است:
XamApp | XamApp.Android | XamApp.UWP | XamApp.iOS
در خود XamApp درصد زیادی (گاهی تا 95%) از کد پروژه پیاده سازی می‌شود که بین سه پلتفرم مشترک است و شامل ظاهر فرم‌ها و منطق برنامه می‌شود. در پاره‌ای از مواقع، لازم می‌شود که از امکانات هر پلتفرم استفاده کنیم و در این صورت به سراغ پروژه‌های Android - iOS - Windows می‌رویم. نه تنها امکانات هر پلتفرم را در همان زبان CSharp و Visual Studio می‌توانید استفاده کنید، بلکه Documentation مربوطه به زبان CSharp برای تک تک امکانات سیستم عامل‌ها وجود دارد و اصلا لازم نیست برای فراگیری نحوه کار AR Kit در iOS به سراغ مستندات Apple بروید و یا برای کار با Intent در Android سری به سایت گوگل بزنید!
برای پیاده سازی UI از XAML استفاده می‌کنیم. XAML خود XML است، به همراه کلی امکانات هیجان انگیز که سعی می‌کنیم بجای ارائه یک توضیح کلی، به مرور و با معرفی امکاناتش، شما را با ماهیت خود XAML آشنا کنیم.
در XAML، همه چیز Tag هست (<>). برای مثال برای ایجاد یک دکمه داریم:
<Button Text="This is a test button" />
در XAML هر تگ، معادل یک کلاس CSharp ای است. در نتیجه ما کلاس Button هم داریم. همچنین Text در مثال بالا به این معنا است که کلاس Button دارای یک Property با نام Text است.

عناصر UI خود به سه دسته تقسیم می‌شوند. Page - Layout - Control
Page‌ها که شامل Content Page - MasterDetail Page - Tabbed Page و ... می‌شوند، صفحات برنامه را تشکیل می‌دهند. Content Page، ساده‌ترین نوع صفحه‌است که کل صفحه نمایش را پر می‌کند و همان طور که از اسمش بر می‌آید، Content ای برای نمایش دارد.

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


ایجاد صورت حساب با استفاده از InvoiceBuilder

InvoiceBuilder به شما کمک می‌کند تا یک صورت حساب را جهت پرداخت آماده کنید.
مثال زیر را در نظر بگیرید:
var result = _onlinePayment.Request(Gateways.Mellat, 123, 25000, "http://www.mywebsite.com/foo/bar/");
همانطور که مشخص است، در این مثال یک صورت حساب با شماره رهگیری ۱۲۳ به مبلغ ۲۵۰۰۰ با یک آدرس بازگشتی به درگاه بانک ملت درخواست داده می‌شود.

اما همین دستور را با کمک InvoiceBuilder نیز می‌توان ایجاد کرد.
نمونه مثال بالا با استفاده از InvoiceBuilder
var result = _onlinePayment.Request(invoice =>
{
    invoice
          .SetTrackingNumber(123)
          .SetAmount(25000)
          .SetCallbackUrl("http://www.mywebsite.com/foo/bar/")
          .UseGateway(Gateways.Mellat);
});

مسلما استفاده از روش اول ساده‌تر به نظر می‌رسد. اما InvoiceBuilder امکانات دیگری را نیز به شما جهت ایجاد یک صورت حساب می‌دهد. در واقع InvoiceBuilder ایجاد یک صورت حساب را به هر روشی که در نظر داشته باشید برای شما میسر می‌کند و همچنین قابل توسعه در اپلیکیشن شما توسط خودتان است.

در زیر نمونه‌هایی از کارایی آن را بررسی می‌کنیم.

  • تولید اتوماتیک کد رهگیری به صورت افزایشی
  • تولید اتوماتیک کد رهگیری به صورت تصادفی
  • ایجاد یک تولید کننده کد رهگیری توسط شما
  • صورت حساب سفارشی برای امکانات اختصاصی درگاه‌های بانکی

تولید اتوماتیک کد رهگیری به صورت افزایشی

در این روش، کد رهگیری (TrackingNumber) که مورد نیاز درگاه‌های بانکی است، به صورت اتوماتیک در هنگام ایجاد درخواست پرداخت، توسط پَرباد تولید می‌شود.
var result = _onlinePayment.Request(invoice =>
{
    invoice
          .UseAutoIncrementTrackingNumber()
          .SetAmount(25000)
          .SetCallbackUrl("http://www.mywebsite.com/foo/bar/")
          .UseGateway(Gateways.Mellat);
});
کد تولید شده، به صورت افزایشی است. در واقع در هر درخواست پرداخت جدید، یک کد رهگیری تولید می‌شود که یک واحد از کد تولید شده‌ی قبلی بیشتر است. 

شما همچنین می‌توانید مقدار اولیه این عدد را جهت شروع تولید، در پارامتر متد تعیین کنید. این مقدار همچنین در قسمت تنظیمات پَرباد نیز توسط متد ConfigureAutoTrackingNumber قابل تنظیم است.

تولید اتوماتیک کد رهگیری به صورت تصادفی

var result = _onlinePayment.Request(invoice =>
{
    invoice
          .UseAutoRandomTrackingNumber()
          .SetAmount(25000)
          .SetCallbackUrl("http://www.mywebsite.com/foo/bar/")
          .UseGateway(Gateways.Mellat);
});
در این روش کد رهگیری، به صورت تصادفی در محدوده Int64 توسط پَرباد تولید خواهد شد. کد‌های تولید شده در این روش تقریبا ٪۹۹.۹ غیر تکراری هستند. اما اگر به تمیز بودن کدهای تولید شده اهمیت می‌دهید، بهتر است از روش AutoIncrement که بالاتر توضیح داده شد، استفاده کنید.

ایجاد یک تولید کننده کد رهگیری توسط شما

اگر بنا به دلایلی قصد دارید خودتان نیز یک منبع تولید کد رهگیری را ایجاد کنید، می‌توانید به روش زیر عمل کنید.
public class MyTrackingNumberProvider : ITrackingNumberProvider
{
    public Task<long> ProvideAsync(CancellationToken cancellationToken = new CancellationToken())
    {
        // تولید و برگشت کد در اینجا
    }
}

نکته ۱: شما همچنین می‌توانید در منبع خود، از تزریق وابستگی‌ها نیز استفاده کنید. بدیهی است سرویسی را که تزریق می‌کنید، باید از قبل توسط سیستم تزریق وابستگی‌های اپلیکیشن شما، ثبت شده باشد.
نکته ۲؛ شما همچنین می‌توانید بدون ایجاد هیچ منبعی، به راحتی از متد SetTrackingNumber در InvoiceBuilder (که بالاتر توضیح داده شده) استفاده کنید.

سپس در هنگام ایجاد درخواست پرداخت به روش زیر از منبع خود استفاده کنید:
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");
        });


در مثال بالا، درگاه مجازی توسط آدرس داده شده در دسترس خواهد بود. توجه داشته باشید که این آدرس حتما باید با یک ( / ) آغاز شده باشد.
سپس درگاه مجازی را در اپلیکیشن خود ثبت می‌کنید:
ASP.NET CORE (Startup.cs)
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseMvc(routes =>
    {
        routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
    });

    // ثبت درگاه مجازی
    app.UseParbadVirtualGateway();
}

ASP.NET WebForms, ASP.NET MVC (Startup.cs)
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/");

و در نهایت به درگاه مجازی هدایت خواهید شد:

نمونه پروژه‌های کامل را در انتهای مقاله می‌توانید مشاهده کنید.

استفاده از پروکسی

با توجه به تغییرات اخیر در بانکداری کشور، احتمال آن وجود دارد که در آینده، بعضی از درگاه‌های بانکی فقط به IP‌های داخل کشور سرویس دهی کنند. اگر وب سایت شما بنا به دلایلی در سروری خارج از کشور میزبانی می‌شود، شما جهت استفاده از درگاه‌های بانکی، نیاز به یک سرور در داخل کشور دارید که نقش پروکسی را برای شما بازی کند. پَرباد این امکان را برای شما محیا کرده و کافیست اطلاعات پروکسی سرور خود را به شکل زیر برای درگاه بانکی مورد نظر ثبت کنید.
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");
        });
در مثال بالا، درگاه بانک ملت (صرفا جهت مثال) با یک پروکسی تنظیم شده است. برای سایر درگاه‌های بانکی، فرمت تنظیمات، کاملا مشابه مثال بالا است.

توکن پرداخت

پَرباد جهت شناسایی و تبادل اطلاعات پرداخت با خارج از سیستم خود و بانک‌ها، از یک توکن به ازاء هر پرداخت استفاده می‌کند. به عبارت دیگر، به ازاء هر درخواست پرداخت یک توکن تولید می‌شود. به این صورت، درخواست‌های پرداخت، غیر قابل دستکاری و غیر قابل حدس زدن توسط کاربران می‌شود.
نکته: پَرباد از یک تولید کننده پیش فرض توکن استفاده می‌کند و شما نیازی به انجام هیچگونه تنظیماتی ندارید. تولید کننده پیش فرض، از یک GUID در Query String استفاده می‌کند.
اگر قصد دارید روش مورد نظر خود را برای تولید توکن جهت شناسایی یک پرداخت پیاده‌سازی کنید، می‌توانید به روش زیر عمل کنید:
ابتدا تولید کننده توکن را تعریف کنید.
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));

ServiceLifetime، تایین کننده طول عمر سرویس شما است.
به این صورت پَرباد، شناسایی و ردیابی یک صورت حساب را با استفاده از تولید کننده توکن شما انجام خواهد داد.


تزریق وابستگی

همانطور که قبلا در مقاله آموزش تنظیمات نیز گفته شد، پَرباد به صورت توکار، از تزریق وابستگی استاندارد مایکروسافت استفاده می‌کند. بنابراین اگر اپلیکیشن شما نیز از تزریق وابستگی مشابهی استفاده می‌کند، نیازی به خواندن و یاد گرفتن این بخش ندارید و به راحتی می‌توانید از اینترفیس IOnlinePayment در هر کجا که نیاز داشتید جهت عملیات پرداخت استفاده کنید.
اما در صورتیکه در اپلیکیشن خود از تزریق وابستگی دیگری ( مانند Autofac ) استفاده می‌کنید، باید این دو سیستم را با یکدیگر هماهنگ کنید. خوشبختانه تمام کتابخانه‌های معروف تزریق وابستگی ( مانند Autofac )  از قبل این کار را برای شما محیا کرده‌اند و شما فقط نیاز به افزودن چند خط کد به اپلیکیشن فعلی خود را دارید.
جهت فهم بهتر و آموزش عملی، یک اپلیکیشن کامل ASP.NET MVC برای شما تهیه شده که از Autofac جهت تزریق وابستگی استفاده می‌کند. در این پروژه خواهید دید چگونه به راحتی پَرباد و Autofac را با یکدیگر هماهنگ کرده و هچنین اینترفیس IOnlinePayment را درون کنترلر تزریق می‌کنیم.
لینک پروژه‌ها در انتهای همین مقاله قابل مشاهده هستند.


Logging
لاگ کردن در پَرباد توسط سیستم استاندارد مایکروسافت انجام می‌شود. این بدان معنی است که شما امکان استفاده از کتابخانه‌های Logging بسیار زیادی را دارید. نحوه استفاده و تنظیم کتابخانه‌های معروف Logging در وب سایت آنها آورده شده و به راحتی می‌توانید آنها را با لاگ مایکروسافت تطابق دهید.

نمونه پروژه‌ها
مقاله‌های مرتبط
نظرات مطالب
MVVM و فراخوانی متدهای اشیاء View از طریق ViewModel
سلام.
ما در تولید محتوای فنی (در زمینه کاری خودمون و به زبان فارسی) به شکلی صحیح، مولفین انگشت شماری داریم. به نظر من برخی از مهمترین دلائل این مساله عبارت است از:

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 هزارتومان پرداخت می کرد...
مطالب
خواندنی‌های 27 فروردین

  • اولین محصول نگارش 2010 مایکروسافت برای دریافت، exchange server 2010 beta (میل سرور)
مطابق سایت رسمی فوق اینطور به نظر میرسه که مایکروسافت قصد جدا سازی برنامه‌ها و مفهوم Office Web applications را از SharePoint دارد (هر چند مانند سابق توانایی یکپارچگی بی‌نظیری بین آفیس و شپرپوینت وجود خواهد داشت)
سایر اولین سری محصولات 2010 ، شامل Microsoft Office 2010 ، Microsoft Visio 2010 و Microsoft Project 2010 خواهند بود.
  • لیستی از 70+145 برگه مرجعه (+ و +)
  • مجموعه انتشارات مایکروسافت 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 را فراخوانی کنیم.


مطالب
چک لیست تهیه یک برنامه ASP.NET MVC
خلاصه نکاتی که من در تهیه یک برنامه ASP.NET MVC رعایت می‌کنم:

- استفاده از 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