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

Gunakan jQuery untuk Mendapatkan Client ID ASP.NET Server Control

jQuery merupakan salah satu library JavaScript yang sangat handal. Berdasarkan informasi dari blog ScottGu di http://weblogs.asp.net/scottgu/archive/2008/09/28/jquery-and-microsoft.aspx, menyatakan bahwa jQuery akan diintegrasikan dengan ASP.NET Ajax. Kemampuan jQuery untuk melakukan query terhadap DOM sangat membantu dalam penulisan kode JavaScript. Dengan jQuery tidak perlu lagi hawatir terhadap perbedaan penulisan pada beberapa browser, cukup dengan satu syntax akan berjalan dengan baik di beberapa browser populer.

Dalam tulisan ini saya akan menunjukkan kemampuan jQuery dalam melakukan query DOM yang di-generate oleh ASP.NET Server Control. Permasalahan utama adalah server control akan membangkitkan client ID secara dynamic jika control tersebut berada di dalam control lain.

Contoh, jika kita membuat page di dalam Master Page, kode server control dalam page berada di dalam Content place holder di berikut:

<asp:Content ID="DefaultContainer" ContentPlaceHolderID="cpMain" runat="server"> <asp:TextBox ID="TextBox1" runat="server" Text="Test"></asp:TextBox> </asp:Content>

akan terender di browser menjadi

<input name="ctl00$cpMainTextBox1" type="text" value="Test" id="ctl00_cpMain_TextBox1" />

Untuk mendapatkan DOM dari input box di atas dari JavaScript tidak dapat dilakukan dengan menyebutkan ID control secara langsung dengan code berikut.

<script type="text/javascript"> <!-- var textBox1 = document.getElementById('TextBox1'); // --> </script>

Control ID akan secara otomatis berubah menjadi unique ID seperti terlihat pada hasil render code di atas sehingga kode getElementById tidak akan pernah menemukan DOM yang dimaksud. Untuk menangani masalah ini dapat dilakukan dengan menuliskan kode JavaScript dalam satu file dengan halaman (file .aspx). Contoh:

<script type="text/javascript"> <!-- var textBox1 = document.getElementById('<%= TextBox1.ClientID %>'); // --> </script>

Dengan cara tersebut memang bisa tapi halaman jadi tampak semrawut karena campur aduk antara tag HTML dan JavaScript. Proses debugging JavaScript dengan metode tersebut juga lebih sulit karena break point tidak bisa diset sebelum halaman dijalankan. Dengan menggunakan jQuery, untuk mendapatkan client ID dari server control dapat dilakukan dengan cara:

<script type="text/javascript"> <!-- var textBox1 = $("input[name$='TextBox1']"); // --> </script>

Kode di atas artinya melakukan query terhadap semua element INPUT yang memiliki attribute name dengan akhiran "TextBox1". Apapun prefix yang dirender oleh ASP.NET, TextBox1 akan selalu terender sebagai akhiran client ID. Dengan menggunakan jQuery, tidak perlu lagi kode JavaScript menjadi satu dalam halaman HTML. Hal ini mempermudah proses debugging dan meningkatkan performance karena kode JavaScript dapat di-cache oleh browser / server.


Tags:
Categories: ASP.NET | JavaScript
Permalink | Comments (12) | Post RSSRSS comment feed

ASP.NET MVC Preview 5 is Now Available on Codeplex

A few days ago, ASP.NET MVC Preview 5 has been released that can be downloaded from http://www.codeplex.com/aspnet. In this release has two new stuffs: (a) Added global registration of view engine; (b) Changed the IVieew engine interface to add the RenderPartial method. Other improvements are: Added support for rendering partial view, added a parameter to specify a default option label for DropDownList control, Moved ASP.NET AJAX extension methods to a separate namespace, Added helpers for RadioButton and TextArea controls and made overall improvement to other helpers, and Remove helper method overloads to avoid ambiguity.

