نظرات مطالب
PersianDatePicker یک DatePicker شمسی به زبان JavaScript که از تاریخ سرور استفاده می‌کند
شروع کنید به مطالعه‌ی مباحث jQuery در سایت: «آموزش (jQuery) جی کوئری 1#». در همان صفحه از متد val برای دریافت مقدار یک textbox قرارگرفته شده در صفحه (در سمت کاربر) می‌توان استفاده کرد.
پرسش‌ها
HttpContext در BlazorSSR

سلام

مشابه سایت جاری از یک CascadingValue بنام ApplicationState در برنامه استفاده کرده ام. در این ApplicationState اعضایی وجود دارند مانند

 public CurrentUserModel? CurrentUser { set; get; }
 public string? UserName { get; set; } 
[CascadingParameter]
 public HttpContext HttpContext { set; get; } 

چنانچه فایل App برنامه بصورت زیر باشد.

<head>
      <HeadOutlet  />  
</head>
<body>
    <Routes  />
</body>

</html>

HttpContext نال نیست ولی اعضای دیگر مانند CurrentUser , UserName در سایر صفحات نال نشان میدهد. نمونه عکس زیر

پس از تغییر HeadOutlet و Routes فایل App به InteractiveServer اینبار برعکس میشود و HttpContext نال میشود و اعضای دیگر ApplicationState مقدار دارند

<body>
    <Routes @rendermode="RenderModeForPage" />
    <script src="_framework/blazor.web.js"></script>
</body>

</html>

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? RenderModeForPage => HttpContext.Request.Path.StartsWithSegments("/Account")
        ? null
        : InteractiveServer;
}

مشابه عکس زیر

راه حل نال نشدن همه اعضاء در هردو صورت InteractiveServer و یا غیر InteractiveServer چیست؟

با تزریق

[Inject] IHttpContextAccessor HttpContextAccessor{ get; set; }

در ApplicationState و مقدار دهی HttpContext مشکل حل میشود ولی شما در سایت از این روش استفاده نکرده اید

 protected override async Task OnInitializedAsync()
 {
     this.HttpContext = HttpContextAccessor.HttpContext;
     CurrentUser = new CurrentUserModel
     {
         IsAdmin = true
     };

 }
مطالب
امکان اعتبارسنجی با تاخیر در ASP.NET 4.5
در نگارش‌های قبلی ASP.NET Web forms اگر نیاز به ارسال محتوای HTML ایی وجود داشت، می‌بایستی کل سیستم اعتبارسنجی حداقل یک صفحه را غیرفعال کرد. برای مثال:
 <%@ Page Language="C#" ValidateRequest="false" %>
 این نقیصه‌ی همه یا هیچ، در ASP.NET MVC وجود ندارد و می‌توان به ازای یک خاصیت خاص، اعتبارسنجی پیش فرض را با اعمال ویژگی AllowHtml موقتا غیرفعال کرد؛ اما مابقی فیلدها و خاصیت‌های فرم همچنان تحت نظر سیستم اعتبارسنجی‌های ورودی ASP.NET قرار خواهند داشت و به این ترتیب امکان ورود اطلاعات خطرناک، خصوصا از لحاظ مباحث XSS، حداقل در آن فیلدها وجود نخواهد داشت.
در ASP.NET 4.5 مفهوم جدیدی به نام Deferred validation معرفی شده‌است تا رفتار Web forms را نیز در برابر ورودی‌های ارسال شده همانند ASP.NET MVC کند. به این معنا که اگر جهت دسترسی به مقدار کوئری استرینگ lastName همانند قبل عمل کنید:
 Request["lastName"]
و کاربر ورودی خطرناکی را وارد کرده باشد، همچنان استثنای A potentially dangerous request.form value was detected صادر می‌شود.
اما اگر در ASP.NET 4.5، کوئری استرینگ را به نحو ذیل دریافت کنید:
 Request.Unvalidated.QueryString["lastName"]
