Ahmad Masykur

Share your knowledge although one function!

About the author

Ahmad Masykur is a Software Architecture Engineer at PT. Freeport Indonesia Jakarta Indonesia.
In this blog, I share things of interest to me. Most topics are likely to be related to software development, but don't hold me to it.

Certificates



Awards


Powered by

Widget Prayer Time not found.

There is an error in XML document (4, 16278).X

Page List

Validators


Ahmad Masykur

ASP.NET 4 Performance Tips

Performance atau dalam Bahasa Indonesia disebut sebagai kinerja merupakan sebuah hal yang penting dalam sebuah aplikasi. Dalam sebuah aplikasi web terdapat beberapa faktor yang menyebabkan kinerja bagus atau buruk. Secara umum kinerja aplikasi dinyatakan bagus jika waktu tanggap (response time) dapat tercapai secepat mungkin. Untuk aplikasi web publik seperti www.facebook.com, www.kaskus.us, www.detik.com dan situs lainnya, dengan kinerja yang baik dapat membuat pengunjung betah mengunjunginya. Untuk aplikasi bisnis, kinerja yang bagus akan meningkatkan kinerja karyawan yang menjadi usernya.

Berikut akan saya utarakan beberapa tips untuk meningkatkan kinerja aplikasi ASP.NET 4. Beberapa tips juga dapat digunakan juga untuk versi ASP.NET sebelumnya.

Aplikasi ASP.NET sebelum dioptimasi.

Pertama akan saya buat aplikasi sederhana menggunakan ASP.NET tanpa optimasi apapun. Dalam contoh ini saya buat sebuah halaman yang menampilkan data tabular yang datanya saya ambil dari XML. Halaman ini menggunakan Ajax dengan UpdatePanel. Buat sebuah aplikasi web project baru dan pilih ASP.NET Web Application.

image

Puat satu class Product untuk entity data product.

namespace WebApplication1
{
    public class Product
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Supplier { get; set; }
        public string Category { get; set; }
        public string QuantityPerUnit { get; set; }
        public decimal UnitPrice { get; set; }
        public decimal UnitsInStock { get; set; }
        public decimal UnitsOnOrder { get; set; }
        public decimal ReorderLevel { get; set; }
    }
}

Buat file XML yang berisi data berikut dan tempatkan dalam folder App_Data. Beri nama file Products.xml