This new release has been used Routing Engine (System.Web.Routing) that shipped with Microsoft .NET Framework SP1. Make sure uninstall previous first before upgrade this release from previous release. This release is not compatible with Microsoft Visual Studio 2008 SP1 beta thus uninstall it first and install new RTM version of SP1. For more information about upgrading and installation, please read release notes that can be downloaded separately from installer package.


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

Server Application Unavailable

Sering kali, saya mendapatkan pesan error "Server Application Unavailable" ketika pertamakali setup IIS dan ASP.NET di komputer baru. Pesan lengkap dapat dilihat pada paragrap berikut.

Server Application Unavailable

The web application you are attempting to access on this web server is currently unavailable.  Please hit the "Refresh" button in your web browser to retry your request.

Administrator Note: An error message detailing the cause of this specific request failure can be found in the application event log of the web server. Please review this log entry to discover what caused this error to occur.

 

Setelah dicek di event viewer ternyata aspnet_wp.exe (WinXP) tidak dapat berjalan karena kekurangan hak akses untuk mengakses sumber daya .NET Framework. Untuk mengatasi permasalahan ini sangat sederhana cukup tambahkan group "LocalComputer\Users" dari 3 user berikut ke.

  1. IWAM_<ComputerName> contoh: AMASYKUR\IWAM_AMASYKUR
  2. IUSR_<ComputerName> contoh: AMASYKUR\IUSR_AMASYKUR
  3. ASPNET

Setelah ketiga ketiga user tersebut ditambahkan sebagai member group Users, reset IIS dengan perintah

C:\WINDOWS\system32>iisreset

Attempting stop...
Internet services successfully stopped
Attempting start...
Internet services successfully restarted

Berhasil deh....


Tags: ,
Categories: ASP.NET
Permalink | Comments (12) | Post RSSRSS comment feed

Masalah ASP.NET pada Oracle 9i: Unable To Load oci.dll

Salah satu masalah ketika membuat aplikasi ASP.NET 2.0 dengan database Oracle 9i adalah instance ASP.NET tidak bisa mengakses driver oracle client (oci.dll). Ini terjadi karena instance ASP.NET tidak memiliki hak akses execute ke file oci.dll yang berada di folder instalasi Oracle Client.

Solusinya dari permasalahan ini cukup mudah. Cari folder tempat file oci.dll berada dan berikan hak akses read & execute pada folder tersebut. Klik tombol [Adcanced] dan centang pilihan "Replace permission entries on all child objects with entries shown here that apply to child objects."

Buka kembali halaman ASP.NET, semoga berhasil.


Categories: ASP.NET
Permalink | Comments (8) | 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

Select, Insert, Update, Delete Tanpa Kode dengan SqlDataSource, DetailsView dan GridView

GridView merupakan web control pada ASP.NET 2.0 yang digunakan untuk menampilkan data dalam format tabel, disajikan dalam format baris dan kolom. GridView akan dirender pada browser sebagai HTML table. GridView memiliki kemampuan untuk menampilkan, megubah (edit) dan menghapus (delete) data hanya dengan beberapa langkah tanpa menuliskan satu baris kode pun. GridView dapat dengan mudah dikonfigurasi untuk membuat tampilan yang dibagi menjadi beberapa halaman (pagging), pengurutan (sorting) dan pengubahan (editing) tanpa menuliskan banyak kode.

GridView tidak memiliki kemampuan untuk melakukan penambahan data (insert), maka untuk melakukan penambahan data digunakan DetailsView control. DetailsView control digunakan untuk menampilkan satu record data dalam format tabel. Tiap field dalam row ditampilkan sebagai baris pada tabel.

Binding Data

Binding Data ke SqlDataSource

Binding data ke database dapat dilakukan dengan menggunakan SqlDataSource. SqlDataSource merupakan representasi data pada database relasional SQL yang digunakan pada data-bound control. SqlDataSource bersama dengan data-bound control dapat digunakan untuk menampilkan, edit, dan pengurutan data pada halaman web dengan kode yang singkat atau bahkan tanpa kode program sama sekali.