به صورت خودکار سیستم اعتبارسنجی غیرفعال شده و امکان دسترسی به محتوای اصلی کوئری استرینگ lastName را خواهید داشت. به این ترتیب دیگر نیازی نخواهید داشت تا اعتبارسنجی کل صفحه را برای دسترسی به یک مقدار خاص غیرفعال نمائید.
برای دسترسی به مقادیر اعتبارسنجی نشده فیلدهای یک فرم ارسالی نیز می‌توان به صورت ذیل عمل کرد:
 Request.Unvalidated.Form[txtData1.UniqueID]
کلاس Request.Unvalidated شامل خاصیت‌های Cookies، Files، Headers و امثال آن نیز می‌باشد.
در اینجا اگر دقت کرده باشید از UniqueID بجای Id استفاده شده‌است؛ از این جهت که مجموعه Form، حاوی Idهای واقعی دریافت شده از کاربر مانند ctl00$MainContent$MessageText می‌باشد.

روش دوم، استفاده از خاصیت جدید ValidateRequestMode یک کنترل سمت سرور است و در اینجا نیز می‌توان صرفا اعتبارسنجی یک کنترل را بجای کل صفحه، غیرفعال کرد:
 <asp:TextBox ID="txtASPNet" ValidateRequestMode="Disabled" runat="server" />
تنظیم خاصیت ذکر شده برای کنترل‌های سمت سرور ضروری است. از این جهت که در حین تشکیل ViewState از محتوای این کنترل‌ها نیز استفاده می‌شود. اینجا است که اگر ValidateRequestMode غیرفعال نشده باشد، باز همان خطای ورودی خطرناک را دریافت خواهید کرد.

البته برای فعال سازی اعتبارسنجی با تاخیر نیاز است اصلاح ذیل را نیز به web.config برنامه اعمال کنید (مقدار پیش فرض آن 4 است):
 <httpRuntime targetFramework="4.5" requestValidationMode="4.5" />
مطالب
آشنایی و استفاده از WCF Data Services در Visualstudio 2012
مقدمه:

WCF Data Services جزئی از NET Framework است که امکان ایجاد سرویس دهنده‌های با قرارداد OData را به روی وب یا Intranet با استفاده از REST مهیا می‌سازد. OData از داده هایی که با Url آدرس پذیر هستند استفاده می‌نماید. دسترسی و تغییر داده‌ها با استفاده از استاندارد HTTP و کلمات GET، PUT، POST و DELETE صورت می‌پذیرد. برای اینکه درک بهتری داشته باشید به یک مثال می‌پردازیم.

ایجاد یک برنامه سرویس دهنده WCF Data Service در 2012 VisualStudio
  1. یک ASP.NET Web Application با نام NorthwindService ایجاد نمایید و بر روی پروژه راست کلیک کنید و از منوی Add گزینه New Item را انتخاب نمایید  از پنجره باز شده از دسته Data گزینه ADO.NET Entity Data Model  را انتخاب و نام ان را Northwind بگذارید.
  2. از پنجره باز شده Generate from Databaseرا انتخاب و با انتخاب کانکشن از نوع Sql Server Compact 4  اتصال به فایل Northwind.sdf را انتخاب تا کلاس‌های لازم تولید شود.
  3. برای تولید data service بر روی پروژه راست کلیک کنید و از منوی Add گزینه New Item را انتخاب نمایید از پنجره باز شده گزینه  WCF Data Service را انتخاب و نام آن را Northwind.svc بگذارید. کد زیر خودکار تولید می‌شود
     public class Northwind : DataService< /* TODO: put your data source class name here */ >
        {
            // This method is called only once to initialize service-wide policies.
            public static void InitializeService(DataServiceConfiguration config)
            {
                // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
                // Examples:
                // config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
                // config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
                config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
            }
        }
  4. برای دسترسی به موجودیت‌های Northwind بجای عبارت put your data source نام مدل را تایپ کنید
    public class Northwind : DataService<NorthwindEntities>
  5. برای فعال کردن دسترسی به منابع data source متغیر config کلاس DataServiceConfiguration را بصورت زیر تنظیم نمایید. تابع SetEntitySetAccessRule با گرفتن نام موجودیت و نحوه دسترسی امکان استفاده از این موجودیت را با استفاده از WCF Data Service فزاهم می‌نمایید. مثلا در زیر امکان دسترسی به موجودیت Orders را با امکان خواندن همه، نوشتن ادقامی و جایگزین فراهم نموده است.
    config.SetEntitySetAccessRule("Orders", EntitySetRights.AllRead 
         | EntitySetRights.WriteMerge 
         | EntitySetRights.WriteReplace );
    config.SetEntitySetAccessRule("Customers", EntitySetRights.AllRead);
  6. اگر بخواهیم امکان خواندن همه موجودیت‌ها را فراهم کنیم از کد زیر می‌توانیم استفاده نمایید که * به معنای همه موجودیت‌های data model می‌باشد
    config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);