<?xml version="1.0" encoding="utf-8" ?>
<Products>
  <Product ID="1" Name="Chai" Supplier="Exotic Liquids" Category="Beverages" QuantityPerUnit="10 boxes x 20 bags" UnitPrice="18.0000" UnitsInStock="39" UnitsOnOrder="0" ReorderLevel="10" />
  <Product ID="2" Name="Chang" Supplier="Exotic Liquids" Category="Beverages" QuantityPerUnit="24 - 12 oz bottles" UnitPrice="19.0000" UnitsInStock="17" UnitsOnOrder="40" ReorderLevel="25" />
  <Product ID="3" Name="Aniseed Syrup" Supplier="Exotic Liquids" Category="Condiments" QuantityPerUnit="12 - 550 ml bottles" UnitPrice="10.0000" UnitsInStock="13" UnitsOnOrder="70" ReorderLevel="25" />
  <Product ID="4" Name="Chef Anton's Cajun Seasoning" Supplier="New Orleans Cajun Delights" Category="Condiments" QuantityPerUnit="48 - 6 oz jars" UnitPrice="22.0000" UnitsInStock="53" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="5" Name="Chef Anton's Gumbo Mix" Supplier="New Orleans Cajun Delights" Category="Condiments" QuantityPerUnit="36 boxes" UnitPrice="21.3500" UnitsInStock="0" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="6" Name="Grandma's Boysenberry Spread" Supplier="Grandma Kelly's Homestead" Category="Condiments" QuantityPerUnit="12 - 8 oz jars" UnitPrice="25.0000" UnitsInStock="120" UnitsOnOrder="0" ReorderLevel="25" />
  <Product ID="7" Name="Uncle Bob's Organic Dried Pears" Supplier="Grandma Kelly's Homestead" Category="Produce" QuantityPerUnit="12 - 1 lb pkgs." UnitPrice="30.0000" UnitsInStock="15" UnitsOnOrder="0" ReorderLevel="10" />
  <Product ID="8" Name="Northwoods Cranberry Sauce" Supplier="Grandma Kelly's Homestead" Category="Condiments" QuantityPerUnit="12 - 12 oz jars" UnitPrice="40.0000" UnitsInStock="6" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="9" Name="Mishi Kobe Niku" Supplier="Tokyo Traders" Category="Meat/Poultry" QuantityPerUnit="18 - 500 g pkgs." UnitPrice="97.0000" UnitsInStock="29" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="10" Name="Ikura" Supplier="Tokyo Traders" Category="Seafood" QuantityPerUnit="12 - 200 ml jars" UnitPrice="31.0000" UnitsInStock="31" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="11" Name="Queso Cabrales" Supplier="Cooperativa de Quesos 'Las Cabras'" Category="Dairy Products" QuantityPerUnit="1 kg pkg." UnitPrice="21.0000" UnitsInStock="22" UnitsOnOrder="30" ReorderLevel="30" />
  <Product ID="12" Name="Queso Manchego La Pastora" Supplier="Cooperativa de Quesos 'Las Cabras'" Category="Dairy Products" QuantityPerUnit="10 - 500 g pkgs." UnitPrice="38.0000" UnitsInStock="86" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="13" Name="Konbu" Supplier="Mayumi's" Category="Seafood" QuantityPerUnit="2 kg box" UnitPrice="6.0000" UnitsInStock="24" UnitsOnOrder="0" ReorderLevel="5" />
  <Product ID="14" Name="Tofu" Supplier="Mayumi's" Category="Produce" QuantityPerUnit="40 - 100 g pkgs." UnitPrice="23.2500" UnitsInStock="35" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="15" Name="Genen Shouyu" Supplier="Mayumi's" Category="Condiments" QuantityPerUnit="24 - 250 ml bottles" UnitPrice="15.5000" UnitsInStock="39" UnitsOnOrder="0" ReorderLevel="5" />
  <Product ID="16" Name="Pavlova" Supplier="Pavlova, Ltd." Category="Confections" QuantityPerUnit="32 - 500 g boxes" UnitPrice="17.4500" UnitsInStock="29" UnitsOnOrder="0" ReorderLevel="10" />
  <Product ID="17" Name="Alice Mutton" Supplier="Pavlova, Ltd." Category="Meat/Poultry" QuantityPerUnit="20 - 1 kg tins" UnitPrice="39.0000" UnitsInStock="0" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="18" Name="Carnarvon Tigers" Supplier="Pavlova, Ltd." Category="Seafood" QuantityPerUnit="16 kg pkg." UnitPrice="62.5000" UnitsInStock="42" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="19" Name="Teatime Chocolate Biscuits" Supplier="Specialty Biscuits, Ltd." Category="Confections" QuantityPerUnit="10 boxes x 12 pieces" UnitPrice="9.2000" UnitsInStock="25" UnitsOnOrder="0" ReorderLevel="5" />
  <Product ID="20" Name="Sir Rodney's Marmalade" Supplier="Specialty Biscuits, Ltd." Category="Confections" QuantityPerUnit="30 gift boxes" UnitPrice="81.0000" UnitsInStock="40" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="21" Name="Sir Rodney's Scones" Supplier="Specialty Biscuits, Ltd." Category="Confections" QuantityPerUnit="24 pkgs. x 4 pieces" UnitPrice="10.0000" UnitsInStock="3" UnitsOnOrder="40" ReorderLevel="5" />
  <Product ID="22" Name="Gustaf's Knäckebröd" Supplier="PB Knäckebröd AB" Category="Grains/Cereals" QuantityPerUnit="24 - 500 g pkgs." UnitPrice="21.0000" UnitsInStock="104" UnitsOnOrder="0" ReorderLevel="25" />
  <Product ID="23" Name="Tunnbröd" Supplier="PB Knäckebröd AB" Category="Grains/Cereals" QuantityPerUnit="12 - 250 g pkgs." UnitPrice="9.0000" UnitsInStock="61" UnitsOnOrder="0" ReorderLevel="25" />
  <Product ID="24" Name="Guaraná Fantástica" Supplier="Refrescos Americanas LTDA" Category="Beverages" QuantityPerUnit="12 - 355 ml cans" UnitPrice="4.5000" UnitsInStock="20" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="25" Name="NuNuCa Nuß-Nougat-Creme" Supplier="Heli Süßwaren GmbH &amp; Co. KG" Category="Confections" QuantityPerUnit="20 - 450 g glasses" UnitPrice="14.0000" UnitsInStock="76" UnitsOnOrder="0" ReorderLevel="30" />
  <Product ID="26" Name="Gumbär Gummibärchen" Supplier="Heli Süßwaren GmbH &amp; Co. KG" Category="Confections" QuantityPerUnit="100 - 250 g bags" UnitPrice="31.2300" UnitsInStock="15" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="27" Name="Schoggi Schokolade" Supplier="Heli Süßwaren GmbH &amp; Co. KG" Category="Confections" QuantityPerUnit="100 - 100 g pieces" UnitPrice="43.9000" UnitsInStock="49" UnitsOnOrder="0" ReorderLevel="30" />
  <Product ID="28" Name="Rössle Sauerkraut" Supplier="Plutzer Lebensmittelgroßmärkte AG" Category="Produce" QuantityPerUnit="25 - 825 g cans" UnitPrice="45.6000" UnitsInStock="26" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="29" Name="Thüringer Rostbratwurst" Supplier="Plutzer Lebensmittelgroßmärkte AG" Category="Meat/Poultry" QuantityPerUnit="50 bags x 30 sausgs." UnitPrice="123.7900" UnitsInStock="0" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="30" Name="Nord-Ost Matjeshering" Supplier="Nord-Ost-Fisch Handelsgesellschaft mbH" Category="Seafood" QuantityPerUnit="10 - 200 g glasses" UnitPrice="25.8900" UnitsInStock="10" UnitsOnOrder="0" ReorderLevel="15" />
  <Product ID="31" Name="Gorgonzola Telino" Supplier="Formaggi Fortini s.r.l." Category="Dairy Products" QuantityPerUnit="12 - 100 g pkgs" UnitPrice="12.5000" UnitsInStock="0" UnitsOnOrder="70" ReorderLevel="20" />
  <Product ID="32" Name="Mascarpone Fabioli" Supplier="Formaggi Fortini s.r.l." Category="Dairy Products" QuantityPerUnit="24 - 200 g pkgs." UnitPrice="32.0000" UnitsInStock="9" UnitsOnOrder="40" ReorderLevel="25" />
  <Product ID="33" Name="Geitost" Supplier="Norske Meierier" Category="Dairy Products" QuantityPerUnit="500 g" UnitPrice="2.5000" UnitsInStock="112" UnitsOnOrder="0" ReorderLevel="20" />
  <Product ID="34" Name="Sasquatch Ale" Supplier="Bigfoot Breweries" Category="Beverages" QuantityPerUnit="24 - 12 oz bottles" UnitPrice="14.0000" UnitsInStock="111" UnitsOnOrder="0" ReorderLevel="15" />
  <Product ID="35" Name="Steeleye Stout" Supplier="Bigfoot Breweries" Category="Beverages" QuantityPerUnit="24 - 12 oz bottles" UnitPrice="18.0000" UnitsInStock="20" UnitsOnOrder="0" ReorderLevel="15" />
  <Product ID="36" Name="Inlagd Sill" Supplier="Svensk Sjöföda AB" Category="Seafood" QuantityPerUnit="24 - 250 g  jars" UnitPrice="19.0000" UnitsInStock="112" UnitsOnOrder="0" ReorderLevel="20" />
  <Product ID="37" Name="Gravad lax" Supplier="Svensk Sjöföda AB" Category="Seafood" QuantityPerUnit="12 - 500 g pkgs." UnitPrice="26.0000" UnitsInStock="11" UnitsOnOrder="50" ReorderLevel="25" />
  <Product ID="38" Name="Côte de Blaye" Supplier="Aux joyeux ecclésiastiques" Category="Beverages" QuantityPerUnit="12 - 75 cl bottles" UnitPrice="263.5000" UnitsInStock="17" UnitsOnOrder="0" ReorderLevel="15" />
  <Product ID="39" Name="Chartreuse verte" Supplier="Aux joyeux ecclésiastiques" Category="Beverages" QuantityPerUnit="750 cc per bottle" UnitPrice="18.0000" UnitsInStock="69" UnitsOnOrder="0" ReorderLevel="5" />
  <Product ID="40" Name="Boston Crab Meat" Supplier="New England Seafood Cannery" Category="Seafood" QuantityPerUnit="24 - 4 oz tins" UnitPrice="18.4000" UnitsInStock="123" UnitsOnOrder="0" ReorderLevel="30" />
  <Product ID="41" Name="Jack's New England Clam Chowder" Supplier="New England Seafood Cannery" Category="Seafood" QuantityPerUnit="12 - 12 oz cans" UnitPrice="9.6500" UnitsInStock="85" UnitsOnOrder="0" ReorderLevel="10" />
  <Product ID="42" Name="Singaporean Hokkien Fried Mee" Supplier="Leka Trading" Category="Grains/Cereals" QuantityPerUnit="32 - 1 kg pkgs." UnitPrice="14.0000" UnitsInStock="26" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="43" Name="Ipoh Coffee" Supplier="Leka Trading" Category="Beverages" QuantityPerUnit="16 - 500 g tins" UnitPrice="46.0000" UnitsInStock="17" UnitsOnOrder="10" ReorderLevel="25" />
  <Product ID="44" Name="Gula Malacca" Supplier="Leka Trading" Category="Condiments" QuantityPerUnit="20 - 2 kg bags" UnitPrice="19.4500" UnitsInStock="27" UnitsOnOrder="0" ReorderLevel="15" />
  <Product ID="45" Name="Rogede sild" Supplier="Lyngbysild" Category="Seafood" QuantityPerUnit="1k pkg." UnitPrice="9.5000" UnitsInStock="5" UnitsOnOrder="70" ReorderLevel="15" />
  <Product ID="46" Name="Spegesild" Supplier="Lyngbysild" Category="Seafood" QuantityPerUnit="4 - 450 g glasses" UnitPrice="12.0000" UnitsInStock="95" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="47" Name="Zaanse koeken" Supplier="Zaanse Snoepfabriek" Category="Confections" QuantityPerUnit="10 - 4 oz boxes" UnitPrice="9.5000" UnitsInStock="36" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="48" Name="Chocolade" Supplier="Zaanse Snoepfabriek" Category="Confections" QuantityPerUnit="10 pkgs." UnitPrice="12.7500" UnitsInStock="15" UnitsOnOrder="70" ReorderLevel="25" />
  <Product ID="49" Name="Maxilaku" Supplier="Karkki Oy" Category="Confections" QuantityPerUnit="24 - 50 g pkgs." UnitPrice="20.0000" UnitsInStock="10" UnitsOnOrder="60" ReorderLevel="15" />
  <Product ID="50" Name="Valkoinen suklaa" Supplier="Karkki Oy" Category="Confections" QuantityPerUnit="12 - 100 g bars" UnitPrice="16.2500" UnitsInStock="65" UnitsOnOrder="0" ReorderLevel="30" />
  <Product ID="51" Name="Manjimup Dried Apples" Supplier="G'day, Mate" Category="Produce" QuantityPerUnit="50 - 300 g pkgs." UnitPrice="53.0000" UnitsInStock="20" UnitsOnOrder="0" ReorderLevel="10" />
  <Product ID="52" Name="Filo Mix" Supplier="G'day, Mate" Category="Grains/Cereals" QuantityPerUnit="16 - 2 kg boxes" UnitPrice="7.0000" UnitsInStock="38" UnitsOnOrder="0" ReorderLevel="25" />
  <Product ID="53" Name="Perth Pasties" Supplier="G'day, Mate" Category="Meat/Poultry" QuantityPerUnit="48 pieces" UnitPrice="32.8000" UnitsInStock="0" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="54" Name="Tourtière" Supplier="Ma Maison" Category="Meat/Poultry" QuantityPerUnit="16 pies" UnitPrice="7.4500" UnitsInStock="21" UnitsOnOrder="0" ReorderLevel="10" />
  <Product ID="55" Name="Pâté chinois" Supplier="Ma Maison" Category="Meat/Poultry" QuantityPerUnit="24 boxes x 2 pies" UnitPrice="24.0000" UnitsInStock="115" UnitsOnOrder="0" ReorderLevel="20" />
  <Product ID="56" Name="Gnocchi di nonna Alice" Supplier="Pasta Buttini s.r.l." Category="Grains/Cereals" QuantityPerUnit="24 - 250 g pkgs." UnitPrice="38.0000" UnitsInStock="21" UnitsOnOrder="10" ReorderLevel="30" />
  <Product ID="57" Name="Ravioli Angelo" Supplier="Pasta Buttini s.r.l." Category="Grains/Cereals" QuantityPerUnit="24 - 250 g pkgs." UnitPrice="19.5000" UnitsInStock="36" UnitsOnOrder="0" ReorderLevel="20" />
  <Product ID="58" Name="Escargots de Bourgogne" Supplier="Escargots Nouveaux" Category="Seafood" QuantityPerUnit="24 pieces" UnitPrice="13.2500" UnitsInStock="62" UnitsOnOrder="0" ReorderLevel="20" />
  <Product ID="59" Name="Raclette Courdavault" Supplier="Gai pâturage" Category="Dairy Products" QuantityPerUnit="5 kg pkg." UnitPrice="55.0000" UnitsInStock="79" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="60" Name="Camembert Pierrot" Supplier="Gai pâturage" Category="Dairy Products" QuantityPerUnit="15 - 300 g rounds" UnitPrice="34.0000" UnitsInStock="19" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="61" Name="Sirop d'érable" Supplier="Forêts d'érables" Category="Condiments" QuantityPerUnit="24 - 500 ml bottles" UnitPrice="28.5000" UnitsInStock="113" UnitsOnOrder="0" ReorderLevel="25" />
  <Product ID="62" Name="Tarte au sucre" Supplier="Forêts d'érables" Category="Confections" QuantityPerUnit="48 pies" UnitPrice="49.3000" UnitsInStock="17" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="63" Name="Vegie-spread" Supplier="Pavlova, Ltd." Category="Condiments" QuantityPerUnit="15 - 625 g jars" UnitPrice="43.9000" UnitsInStock="24" UnitsOnOrder="0" ReorderLevel="5" />
  <Product ID="64" Name="Wimmers gute Semmelknödel" Supplier="Plutzer Lebensmittelgroßmärkte AG" Category="Grains/Cereals" QuantityPerUnit="20 bags x 4 pieces" UnitPrice="33.2500" UnitsInStock="22" UnitsOnOrder="80" ReorderLevel="30" />
  <Product ID="65" Name="Louisiana Fiery Hot Pepper Sauce" Supplier="New Orleans Cajun Delights" Category="Condiments" QuantityPerUnit="32 - 8 oz bottles" UnitPrice="21.0500" UnitsInStock="76" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="66" Name="Louisiana Hot Spiced Okra" Supplier="New Orleans Cajun Delights" Category="Condiments" QuantityPerUnit="24 - 8 oz jars" UnitPrice="17.0000" UnitsInStock="4" UnitsOnOrder="100" ReorderLevel="20" />
  <Product ID="67" Name="Laughing Lumberjack Lager" Supplier="Bigfoot Breweries" Category="Beverages" QuantityPerUnit="24 - 12 oz bottles" UnitPrice="14.0000" UnitsInStock="52" UnitsOnOrder="0" ReorderLevel="10" />
  <Product ID="68" Name="Scottish Longbreads" Supplier="Specialty Biscuits, Ltd." Category="Confections" QuantityPerUnit="10 boxes x 8 pieces" UnitPrice="12.5000" UnitsInStock="6" UnitsOnOrder="10" ReorderLevel="15" />
  <Product ID="69" Name="Gudbrandsdalsost" Supplier="Norske Meierier" Category="Dairy Products" QuantityPerUnit="10 kg pkg." UnitPrice="36.0000" UnitsInStock="26" UnitsOnOrder="0" ReorderLevel="15" />
  <Product ID="70" Name="Outback Lager" Supplier="Pavlova, Ltd." Category="Beverages" QuantityPerUnit="24 - 355 ml bottles" UnitPrice="15.0000" UnitsInStock="15" UnitsOnOrder="10" ReorderLevel="30" />
  <Product ID="71" Name="Flotemysost" Supplier="Norske Meierier" Category="Dairy Products" QuantityPerUnit="10 - 500 g pkgs." UnitPrice="21.5000" UnitsInStock="26" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="72" Name="Mozzarella di Giovanni" Supplier="Formaggi Fortini s.r.l." Category="Dairy Products" QuantityPerUnit="24 - 200 g pkgs." UnitPrice="34.8000" UnitsInStock="14" UnitsOnOrder="0" ReorderLevel="0" />
  <Product ID="73" Name="Röd Kaviar" Supplier="Svensk Sjöföda AB" Category="Seafood" QuantityPerUnit="24 - 150 g jars" UnitPrice="15.0000" UnitsInStock="101" UnitsOnOrder="0" ReorderLevel="5" />
  <Product ID="74" Name="Longlife Tofu" Supplier="Tokyo Traders" Category="Produce" QuantityPerUnit="5 kg pkg." UnitPrice="10.0000" UnitsInStock="4" UnitsOnOrder="20" ReorderLevel="5" />
  <Product ID="75" Name="Rhönbräu Klosterbier" Supplier="Plutzer Lebensmittelgroßmärkte AG" Category="Beverages" QuantityPerUnit="24 - 0.5 l bottles" UnitPrice="7.7500" UnitsInStock="125" UnitsOnOrder="0" ReorderLevel="25" />
  <Product ID="76" Name="Lakkalikööri" Supplier="Karkki Oy" Category="Beverages" QuantityPerUnit="500 ml" UnitPrice="18.0000" UnitsInStock="57" UnitsOnOrder="0" ReorderLevel="20" />
  <Product ID="77" Name="Original Frankfurter grüne Soße" Supplier="Plutzer Lebensmittelgroßmärkte AG" Category="Condiments" QuantityPerUnit="12 boxes" UnitPrice="13.0000" UnitsInStock="32" UnitsOnOrder="0" ReorderLevel="15" />  
