IIS 7.5 Logging with Sitecore 6.x in Integrated Pipeline Mode

by aboo bolaky 4. December 2010 21:48

When you run Sitecore 6.x in Integrated Pipeline Mode, You will notice that ALL IIS log entries contain the log entry for the resquest to the layout (aspx) page (instead of the actual sitecore item .e.g /ContactUs.aspx).

This problem is partly related to another issue outlined on Stack Overflow  [http://stackoverflow.com/questions/353541/iis7-rewritepath-and-iis-log-files]

If you run Sitecore in Classic Mode, the problem disappears. However, if you still wish to use Integrated Pipeline Mode, you will have to intercept the request  before the Sitecore HttpModule (Sitecore.Nexus.dll) gets involved.

Solution

Create a class that extends System.Web.IHttpModule  and  set the path back to the original value after the request has been processed but before the IIS logging module writes the log entry.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;

namespace Test
{
    public class RewritePath : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += OnBeginRequest;
            context.LogRequest += OnEndRequest;
        }

        static void OnBeginRequest(object sender, EventArgs e)
        {
            var app = (HttpApplication)sender;
            app.Context.Items["OriginalPath"] = app.Context.Request.Path;
        }

        static void OnEndRequest(object sender, EventArgs e)
        {
            var app = (HttpApplication)sender;
            var originalPath = app.Context.Items["OriginalPath"] as string;
            if (originalPath != null)
            {
                app.Context.RewritePath(originalPath);
            }
        }

        public void Dispose()
        {

        }

    }
}

Locate the Modules Section (under system.webServer ..remember we’re running in Integrated Pipeline Mode) and plug the module in BEFORE the Sitecore Nexus HttpModule

 

Here's what's captured when everything is compiled and deployed

 

Thanks Sitecore Support.

Tags: ,

.Net | Applications | Sitecore | Tips & Tricks

Registering XSLT Extension Objects with the ASP XML control

by aboo bolaky 23. October 2009 07:01

I once inherited a sublayout that inlcuded an asp:xml control. The asp:xml control was there to handle and display an xml feed from another system, while the rest of the sublayout concentrated on rendering related feed content from Sitecore. The presentation of the xml feed was handled via an xlst rendering.

In this particular situation, I made use use of XSL extensions in the XSLT file. Registering the XSL Extension was fairly easy.

   
<xslExtensions>   
	<extension mode="on" type="Utils.XslHelper, Utils"
	           namespace="http://www.sitecore.net/Utils" 
		   singleInstance="true" />
	   .....
</xslExtensions>



Registering the extension in the xsl file

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:MyExtension="http://www.sitecore.net/Utils"
 exclude-result-prefixes="MyExtension" >

<xsl:value-of select="MyExtension:HelloWorld()" />



Binding the XML control to the XML Data

protected override void OnInit(EventArgs e)
    {
        if (!this.IsPostBack)
        {
            string xmlContent = "xml data goes here";
            XsltArgumentList list = new XsltArgumentList();
            Utils.XslHelper ext = new Utils.XslHelper();
            list.AddExtensionObject("http://www.sitecore.net/Utils", ext);
            Xml1.TransformArgumentList = list;
            Xml1.DocumentContent = xmlContent;
        }
    }

It turns out that, even though I had previously registered the xsl extension in the xslt file, I also had to register it via code as well. Otherwise, the following exception occurs at runtime.

Cannot find the script or external object that implements prefix 'MyExtension'.

Sorted!

Tags: ,

.Net | Asp.Net | Sitecore | Tips & Tricks

Retrieving the DATA folder installation path from MS SQL Server using T/SQL

by aboo bolaky 10. October 2009 19:57

This would be useful for creating databases using SQL scripts. The SQL query below returns the installation path of the DATA folder for the installed SQL Server.

SQL Script

 

DECLARE @device_directory NVARCHAR(520)

SELECT @device_directory = 
	SUBSTRING(filename, 1, CHARINDEX(N'master.mdf', LOWER(filename)) - 1)
FROM master.dbo.sysaltfiles 
WHERE dbid = 1 AND fileid = 1

print @device_directory

Output

C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\

Tags:

The AByss | Tips & Tricks

Bold style for matching results with AutoCompleteExtender - Implemented using a Trie

by aboo bolaky 7. October 2009 18:22