دسترسی به WCF Data Service بوسیله مرورگر وب
برای دسترسی به وب سرویس برنامه را اجرا نمایید تا آدرس http://localhost:8358/Northwind.svc مشخصات وب سرویس را نمایش دهد
<service xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom" xml:base="http://localhost:8358/Northwind.svc/">
<workspace>
<atom:title>Default</atom:title>
<collection href="Categories">
<atom:title>Categories</atom:title>
</collection>
<collection href="Customers">
<atom:title>Customers</atom:title>
</collection>
<collection href="Employees">
<atom:title>Employees</atom:title>
</collection>
<collection href="Order_Details">
<atom:title>Order_Details</atom:title>
</collection>
<collection href="Orders">
<atom:title>Orders</atom:title>
</collection>
<collection href="Products">
<atom:title>Products</atom:title>
</collection>
<collection href="Shippers">
<atom:title>Shippers</atom:title>
</collection>
<collection href="Suppliers">
<atom:title>Suppliers</atom:title>
</collection>
</workspace>
</service>
 حال اگر آدرس را به http://localhost:8358/Northwind.svc/Products وارد نمایید لیست کالا‌ها بصورت Atom xml قابل دسترس می‌باشد.
ایجاد یک برنامه گیرنده WCF Data Service در Visual Studio 2012
  1. بر روی Solution پروژه جاری راست کلیک و از منوی Add گزینه New Project را انتخاب و یک پروژه از نوع WPF Application با نام NorthwindClient ایجاد نمایید.
  2. در پنجره MainWindow مانند کد زیر از یک Combobox و DataGrid برای نمایش اطلاعات استفاده نمایید
        <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Northwind Orders" Height="335" Width="425" 
            Name="OrdersWindow" Loaded="Window1_Loaded">
        <Grid Name="orderItemsGrid">
            <ComboBox DisplayMemberPath="Order_ID" ItemsSource="{Binding}"
                      IsSynchronizedWithCurrentItem="true" 
                      Height="23" Margin="92,12,198,0" Name="comboBoxOrder" VerticalAlignment="Top"/>
            <DataGrid ItemsSource="{Binding Path=Order_Details}"  
                      CanUserAddRows="False" CanUserDeleteRows="False"  
                      Name="orderItemsDataGrid" Margin="34,46,34,50"
                      AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTextColumn  Header="Product" Binding="{Binding Product_ID, Mode=OneWay}" />
                    <DataGridTextColumn  Header="Quantity" Binding="{Binding Quantity, Mode=TwoWay}" />
                    <DataGridTextColumn  Header="Price" Binding="{Binding UnitPrice, Mode=TwoWay}" />
                    <DataGridTextColumn  Header="Discount" Binding="{Binding Discount, Mode=TwoWay}" />                
                </DataGrid.Columns>     
            </DataGrid>
            <Label Height="28" Margin="34,12,0,0" Name="orderLabel" VerticalAlignment="Top" 
                   HorizontalAlignment="Left" Width="65">Order:</Label>
            <StackPanel Name="Buttons" Orientation="Horizontal" HorizontalAlignment="Right" 
                        Height="40" Margin="0,257,22,0">
                <Button Height="23" HorizontalAlignment="Right" Margin="0,0,12,12" 
                    Name="buttonSave" VerticalAlignment="Bottom" Width="75" 
                        Click="buttonSaveChanges_Click">Save Changes
                </Button>
                <Button Height="23" Margin="0,0,12,12" 
                    Name="buttonClose" VerticalAlignment="Bottom" Width="75" 
                        Click="buttonClose_Click">Close</Button>
            </StackPanel>
        </Grid>
    </Window>

  3. برای ارجاع به wcf data service بر روی پروژه راست کلیک و گزینه Add Service Reference را انتخاب نمایید در پنجره باز شده گزینه Discover را انتخاب تا سرویس را یافته و نام Namespase را Northwind بگذارید.
  4. حال مانند کد زیر یک شی از مدل NorthwindEntities با آدرس وب سرویس ایجاد نموده ایم و نتیحه کوئری با استفاده از کلاس DataServiceCollection به DataContext گرید انتصاب داده ایم که البته پیش فرض آن آشنایی با DataBinding در WPF است.
            private NorthwindEntities context;
            private string customerId = "ALFKI";
            private Uri svcUri = new Uri("http://localhost:8358/Northwind.svc");
    
            private void Window1_Loaded(object sender, RoutedEventArgs e)
            {
                try
                {
                    context = new NorthwindEntities(svcUri);
                    var ordersQuery = from o in context.Orders.Expand("Order_Details")
                                      where o.Customers.Customer_ID == customerId
                                      select o;
                    DataServiceCollection<Orders> customerOrders = new DataServiceCollection<Orders>(ordersQuery);
                    this.orderItemsGrid.DataContext = customerOrders;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
    
  5. با صدا زدن تابع SaveChanges مدل می‌توانید تغییرات را در پایگاه داده ذخیره نمایید.
    private void buttonSaveChanges_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            context.SaveChanges();
        }
        catch (DataServiceRequestException ex)
        {
            MessageBox.Show(ex.ToString());
    
        }
    }

  1. برنامه را اجرا نمایید تا خروجی کار را مشاهده نمایید. مقادیر Quantity را تغییر دهید و دکمه Save Changes را انتخاب تا تغییرات دخیره شود.