</Products>

Buat beberapa file JavaScript berikut

1. Divider.js

// Divider.js
function divider(value1, value2) {
    if (typeof (value1) == "number" && typeof (value2) == "number") {
        var result = value1 / value2;
        return result;
    } else {
        return null;
    }
}

2. Multiplier.js

// Multiplier.js
function multiplier(value1, value2) {
    if (typeof (value1) == "number" && typeof (value2) == "number") {
        var result = value1 * value2;
        return result;
    } else {
        return null;
    }
}

3. Default.js

// Default.js
$(document).ready(function () {
    $('#Multiplier').click(function () {
        var value1 = parseFloat($('#Value1').val());
        var value2 = parseFloat($('#Value2').val());
        $('#Result').val(multiplier(value1, value2));
    });
    $('#Divider').click(function () {
        var value1 = parseFloat($('#Value1').val());
        var value2 = parseFloat($('#Value2').val());
        $('#Result').val(divider(value1, value2));
    });
});

Ketiga file javascript file tersebut beserta jQuery akan digunakan dalam halaman default.aspx. Ganti halaman Default.aspx yang sudah dibuat oleh Visual Studio project template dengan code berikut.

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <script type="text/javascript" src="Scripts/jquery-1.3.2.min.js"></script>
    <script type="text/javascript" src="Scripts/multiplier.js"></script>
    <script type="text/javascript" src="Scripts/divider.js"></script>
    <script type="text/javascript" src="Scripts/Default.js"></script>
    <h2>
        Welcome to ASP.NET!
    </h2>
    <asp:ScriptManager runat="server" EnablePartialRendering="true">
    </asp:ScriptManager>
    <asp:Label runat="server" AssociatedControlID="PageListBox">Page:</asp:Label>
    <asp:DropDownList runat="server" ID="PageListBox" AutoPostBack="true" OnSelectedIndexChanged="PageIndexChanged" ></asp:DropDownList>
    <input type="text" name="Value1" id="Value1" value="1" />
    <input type="button" name="Muntiplier" id="Multiplier" value="x" />
    <input type="button" name="Divider" id="Divider" value="/" />
    <input type="text" name="Value2" id="Value2" value="1" />=
    <input type="text" name="Result" id="Result" value="" />
    <asp:UpdatePanel runat="server">
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="PageListBox" />
        </Triggers>
        <ContentTemplate>
            <asp:GridView ID="ProductView" runat="server" AutoGenerateColumns="false" EnableSortingAndPagingCallbacks="False" AllowSorting="True">
                <Columns>
                    <asp:BoundField HeaderText="Name" DataField="Name" />
                    <asp:BoundField HeaderText="Supplier" DataField="Supplier" />
                    <asp:BoundField HeaderText="Category" DataField="Category" />
                    <asp:BoundField HeaderText="Quantity Per Unit" DataField="QuantityPerUnit" />
                    <asp:BoundField HeaderText="Unit Price" DataField="UnitPrice" />
                    <asp:BoundField HeaderText="Units In Stock" DataField="UnitsInStock" />
                    <asp:BoundField HeaderText="Units On Order" DataField="UnitsOnOrder" />
                    <asp:BoundField HeaderText="Reorder Level" DataField="ReorderLevel" />
                </Columns>
            </asp:GridView>
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>

Buat code behind untuk default.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;

namespace WebApplication1
{
    public partial class _Default : System.Web.UI.Page
    {
        private IEnumerable<Product> GetProducts()
        {
            var data = XDocument.Load(Server.MapPath("~/App_data/Products.xml"), LoadOptions.None);
            var q = from c in data.Descendants("Product")
                    select new Product
                    {
                        ID = int.Parse(c.Attribute("ID").Value),
                        Name = c.Attribute("Name").Value,
                        Supplier = c.Attribute("Supplier").Value,
                        Category = c.Attribute("Category").Value,
                        QuantityPerUnit = c.Attribute("QuantityPerUnit").Value,
                        UnitPrice = decimal.Parse(c.Attribute("UnitPrice").Value),
                        UnitsInStock = decimal.Parse(c.Attribute("UnitsInStock").Value),
                        UnitsOnOrder = decimal.Parse(c.Attribute("UnitsOnOrder").Value),
                        ReorderLevel = decimal.Parse(c.Attribute("ReorderLevel").Value)
                    };
            return q;
        }
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                var products = GetProducts();
                PageListBox.Items.Clear();
                for (int i = 0; i < (int)(Math.Ceiling((double)products.Count() / 10)); i++)
                {
                    PageListBox.Items.Add(new ListItem((i + 1).ToString()));
                }
                ProductView.DataSource = products.Take(10);
                ProductView.DataBind();
            }
        }
        protected void PageIndexChanged(object sender, EventArgs e)
        {
            var products = GetProducts();
            int selectedPage = int.Parse(((DropDownList)sender).SelectedValue);
            ProductView.DataSource = products.Skip((selectedPage - 1) * 10).Take(10);
            ProductView.DataBind();
        }
    }
}

Analisis

Setelah semua kode disiapkan, buka halaman dengan browser. Saya gunakan Firefox dengan add-ons Firebug dan YSlow untuk menganalisis kinerja dari halaman yang dibuat.

image

Kita bisa lihat bahwa untuk membuka halaman untuk pertama kalinya membutuhkan waktu 6,53 detik. Kemudian saya akan cek untuk akses halaman untuk yang kedua kalinya dan seterusnya. Tekan menu Home untuk mengakses halaman itu kembali, hasilnya sebagai berikut.

image

Permintaan yang kedua jauh lebih cepat dari sebelumnya, yaitu hanya 4,16 detik. Mari kita analisis penyebab lambatnya permintaan yang pertama. Dilihat dari jumlahnya, akses yang pertama terdapat sebelas permintaan untuk membuka satu halaman; sedangkan akses yang kedua hanya ada enam permintaan. Hal ini disebabkan karena akses yang pertama akan mengambil semua file dari server. Sedangkan akses yang kedua beberapa file yang dibungkus oleh ScriptResource.axd dan WebResource.axd telah dicache di browser sehingga tidak diambil lagi.

Mari kita analisis lebih dalam dengan YSlow pada tab Components

image

Kita bisa lihat bahwa terdapat delapan (8) buah permintaan file javascript (JS) terlihat cukup lama. Browser akan mengunduh file JavaScript satu per satu karena adanya ketergantungan file JavaScript degan file JavaScript lainnya. Walaupun browser dapat mengunduh file tersebut secara bersamaan, namun server web hanya dapat melayani maksimal dua (2) permintaan dari user yang sama dalam waktu bersamaan. Ini membuat tanggapan (response) dari server menjadi lama. Pada permintaan yang kedua, sebagian dari file tersebut tidak diminta lagi pada akses yang kedua karena sudah ada di client (browser) sehingga lebih cepat.

Dengan data tersebut di atas, apa yang bisa kita lakukan? Kita bisa mencache semua file JavaScript dengan memasukkannya sebagai embeded resource sebagaimana JavaScript milik ASP.NET Ajax dan WebForms. Dengan cara tersebut dapat mempercepat permintaan yang kedua kalinya dan seterusnya, namun tetap lambat untuk permintaan yang pertama. Lalu apa yang bisa kita lakukan untuk mempercepat permintaan yang pertama? Dalam ASP.NET 4 terdapat fitur yang menarik yaitu penggabungan semua JavaScript menjadi satu file. Sebenarnya fitur ini telah ada dalam ASP.NET 3.5 SP1 namun di ASP.NET 4 terdapat pengembangan yang memungkinkan JavaScript milik WebForms diikutsertakan dalam paket kombinasi tersebut.