SqlDataSource dapat dihubungkan dengan semua database yang menggunakan ADO.NET provider seperti SqlClient, OleDb, Odbc, atau OracleClient. Set property ConnectionString untuk dapat berhubungan dengan database. ConnectionString dapat diambil dari Web.config. Untuk mengambil data dari database, cukup dengan menuliskan query pada property SelectCommand. Demikian juga untuk insert, update dan delete cukup dengan memasukkan query ke dalam InsertCommand, UpdateCommand dan DeleteCommand. Jika database yand diguakan mendukung stored procedure, property SelectCommand, InsertCommadn, UpdateCommand dan DeleteCommand juga dapat diisi dengan nama stored procedure. Query SQL juga mendukung query yang mengandung parameter. Untuk menambahkan parameter cukup tambahkan object Parameter pada collection pada masing-masing command.

Langkah untuk membuat SqlDataSource sebagai berikut.

Sebelum membuat object SqlDataSource, buat dulu tabel yang akan digunakan. Buat tabel AddressBook sederhana yang menyimpan nama, alamat dan nomor telepon.


CREATE TABLE AddressBook (
    AddressId   int   IDENTITY(1,1) NOT NULL,
    FullName    nvarchar(50)   NOT NULL,
    Address      nvarchar(150) NOT NULL,
    PhoneNumber nvarchar(20)   NOT NULL )

Berikutnya, buat connectionstring. ConnectionString dapat ditulis langsung pada property SqlDataSource atau dapat juga dimasukkan ke dalam Web.config.


<connectionStrings>

    <add name="TestDBConnectionString"

        connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=TestDB;Integrated Security=True"

        providerName="System.Data.SqlClient" />

</connectionStrings>

Selanjutnya buat object SqlDataSource dengan memasukkan query insert, select, update dan delete dan connectionstring di ambil dari Web.config.


<asp:SqlDataSource ID="SqlDataSource1" runat="server"
    ConnectionString="<%$ ConnectionStrings:TestDBConnectionString %>"
        ProviderName="System.Data.SqlClient"
        SelectCommand="SELECT AddressId, FullName, Address, PhoneNumber FROM AddressBook ORDER BY FullName"
        UpdateCommand="UPDATE AddressBook SET FullName=@FullName, Address=@Address, PhoneNumber=@PhoneNumber WHERE AddressId=@AddressId"
        DeleteCommand="DELETE FROM AddressBook WHERE AddressId=@AddressId"
        InsertCommand="INSERT INTO AddressBook (FullName, Address, PhoneNumber) VALUES (@FullName, @Address, @PhoneNumber)">
</asp:SqlDataSource>

Setelah tabel dan SqlDataSource sudah siap, berikutnya adalah pembuatan GridView dan DetailsView

GridView dan DetailsView

Buat page baru dan tempatkan GridView dalam page. Tambahkan kolom FullName, Address dan PhoneNumber ke dalam GridView, set property DataSourceID dengan ID SqlDataSource yang dibuat sebelumnya. Kemudian set property DataKeyFields dengan primary key tabel dan set property AutoGenerateColumns menjadi false.


<asp:GridView ID="gridPhoneBook" runat="server"
DataKeyNames="AddressId"
AutoGenerateColumns="False"
AllowPaging="True"
Caption="Address Book"
DataSourceID="SqlDataSource1"
EmptyDataText="No data to display">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:BoundField DataField="FullName" HeaderText="Full Name" />
<asp:BoundField DataField="Address" HeaderText="Address" />
<asp:BoundField DataField="PhoneNumber" HeaderText="Phone Number" />
</Columns>
</asp:GridView>

Selanjutnya buat DetailView untuk menambahkan record ke dalam tabel.


