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

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