This article will focus on the implementation of the AjaxControlToolkit's AutoCompleteExtender into a simple ASP.NET application. What I'm trying to do here is pull the data from a database and use the AutoCompleteExtender to display the data as the user types characters in a textbox.

Server Implementation

Im not going to focus on how to retrieve the data (from a table of around 60,000 records). I'm going to use the simplistic SQLConnection/SQLCommand/SQLDataReader classes and passing sql command as plain text (as opposed to Stored Procedures). The key issue is how and what is the best way to store the data once being retrieved. Generally, Autocomplete comes in 2 flavours:-

1: Find words based on letters anywhere in a phrase (performing a LIKE '%ar%'  in SQL).

2: Find words that start with specific characters ( LIKE 'ar%' in SQL).

In the first instance, you're pretty much tied up to using the LIKE clause (be it in a stored proc or simple text). The determining factor here is how and when to cache the data since each character typed in invokes the webservice and queries the database. Each query will yield a different result set.

In the second instance (the focus of this article), the more you add characters to the keyword, you are, in fact, narrowing down the scope of search. This means that the data we initially load is deterministic and hence we can cache it somewhere. But the real deal here is :which  data structure do we hold our words in? List<>, DataTable, Linked List??

Trie 

You might have already figured this one out. Anyway, a trie is an ordered tree data structure (a.k.a prefix tree) that stores the information about the contents of each node in the path from the root to the node, rather than the node itself. What this means is that each part between the root and any leaf represents a key and the goal is to find the key by traversing the tree.

Implementation

Eyal Mey-Tal has implemented a Trie structure in C#.Head to the CodePlex site to download it.

WebMethod to retrieve data

[WebMethod]
    public string[] GetNames(string prefixText, int count)
    {
        Trie trie = (Trie)Context.Cache["Trie"];
        if (trie == null)
        {
            trie = new Trie();
            using (SqlConnection con = new SqlConnection("server=(local);database=autocomplete;user id=xxx;Password=xxx;"))
            {
                SqlCommand cmd = new SqlCommand("select word from AutoCompleteData", con);
                cmd.CommandType = System.Data.CommandType.Text;
                con.Open();
                SqlDataReader dr = cmd.ExecuteReader();
                if (dr.HasRows)
                {
                    while (dr.Read())
                    {
                        trie.Add(dr.GetString(0));
                    }
                    con.Close();
                }
            }
            //simple caching here  
            Context.Cache["Trie"] = trie;
        }
        List list = trie.GetCompletionList(prefixText);
        return list.Take(count).ToArray();
    }

 

Setting up the AutoCompleteExtender was easy. To get the autocomplete working, I only had to modify a few of the extender's attributes (.e.g. CompletionSetCount, TargetControlID, ServicePath, ServiceMethod, DelimiterCharacters ..) and data was being returned as I typed in characters. However, making the extender look good was a different story.

Client-Side Implementation 