Tips 1: Gabungkan File-File JavaScript Menjadi Satu.

Dengan menggabungkan semua file JavaScript menjadi satu, tidak ada lagi permintaan bolak-balik dari client ke server. Kita praktekkan langsung dalam kode ASP.NET. Masukkan semua referensi JavaScript ke CompositeScript dalam ScriptManager.

<asp:ScriptManager runat="server" EnablePartialRendering="true">
    <CompositeScript>
        <Scripts>
            <asp:ScriptReference Assembly="System.Web" Name="WebForms.js" />
            <asp:ScriptReference Assembly="System.Web" Name="Menu.js" />
            <asp:ScriptReference Assembly="System.Web" Name="MenuStandards.js" />
            <asp:ScriptReference Name="MicrosoftAjax.js" />
            <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" />
            <asp:ScriptReference Path="Scripts/jquery-1.3.2.min.js" />
            <asp:ScriptReference Path="Scripts/multiplier.js" />
            <asp:ScriptReference Path="Scripts/divider.js" />
            <asp:ScriptReference Path="Scripts/Default.js" />
        </Scripts>
    </CompositeScript>
</asp:ScriptManager>

Sekarang kita bisa lihat bahwa hanya ada empat permintaan ke server untuk menampilkan halaman yang sama. Dikarenakan jumlah permintaan lebih sedikit, waktu yang dibutuhkan untuk menampilkan halaman juga lebih singkat yaitu 3,96 detik. Bahkan lebih cepat dari permintaan kedua sebelumnya.

image

Sekarang kita cek untuk permintaan kedua.

image

Seluruh permintaan selesai hanya dalam waktu 2,27 detik. Suatu peningkatan kinerja yang luar biasa.

Dari CompositeScript tersebut, kita kombinasikan semua JavaScript yang ada dalam embeded resource maupun yang berupa file. Untuk yang berupa file kita dengan mudah dapat mengidentifikasinya, lalu bagaimana cara mengetahui embeded JavaScript apa saja yang kita gunakan? Pertama kita harus tahu assembly apa yang kita gunakan. Karena kita menggunakan WebForm dan ScriptManager otomatis kita menggunakan assembly System.Web dan System.Web.Extensions. Assembly System.Web menggunakan WebForms.js sebagai JavaScript utama sedangkan ScriptManager meng-embed MicrosoftAjax.js. Kedua javascript tersebut harus ada sebelum kita menggunakan control yang lain.

Untuk mengetahui JavaScript yang digunakan oleh control, kita klik pada Response tab pada Firebug untuk mendapatkan isi dari javascript. Berbekal informasi isi dari javascript, kita dapat mencari embeded resource dengan menggunakan Reflector. Buka reflector dan lihat pada assembly System.Web. Cari file javascript yang berkaitan dengan control yang kita gunakan kemudian klik ganda untuk melihat isinya. Jika isinya cocok, maka file tersebut yang kita masukkan dalam CompositeScript.

image

image

Adakah yang bisa dioptimalkan lagi? Untuk permintaan terhadap default.aspx masih membutuhkan waktu lebih dari 1 detik. Ketika kita bukan halaman default.aspx dengan lihat sumber (view source), kita dapatkan banyak kode yang jumlahnya cukup besar. Mari kita optimalkan isi dari default.aspx

image

Tips 2: Gunakan ViewState Seperlunya

Karena sifat dari web adalah stateless, ViewState digunakan untuk menjaga status dari halaman untuk digunakan di server. Setiap control yang dirender ke halaman selalu memiliki ViewState padahal tidak semuanya digunakan. Kita harus jeli mana yang kita gunakan dan mana yang tidak. Jika pada waktu postback, kita tidak memerlukan nilai dari control tersebut, kita tidak perlu menyimpan ViewState. Karena pada contoh ini kita hampir tidak memerlukan ViewState, kita bisa matikan semua ViewState kecuali DropDownList yang memang diperlukan untuk menentukan halaman berapa yang dibuka. Hasil dari optimasi adalah sebagai berikut.

image

Dari local komputer, perubahan tidak begitu berarti karena tidak ada latency terhadap jaringan. Yang jadi catatan di sini adalah ukuran file default.aspx yang didownload. Semula default.aspx berukuran 9,2 kini hanya berukuran 6,7; hemat 30% dari bandwidth. Lalu apa lagi yang bisa dioptimasi?

Tips 3: Manfaatkan Microsoft CDN untuk Situs Publik

Jika situs anda untuk konsumsi publis, CDN memberikan manfaat untuk mempercepat akses dengan memanfaatkan server CDN Microsoft yang tersebar di seluruh dunia. Pengunjung akan mendapatkan server CDN terdekat dengan tempat dia akses. Jika diakses dari Indonesia, kita akan mendapatkan server CDN yang ada di Singapore, jika diakses dari US maka akan download JavaScript dari US sehingga aplikasi kita akan lebih cepat diakses oleh pengunjung manapun.

Untuk memanfaatkan Microsoft CDN, set EnableCDN menjadi true pada ScriptManager

image

Selain mengeset property EnableCDN menjadi true, kita juga perlu mengeluarkan MicrosoftAjax.js dan MicrosoftAjaxWebForms.js dari CompositeScript. Jika tidak, kedua JavaScript tesebut akan tetap diambil dari local resource dan masuk dalam CompositeScript. Dengan setting EnableCDN kedua file tersebut akan diambil dari server Microsoft CDN. Selain kedua library tersebut, kita juga bisa memanfaatkan library lain yang sudah tersedia di CDN (Baik Microsoft CDN, Google CDN maupun server lain) seperti jQuery. Caranya dengan megeset lokasi CDN di Application_Start dalam Global.asax.

void Application_Start(object sender, EventArgs e)
{
    // Code that runs on application startup
    // map a simple name to a path
    ScriptManager.ScriptResourceMapping.AddDefinition("jQuery", new ScriptResourceDefinition
    {
        Path = "~/scripts/jquery-1.3.2.min.js",
        DebugPath = "~/scripts/jquery-1.3.2.js",
        CdnPath = "http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.min.js",
        CdnDebugPath = "http://ajax.microsoft.com/ajax/jQuery/jquery-1.3.2.js"
    });
}

Kode di atas mendefinisikan jQuery untuk lokasi di lokal dan CDN baik untuk versi debug maupun release.

Definisi tersebut yang kemudian digunakan di ScriptManager.

<asp:ScriptManager runat="server" EnablePartialRendering="true" 
    EnableViewState="False" LoadScriptsBeforeUI="False" EnableCdn="True">
    <Scripts>
        <asp:ScriptReference Name="jQuery" />
    </Scripts>
    <CompositeScript>
        <Scripts>
<%--
            <asp:ScriptReference Assembly="System.Web" Name="WebForms.js" />
            <asp:ScriptReference Assembly="System.Web" Name="Menu.js" />
            <asp:ScriptReference Assembly="System.Web" Name="MenuStandards.js" />
            <asp:ScriptReference Name="MicrosoftAjax.js" />
            <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" />
            <asp:ScriptReference Path="Scripts/jquery-1.3.2.min.js" />
--%>                
            <asp:ScriptReference Path="Scripts/multiplier.js" />
            <asp:ScriptReference Path="Scripts/divider.js" />
            <asp:ScriptReference Path="Scripts/Default.js" />
        </Scripts>
    </CompositeScript>
</asp:ScriptManager>

Dari kode di atas, kita remark semua library yang akan kita ambil dari CDN. Semua library yang ada dalam assembly Microsoft ASP.NET sudah tersedia di Microsoft CDN. Library lainnya harus dimasukkan dalam Scripts di luar CompositeScript. Hasil akses dari kode yang sudah diubah sebagai berikut.

image

Terlihat bahwa waktu yang dibutuhkan lebih lama dari kode kita sebelumnya yang menggabungkan semua script menjadi satu. Hal ini wajar karena demo ini menggunakan komputer lokal sehingga akses jaringan jauh lebih cepat dibandingkan akses ke Internet. Kecepatan akan terasa sewaktu aplikasi sudah dihost di Internet.

Tips 4: Tempatkan Referensi Script di Bawah User Interface

image

Pada property ScriptManager, set nilai LoadScriptsBeforeUI menjadi False. Hal ini akan membuat referensi Script dirender sebelum tag penutup </body>. Hal ini membuat browser akan mendownload semua UI terlebih dahulu sebelum JavaScript sehingga halaman tampak lebih cepat tampil.

Tips 5: Gunakan Browser Cache

Penggunaan cache penting untuk mengurangi beban jaringan. Dengan menggunakan cache, browser tidaka akan mengambil halaman dari server lagi melainkan dari cache selama cache belum kadaluarsa. Cache hanya berlaku untuk HTTP GET sehingga ketika kita postback tetap akan mendapatkan data yang valid. Untuk memanfaatkan cache, cukup tambahkan directive OutputCache pada tiap page yang akan di-cache seperti contoh berikut.

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>
<%@ OutputCache Duration="86400" Location="Client" VaryByParam="None" %>    

Dalam contoh di atas, cache diset masa kadaluarsa selama satu hari. Halaman akan dicache selama sehari sehingga akan mengurangi beban server. Sebenarnya fungsi cache ini sudah ada sejak ASP.NET 2.0 dan masih valid sampai ASP.NET 4.0.

Demikian beberapa tips yang bisa meningkatkan kinerja aplikasi web kita. Semoga bermanfaat.


Categories: ASP.NET AJAX | ASP.NET | Tips
Permalink | Comments (2) | Post RSSRSS comment feed

ASP.NET Ajax Client Template | Select Command