در اینجا در یک برنامه ویندوزی استفاده از WCF Data Service را تست نمودیم اما براحتی به همین شیوه در یک برنامه وب نیز قابل استفاده است.  
مطالب
ASP.NET MVC #3

تهیه پیش‌نیازهای شروع به کار با ASP.NET MVC

در زمان نگارش این مطلب، نگارش نهایی ASP.NET MVC 3 در دسترس است و همچنین نگارش بتای 4 آن نیز قابل دریافت و نصب می‌باشد. بنابراین فعلا اساس را بر مبنای نگارشی قرار خواهیم داد که در محیط کاری قابل استفاده باشد.
ASP.NET MVC 3 پس از ارائه Visual Studio 2010، منتشر شد و VS.NET به صورت پیش فرض به همراه ASP.NET MVC 2 است. ساده‌ترین روش نصب ASP.NET MVC 3 بر روی VS 2010 استفاده از برنامه رایگانی است به نام Web Platform Installer. این برنامه را از این آدرس می‌توان دریافت کرد: http://microsoft.com/web/downloads
پس از دریافت آن حداقل دو راه برای نصب ASP.NET MVC 3 وجود دارد. یا گزینه‌ی نصب ASP.NET MVC 3 Tools Update را انتخاب کنید و یا سرویس پک یک VS 2010 را از طریق این برنامه یا جداگانه (بسته کامل و مستقل) دریافت و نصب نمائید. VS 2010 SP1 نیز به همراه ASP.NET MVC 3 است؛ همچنین IIS Express را که نسخه ساده شده IIS 7.5 مخصوص توسعه دهنده‌ها است، می‌توان با این نگارش یکپارچه کرد.


بنابراین به صورت خلاصه بهترین کار این است که سرویس پک یک VS 2010 را یکبار نصب نمائید. اگر این نصب از طریق برنامه Web Platform Installer باشد، به صورت خودکار IIS Express را هم انتخاب و نصب خواهد کرد. اگر فقط SP1 را به صورت مستقل دریافت کرده‌اید، حاوی IIS Express نیست و باید جداگانه آن‌را دریافت و نصب نمائید (^). البته نصب IIS Express در اینجا یک گزینه اختیاری است و الزامی نیست.



مروری بر ساختار یک پروژه ASP.NET MVC

پس از نصب پیش نیازها، امکان انتخاب یک پروژه وب ASP.NET MVC 3 در VS 2010 میسر خواهد شد:


در اینجا گزینه‌ی ASP.NET MVC 3 Web Application را انتخاب می‌کنیم. در صفحه بعدی که ظاهر می‌شود:


حالت Internet Application به همراه یک سری مدل و کنترلر از پیش نوشته شده جهت مدیریت ورود به سایت و ثبت نام در سایت است و حالت Empty تنها به همراه ساختار پیش فرض پوشه‌های یک پروژه ASP.NET MVC است.
فعلا جهت توضیحات اولیه بیشتر، گزینه‌ی Internet Application و نوع View Engine را هم ASPX انتخاب می‌کنیم. کار View Engine، رندر یک View به شکل HTML و ارائه نهایی اطلاعات آن به کاربر است. این نوع‌های متفاوت هم فقط در Syntax تفاوت دارند (به آن templating language هم گفته می‌شود). نوع ASPX همان Syntax متداول قدیمی ASP.NET را تداعی می‌کند و نوع Razor به صورت اختصاصی برای ASP.NET MVC تهیه شده است.
باید در نظر داشت که گزینه مرجح از نگارش 3 به بعد، Razor است (البته این هم سلیقه‌ای است. اگر هیچکدام از این دو را هم نخواهید استفاده کنید مشکلی نیست! می‌شود کلا آن را عوض کرد). هدفم هم از انتخاب ASPX نمایش یک سری ریزه کاری است که شاید برای برنامه نویس‌های ASP.NET Web forms جالب باشد. این موارد را در حالت انتخاب Razor به این وضوح مشاهده نخواهید کرد و محیط خیلی ساده شده است.


همانطور که ملاحظه می‌کنید این فریم ورک یک سری پوشه پیش فرض را توصیه می‌کند. بدیهی است که ضرورتی ندارد تا پوشه Models یا پوشه Controllers حتما در همین پروژه قرار داشته باشند؛ چون زمانیکه پروژه کامپایل شد، محل این پوشه بندی‌ها آنچنان اهمیتی ندارد.
نکته جالب در این تصویر، فایل Site.Master است. بله، این فایل شبیه به همان فایل master page موجود در ASP.NET Web form است که قالب کلی سایت را به همراه داشته و سایر صفحات، قالب خود را از آن به ارث می‌برند. حتی تگ runat=server هم به وضوح در این فایل، در چندین جای آن قابل مشاهده است. تنها تفاوت آن نداشتن فایل code behind است. asp:ContentPlaceHolder نیز در آن تعریف شده است. خلاصه این محیط جدید به معنای دور ریختن تمام آنچیزی که در Web forms وجود دارد نیست. برای نمونه اگر فایل ChangePassword.aspx موجود در پوشه Account را باز کنید، باز هم همان asp:Content معروف به همراه تگ runat=server قابل مشاهده است. برای مثال این محتوای صفحه Error.aspx پیش فرض آن است:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<System.Web.Mvc.HandleErrorInfo>" %>

<asp:Content ID="errorTitle" ContentPlaceHolderID="TitleContent" runat="server">
Error
</asp:Content>

<asp:Content ID="errorContent" ContentPlaceHolderID="MainContent" runat="server">
<h2>
Sorry, an error occurred while processing your request.
</h2>
</asp:Content>

اگر از قسمت Inherits آن صرفنظر کنیم، «هیچ» تفاوتی با ASP.NET Web forms ندارد؛ علت هم به این بر می‌گردد که موتوری که Web forms و MVC از آن استفاده می‌کنند، یکی است. هر دو بر فراز موتور ASP.NET معنا پیدا خواهند کرد.