<asp:DetailsView ID="detailPhoneBook" runat="server"
AutoGenerateRows="False" DataKeyNames="AddressId"
DataSourceID="SqlDataSource1"
Caption="Details"
AllowPaging="true">
<Fields>
<asp:BoundField DataField="FullName" HeaderText="Full Name" />
<asp:BoundField DataField="Address" HeaderText="Address" />
<asp:BoundField DataField="PhoneNumber" HeaderText="Phone Number" />
<asp:CommandField ShowInsertButton="True" />
</Fields>
<EmptyDataTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="False" CommandName="New" Text="New">
</asp:LinkButton>
</EmptyDataTemplate>
</asp:DetailsView>

Pada declarative kode di atas, EmptyDataTemplate digunakan untuk menampilkan tombol New jika tabel masih dalam keadaan kosong. Jika tabel dalam keadaan kosong, tombol New yang dihasilkan dari CommandField ShowInsertButton="true" tidak akan muncul.

Demikian paparan singkat pemanfaatan GridView, DetailsView untuk manipulasi data dengan menggunakan SqlDataSource. Semoga bisa bermanfaat bagi yang baru mulai belajar ASP.NET.


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

Membuat HttpHandler untuk Resize Image

Ketika membuat sebuah galeri foto, sering kali harus membuat beberapa versi ukuran foto. Foto-foto kecil ditampilkan secara berjajar. Ketika foto diklik, akan muncul foto dengan ukuran besar. Pada waktu slide-show, maka foto ukuran sedang yang ditampilkan. Untuk membuat foto dengan ukuran yang bermacam-macam dapat dilakukan dengan merubah ukuran secara run-time.

Berikut adalah class untuk melakukan resize ukuran image.

public class PhotoManager {
    public static byte[] ResizeImageFile(byte[] imageFile, int targetSize) {
        using (System.Drawing.Image oldImage = System.Drawing.Image.FromStream(new MemoryStream(imageFile))) {
            Size newSize = CalculateDimensions(oldImage.Size, targetSize);
            using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height, PixelFormat.Format24bppRgb)) {
                using (Graphics canvas = Graphics.FromImage(newImage)) {
                    canvas.SmoothingMode = SmoothingMode.AntiAlias;
                    canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize));
                    MemoryStream m = new MemoryStream();
                    newImage.Save(m, ImageFormat.Jpeg);
                    return m.GetBuffer();
                }
            }
        }
    }

    private static Size CalculateDimensions(Size oldSize, int targetSize) {
        Size newSize = new Size();
        if (oldSize.Height > oldSize.Width) {
            newSize.Width = (int)(oldSize.Width * ((float)targetSize / (float)oldSize.Height));
            newSize.Height = targetSize;
        } else {
            newSize.Width = targetSize;
            newSize.Height = (int)(oldSize.Height * ((float)targetSize / (float)oldSize.Width));
        }
        return newSize;
    }
}

Dalam kode di atas, targetSize merupakan target panjang image yang akan diperoleh. Untuk mengirimkan gambar ke client, dibutuhkan sebuah handler.

Berikut adalah handler mengirimkan image ke client. Kode dibawah disimpan dalam file dengan extention .ashx yang akan dikerjakan oleh web server sebagai sebuah web handler.

<%@ WebHandler Language="C#" Class="Handler" %>

using System;
using System.IO;
using System.Web;

public class Handler : IHttpHandler {

	public bool IsReusable {
		get {
			return true;
		}
	}
	
	public void ProcessRequest (HttpContext context) {
		// Set up the response settings
		context.Response.ContentType = "image/jpeg";
		context.Response.Cache.SetCacheability(HttpCacheability.Public);
		context.Response.BufferOutput = false;
		// Get photo from file system
        string filename = context.Request.QueryString("FileName");
        if (filename != null)
        {
            using (FileStream fileStream = new FileStream(context.Server.MapPath("images\\" + filename)))
            {
                using (BinaryReader reader = new BinaryReader(fileStream))
                {
                    byte[] imageFile = reader.ReadBytes(fileStream.Length);
                    byte[] stream;
                    stream = (context.Request.QueryString("Size") != null) ? PhotoManager.ResizeImageFile(imageFile, int.Parse(context.Request.QueryString("Size"))) : imageFile;
                    // Write image stream to the response stream
                    const int buffersize = 1024 * 16;
                    byte[] buffer = new byte[buffersize];
                    int count = stream.Read(buffer, 0, buffersize);
                    while (count > 0)
                    {
                        context.Response.OutputStream.Write(buffer, 0, count);
                        count = stream.Read(buffer, 0, buffersize);
                    }
                }
            }
        }
    }
}