ASP.NET Ajax client template juga memiliki fitur menarik yaitu select command sebagaimana GridView pada ASP.NET server control. Pada contoh post sebelumnya, saya telah tunjukkan bagaimana membuat sebuah client template pada sebuah table. Pada post kali ini saya akan buat baris pada table tersebut dapat dipilih dengan melakukan klik pada salah satu baris. Ada dua cara untuk melakukan hal ini, secara declarative dan imperative (JavaScript).

Object control DataView memiliki property selecteditemclass yang dapat diisi dengan class element yang dipilih. Property tersebut dapat diset secara declarative maupun imperative (JavaScript). Sebelum membuat DataView dapat dipilih, buat dulu class yang ditampilkan saat row terpilih. Class tersebut diberi nama selected-row

<style type="text/css"> .sys-template { display:none; visibility:hidden; } .selected-row { background: #ffff7f; color: Green; } </style>
Select Command secara Declarative

Untuk membuat DataView dapat dipilih secara declarative, tambahkan property sys:command="select" pada table row (TR) dan selecteditemclass property pada dataview seperti pada contoh berikut.

<tbody id="stockListView" class="sys-template" sys:attach="dataview" dataview:serviceuri="StockService.svc" dataview:query="GetStocks" dataview:selecteditemclass="selected-row"> <tr sys:command="select" style="cursor: pointer" > <td>{{Symbol}}</td> <td>{{Quote}}</td> <td>{{Change}}</td> <td>{{Day}}</td> <td>{{Time}}</td> </tr> </tbody>

Dengan hanya menambahkan property tersebut, sekarang table dapat dipilih (select) dan warna pada baris yang dipilih akan berubah.

Select Command secara Imperative

Penggunaan select command juga dapat dilakukan secara imperative dengan JavaScript. Perlakuannya sama antara declarative dan imperative. Pada cara imperative, row template ditambahkan attribute sys:command="select".

<tbody id="stockListView" class="sys-template"> <tr sys:command="select" style="cursor: pointer"> <td>{{Symbol}}</td> <td>{{Quote}}</td> <td>{{Change}}</td> <td>{{Day}}</td> <td>{{Time}}</td> </tr> </tbody>

Jangan lupa pada tag body juga ditambahkan namespace sys untuk supaya attribute sys dikenali dalam body html.

<body xmlns:sys="javascript:Sys">

Setelah semua attribute disiapkan, tinggal menambahkan property selectedItemClass pada object DataView.

var dataview = $create( Sys.UI.DataView, { serviceUri: "StockService.svc", query: "GetStocks", selectedItemClass: "selected-row" }, {}, {}, $get("stockListView") );

Tampilan baris yang dipilih akan seperti pada gambar di bawah

image

Dengan client template, pemprograman halaman html yang interactive menjadi lebih mudah.

Source-code contoh program ini dapat diunduh pada link di bawah.


Categories: ASP.NET AJAX
Permalink | Comments (11) | Post RSSRSS comment feed

ASP.NET Ajax Client Template | JavaScript Client Binding

Dari post sebelumnya, telah saya bahas mengenai ASP.NET Ajax 4.0 Client Template. Pada tulisan tersebut, saya bahas binding data tanpa koding javascript sedikitpun. Dengen client template memang sangat membatu dalam proses binding di sisi client. Binding tidak hanya bisa dilakukan secara declarative seperti pada post sebelumnya. Ada kalanya perlu dilakukan binding secara programming dengan JavaScript. Untuk melakukan binding dengan JavaScript, langkah persiapan yang dilakukan sama seperti pada declarative binding. Perbedaannya pada bagaimana cara membinding data dari datasource ke template.

Berikut saya jelaskan apa yang harus dilakukan untuk client binding dengan JavaScript. Kita asumsikan service dan template yang digunakan sama seperti pada post sebelumnya.

Pada halaman HTMl tidak perlu dideklarasikan XML namespace baru seperti pada metode declarative binding. Template masih tetap sama, hanya attribute sys:attach, dataview:serviceuri dan dataview:query tidak perlu ditulis lagi.

<body> <div> <table border="1"> <thead> <tr> <td>Symbol</td> <td>Quote</td> <td>Change</td> <td>Day</td> <td>Time</td> </tr> </thead> <tbody id="stockListView" class="sys-template"> <tr> <td>{{Symbol}}</td> <td>{{Quote}}</td> <td>{{Change}}</td> <td>{{Day}}</td> <td>{{Time}}</td> </tr> </tbody> </table> </div> </body>

Selanjutnya tinggal  buat binding data dengan JavaScript. Attribute sys:attach, dataview:serviceuri dan dataview:query yang sebelumnya ditulis di deklarasi tag, sekarang digantikan dengan JavaScript object.

<script type="text/javascript"> function pageLoad() { $create( Sys.UI.DataView, { serviceUri: "StockService.svc", query: "GetStocks" }, {}, {}, $get("stockListView") ); } </script>

Kita dapat melakukan binding kapan saja apakah setelah menekan tombol tertentu atau pada waktu pageLoad seperti contoh di atas. Contoh kode untuk client binding dengan JavaScript ini dapat diunduh dari link di bawah.


Categories: ASP.NET AJAX
Permalink | Comments (8) | Post RSSRSS comment feed

ASP.NET Ajax Client Template | Bener-bener Ajax

Masih menggunakan UpdatePanel untuk membuat halaman web "seakan-akan" mendukung Ajax? UpdatePanel bukan Ajax yang sebenarnya tapi hanya partial rendering saja. Terdapat dua jenis template ajax pada teknologi Microsoft. Pertama server side template yang dibungkus oleh UpdatePanel. Dan yang kedua adalah client side template yang terdapat pada ASP.NET Ajax 4.0 (saat ini masih preview 3). Dalam tulisan kali ini saya akan menunjukkan bagaimana mudahnya bikin ajax dengan client template ASP.NET Ajax 4.0.

Untuk membuat client template, yang dibutuhkan adalah.

  1. ASP.NET Ajax 4.0 Preview 3 (http://www.codeplex.com/aspnet)
  2. Ajax-Enabled WCF Service sebagai datasource
  3. Html page

Langkah langkah pembuatan ASP.NET Client Template.

Buat class StockInfo.cs
using System.Runtime.Serialization; namespace AjaxClientTemplate { [DataContract] public class StockInfo { [DataMember] public string Symbol { get; set; } [DataMember] public string Quote { get; set; } [DataMember] public string Change { get; set; } [DataMember] public string Day { get; set; } [DataMember] public string Time { get; set; } } }
Buat WCF Service

Buat Ajax-Enable WCF Service dengan add new item --> Ajax Enabled WCF Service dan ganti isinya dengan

using System.Collections.Generic; using System.Linq; using System.ServiceModel; using System.ServiceModel.Activation; namespace AjaxClientTemplate { [ServiceContract(Namespace = "contoh.com")] [AspNetCompatibilityRequirements( RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class StockService { // Add [WebGet] attribute to use HTTP GET [OperationContract] public IEnumerable<StockInfo> GetStocks() { var stocks = new List<StockInfo> { new StockInfo { Symbol = "FCX", Quote = "Freeport McMoRan", Change = "3.72 (16.69%)", Day = "21.50 - 26.05", Time = "Nov 13" }, new StockInfo { Symbol = "YHOO", Quote = "Yahoo! Inc", Change = "0.81 (7.83%)", Day = "9.76 - 11.17", Time = "Nov 13" }, new StockInfo { Symbol = "GOOG", Quote = "Google Inc", Change = "21.08 (7.24%)", Day = "280.00 - 313.00", Time = "Nov 13" } }; return stocks.AsEnumerable(); } } }

 

Buat Halaman Html

Pada halaman html tambahkan MicrosoftAjax.js (atau MicrosoftAjax.debug.js untuk versi debug) pada project dengan add new existing item. File ini biasanya terdapat di C:\Program Files\Microsoft ASP.NET 3.5 Extensions\MicrosoftAjaxLibrary\System.Web.Extensions\3.6.0.0\3.6.20830.0

Tambahkan juga file MicrosoftAjaxTemplates.js (atau MicrosoftAjaxTemplates.debug.js untuk versi debug) yang didownload dari http://www.codeplex.com/aspnet. Pada halaman html referensikan kedua file javascript tersebut pada bagian header.

<script type="text/javascript" src="MicrosoftAjaxAdoNet.debug.js" ></script> <script type="text/javascript" src="MicrosoftAjaxTemplates.debug.js" ></script>

Buat style sys-template dengan style display: none untuk membuat template tidak ditampilkan sebelum di-bind.

<style type="text/css"> .sys-template { display:none; visibility:hidden; } </style>

Tambahkan beberapa namespace pada body tag.

<body xmlns:sys="javascript:Sys" xmlns:dataview="javascript:Sys.UI.DataView" sys:activate="*">

Terakhir buat template untuk menampilkan data.

<table border="1"> <thead> <tr> <td>Symbol</td> <td>Quote</td> <td>Change</td> <td>Day</td> <td>Time</td> </tr> </thead> <tbody id="stockListView" class="sys-template" sys:attach="dataview" dataview:serviceuri="StockService.svc" dataview:query="GetStocks"> <tr> <td>{{Symbol}}</td> <td>{{Quote}}</td> <td>{{Change}}</td> <td>{{Day}}</td> <td>{{Time}}</td> </tr> </tbody> </table>

Hasil akhir halaman tersebut seperti terlihat pada gambar berikut.

image

Dengan Web Development Helper dapat dilihat bahwa data yang dikirim dari server berupa JSON string, bukan html seperti pada UpdatePanel.

image

Dengan menggunakan ASP.NET Ajax client template, aplikasi jauh lebih cepat daripada UpdatePanel karena hanya data yang ditransmisikan antara client dan server. Ini ajax sebenarnya, bukan ajax bohong-bohongan dengan UpdatePanel.

Source-code contoh tersebut dapat diunduh dari link di bawah


Categories: ASP.NET AJAX
Permalink | Comments (7) | Post RSSRSS comment feed

Deserialize JSON String ke Strong-Type Object.

Tulisan ini merupakan kelanjutan dari post sebelumnya tentang Json Serializer dan Deserializer. Pada tulisan sebelumnya, string JSON dideserialize ke dalam Generic Dictionary. Kekurangan dari metode tersebut adalah kita tidak bisa menggunakan strong-type object untuk deserialize JSON. Metode tersebut juga sudah dianggap usang oleh .NET Framework 3.5 karena dalam framework tersebut sudah disediakan pengganti System.Web.Script.Serialization.JavaScriptSerializer yaitu System.Runtime.Serialization.Json.DataContractJsonSerializer.

Untuk dapat menggunakan System.Runtime.Serialization.Json.DataContractJsonSerializer perlu menambahkan dua assembly reference ke dalam project yaitu: System.Runtime.Serialization (butuh .NET Framework 3.0) dan System.ServiceModel.Web (butuh .NET Framework 3.5). Setelah kedua assembly ini direferensikan, beberapa hal yang perlu disiapkan diantaranya.

1. Tambahkan kedua namespace berikut

using System.Runtime.Serialization.Json; using System.Runtime.Serialization;

2. Buat class yang digunakan untuk men-deserialize JSON string.

Dalam contoh ini dibuat class berdasarkan JSON yang sama seperti tulisan sebelumnya (Json Serializer dan Deserializer). Struktur string JSON tersebut adalah:

var dateFormat = '<%= GlobalCallCenter.Common.CallCenterConfig.Get("SHORT_DATE_FORMAT") %>'; var filter = { instance: $get('<%= instanceList.ClientID %>').value, requestNo: $get('<%= requestNoTextBox.ClientID %>').value, category: $get('<%= categoryList.ClientID %>').value, itemCategory: $get('<%= itemAffectedList.ClientID %>').value, ticketGroup: $get('<%= ticketGroupList.ClientID %>').value, status: $get('<%= statusList.ClientID %>').value, requestType: $get('<%= typeList.ClientID %>').value, startDate: Date.parseLocale($get('<%= dateFromTextBox.ClientID %>').value, dateFormat), finishDate: Date.parseLocale($get('<%= dateToTextBox.ClientID %>').value, dateFormat), requestedFor: $get('requestedForEmployeeId').value, assigneeId: ($get('<%= assigneeForEmployeeId.ClientID %>') != null) ? $get('<%= assigneeForEmployeeId.ClientID %>').value : $get('<%= assigneeForEmployeeIdLabel.ClientID %>').innerHTML };


Dari JSON tersebut di atas, dibuat class sebagai berikut:

[DataContract(Name = "Filter", Namespace = "")] protected internal class Filter { [DataMember(Name = "instance", Order = 1)] public string Instance { get; set; } [DataMember(Name = "requestNo", Order = 2)] public string RequestNo { get; set; } [DataMember(Name = "category", Order = 3)] public string Category { get; set; } [DataMember(Name = "itemCategory", Order = 4)] public string ItemCategory { get; set; } [DataMember(Name = "ticketGroup", Order = 5)] public string TicketGroup { get; set; } [DataMember(Name = "status", Order = 6)] public string Status { get; set; } [DataMember(Name = "requestType", Order = 7)] public string RequestType { get; set; } [DataMember(Name = "startDate", Order = 9)] public DateTime StartDate { get; set; } [DataMember(Name = "finishDate", Order = 10)] public DateTime FinishDate { get; set; } [DataMember(Name = "requestedFor", Order = 10)] public string RequestedFor { get; set; } [DataMember(Name = "assigneeId", Order = 10)] public string AssigneeId { get; set; } }

3. Buat implementasi deserialization.

Seperti pada tulisan sebelumnya di Json Serializer dan Deserializer, saya gunakan contoh yang sama yaitu event callback pada Janus Grid sebagai berikut.

protected void GridEX1_CustomCallBack(object sender, Janus.Web.Common.CustomCallBackEventArgs e) { var edata = System.Web.HttpUtility.UrlDecode(e.EventData.ToString()); System.IO.MemoryStream stream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(edata.ToString())); DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Filter)); Filter filter = (Filter)serializer.ReadObject(stream); }

Dengan menggunakan strong-type kita langsung dapat mengakses property dari class tersebut, seperti terlihat pada gambar berikut.

image

Berbeda dari tulisan sebelumnya, dengan menggunakan strong-type object, semua property dapat diakses sesuai dengan tipe yang sudah didefinisikan.

Semoga bermanfaat.


Categories: ASP.NET AJAX | JavaScript | JSON
Permalink | Comments (8) | Post RSSRSS comment feed

JSON Serializer & Deserializer

Saya ingin berbagi sedikit tips mengenai JSON serializer dan deserializer yang ada di ASP.NET AJAX. Dengan menggunakan ASP.NET Ajax pertukaran data antara client (JavaScript) dengan server menjadi gampang banget. Kita tidak perlu lagi pake XMLyang rumit. Dengan JSON data mudah banget di-parse.

Contoh code di client (JS):

function getFilterData() { var dateFormat = '<%= HelpdeskSystem.DateFormat %>'; var filter = { instance: $get('<%= instanceList.ClientID %>').value, requestNo: $get('<%= requestNoTextBox.ClientID %>').value, category: $get('<%= categoryList.ClientID %>').value, itemCategory: $get('<%= itemAffectedList.ClientID %>').value, ticketGroup: $get('<%= ticketGroupList.ClientID %>').value, status: $get('<%= statusList.ClientID %>').value, requestType: $get('<%= typeList.ClientID %>').value, startDate: Date.parseLocale($get('<%= dateFromTextBox.ClientID %>').value, dateFormat), finishDate: Date.parseLocale($get('<%= dateToTextBox.ClientID %>').value, dateFormat), requestedFor: $get('requestedForEmployeeId').value, assigneeId: ($get('<%= assigneeForEmployeeId.ClientID %>') != null) ? $get('<%= assigneeForEmployeeId.ClientID %>').value : $get('<%= assigneeForEmployeeIdLabel.ClientID %>').innerHTML }; return Sys.Serialization.JavaScriptSerializer.serialize(filter); // Serialize object to JSON string }

Di server side (C#), tinggal di-deserialize. Dalam hal ini saya pake data JSON tersebut pada event CallBack Janus Grid:

protected void GridEX1_CustomCallBack(object sender, Janus.Web.Common.CustomCallBackEventArgs e) { System.Web.Script.Serialization.JavaScriptSerializer jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer(); var edata = System.Web.HttpUtility.UrlDecode(e.EventData.ToString()); var data = jsSerializer.DeserializeObject(edata); // data selanjutnya di prosess di sini }

Simple banget.

Hasil deserialize object ketika debugging tersebut dapat dilihat seperti gambar di bawah.

image

Dari gambar tersebut, string JSON telah di-deserialize menjadi object (string, Date, dll). Mudah bukan?

Semoga bermanfaat.


Categories: ASP.NET AJAX | JavaScript | JSON | Tips
Permalink | Comments (4) | Post RSSRSS comment feed

JSON vs XML

JSON (JavaScript Object Notation) merupakan format pertukaran data berdasarkan notasi JavaScript. Dari beberapa sumber mengatakan bahwa JSON lebih baik dari XML sebagai format pertukaran data. Benarkah demikian? Saya coba untuk membuat test sedarhana membandingkan kedua format data tersebut pada ASP.NET WebService.

Saya menggunakan dua parameter pembanding yaitu besar stream yang ditransmisikan dan response time. Untuk menganalisis kinerja keduanya saya gunakan tool buatan Nikhil Kotari yaitu Web Development Helper yang dapat di download dari situs pribadinya di Nikhil Kothari's Projects - Web Development Helper

Pertama saya buat sebuat object Employee dengan data EmpId, Name, Sex dan Title. object ini yang akan diserialisasi ke JSON dan XML sebagai return value WebService.

namespace JSONSample
{
    public class Employee
    {
        public string EmpId { get; set; }
        public string Name { get; set; }
        public string Title { get; set; }
        public char Sex { get; set; }
    }
}

Selanjutnya buat web service dengan dua method yang mengembalikan Employee dalam format JSON dan XML. Jangan lupa untuk menambahkan namespace System.Web.Script.Services dan class attribute [ScriptService]

using System;
using System.Collections;
using System.ComponentModel;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.Web.Script.Services;

namespace JSONSample
{
    /// <summary>
    /// Summary description for WebService1
    /// </summary>
    [WebService(Namespace = "">http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    [ScriptService]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
    // [System.Web.Script.Services.ScriptService]
    public class WebService1 : System.Web.Services.WebService
    {

        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
        public Employee GetEmployee(string EmpId)
        {
            var emp = new Employee();
            emp.EmpId = EmpId;
            emp.Name = "Ahmad Masykur";
            emp.Sex = 'M';
            emp.Title = "Analyst, Application Architecture";
            return emp;
        }
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public Employee GetEmployeeJSON(string EmpId)
        {
            var emp = new Employee();
            emp.EmpId = EmpId;
            emp.Name = "Ahmad Masykur";
            emp.Sex = 'M';
            emp.Title = "Analyst, Application Architecture";
            return emp;
        }
    }
}

Berikutnya adalah buat kode javascript untuk memanggil memanggil kedua method pada WebService yang telah dibuat sebelumnya.

var displayElement1;
var displayElement2;

// Initializes global variables and session state.
function pageLoad()
{
    displayElement1 = $get("ResultId1");
    displayElement2 = $get("ResultId2");
}
function getEmployee() {
    JSONSample.WebService1.GetEmployee("894683", OnSucceeded, OnFailed);
    JSONSample.WebService1.GetEmployeeJSON("894683", OnSucceeded, OnFailed);
}

// Callback function invoked on successful
// completion of the page method.
function OnSucceeded(result, userContext, methodName)
{
    if (methodName=="GetEmployee") { // xml
        displayElement1.innerHTML = result.documentElement.selectSingleNode('//Name').text;
    }
    else { // json
        displayElement2.innerHTML = result.Name;
    }
}

// Callback function invoked on failure
// of the page method.
function OnFailed(error, userContext, methodName)
{
    if(error !== null)
    {
        displayElement.innerHTML = "An error occurred: " +
            error.get_message();
    }
}

if (typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();

Terakhir buat halaman ASP.NET AJAX yang akan meregister JavaScript dan WebService sehingga WebService dapat dipanggil melalui JavaScript oleh ASP.NET AJAX proxy service.


<%@ Page Language="C#" AutoEventWireup="true" Inherits="System.Web.UI.Page" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server">    <title>Untitled Page</title></head><body>    <form id="form1" runat="server">    <div>        <asp:ScriptManager ID="ScriptManager1" runat="server">        <Scripts>            <asp:ScriptReference Path="~/clientscript.js" />        </Scripts>        <Services>            <asp:ServiceReference Path="~/WebService1.asmx" />        </Services>        </asp:ScriptManager>           <input type="button" value="Invoke" onclick="getEmployee()" />        <div id="ResultId1"></div>        <div id="ResultId2"></div>    </div>    </form></body></html>

Setelah dijalankan, aktifkan Web Development Helper dan check Enable Logging. Selanjutnya klik tombol Invoke tiga kali pada halaman dan periksa hasilnya.

image

Dari hasil keluaran log dapat dilihat bahwa dengan data yang sama, format XML memerlukan 226 byte sedangkan JSON hanya 132 byte. Ini jauh lebih kecil (kurang dari setengah) dibandingkan XML. Dari sisi response time, pada invoke yang pertama XML membutuhkan waktu 0:0:3430 sedangkan JSON 0:0:3280 dan invoke berikutnya untuk XML 0:0:0150 sedangkan JSON 0:0:0000. Dari data ini membuktikan bahwa JSON memang lebih ringan dibandingkan XML baik dari sisi ukuran stream yang ditransmisikan lebih kecil maupun waktu proses di server juga lebih singkat.


Tags: ,
Categories: ASP.NET AJAX | JavaScript | JSON
Permalink | Comments (15) | Post RSSRSS comment feed

Ajax Upload dengan Hidden IFrame

Salah satu permasalahan pada ASP.NET AJAX Update Panel adalah tidak dapat melakukan asynchronous communication pada proses upload file. Hal ini disebabkan karena pada dasarnya object XMLHttpRequest (XHR) tidak dapat mengirimkan sebuah file dengan alasan keamanan. Pada beberapa situs seperti Google Mail dan Community Server tetap dapat melakukan upload file tanpa me-refresh seluruh halaman.

Solusi Alternatif

Saah satu alternatif cara untuk melakukan upload tanpa harus me-refresh seluruh halaman adalah menggunakan IFrame yang tersembunyi (hidden IFrame). Pada halaman utama disisipkan sebuah iframe yang berisi sebuah halaman kosong dan pada form target halamannya diarahkan ke halaman kosong yang ada di dalam iframe tersebut. Dengan cara ini hanya bagian IFrame saya yang akan melakukan komunikasi dengan server tanpa mempengaruhi keseluruhan halaman.

Langkah langkah trik ini adalah sebagai berikut.

  1. Tambahkan hidden IFrame pada halaman dan set sembunyikan dengan style="display:none".


    <iframe name="hiddenFrame" src="blank.htm" mce_src="blank.htm" style="display:none"></iframe>

  2. Buat file blank.htm pada sollution.
    File ini dibutuhkan untuk memastikan bahwa IFrame masih dalam lingkup domain yang sama dengan halaman utama. Jika file blank.htm berada di luar domain (misal default blank.htm yang ada di komputer lokal) maka akan ada penolakan hak akses terhadap eksekusi script di luar domain.
  3. Tambahkan kontrol FileUpload ke dalam form

    <asp:FileUpload ID="fileUpload1" runat="server" />
  4. Buat fungsi submitForm yang berfungsi melakukan submit terhadap hidden IFrame.

    // Fungsi memiliki dua parameter yang berisi referensi element IFrame
    // dan element ID control FileUpload
    function submitForm(frameName,upload){
         // Diasumsikan bahwa halaman utama adalah default.aspx
         document.forms[0].action="default.aspx"
         // Inti dari trik ini adalah mengeset target form ke hidden IFrame
         document.forms[0].target=frameName;
         // setTimeout digunakan untuk mengupdate dokumen dengan thread yang terpisah,
         // jika tidak maka dokumen tidak akan baru terupdate setelah download selesai.
         window.setTimeout(function(){
             var uploadE=document.getElementById(upload);
             uploadE.parentElement.appendChild(document.createTextNode(uploadE.value));
             uploadE.parentElement.replaceChild(uploadE.cloneNode(true),uploadE);
         },100);
         document.forms[0].submit();
    }
  5. Buat tombol dan tambahkan attribute onclick untuk memanggil fungsi submitForm yang telah dibuat sebelumnya.

    <button onclick="javascript:submitForm('hiddenFrame','<%= fileUpload1.ClientID %>')">Upload</button>
  6. Tambahkan web kontrol label yang akan diisi dengan jam pertama kali halaman dimuat,

    <asp:Label ID="lblTime" runat="server" />
  7. Pada code behind, saat Page_Load set label dengan jam berjalan dan cek jika ada file yang diupload, simpan ke dalam server.

    protected void Page_Load(object sender, EventArgs e)
    {
         lblTime.Text = DateTime.Now.ToLongTimeString();
         if (fileUpload1.HasFile)
        {
             fileUpload1.SaveAs(Server.MapPath("App_Data/") + fileUpload1.FileName);
         }
    }
  8. Selesai

Dari langkah-langkah tersebut di atas, secara lengkap kode dapat dilihat sebagai berikut.

File default.aspx


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="HiddenIFrameUpload._Default" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server">    <title>Untitled Page</title></head><body>    <asp:Label ID="lblTime" runat="server" />    <iframe name="hiddenFrame" src="blank.htm" style="display:none"></iframe>    <form id="form1" runat="server" enctype="multipart/form-data" >         <div id="uploadContainer">              <asp:FileUpload ID="fileUpload1" runat="server" />              <button onclick="javascript:submitForm('hiddenFrame','<%= fileUpload1.ClientID %>')">Upload</button>         </div>     </form>    <script type="text/javascript">         function submitForm(frameName,upload){             document.forms[0].action="Default.aspx"             document.forms[0].target=frameName;             window.setTimeout(function(){                  var uploadE=document.getElementById(upload);                  uploadE.parentElement.appendChild(document.createTextNode(uploadE.value));                  uploadE.parentElement.replaceChild(uploadE.cloneNode(true),uploadE);             },100);             document.forms[0].submit();    }    </script></body></html>

File default.aspx.cs


using System;
using System.Web;

namespace HiddenIFrameUpload
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            lblTime.Text = DateTime.Now.ToLongTimeString();
            if (fileUpload1.HasFile)
            {
                fileUpload1.SaveAs(Server.MapPath("App_Data/") + fileUpload1.FileName);
            }

        }
    }
}

HiddenIFrameUpload.zip (5.88 kb)


Permalink | Comments (14) | Post RSSRSS comment feed

ASP.NET AJAX: UpdatePanel

UpdatePanel adalah salah satu control ASP.NET AJAX untuk melakukan partial rendering pada sebuah halaman. UpdatePanel bekerja bersama-sama dengan ScriptManager untuk membuat halaman web dengan rasa AJAX.

Partial Rendering

Partial-rendering adalah cara untuk memperbarui sebagian tampilan halaman, bukan keseluruhan halaman. Dibandingkan dengan melakukan postback dan reload keseluruhan halaman, partial-rendering memberikan banyak manfaat baik dari sisi kecepatan maupun efisiensi, karena hanya sebagian halaman saja yang diproses dan bukan keseluruhan halaman. Bagian halaman yang statis seperti logo dan beberapa teks statis lainnya tidak ikut diproses lagi.

Beberapa manfaat dari partial rendering adalah efisiensi sumberdaya (resources) baik di server maupun client dan efisiensi bandwidth yang digunakan. Di sisi server, server hanya akan memproses bagian halaman yang akan dirender, bukan keseluruhan halaman sebagaimana halaman ASP.NET konvensional. Di sisi client, browser juga hanya akan memproses sebagian dari halaman sehingga akan tampak lebih cepat dibandingkan reload keseluruhan halaman. Dari sisi bandwidth yang digunakan jelas lebih efisien karena data yang dilewatkan hanya sebagian dari halaman, sehingga menghemat bandwidth dengan tidak megirimkan data yang sama tiap kali postback.

Control UpdatePanel

UpdatePanel adalah sebuah control server yang untuk melakukan partial-rendering. Bersama dengan ScriptManager control server dan class PageRequestManager di client, UpdatePanel akan melakukan update pada daerah tertentu di halaman secara asinkron. Dengan menggunakan UpdatePanel, hanya element yang berada di dalam UpdatePanel yang akan diproses.

Gambar di bawah ini mengilustrasikan halaman yang dimuat pertama kali dan melakukan postback secara asinkron untuk mengupdate isi dari control UpdatePanel.

Untuk melakukan partial-rendering sangatlah mudah, tempatkan semua control yang akan dibuat partial-rendering ke dalam UpdatePanel Control. Jangan lupa, tempatkan satu  control ScriptManager pada halaman, UpdatePanel membutuhkan control ini untuk melakukan postback secara asinkron.

<script runat="server">
protected void Button1_Click(object sender, EventArgs e)
{
    Label1.Text = DateTime.Now.ToLongTimeString();
}
</script>
<form id="form2" runat="server">
<div>
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <asp:Label ID="Label2" runat="server" Text="Waktu server "></asp:Label><br />
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label><br />
            <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
        </ContentTemplate>
    </asp:UpdatePanel>
 </div>
</form>

Pada contoh di atas, semua control yang berada di dalam UpdatePanel bersifat partial-rendering. Semua postback dari control di dalam UpdatePanel dilakukan secara asinkron. Pada waktu Button1 di-click, dia akan memanggil method Button1_Click dan mengeset Label1.Text menjadi waktu server. Proses postback dilakukan secara asinkron, hanya control yang berada di dalam UpdatePanel yang berpengaruh.

Men-Trigger UpdatePanel dari Control di Luar UpdatePanel

Selain control yang berada di dalam UpdatePanel, UpdatePanel juga bisa di-trigger dari luar. Untuk melakukan hal ini, tambahkan element <asp:AsyncPostBackTrigger> yang ditempatkan di dalam element <Trigger> pada UpdatePanel. Set control ID dengan nama control yang akan mentrigger UpdatePanel tersebut. Element <Trigger> dapat berisi lebih dari satu element <asp:AsyncPostBackTrigger>

<script runat="server">
protected void Button1_Click(object sender, EventArgs e)
{
    Label1.Text = DateTime.Now.ToLongTimeString();
}
</script>
<form id="form2" runat="server">
<div>
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <asp:Label ID="Label2" runat="server" Text="Waktu server"></asp:Label><br />
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label><br />
        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="Button1" />
        </Triggers>
    </asp:UpdatePanel>
    <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
 </div>
</form>

Menampilkan Status Update dengan UpdateProgress

UpdateProgress digunakan untuk menampilkan informasi status dari UpdatePanel. Layout control UpdateProgress dapat diatur untuk mendapatkan tampilan yang menarik di dalam element <ProgressTemplate>. Kita dapat menempatkan element apapun (HTML element maupun control server ASP.NET) di dalam <ProgressTemplate>.

Untuk menerapkan UpdateProgress, cukup menempelkan control UpdateProgress pada halaman.

<script runat="server">
protected void Button1_Click(object sender, EventArgs e)
{
    System.Threading.Thread.Sleep(2000);
    Label1.Text = DateTime.Now.ToLongTimeString();
}
</script>
<form id="form2" runat="server">
<div>
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <asp:Label ID="Label2" runat="server" Text="Waktu server"></asp:Label><br />
    <asp:UpdateProgress ID="UpdateProgress1" runat="server">
    <ProgressTemplate>
      An update is in progress...
    </ProgressTemplate>
    </asp:UpdateProgress>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label><br />
        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="Button1" />
        </Triggers>
    </asp:UpdatePanel>
    <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
 </div>
</form>

Pada contoh di atas, terdapat baris System.Threading.Thread.Sleep(2000) di method Button1_Click. Baris ini digunakan untuk simulasi bahwa proses update sedang berjalan dengan menghentikan sementara proses selama 2 detik. Jika baris ini dihilangkan, pesan pada UpdateProgress akan ditampilkan dalam waktu yang sangat singkat sehingga tidak dapat terlihat. Pada project nyata, baris ini sebaiknya tidak digunakan.

Control UpdateProgress juga bisa diset property AssociatedUpdatePanelID untuk menentukan UpdatePanel mana yang akan men-trigger UpdateProgress ini. Jika property ini tidak di-set, maka tiap posback asinkron akan men-trigger UpdateProgress ini.

Dengan menggunakan UpdatePanel dan UpdateProgress, kita tidak perlu mendalami JavaScript untuk membuat aplikasi AJAX. Hanya dengan menempatkan UpdatePanel, aplikasi kita sudah bisa memanfaatkan kemampuan AJAX yang ringan, cepat serasa aplikasi desktop.


Categories: AJAX | ASP.NET AJAX
Permalink | Comments (31) | Post RSSRSS comment feed

Berkenalan dengan ASP.NET AJAX

ASP.NET AJAX (dulu disebut sebagai Atlas CTP) merupakan salah satu framework AJAX untuk ASP.NET 2.0. Dengan menggunakan ASP.NET AJAX, kita dapat membuat aplikasi web lebih responsif dan interaktif. Untuk membuat aplikasi web AJAX-enabled menggunakan ASP.NET AJAX sangatlah mudah. Programmer web dengan kemampuan Javascript terbatas pun bisa membuat aplikasi web yang resonsif dan interaktif menggunakan ASP.NET AJAX. ASP.NET AJAX dapat di-download di http://ajax.asp.net.

Beberapa keunggulan aplikasi web menggunakan ASP.NET AJAX dibandingkan dengan aplikasi web yang secara penuh berbasis server antara lain.

  • Lebih efisien karena sebagian proses dilakukan di browser.
  • Elemen UI yang lebih familiar seperti indikator proses, tooltips dan jendela pop-up.
  • Update sebagaian halaman yang hanya mengganti sebagian dari halaman web (partial rendering).
  • Integrasi client dengan ASP.NET application services untuk form authentikasi dan user profiles.
  • Framework yang mudah disesuaikan dengan kebutuhan sebagaimana server-control.
  • Mendukung sebagian besar browser terkenal termasuk Microsoft Internet Explorer, Mozilla Firefox dan Apple Safari.

Arsitektur ASP.NET AJAX

ASP.NET AJAX merupakan framework yang terdiri dari pustaka script client dan komponen server yang terintegrasi. ASP.NET AJAX juga didukung dengan ASP.NET AJAX Control Toolkit dan beberapa fitur tambahan lainnya.

Ilistrasi berikut menggambarkan fungsionalitas yang ada pada pustaka client script dan komponen server ASP.NET AJAX.

Arsitektur server dan client ASP.NET AJAX

Arsitektur Server ASP.NET AJAX

Komponen server ASP.NET AJAX terdiri dari kontrol-kontrol web server ASP.NET dan komponen-komponen untuk mengatur UI dan alur aplikasi, juga mengatur serialization, validasi, pengembangan control server, dan lain sebagainya.

Control-control Server ASP.NET AJAX

Control-control server ASP.NET AJAX terdiri dari kode server dan client yang terintegrasi untuk membangun cita rasa AJAX. Berikut adalah daftar dari kontrol-kontrol server yang sering digunakan.

  1. ScriptManager
    Mengatur sumberdaya script komponen-komponen client, merender bagian dari halaman, localization, globalization, dan custom user script. Script manager dibutuhkan oleh UpdatePanel, UpdateProgress dan kontrol Timer.
  2. UpdatePanel
    Digunakan untuk membuat rendering sebagian halaman (partial rendering), bukan keseluruhan halaman.
  3. UpdateProgress
    Memberikan informasi mengenai status bagian halaman yang ter-update dalam kontrol UpdatePanel.
  4. Timer
    Melakukan postback ke server berdasarkan interval waktu yang telah ditentukan. Kontrol Timer dapat digunakan untuk melakukan postback keseluruhan halaman atau sebagaian halaman yang ada dalam UpdatePanel.

Web Services ASP.NET AJAX

ASP.NET AJAX menyediakan web services yang dapat digunakan oleh script client dan dapat bekerja bersama dengan application services ASP.NET. Dengan menggunakan ASP.NET AJAX, pemanggilan web service menggunakan script client dapat dilakukan dengan mudah karena telah disediakan komponen network di dalamnya.

Kemampuan Control Server ASP.NET AJAX untuk Dikembangkan

Control-control ASP.NET AJAX baru dapat dibuat sesuai dengan kebutuhan. Dengan kemampuan ini, server kontrol ASP.NET AJAX dapat terus berkembang sesuai dengan kebutuhan. Beberapa control ASP.NET AJAX yang telah siap pakai dapat ditemukan di Microsoft ASP.NET AJAX Control Toolkit.

Arsitektur Client ASP.NET AJAX

Pustaka script client ASP.NET AJAX  terdapat pada beberapa file (.js). Beberapa layer yang ada di pustaka ASP.NET AJAX antara lain:

  • Layer browser compatibility. Layer ini menyediakan kompatibilitas sebagian besar browser populer (termasuk Microsoft Internet Exploere, Mozilla Firefox, dan Apple Safari).
  • Service inti ASP.NET AJAX, yang mengandung komponen-komponen inti seperti clases, namespaces, event handling, inheritance, tipe data, dan serialisasi object.
  • Pustaka class ASP.NET AJAX, berisi komponen-komponen seperti string builder dan penanganan error tingkat lanjut.
  • Layer network yang menangani komunikasi antara service client web dengan aplikasi dan mengatur pemanggilan method secara asinkron.
  • Dukungan pustaka JavaScript yang terkandung dalam assembly atau berada dalam file (.js). Penyatuan script JavaScript ke dalam assembly dapat mempermudah pemasangan aplikasi (deployment) dan memecahkan masalah versioning.
  • Dukungan atas pengaksesan server-based forms authentication dan informasi profile dalam script client. Dukungan ini juga terdapat pada aplikasi web yang tidak dibuat dengan ASP.NET selama aplikasi tersebut menggunakan pustaka ASP.NET AJAX.
  • Dukungan atas mode release dan debug serta mendukung localization yang tertanam dalam assembly maupun terpisah dalam file JavaScript.

Debuging

Arsitektur ASP.NET AJAX menyediakan model untuk mode release dan debug. Pada mode release, pemeriksaan error dan penanganan exception telah dioptimasi untuk performance dengan script yang minimum. Pada mode debug, menyediakan lebih banyak fitur seperti pengecekan type dan argument.

Dalam class debug helper (Sys.Debug) tersedia method-method untuk menampilkan object-object ke dalam form yang mudah dibaca pada bagian bawah halaman web. Helper ini juga menampilkan pesan trace untuk melakukan assertions dan break ke debugger.

Localization dan Globalization

Pada arsitektur ASP.NET AJAX server dan client tersedia mekanisme model localization dan globalization pada script client. Dengan fitur ini, kita dapat merancang aplikasi dengan berbagai macam locale UI (bahasa dan kultur) menggunakan satu basis kode. Sebagai contoh, untuk menampilkan tanggal atau angka, ASP.NET AJAX akan memformat tampilan sesuai dengan seting culture pada browser pengguna tanpa harus melakukan postback ke server.

ASP.NET AJAX Control Toolkit

ASP.NET AJAX Control Toolkit adalah kumpulan contoh-contoh komponen kontrol yang memanfaatkan kemampuan ASP.NET AJAX. Kontrol-kontrol ini dapat di-download di situs ASP.NET AJAX.


Categories: AJAX | ASP.NET AJAX
Permalink | Comments (22) | Post RSSRSS comment feed