This is the bit where I'm open to suggestions. I'm no Javascript/JQuery expert but however, I finally got the extender working as I wanted it to. Characters relevant to the ones the user has typed become highlighted in the drop down list. It took me a while to dig this solution out. The javascript is awkward and needs to be refactored. Netherless, the solution works for IE and Firefox [ good enough for me :) ]

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AutoComplete.aspx.cs" Inherits="AutoComplete.AutoComplete" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>
    <style>
        .autocomplete_completionListElement
        {
            margin: 0px !important;
            background-color: inherit;
            color: windowtext;
            border: buttonshadow;
            border-width: 1px;
            border-style: solid;
            cursor: 'default';
            overflow: auto;
            height: 200px;
            text-align: left;
            list-style-type: none;
            padding-left: 1px;
        }
        
        /* AutoComplete highlighted item */
        
        .autocomplete_highlightedListItem
        {
            background-color: #aaff90;
            color: black;
            padding: 1px;
            cursor: hand;
        }
        
        /* AutoComplete item */
        
        .autocomplete_listItem
        {
            background-color: window;
            color: windowtext;
            padding: 1px;
        }
    </style>
    <script type="text/javascript">

        function acePopulated(sender, e) {

            var behavior = $find('AutoCompleteEx');

            var target = behavior.get_completionList();
            if (behavior._currentPrefix != null) {
                var prefix = behavior._currentPrefix.toLowerCase();
                var i;
                for (i = 0; i < target.childNodes.length; i++) {
                    var sValue = target.childNodes[i].innerHTML.toLowerCase();
                    if (sValue.indexOf(prefix) != -1) {
                        var fstr = target.childNodes[i].innerHTML.substring(0, sValue.indexOf(prefix));
                        var pstr = target.childNodes[i].innerHTML.substring(fstr.length, fstr.length + prefix.length);
                        var estr = target.childNodes[i].innerHTML.substring(fstr.length + prefix.length, target.childNodes[i].innerHTML.length);
                        target.childNodes[i].innerHTML = "<div class='autocomplete-item'>" + fstr + '<B>' + pstr + '</B>' + estr + "</div>";
                    }
                }
            }

        }

        function aceSelected(sender, e) {
            var value = e.get_value();
            if (!value) {
                if (e._item.parentElement && e._item.parentElement.tagName == "LI")
                    value = e._item.parentElement.attributes["_value"].value;
                else if (e._item.parentElement && e._item.parentElement.parentElement.tagName == "LI")
                    value = e._item.parentElement.parentElement.attributes["_value"].value;
                else if (e._item.parentNode && e._item.parentNode.tagName == "LI")
                    value = e._item.parentNode._value;
                else if (e._item.parentNode && e._item.parentNode.parentNode.tagName == "LI")
                    value = e._item.parentNode.parentNode._value;
                else value = "";
            }
            var searchText = $get('<%=txtWord.ClientID %>').value;
            searchText = searchText.replace('null', '');

            sender.get_element().value = searchText + value;
        }
                                       
   
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <div style="text-align: center; margin-top: 200px">
        Search :
        <asp:TextBox ID="txtWord" runat="server" AutoComplete="off" Width="200px" />
    </div>
    <cc1:AutoCompleteExtender runat="server" BehaviorID="AutoCompleteEx" ID="autoComplete1"
        TargetControlID="txtWord" ServicePath="MyService.asmx" ServiceMethod="GetNames"
        MinimumPrefixLength="1" CompletionInterval="1000" EnableCaching="true" CompletionSetCount="20"
        CompletionListCssClass="autocomplete_completionListElement" CompletionListItemCssClass="autocomplete_listItem"
        CompletionListHighlightedItemCssClass="autocomplete_highlightedListItem" OnClientPopulated="acePopulated"
        OnClientItemSelected="aceSelected" DelimiterCharacters=";" ShowOnlyCurrentWordInCompletionListItem="true">
    </cc1:AutoCompleteExtender>
    </form>
</body>
</html>





Result

 

 

Downloads

The source code (with database script in ~/App_Data (around 60,000 records )) can be downloaded below.

AutoCompleteVS2008Sln.zip (4.84 mb)

Enjoy ....

Tags:

.Net | Asp.Net | Tips & Tricks

Very Cool CSS Message Boxes for different message types

by Aboo Bolaky 31. July 2009 07:12

Janko Jovanovic has written a very nice article about ways to display different types of messages using CSS. The messages outlined are of the following types

  • Information messages
  • Success messages
  • Warning messages
  • Error messages
  • Validation messages

 

I believe what makes the article really stand out is the fact that he walks you through the css implementation as well. We're bound to display these types of messages on any web application we develop, so, please have a look at what he's achieved.

Tags:

Freebies | The AByss | Tips & Tricks

Filter Duplicates in MS Excel 2007

by Aboo Bolaky 21. July 2009 06:41


Forget the flimsy conditional formulae you had to use in order to filter duplicates in Excel 2000-2003.

Excel 2007 makes it a lot easier.

You just need to highlight the column you want to remove duplicates from, navigate to the Styles Ribbon, then Conditional Formatting -> Highlight Cells Rules -> Duplicate Values. You then only need to choose which color to apply for duplicate cell values..

et voila !!!

Tags:

The AByss | Tips & Tricks

Burn ISO Images on DVD using ImgBurn

by Aboo Bolaky 13. July 2009 03:38

I just realised how easy it is to burn .iso files onto dvds. Previously, I used to have many issues with the various tools that were available out there..mainly because I was running a 64-bit OS. Now, on top of Windows 7 RC (x64), everything seems to be a lot easier.

ImgBurn

Supports a wide range of image file formats - including BIN, CUE, DI, DVD, GI, IMG, ISO, MDS, NRG and PDI.

Burns Audio CD's from any file type supported via DirectShow / ACM - including AAC, APE, FLAC, M4A, MP3, MP4, MPC, OGG, PCM, WAV, WMA and WV.