Pada halaman web tinggal panggil handler yang telah dibuat dengan querystring nama file dan ukuran image.

<img src="Handler.ashx?FileName=myimage.jpg&Size=320"style="border:4px solid white" alt="My Image" />

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

Menulis Alamat Email yang Aman dari Spam

Spam adalah penyalahgunaan dalam penampilan berita elektronik untuk pengiriman berita iklan dan keperluan lainnya yang mengakibatkan ketidaknyamanan bagi para pengguna web (http://id.wikipedia.org/wiki/Spam). Sering kali kita mendapatkan email spam.

Dari mana email spam itu berasal? Bagaimana si pengirim spam mengetahui alamat email kita? Ada banyak cara yang dapat dilakukan oleh pengirim email spam untuk mendapatkan alamat email. Salah satu cara yang banyak digunakan adalah dengan mencari pola email dari halaman-halaman yang dipublikasikan. Pola emal sangat unik yaitu nama@domain sehingga dengan mudah dikenali bahwa itu adalah alamat email. Dengan menggunakan robot untuk membaca halaman-halaman web yang saling berkaitan, digunakan regular expression sederhana maka semua alamat email dalam satu halaman dapat diambil oleh si pengirim spam.

Untuk menanggulangi pembacaan alamat email oleh spam dapat dilakukan dengan berbagai cara, salah satu cara adalah dengan mengubah tulisan yang masih bisa dipahami oleh manusia tapi tidak terbaca oleh robot. Perubahan tulisan yang umum digunakan adalah emailku@domainku.web.id ditulis menjadi:

  • emailku[at]domainku[dot]web[dot]id
  • emailkuNOSPAM@domainku.web.id (dengan menambahkan keterangan "hilangkan NOSPAM")
  • emailku^at^domainku.web.id
  • dan lain sebagainya.

Dengan merubah penamaan alamat email, minimal mengurangi jumlah robot yang bisa membaca alamat email yang dipublikasikan tersebut. Namun robot yang lebih cerdas juga dapat membaca pola-pola yang umum tersebut. Salah satu trik untuk melindungi publikasi alamat email dari spam robot adalah menggunakan Javascript karena biasanya robot sangat sulit untuk menterjemahkan Javascript.

// Opens the caller's default e-mail client
// with the subject filled if specified.
function SafeMail(name, domain, subject)
{
  if (subject != null)
    subject = "?subject=" + subject;
  location.href="mailto:" + name + "@" + domain + subject;
}

Script di atas sebenarnya hanya untuk menyembunyikan pola penulisan mailto:nama@domain dengan sebuah fungsi Javascript. Fungsi tersebut digunakan untuk menggabungkan potongan-potongan pola email menjadi pola email yang sebenarnya.

Berikut contoh penulisan pada halaman html untuk menyembunyikan pola email dengan fungsi di atas.

<h1>About the author</h1> 
<div class="vcard">
<span class="fn">Ahmad Masykur</span> is a software developer at <a href="http://www.bataviasoft.com/">
<span class="org">Bataviasoft</span></a> 
<span class="adr"><span class="locality">Jakarta</span> 
<span class="country-name">Indonesia</span></span>.
</div> 
<!-- Email -->
<div style="float:right;">
<a href="javascript:SafeMail('ahmad', 'masykur.web.id', 'Menulis Alamat Email yang Aman dari Spam')">E-mail me</a>
</div>

Dengan cara tersebut, yang ditampilkan di halaman hanyalah tulisan E-mail me. Pada waktu link di-klik, otomatis akan membuka email-client yang telah tersisi alamat email dan subject.


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

Upload dan Download File

Upload file di ASP.NET dapat menggunakan ASP.NET Web Control FileUpload. Untuk implementasi upload tinggal pasang control FileUpload dan satu Button.

<asp:FileUpload ID="fileUpload" runat="server" Width="300" />
<asp:Button id="btnUpload" runat="server" Text="Upload" />

Pada codebehind, buat handler untuk btnUpload.Click

Private Sub btnUpdate_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnUpdate.Click
    Try
        Dim objFile As FileInfo = New FileInfo

        If fileUpload.PostedFile Is Nothing Then
            Exit Sub
        End If
        If Not fileUpload.HasFile Then
            Exit Sub
        End If

        Dim path As String = Me.MapPath("files/")
        path = path.Replace("/", "\")
        If Not Directory.Exists(path) Then
            Directory.CreateDirectory(path)
        End If
        fileUpload.SaveAs(path + fileUpload.PostedFile.FileName)

    Catch exc As Exception    
        'Exception code here
    End Try
End Sub

Untuk download file, kita bisa menggunakan Response untuk mengirimkan data ke client. Misalkan ada sebuat tombol untuk download, handler tombol tersebut dapat ditulis sebagai berikut.

Dim path As String = Me.MapPath("files/")
path = path.Replace("/", "\")
Dim namafile As String = "namafile.ext"
Response.Clear()    'Bersihkan buffer stream
'Tambahkan header namafile
Response.AppendHeader("content-disposition", "attachment; filename=" + namafile)
Response.WriteFile(path + namafile)
Response.End()
Response.Close()

Jika file yang diupload perlu diolah terlebih dahulu atau disimpan dalam database, maka file tersebut dapat dibaca menggunakan BinaryReader. Berikut contoh sederhana untuk melakukan enkripsi sebelum file disimpan di filesystem atau database.

Private Sub btnUpdate_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnUpdate.Click
    Try
        Dim objFile As FileInfo = New FileInfo

        If fileUpload.PostedFile Is Nothing Then
            Exit Sub
        End If
        If Not fileUpload.HasFile Then
            Exit Sub
        End If

        Dim path As String = Me.MapPath("files/")
        path = path.Replace("/", "\")
        If Not Directory.Exists(path) Then
            Directory.CreateDirectory(path)
        End If
        Dim uploadedStream As New BinaryReader(fileUpload.PostedFile.InputStream)
	  Dim bytesStream As Byte() = uploadedStream.ReadBytes(fileUpload.PostedFile.ContentLength)
        'Tutup stream
        uploadedStream.Close()
        'Panggil fungsi enkripsi (contoh)
        Dim cipherStream As Byte() = Encrypt(bytesStream)
        'Simpan hasil enkripsi dalam filesystem
        Using _fileStream As New FileStream(path + fileUpload.FileName, FileMode.Create, FileAccess.Write)
            _fileStream.Write(cipherStream, 0, cipherStream.Length)
            _fileStream.Flush()
            _fileStream.Close()
        End Using
    Catch exc As Exception    
        'Exception code here
    End Try
End Sub

Jika file telah dienkripsi, maka pada waktu download file tersebut juga harus didekripsi sebelum dikirimkan ke client.

path = path.Replace("/", "\") 
Dim namafile As String = "namafile.ext" 
'Buka stream
Dim _fileStream As New FileStream(path + namafile, FileMode.Open, FileAccess.Read)
Dim _binReader As New BinaryReader(_fileStream)
Dim _cipherStream As Byte() = _binReader.ReadBytes(_fileStream.Length)
_binReader.Close()
_fileStream.Close()
'Panggil fungsi dekripsi (contoh)
Dim _plainStream As Byte() = Decrypt(_cipherStream)
'Kirim stream ke client
Response.Clear() 'Bersihkan buffer stream 
'Tambahkan header namafile 
Response.AppendHeader("content-disposition", "attachment; filename=" + namafile) 
Response.BinaryWrite(plainStream)
Response.Flush()
Response.End() 
Response.Close()

Semoga bermanfaat


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