قرار دادهای پوشه‌های پیش فرض یک پروژه ASP.NET MVC

  • پوشه Controllers حاوی کلاس‌های کنترلری است که درخواست‌های رسیده را مدیریت می‌کنند.
  • پوشه Models حاوی کلاس‌هایی است که اشیاء تجاری و همچنین کار با اطلاعات را تعریف و مدیریت می‌کنند.
  • در پوشه Views، فایل‌های قالب‌های رابط کاربری که مسئول ارائه خروجی به کاربر هستند قرار می‌گیرند. همچنین مطابق قرارداد دیگری، اگر نام کنترلر ما مثلا ProductController باشد (با توجه به اینکه نام کلاس آن هم مطابق قرارداد، مختوم به کلمه Controller است)، فایل‌های Viewهای مرتبط با آن در پوشه Views/Product قرار خواهند گرفت.
  • در پوشه Scripts،‌ فایل‌های جاوا اسکریپت مورد استفاده در سایت قرار خواهند گرفت.
  • پوشه Content محل قرارگیری فایل‌های CSS و تصاویر است.
  • پوشه App_Data جایی است که فایل‌هایی با قابلیت read/write در آن قرار می‌گیرند (و باید دقت داشت که فقط همینجا هم باید قرار گیرند و گرنه این نوشتن‌ها در مکان‌های متفرقه، ممکن است سبب ری استارت شدن برنامه شوند:(^)).

نظرات مطالب
اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 بدون استفاده از سیستم Identity
سلام؛ چطور می‌تونیم بعد از این که login با موفقیت انجام شد یک action رو صدا بزنیم که مثلا صفحه home رو نشون بده. در واقع بعد از اینکه token رو بعد از login بدست آوردم می‌خوام یه action رو با jwt toke صدا بزنم که بره اون صفحه رو load کنه. راهی مثل :window.location در javascript یا a href در html که بشه باهاش token رو فرستاد برای باز کردن action Authorize  شده. ممنون.
نظرات مطالب
قابلیت های کاربردی ASP.NET WebFroms - قسمت اول
وقتی از مستر پیج استفاده می‌کنیم این script manager  رو تو تگ ContentPlaceHolder هد باید اضافه کنیم؟ یا جای دیگه و بعد از استفاده کردن دیگه تو کل صفحات نیازی به فراخونی نیست؟ و در هر جایی می‌شه از فایلای jquery استفاده کرد؟
مطالب
آماده سازی Jasmine برای پروژه های Asp.Net MVC
با گسترش روز افزون برنامه‌های تحت وب، نیاز به یک سری ابزار برای تست و اطمینان از نحوه عملکرد صحیح کدهای نوشته شده احساس می‌شود. Jasmine یکی از این ابزار‌های قدرتمند برای تست کد‌های JavaScript است.
چندی پیش در سایت جاری چند مقاله خوب توسط یکی از دوستان درباره Qunit منتشر شد. Qunit یک ابزار قدرتمند و مناسب برای تست کد‌های جاوااسکریپت است و در اثبات صحت این گفته همین کافیست که بدانیم برای تست کد‌های نوشته شده در پروژه‌های متن بازی هم چون Backbone.Js و JQuery از این فریم ورک استفاده شده است. اما به احتمال قوی در ذهن شما این سوال مطرح شده است که خب! در صورت آشنایی با Qunit چه نیاز به یادگیری Jasmine یا خدای نکرده Mocha و FuncUnit است؟ هدف صرفا معرفی یک ابزار غیر برای تست کد است نه مقایسه و نتیجه گیری برای تعیین میزان برتری این ابزارها. اصولا مهم‌ترین دلیل برای انتخاب، علاوه بر امکانات و انعطاف پذیری، فاکتور راحتی و آسان بودن در هنگام استفاده است که به صورت مستقیم به شما و تیم توسعه نرم افزار بستگی دارد.

اما به عنوان توسعه دهنده نرم افزار که قرار است از این ابزار استفاده کنیم بهتر است با تفاوت‌ها و شباهت‌های مهم این دو فریم ورک آشنا باشیم:

»Jasmine یک فریم ورک تست کدهای جاوا اسکریپ بر مبنای Behavior-Driven Development است در حالی که Qunit بر مبنای Test-Driven Development است و همین مسئله مهم‌ترین تفاوت بین این دو فریم ورک می‌باشد.
»اگر قصد دارید که از Qunit نیز به روش BDD استفاده نمایید باید از ترکیب Pavlov به همراه Qunit استفاده کنید.
»Jasmine از مباحث مربوط به Spies و Mocking به خوبی پشتیبانی می‌کند ولی این امکان به صورت توکار در Qunit فراهم نیست. برای اینکه بتوانیم این مفاهیم را در Qunit پیاده سازی کنیم باید از فریم ورک‌های دیگر نظیر SinonJS به همراه Qunit استفاده کنیم.
»هر دو فریم ورک بالا به سادگی و راحتی کار معروف هستند 
»تمام موارد مربوط به الگوهای Matching در هر دو فریم ورک به خوبی تعبیه شده است
» هر دو فریم ورک بالا از مباحث مربوط به Asynchronous Testing  برای تست کد‌های Ajax ای به خوبی پشتیبانی می‌کنند.