You can use it to build DVD Video discs (from a VIDEO_TS folder), HD DVD Video discs (from a HVDVD_TS folder) and Blu-ray Video discs (from a BDAV / BDMV folder) with ease.

Supports Unicode folder/file names, so you shouldn't run in to any problems if you're using an international character set.

Supports all the windows OS's - Windows 95, 98, Me, NT4, 2000, XP, 2003, Vista, 2008 and 7 (including all the 64-bit versions). It also nicely integrates with the context menu. 

 

AND, ABOVE ALL, IT'S FREE !!! ImgBurn Website

Tags:

Freebies | Tips & Tricks

The Sitecore Way

by Aboo Bolaky 9. July 2009 07:09

4 months since my last post. This should give you an idea of my hectic life as a software developer.  Build..Test.. Deploy.....Build..Test.. Deploy.. This seems to be the only thing that I have been doing lately and hasn't left me with any time to do anything else.

Things have got to change and NOW is the time :-)

Back in Febuary, I came accros a file (via some random Google Search about Sitecore) that outlined some good one-liners about building websites using Sitecore. At that time, I added the link to my favourites and didn't pay much attention to it. Now that I've accessed the link again (by mistake..), I realise that so many of those "guidelines" are correct. Unfortunately, I did not capture the author of the text file at that time. Here's the online version

The Sitecore Way

1) Think about the CMS users not just the Web site. The Sitecore Way.

2) Use XSLT to minimize code compilation for maintenance. The Sitecore Way.

3) Get better performance with ASP.NET user-controls.  The Sitecore Way.

4) Use an ASP.NET master for your layouts. The Sitecore Way.

5) Return Item ID for XSLT extension results. The Sitecore Way.

6) Avoid setting language in a request after the Sitecore pipeline. The Sitecore Way.

7) Use icons for your masters and templates. The Sitecore way.

8) Protect /sitecore as much as you can. The Sitecore way.

9) Cookieless is possible, but be careful. The Sitecore way.

10) It's very important to Organize the content structure correctly. The Sitecore Way.

11) Finalize design as much as you can before implementation. The Sitecore way.

12) Ask for design behavior specs not just content info. The Sitecore way.

13) Use file system for large files instead of media library. The Sitecore way.

14) Use source-control for new/changed files inside Sitecore. The Sitecore Way.

15) Please avoid inline C# code in XSLT. The Sitecore way.

16) Test renderings using the debugger ALWAYS. The Sitecore way.

17) Multi-site, multi-language, identify what the client needs. The Sitecore Way.

18) Globalization is easy with Sitecore...use it. The Sitecore way.

19) Create custom XAML apps for better experience. The Sitecore way.

20) Use Sitecore's security mechanism for other applications. The Sitecore way.

21) Be careful of data cache synchronization between two sites. The Sitecore way.

22) Remove default favico.ico or your client might yell at you. The Sitecore way.

23) To stage or not to stage. We say to stage. The Sitecore way.

24) Use Lucene.net if you can for site search...it's FREE. THe Sitecore way.

25) Disaster recovery plan: zipped Web site and DB backups.  The Sitecore way.

26) Minimize rendering URL parameters to keep an SEO-friendly site. The Sitecore way.

27) Dont' forget the robots.txt...just good Web practice. The Sitecore way.

28) Analyze secuirty by feature and content access. The Sitecore way.

29) Download the Enhanced Email Action, why not? The Sitecore way.

30) Content analysis should be a top priority. The Sitecore way.

31) Use nested templates but be careful. The Sitecore way.

32) Make life easy by using a sticky session load-balancer. The Sitecore way.

33) More than a CMS, it's an integration platform. The Sitecore way.

34) Get more value by integrating it with internal systems. The Sitecore way.

35) Deliver templates and masters early to  avoid content freeze. The Sitecore way.

36) Physical storage of data does not look like Sitecore XML. THe Sitecore way.

37) Ever used Sitecore Query to query the Sitecore XML?  It's cool. The Sitecore way.

38) Use the search in the Sitecore bar for a quick content search. The Sitecore way.

39) No gray desktop background or you might loose your cursor : ). THe Sitecore way.

40) Drag content items on the desktop to create a shortcut. The Sitecore Way.

Credits: Unknown Author

 

How many of these have you achieved????

 

Tags: ,

