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

Resolving Issue: Unable to Install Nokia WRT Plugin on Visual Studio 2008 Team Suite

I have downloaded Nokia Web Runtime Plugins for Visual Studio to develop web-based widget on Symbian device. I have problem to Install WRT on my VSTS 2008 SP1.  When install the plugins, I’m always getting message “The setup requires Microsoft Visual Studio 2008 Service Pack 1. Please install Visual Studio 2008 Service Pack 1 and run this setup again”. What’s wrong? I have an instance of Microsoft Visual Studio Team System 2008 Team Suite  with the SP1 which is VS90sp1-KB945140-ENU.exe installed.

image

I have solution from Nokia forum. It is a bug of WRT installer that mistype the installation condition checking. To resolve issue:

  1. Download the Orca MSI editor.
  2. Open the WRT plugin MSI with Orca.
  3. Get the table _VsdLaunchCondition.
  4. Here is the string for Visual Studion version checking.
  5. Replace VS2008TS_SP strings (2 times) with VSTS2008TS_SP.
  6. Save and Close.
  7. Viola, the installation is working now.

Permalink | Comments (0) | Post RSSRSS comment feed

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

Installing TwitterPing Extension for BlogEngine.NET

After a few months no blogging to this site. I will start to blogging again with installing new extension into my blog. I have found a good extention to ping my twitter account (http://twitter.com/cahnom)  every new blog post has been created. You can download the extension from here.

Installation is quite simple:

  1. Extract TwitterPing10Extension.zip file in your local system
  2. Upload file Yedda.Twitter.dll to BlogEngine's \Bin folder
  3. Upload file TwitterPing.cs to BlogEngine's \App_Code\Extensions
  4. Enter your username and password under the Extensions tab in the administration pane
  5. You are ready to go. Test it.

Happy blogging.


Categories: Twitter | BlogEngine
Permalink | Comments (0) | Post RSSRSS comment feed

Create DeepZoom with/without Silverlight using Seadragon

Seadragon is Deep Zoom implementation purely using JavaScript without Silverlight. You can zoom in/out using mousewheel and drag it to pan arround as sample picture below.

To create seadragon like picture above, you can upload your image to http://seadragon.com. You will receive unique URL after uploading images is done which can be embedden to your web page. Seadragon will automatically checking your machine. If you have Silverlight installed on your machine, Silverlight version will be used. If Silverlight is not installed yet, Seadragon will use javascript version.


Permalink | Comments (0) | Post RSSRSS comment feed

Silverlight 3.0 Available for Download Today

Microsoft officials wouldn’t say a month ago whether the actual Silverlight 3 bits would be available by the day of the official launch, which is July 10. But it turns out they are available a day earlier.

If you try to install this version but you have already Silverlight 2.0 for Developer installed on your machine, you will get error message: Unable to install Silverlight. Your Silverlight developer components are out of date.

image

If you are not a developer and want to avoid this error, please uninstall previous Silverlight version first by following the Silverlight Uninstall Instructions. If you are a developer, download and install Silverlight 3.0 for Developer here.

image

Installation will upgrade current version of Silverlight on your machine. You do not need to install Silverlight 3.0 if you have installed Silverlight 3.0 for developer.

image

Same as previous version, Silverlight shipped not followed with developer tools. Expression Blend 3 and Silverlight Tools for Visual studio still Beta or RC. Expression Blend 3 + SketchFlow RC available for download from http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=92e1db7a-5d36-449b-8c6b-d25f078f3609. I'm still waiting for RTM version of developer tools.


Categories: Silverlight
Permalink | Comments (4) | Post RSSRSS comment feed

Create IE8 Accelerator for BlogEngine.NET 1.5

I have created IE8 WebSlices for BlogEngine.NET 1.5 yesterday. I will add new feature stuff to BlogEngine to support IE8 features. Today, I have wrote new IE8 accelerator for BlogEngine.NET 1.5. I’m added new handler named AcceleratorHandler to BlogEngine to handle accelerator request. This handler provide accelerator XML information and preview page.

I have add new menu named Accelerator in my BlogEngine theme.

image

Click Accelerator menu to add the accelerator and then click Add button on the confirmation dialog window.

image

If we navigate away from our site and want to search text from our site. Select text inside the page and navigate to the accelerator. Now you can search from your site anywhere. Here is screen capture of the accelerator.

image

To enable this feature to BlogEngine.NET. Please follow steps below.

Create AcceleratorHandler

Create new handler for accelerator in BlogEngine.Core project. Here is the source code of the accelerator.

using System;
using System.Collections.Generic;
using System.Web;
using System.Xml;
using System.IO;
using System.Web.UI;
namespace BlogEngine.Core.Web.HttpHandlers
{
    class AcceleratorHandler : IHttpHandler
    {
        #region IHttpHandler Members
        public bool IsReusable
        {
            get { return false; }
        }
        public void ProcessRequest(HttpContext context)
        {
            if (!string.IsNullOrEmpty(context.Request.QueryString["q"]))
            {
                // Searches posts and pages
                WriteSearchResult(context);
            }
            else
            {
                WriteAcceleratorInfo(context);
            }
        }
        private void WriteSearchResult(HttpContext context)
        {
            List<IPublishable> searchResult = Search.Hits(context.Request.QueryString["q"], false);
            context.Response.ContentType = "text/html";
            context.Response.AppendHeader("Content-Disposition", "inline; filename=search.html");
            Stream  stream = context.Response.OutputStream;
            using (TextWriter streamWriter = new StreamWriter(stream))
            {
                using (HtmlTextWriter htmlTextWriter = new HtmlTextWriter(streamWriter))
                {
                    htmlTextWriter.WriteFullBeginTag("html");
                    htmlTextWriter.WriteFullBeginTag("head");
                    htmlTextWriter.WriteFullBeginTag("title");
                    htmlTextWriter.Write(BlogSettings.Instance.Name);
                    htmlTextWriter.WriteEndTag("title");
                    htmlTextWriter.WriteEndTag("head");
                    htmlTextWriter.WriteBeginTag("body");
                    htmlTextWriter.WriteAttribute("style", "font-family:Arial,Hevetica,Sans-serif;");
                    htmlTextWriter.Write(HtmlTextWriter.TagRightChar);
                    htmlTextWriter.WriteFullBeginTag("dl");
                    foreach (IPublishable result in searchResult)
                    {
                        htmlTextWriter.WriteFullBeginTag("dt");
                        htmlTextWriter.WriteBeginTag("a");
                        htmlTextWriter.WriteAttribute("href", result.AbsoluteLink.ToString());
                        htmlTextWriter.Write(HtmlTextWriter.TagRightChar);
                        htmlTextWriter.Write(result.Title);
                        htmlTextWriter.WriteEndTag("a");
                        htmlTextWriter.WriteBeginTag("br");
                        htmlTextWriter.Write(HtmlTextWriter.SelfClosingTagEnd);
                        htmlTextWriter.WriteBeginTag("dd");
                        htmlTextWriter.WriteAttribute("style", "margin:0px;font-size:smaller;");
                        htmlTextWriter.Write(HtmlTextWriter.TagRightChar);
                        string description;
                        if (string.IsNullOrEmpty(result.Description))
                        {
                            string desc = Utils.StripHtml(result.Content);
                            string shortDesc;
                            if (desc.Length < 200)
                            {
                                shortDesc = desc;
                            }else
                            {
                                shortDesc = desc.Substring(0, 196) + " ...";
                            }
                            description = shortDesc;
                        } else
                        {
                            description = result.Description;
                        }
                        htmlTextWriter.Write(description);
                        htmlTextWriter.WriteEndTag("dd");
                        htmlTextWriter.WriteEndTag("dt");
                    }
                    htmlTextWriter.WriteEndTag("dl");
                    htmlTextWriter.WriteEndTag("body");
                    htmlTextWriter.WriteEndTag("html");
                }
            }
            context.Response.Flush();
            context.Response.End();
        }
        private void WriteAcceleratorInfo(HttpContext context)
        {
            context.Response.ContentType = "application/xml";
            context.Response.AppendHeader("Content-Disposition", "inline; filename=accelerator.xml");
            XmlWriterSettings writerSettings = new XmlWriterSettings();
            writerSettings.Encoding = System.Text.Encoding.UTF8;
            writerSettings.Indent = true;
            Stream stream = context.Response.OutputStream;
            using (XmlWriter writer = XmlWriter.Create(stream, writerSettings))
            {
                writer.WriteStartElement("openServiceDescription", "http://www.microsoft.com/schemas/openservicedescription/1.0");
                writer.WriteElementString("homepageUrl", Utils.AbsoluteWebRoot.ToString());
                writer.WriteStartElement("display");
                writer.WriteElementString("name", "Search in " + BlogSettings.Instance.Name + " weblog");
                writer.WriteElementString("icon", new Uri(Utils.AbsoluteWebRoot, "pics/blogengine.ico").ToString());
                writer.WriteEndElement();
                writer.WriteStartElement("activity");
                writer.WriteAttributeString("category", "search");
                writer.WriteStartElement("activityAction");
                writer.WriteAttributeString("context", "selection");
                writer.WriteStartElement("preview");
                writer.WriteAttributeString("action", new Uri(Utils.AbsoluteWebRoot, "accelerator.axd").ToString());
                writer.WriteStartElement("parameter");
                writer.WriteAttributeString("name", "q");
                writer.WriteAttributeString("value", "{selection}");
                writer.WriteEndElement();
                writer.WriteEndElement();
                writer.WriteStartElement("execute");
                writer.WriteAttributeString("action", new Uri(Utils.AbsoluteWebRoot, "search.aspx").ToString());
                writer.WriteStartElement("parameter");
                writer.WriteAttributeString("name", "q");
                writer.WriteAttributeString("value", "{selection}");
                writer.WriteAttributeString("type", "text");
                writer.WriteFullEndElement();
            }
            context.Response.Flush();
            context.Response.End();
        }
        #endregion
    }
}

 

Add handler to web.config file.

I the httlHandlers, add following line

<httpHandlers>
    <add verb="*"
         path="accelerator.axd"
         type="BlogEngine.Core.Web.HttpHandlers.AcceleratorHandler, BlogEngine.Core"
         validate="false"/>

In the handlers element, add following line

<handlers accessPolicy="Read, Write, Script, Execute">
    <add name="AcceleratorHandler" 
         verb="*" 
         path="accelerator.axd" 
         type="BlogEngine.Core.Web.HttpHandlers.AcceleratorHandler, BlogEngine.Core" 
         resourceType="Unspecified" 
         requireAccess="Script" 
         preCondition="integratedMode"/>

Add new button to your selected theme. Your modification may look like lines below.

<a href="javascript:window.external.AddService('<%=Utils.AbsoluteWebRoot + "accelerator.axd" %>');" style="float:left">Accelerator</a>

Rebuild you solution and republish to hosted server.

Enjoy with new stuff of IE8 accelerator.


Categories: BlogEngine
Permalink | Comments (0) | Post RSSRSS comment feed

Create WebSlices for BlogEngine.NET 1.5

Web Slices are snippets of the entire page that a user can subscribe to. Web Slices will be kept updated by the browser automatically, and can be viewed directly from the Favorites bar, complete with graphics and visuals. BlogEngine.NET is most popular blog software developed in ASP.NET technology. WebSlices is not yet supported by latest version of BlogEngine.NET (version 1.5.0). I will show you step by step creating WebSlices for BlogEngine.NET.

Prepare service for WebSlices

WebSlices can use XML RSS service to display the data. WebSlices will display first item of RSS information. To display n of latest blog posts, we should modify RSS service to show all information in latest item. BlogEngine use syndication handler for RSS which served by SyndicationHandler.cs file in BlogEngine.Core assembly. Please modify following files to extend syndication handler to be support WebSlices.

SyndicationFormat.cs

Add new enum named WebSlices

/****************************************************************************
Modification History:
*****************************************************************************
Date		Author		  Description
*****************************************************************************
04/11/2007  brian.kuhn    Created SyndicationFormat Enumeration
08/30/2007  brian.kuhn    Moved SyndicationFormat enum to root of library
06/13/2009  Ahmad Masykur Add WebSlices enumeration
****************************************************************************/
using System;
namespace BlogEngine.Core
{
    /// <summary>
    /// Represents common types of syndication formats.
    /// </summary>
    public enum SyndicationFormat
    {
        /// <summary>
        /// No syndication format specified.
        /// </summary>
        None    = 0,
        /// <summary>
        ///  Indicates that a feed conforms to the Atom syndication format.
        /// </summary>
        Atom    = 1,
        /// <summary>
        /// Indicates that a feed conforms to the RSS syndication format.
        /// </summary>
        Rss     = 2,
        /// <summary>
        /// Indicates that a feed conforms to the IE8 WebSlices syndication format.
        /// </summary>
        WebSlices = 3
    };
}

SyndicationHandler.cs

In SetHeaderInformation method, add highlighted lines below.

/// <summary>
/// Sets the response header information.
/// </summary>
/// <param name="context">An <see cref="HttpContext"/> object that provides references to the intrinsic server objects (for example, <b>Request</b>, <b>Response</b>, <b>Session</b>, and <b>Server</b>) used to service HTTP requests.</param>
/// <param name="items">The collection of <see cref="IPublishable"/> instances used when setting the response header details.</param>
/// <param name="format">The format of the syndication feed being generated.</param>
/// <exception cref="ArgumentNullException">The <paramref name="context"/> is a null reference (Nothing in Visual Basic) -or- the <paramref name="posts"/> is a null reference (Nothing in Visual Basic).</exception>
private static void SetHeaderInformation(HttpContext context, List<IPublishable> items, SyndicationFormat format)
{
	DateTime lastModified = DateTime.MinValue;
	foreach (IPublishable item in items)
	{
		if (item.DateModified.AddHours(-BlogSettings.Instance.Timezone) > lastModified)
			lastModified = item.DateModified.AddHours(-BlogSettings.Instance.Timezone);
	}
	switch (format)
	{
		case SyndicationFormat.Atom:
			context.Response.ContentType = "application/atom+xml";
			context.Response.AppendHeader("Content-Disposition", "inline; filename=atom.xml");
			break;
		case SyndicationFormat.Rss:
			context.Response.ContentType = "application/rss+xml";
			context.Response.AppendHeader("Content-Disposition", "inline; filename=rss.xml");
			break;
		case SyndicationFormat.WebSlices:
			context.Response.ContentType = "application/rss+xml";
			context.Response.AppendHeader("Content-Disposition", "inline; filename=webslices.xml");
		break;
	}
	if (Utils.SetConditionalGetHeaders(lastModified))
		context.Response.End();
}

SyndicationGenerator.cs

Add new WriteWebSlicesFeed method below

private void WriteWebSlicesFeed(Stream stream, List<IPublishable> publishables, string title)
{
    XmlWriterSettings writerSettings = new XmlWriterSettings();
    writerSettings.Encoding = System.Text.Encoding.UTF8;
    writerSettings.Indent = true;
    using (XmlWriter writer = XmlWriter.Create(stream, writerSettings))
    {
        writer.WriteStartElement("rss");
        writer.WriteAttributeString("version", "2.0");
        writer.WriteStartElement("channel");
        writer.WriteElementString("title", "Latest Posts");
        writer.WriteElementString("ttl", "15");
        writer.WriteStartElement("item");
        writer.WriteElementString("title", title);
        StringBuilder description = new StringBuilder();
        description.Append("<div style=\"font-family: arial, helvetica, sans-serif;\">");
        description.Append("<div style=\"background-color: #f0f0f0;\"><h1 style=\"margin:0px; padding:0px; font-size: x-large;\">" + title + "</h1><h2 style=\"margin:0px; padding:0px; font-size: small; font-weight: normal; font-style: italic;\">" + blogSettings.Description + "</h2></div>");
        description.Append("<ul style=\"list-style-type: none;margin: 0;padding: 0px;\">");
        for (int i = 0; (i < 10) && (i < BlogSettings.Instance.NumberOfRecentPosts); i++)
        {
            description.Append("<li style=\"margin-left: 0px;\"><div style=\"display:block; border-top: 1px solid #efefef; border-bottom: 1px solid #efefef;\"><a href=\"" + publishables[i].AbsoluteLink + "\" target=\"_blank\" title=\"" + publishables[i].Title + "\" style=\"text-decoration: none; font-size: small; color: #000090; width:500px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; \">" + publishables[i].Title + "</a></li>");
        }
        description.Append("</ul>");
        description.Append("</div>");
        writer.WriteElementString("description", System.Web.HttpUtility.HtmlDecode(description.ToString()));
        writer.WriteEndElement();
        writer.WriteFullEndElement();
    }
}

Add highlighted lens below in WriteFeed method.

/// <summary>
/// Writes a generated syndication feed that conforms to the supplied <see cref="SyndicationFormat"/> using the supplied <see cref="Stream"/> and collection.
/// </summary>
/// <param name="format">A <see cref="SyndicationFormat"/> enumeration value indicating the syndication format to generate.</param>
/// <param name="stream">The <see cref="Stream"/> to which you want to write the syndication feed.</param>
/// <param name="publishables">The collection of <see cref="IPublishable"/> objects used to generate the syndication feed content.</param>
/// <param name="title">The title of the RSS channel</param>
public void WriteFeed(SyndicationFormat format, Stream stream, List<IPublishable> publishables, string title)
{
	if (stream == null)
	{
		throw new ArgumentNullException("stream");
	}
	if (publishables == null)
	{
		throw new ArgumentNullException("publishables");
	}
	if (!stream.CanWrite)
	{
		throw new ArgumentException(String.Format(null, "Unable to generate {0} syndication feed. The provided stream does not support writing.", format), "stream");
	}
	//------------------------------------------------------------
	//	Write syndication feed based on specified format
	//------------------------------------------------------------
	switch (format)
	{
		case SyndicationFormat.Atom:
			this.WriteAtomFeed(stream, publishables, title);
			break;
		case SyndicationFormat.Rss:
			this.WriteRssFeed(stream, publishables, title);
			break;
		case SyndicationFormat.WebSlices:
			this.WriteWebSlicesFeed(stream, publishables, title);
			break;
	}
}

Master page file of selected theme.

Find <asp:contentplaceholder /> element and add hslice class to parent element of placeholder. Add some information to provide WebSlice title and service source. Your modification of master page may look like following lines.

<div id="main" class="hslice">
    <div style="display:none">
        <p class="entry-title">
            <%=BlogSettings.Instance.Name %>
        </p>
        <a rel="feedurl" href="<%=Utils.AbsoluteWebRoot + "syndication.axd?format=webslices" %>"></a>
    </div>
    <asp:contentplaceholder id="cphBody" runat="server">
    </asp:contentplaceholder>
</div>

Build BlogEngine solution. Your BlogEngine is now support WebSlices feed. You only redeploy BlogEngine.Core.dll and selected theme to make WebSlices support of your blog.

Happy nice blogging with IE8.


Tags: ,
Categories: BlogEngine
Permalink | Comments (0) | Post RSSRSS comment feed

BlogEngine.NET 1.5 was released a few days ago

BlogEngine.NET was released a few days ago as announced by Mads in his blog. In this release, blogengine.net now support some IIS7 features. New features in this release are:

  • Nested comments
  • Superb Windows Live Writer integration (including tags)
  • Latest TinyMCE text editor
  • Mono 2.4 support that just works
  • Doesn't screw with jQuery and Prototype anymore
  • Better database support out of the box
  • Higher performance
  • ...and of course a lot of general improvements, tweaks and bug fixes

This release is claimed more stable than older.

Al Nyveldt also posted installation screen cast in his blog.

You can learn by watching this video to install BlogEngine.NET with XML or database data.

This is release is probably be the last release supporting IIS6 and .NET 2.0. In the next release, BlogEngine will be only support II7 and upcoming IIS7.5 to give extra possibilities like extension-less URL even on hosted environment.


Categories: BlogEngine
Permalink | Comments (0) | Post RSSRSS comment feed

Drawing using JavaScript and jQuery

Drawing functionality is not supported in most of popular browsers except Firefox and Safari with Canvas object. Using little trick we can draw line and circle using JavaScript. This is not best practice because need lot of execution time but it can be alternative way to draw simple and little objects.

Basically this trick is drawing many DIV elements with 1x1 pixel size inside the document. Basically we can't draw 1x1 pixel suze DIV element in IE. To resolve this issue, you can add IMG element inside the DIV with 1x1 pixel image. Here's the complete code to draw line and circle into HTML document.

<html> <head> <title>Drawing</title> <script type="text/javascript" src="jquery-1.3.2.min.js"></script> <script type="text/javascript"> $(document).ready(function() { line(50,30, 100, 150); circle(110,110, 100); }); function line(x1, y1, x2, y2) { c = $(document.body); var dx = Math.abs(x2-x1); var dy = Math.abs(y2-y1); var d = Math.max(dx, dy); var i=0; for(i=0; i < d; i++) { var img = $(document.createElement('img')).attr('src', 'blank.gif'); var div = $(document.createElement('div')).width(1).height(1).css({'background-color': '#f00', position: 'absolute', left: Math.min(x1,x2)+(i*dx/d), top: Math.min(y1,y2)+(i*dy/d) }); div.append(img); c.append(div); } } function circle(x, y, r) { c = $(document.body); var l = 2 * Math.PI * r; var i=0; for(i=0; i < l * (1+((10-Math.log(r+1))/10)); i++) { var x2 = r * Math.sin(360 * i/l); var y2 = r * Math.cos(360 * i/l); var img = $(document.createElement('img')).attr('src', 'blank.gif'); var div = $(document.createElement('div')).width(1).height(1).css({'background-color': '#f00', position: 'absolute', left: x+x2, top: y+y2 }); div.append(img); c.append(div); } } </script> </head> <body> </div> </body> </html>

The result of rendered document is

image

I hope this trick is useful.


Categories: JavaScript
Permalink | Comments (2) | Post RSSRSS comment feed

How to Make Our Website to be Ready for IE8

Today, I have email from Microsoft TechNet Flash about "how to get ready for IE8". It is challenge for me to make my blog ready for IE8. My blog have already XHTML 1.0 Transitional and CSS 2.1 compliance, but still reported as not ready for IE8 (see picture below).

image

What happen with my blog? IE8 have difference standard with W3C? After following link from TechNet flash email, the problem is: my blog have not META tag to tell IE8 that the page is ready for IE8 view. After apply X-UA-Compatible META tag in my BlogEngine theme, my blog is now comply with IE8.

image

Here’s requirement to be ready for IE8.

  1. Make sure your HTML markup is comply to HTML 4, XHTML 1.0 or XHTML 1.1 defined in doctype of the page. You can validate your page with online markup validation tools at http://validator.w3.org/
  2. Make sure your CSS is use at least CSS level 2.1 compliance. You can validate your page with online CSS validation tools at http://jigsaw.w3.org/css-validator/
  3. Place the following HTML META tag into the top of the HEAD element of each Web page (before tags other than TITLE or META):
    <meta http-equiv="X-UA-Compatible" content="IE=8"/>
    This will tell Windows Internet Explorer 8 to render each page using CSS 2.1 standards.

After HTML, CSS and HTML META has been applied, the page will ready for IE8.

References:

http://msdn.microsoft.com/en-us/ie/cc405106.aspx
http://msdn.microsoft.com/id-id/library/cc817570(en-us).aspx
http://msdn.microsoft.com/id-id/library/dd433047(en-us,VS.85).aspx
http://msdn.microsoft.com/id-id/library/cc817572(en-us).aspx


Categories: Tips | IE
Permalink | Comments (3) | Post RSSRSS comment feed