بررسی چند مفهوم
قبل از شروع، بهتر است که با چند مفهوم کلی و در عین حال مهم این فریم ورک آشنا شویم
describe('JavaScript addition operator', function () {
 it('adds two numbers together', function () {
  expect(1 + 2).toEqual(3);
 });
});


در کد بالا یک نمونه از تست نوشته شده با استفاده از Jasmine را مشاهده می‌کنید. دستور describe  برای تعریف یک تابع تست مورد استفاده قرار می‌گیرد که دارای دو پارامتر ورودی است. ابتدا یک نام را به این تست اختصاص دهید(بهتر است که این عنوان به صورت یک جمله قابل فهم باشد). سپس یک تابع به عنوان بدنه تست نوشته می‌شود. به این تابع Spec گفته می‌شود.
در تابع it کد بالا شما می‌توانید کد‌های مربوط بدنه توابع تست خود را بنویسید. برای پیاده سازی Assert در توابع تست مفهوم expectation‌ها وجود دارد. در واقع expect برای بررسی مقادیر حقیقی با مقادیر مورد انتظار مورد استفاده قرار می‌گیرد و شامل مقادیر true یا false خواهد بود.
برای Setup و Teardown توابع تست خود باید از توابع beforeEach و afterEach که بدین منظور تعبیه شده اند استفاده کنید.
describe("A spec (with setup and tear-down)", function() {
  var foo;

  beforeEach(function() {
    foo = 0;
    foo += 1;
  });

  afterEach(function() {
    foo = 0;
  });

  it("is just a function, so it can contain any code", function() {
    expect(foo).toEqual(1);
  });

  it("can have more than one expectation", function() {
    expect(foo).toEqual(1);
    expect(true).toEqual(true);
  });
});
کاملا واضح است که در تابع beforeEach مجموعه دستورالعمل‌های مربوط به setup تست وجود دارد. سپس دو تابع it برای پیاده سازی عملیات Assertion نوشته شده است. در پایان هم دستورات تابع afterEach ایجاد می‌شوند.

اگر در کد تست خود قصد دارید که یک تابع describe یا it را غیر فعال کنید کافیست یک x به ابتدای آن‌ها اضافه کنید و دیگر نیاز به هیچ کار اضافه دیگری برای comment کردن کد نیست.
xdescribe("A spec", function() {
  var foo;

  beforeEach(function() {
    foo = 0;
    foo += 1;
  });

  xit("is just a function, so it can contain any code", function() {
    expect(foo).toEqual(1);
  });
});
توابع describe و it بالا در هنگام تست نادیده گرفته می‌شوند و خروجی آن‌ها مشاهده نخواهد شد.

درادامه قصد پیاده سازی یک مثال  را با استفاده از Jasmine و RequireJs در پروژه Asp.Net MVC دارم.
برای شروع آخرین نسخه Jasmine را از اینجا دریافت نمایید. یک پروژه Asp.Net MVC به همراه پروژه تست به صورت Empty ایجاد کنید(در هنگام ایجاد پروژه، گزینه create unit test را انتخاب نمایید). فایل دانلود شده را unzip نمایید و دو پوشه lib و spec ،به همراه فایل specRunner.html را در پروژه تست خود کپی نمایید. 
  • فولدر lib شامل فایل‌ها کد‌های Jasmine برای setup و tear down و spice و تست کد‌های شما می‌باشد.
  • فایل specRunner.html به واقع یک فایل برای نمایش فایل‌های تست و همچنین نمایش نتیجه تست است.
  • فولدر spec نیز شامل کد‌های Jasmine برای کمک به نوشتن تست می‌باشد.

