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

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 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

Updating Prayer Widget due to Previous IP to Geo Service was Unavailable

I was developed Prayer Time widget a month ago. I was used IP to geo service that not available anymore. This update using hostip.info service instead. The hostip.info service is not reliable enough for all IP world wide. Some IPs are not covered yet but more stable than previous service.

Here’s core of my code to retrieve geographic information from hostip.info.

WebClient webClient = new WebClient();
string responseString = null;
try
{
    responseString =
        webClient.DownloadString(string.Format("http://api.hostip.info/get_html.php?ip={0}&position=true",
                                               ipAddress));
}
catch (WebException)
{
    responseString = string.Empty;
}
catch (Exception)
{
    responseString = string.Empty;
}
Regex regex = new Regex("Country\\:\\s(?<Country>[A-Za-z0-9]+)\\s\\((?<CountryId>[A-Z]{2})\\)\\nCity\\:\\s(?<City>[A-Za-z0-9]+)\\nLatitude\\:\\s(?<Latitude>\\-?[0-9\\.]+)\\nLongitude\\:\\s(?<Longitude>\\-?[A-Za-z0-9\\.]+)");
if (!string.IsNullOrEmpty(responseString))
{
    Match m = regex.Match(responseString);
    if (m.Success)
    {
        city = m.Groups["City"].Value;
        country = m.Groups["Country"].Value;
        countryId = m.Groups["CountryId"].Value;
        longitude = m.Groups["Longitude"].Value;
        latitude = m.Groups["Latitude"].Value;
    }
}

The complate source code can be downloaded here.

I hope this update will be more reliable that previous version.


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

Prayer Time Widget for BlogEngine.NET 1.4.x

Prayer Time is time schedule for moslem prayer. This widget shows the daily prayer time based on user location. Thispicture below shows prayer time at January 11, 2009 in Jakarta. If you are from outside of Jakarta, the prayer time will automatically calculate base on your location.

image

I’m using prayer time algorithm from here and previous post here. This widget use Shafii and Muslim World League calculation except Indonesia and Malay use custom calculation.

Complete source code can be downloaded from here. The installation is very easy, follow installation steps below:

  1. Extract the zip file to widget folder of your BlogEngine.NET site
  2. Login as Administrator
  3. Goto buttom of page
  4. Select “Prayer Time” from available widgets in combo box as picture below.
  5. Click Add.
  6. You can also move the widget to another location by refreshing the browser and drag n drop “Prayer Time” widget to desired location.

image

 

I hope this widget be useful for moslem blogger.


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

Upgrade to BlogEngine.NET 1.4.5

Alhamdulillah, my weblog already upgraded from BlogEngine 1.2 to BlogEngine.NET 1.4.5. Upgrading process is easy but should be carefully because there are incompatible settings and themes between BlogEngine 1.2 and BlogEngine 1.4.5. To upgrade BlogEngine from version 1.3 or 1.2 to version 1.4.x, you must prepare following items before upgrading:

  1. Upgrade theme if you are using custom theme (not included in theme package).
  2. Backup your xml data or database
  3. Backup your settings
  4. Create custom widget (if needed).

I’m alredy updated my theme (Cogitation) for BlogEngine 1.4.x and create new widget (Image List) for displays image in the side bar. You can download Cogitation theme and Image List widget from following links.

After upgrading BlogEngine, theme and installing widget, you might be need to reconfigure widgets. Rearange and add widget that you want to display in side bar.

I hope my theme and widget are useful for you.


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

Image List Widget for BlogEngine.NET 1.4

BlogEngine.NET now available for download. This version of BlogEngine.NET introduce new dynamic controls called widget. You can add new widget, delete and move existing widget anywhere in the widget zone (commonly on side bar).

image

To support new BlogEngine.NET widget model, I'm developed new widget for displaying images list. You can download this widget from following link.

The installation is very easy. Just extract the package to widgets folder and login as admin user to add this widget to widget zone.

I hope this helps,

 

Ahmad Masykur


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

Upgrade BlogEngine.NET ke versi 1.3

Alhamdulillah situs www.masykur.web.id telah berhasil diupgrade ke BlogEngine.NET versi terbaru (v1.3). Walaupun masih repot dalam proses upgrade, Alhamdulillah setelah lebih dari satu jam upload semua file yang dibutuhkan melalui web2ftp.de (karena direct FTP dari PC kantor saya tidak bisa). Sekarang www.masykur.web.id telah memiliki tenaga baru.

Untuk melakukan upgrade dari versi lama ke baru berikut sedikit tips yang mungkin berguna.

  1. Pastikan tidak ada file versi lama di dalam direktori App_Code, karena biasanya tiap kenaikan versi minor, ada beberapa file yang dihapus.
  2. Selamatkan theme yang telah dikustomisasi supaya tidak tertimpa dengan yang baru.
  3. Jangan timpa file yang ada di direktori App_Data karena direktori ini digunakan untuk menyimpan semua data dari daftar user dan password serta seting blog ada dalam direktori tersebut.
  4. Tidak perlu upload file dalam direktori admin\tiny_mce dan pics\flags karena tidak berisi file yang sama dari versi awal hingga sekarang.

Demikian sedikit informasi yang mungkin berguna bagi para pengguna BlogEngine.NET dalam melakukan upgrade.


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