.Net | Applications | Sitecore | Tips & Tricks

Listview losing viewstate on postback in Sitecore V6

by Aboo Bolaky 21. February 2009 08:23

This post will most probably apply to the GridView and LoginView controls as well.

The Problem

Lets assume that you've successfully bound a listview to your datasource and configured all the properties on the listview to display the Select/Edit/Delete links. You then have the task to write the logic in the appropriate events of the usercontrol/sublayout. While I was implementing the Edit functionality, I implemented the OnItemCommand event of the Listview to display an Edit Panel with the data populated from the selected row. I was a bit suprised to see that the end result wasn't what I was expecting:

The Edit Panel shows up but the Listview has left the party.!!

The Frustration 

It dawned on me that, at some point, I must have messed up somewhere in the code.So, I began putting "EnableViewState=true" to every control.. (this shows how desperate I was!!). I also reverted to "AutoEventFireUp=false" (Originally, I was manually hooking up the events..).I tried databinding on every possible method I could lay my hands on!!. I lost confidence on the fact that this was a really easy task and yet, it was taking me hours to get to the bottom of the problem. I completely lost my mind....I began googling on the issue ["postback..losing viewstate"], I started to watch a few videos that demonstrate the functionality of the ListView..I even got the point where I created another item in Sitecore, assigned the same sublayout to the item's presentation and accessed the item using the url.. I ended up in the same situation.... I surrendered...I left the battlefield...wounded..!!![White flag..Sealed].

The Solution

I finally blamed it on Sitecore!! Who knows, maybe it was a known issue in one of their releases or maybe I just needed to upgrade to the latest stable release(090120). Out of desperation, I tried searching on the Forums and found that I wasn't the only one experiencing this issue.I came across this forum post. Thanks to Mark Cassidy, I eventually finished my task (It had taken me almost a day...and that had messed up (big time) on my initial estimate!!!)

The solution, as Mark outlined, is to add the type of the control (in my case, System.Web.UI.WebControls.ListView) to the typesThatShouldNotBeExpanded element in the web.config. Presumably, for the sake of consistency, you might also append the System.Web.UI.WebControls.Gridview to the list (in case your website makes use of one!!). From what I've read so far, no one knows about the purpose of the typesThatShouldNotBeExpanded element .!! {Sigh...Sitecore!! What did you do that to me????}

In hindsight, only laughs...Good Days...Good Times...

I hope this helps someone!!!

Back to Sitecore  ......

Tags:

.Net | Applications | Sitecore | Tips & Tricks

The AddAspxExtension property in Sitecore V6

by Aboo Bolaky 11. February 2009 07:53

In Sitecore 6.0, a new Link Manager class has been added. In the web.config, a few properties affect the functionality of the Link Manager. I've already posted on the EncodeNames property (fyi, default value : false).

The AddAspxExtension Property

On the surface, I can clearly relate to the functionality of this property. If this is set to false, we are instructing Sitecore to render links (i.e via <sc:link>) without any extensions. This is (alledgedly) GREAT NEWS for SEO experts. If you leverage this functionality with some Url Rewriting (either via Helicon Isapi Rewrite Lite (free)  or UrlRewriter.Net ), you must be thinking that you will have a Sitecore front-end website without any extensions.

The Glitch...

If you spent most of your time in implementing regular expressions to rewrite (under the hood) those extensionless links to .aspx and feed them back to Sitecore, Well...I'm afraid you have wasted your precious time (no matter how cool your regex expressions are!!). The moment you try to access the Content Editor in the CMS, you  simply receive some weird error messages. Sometimes, it's the dreaded YSOD (Object Reference not set to an instance of an object) or occasionally a 404 page welcomes you. With the AddAspxExtension property set to false, you might end up with a fancy looking frontend and NO backend support at all. Not very usefull... Did a bit of research on SDN5, turns out that the symptoms are correct

This has led me to believe that, in the midst of tackling problems that vary in programming complexity and requirements , always take a step back and test both the front end and back end when dealing with "unchanted territories".

And then...

The search to build an SEO friendly website in Sitecore continues.. Surely, I'll get the better of this (it's just a matter of time...why not build up the suspense?)  and will let you know how I did it !!!! 

Back to Sitecore now....

Tags:

.Net | Applications | Sitecore | Tips & Tricks

Tag cloud

Flash Player 9 required.

About Me

I wish I could write something here..
//TODO: ElaborateMe