در این مثال قصد داریم فایل‌های player.js و song.js که به عنوان نمونه به همراه این فریم ورک قرار دارد را در قالب یک پروژه MVC به همراه RequireJs، تست نماییم. در نتیجه این فایل‌ها را از فولدر src انتخاب نمایید و آن‌ها را در قسمت Scripts پروژه اصلی خود کپی کنید(ابتدا بک پوشه به نام App بسازید و فایل‌ها را در آن قرار دهید)

برای استفاده از requireJs باید دستور define را در ابتدا این فایل‌ها اضافه نماییم. در نتیجه فایل‌های Player.js و Song.js را باز کنید و تغییرات زیر را در ابتدای این فایل‌ها اعمال نمایید.

Song.js

define(function () {
    function Song() {
    }

    Song.prototype.persistFavoriteStatus = function (value) {
        // something complicated
        throw new Error("not yet implemented");
    };
});
Player.js
define(function () {
    function Player() {
    }
    Player.prototype.play = function (song) {
        this.currentlyPlayingSong = song;
        this.isPlaying = true;
    };

    Player.prototype.pause = function () {
        this.isPlaying = false;
    };

    Player.prototype.resume = function () {
        if (this.isPlaying) {
            throw new Error("song is already playing");
        }

        this.isPlaying = true;
    };

    Player.prototype.makeFavorite = function () {
        this.currentlyPlayingSong.persistFavoriteStatus(true);
    };
});
حال فایل SpecRunner.html را بازکنید و کد‌های مربوط به تگ script که به مسیر اصلی فایل‌های تست  اشاره می‌کند را Comment نمایید و به جای آن تگ Script مربوط به RequireJs را اضافه نمایید. برای پیکر بندی RequireJs باید از baseUrl و paths استفاده کرد.

baseUrl در پیکر بندی requireJs به مسیر فایل‌های پروژه که در پروژه اصلی MVC قرار دارد اشاره می‌کند. paths برای تعیین مسیر فایل‌های تست که در پوشه spec در پروژه تست قرار دارد اشاره می‌کند. اگر دقت کرده باشید به دلیل اینگه تگ‌های script مربوط به لود فایل‌های SpecHelper.js و PlayerSpec.js به صورت comment در آمده اند در نتیجه این فایل‌ها لود نخواهند شد و خروجی مورد نظر مشاهده نمی‌شود. در این جا باید از مکانیزم AMD موجود در RequireJs استفاده نماییم و فایل‌های مربوطه را لود کنیم. برای این کار نیاز به اضافه کردن دستور require در ابتدای تگ script به صورت زیر در این فایل است. در نتیجه فایل‌های PlayerSpec و SpecHelper نیز توسط RequireJs لود خواهند شد.



نیاز به یک تغییر کوچک دیگر نیز وجود دارد. فایل PlayerSpec را باز نمایید و وابستگی فایل‌های آن را تعیین نمایید. از آن جا که این فایل برای تست فایل‌های Player , Song ایجاد شده است در نتیجه باید از define برای تعیین این وابستگی‌ها استفاده نماییم.

یادآوری:

»دستور describe در فایل بالا برای تعریف تابع تست است. همان طور که می‌بینید بک نام به آن داده می‌شود به همراه بدنه تابع تست. 

»دستور beforeEach برای آماده سازی مواردی است که قصد داریم در تست مورد استفاده قرار گیرند. همانند متد‌های Setup در UnitTest.

» دستور expect نیز معادل Assert در UnitTest است و برای بررسی صحت عملکرد تست نوشته می‌شود.

اگر فایل SpecRunner.html را دوباره در مرورگر خود باز نمایید تصویر زیر را مشاهده خواهید کرد که به عنوان موفقیت آمیز بودن پیکر بندی پروژه و تست‌های آن می‌باشد.


 

 
نظرات مطالب
استفاده از Kendo UI templates
از Url.Action باید برای تولید Url استفاده کنید.
قالب پویا بر اساس اطلاعات یک ردیف
#= productDetails(data) #
با این متد
<script>
function productDetails(product) {
    var action = '@Url.Action("ProductDetails", "Product")';

    var html = kendo.format("<a href='{0}/{1}'>Show Product Details</a>",
        action,
        product.ProductID
    );

    return html;
}
</script>
مثال‌های بیشتر در اینجا