Frederik Vig – ASP.NET developer

Follow me

Posts tagged ‘EPiCode.Extensions’

EPiCode.Extensions and ambiguous reference

On new projects where I use EPiCode.Extensions I always register the namespace EPiCode.Extensions in my web.config – that way I can use the extension methods in my .aspx and .ascx files without needing to register EPiCode.Extensions in every file.

...
      <namespaces>
        ...
        <add namespace="EPiCode.Extensions" />     
      </namespaces>
    </pages>
...

Sometimes this can cause some problems when you have other extension methods with the same method signature.

Ambiguous call between two extension methods with the same signature

In this case it was with EPiServer Composer. To fix it I created a simple web.config file that I placed inside the Dropit\Plugin\Extension folder.

Here’s the code.

<?xml version="1.0"?>
<configuration>
  <system.web>
      <pages>
          <namespaces>
              <remove namespace="EPiCode.Extensions" />
          </namespaces>
      </pages>
  </system.web>
</configuration>

You can also use the location element of your main web.config file instead.

<location path="dropit">
        <system.web>
            <pages>
                <namespaces>
                    <remove namespace="EPiCode.Extensions" />
                </namespaces>
            </pages>
        </system.web>
    </location>

And that’s it! This will also work for all the sub directories as well.

On a side-note: I’ve been adding a lot of new extension methods lately to the project. I’ve listed them on the project’s wiki-page. Go check them out!

Extending PageData with some cool Html Helpers

I’ve been reading up on ASP.NET MVC recently. One of the things I love about ASP.NET MVC is the control we as developers have over our markup. ASP.NET MVC doesn’t use server controls, instead it relies heavily on extension methods for generating markup. For some time now I’ve been playing with the idea of adding similar functionality to EPiServer and the EPiCode.Extensions project.

This evening I started adding some of these Html Helpers to the project. I’ve started by focusing on generating links (anchors, hyperlinks). Nothing special, but something that I think will save a lot of repetitive coding.

Update: 08.12.2009

I wrote another blog post explaining my thoughts more: Html Helpers vs Server controls.

LinkExtensions

using System;
using System.Collections.Generic;
using System.Web.Routing;
using EPiCode.Extensions.Helper;
using EPiServer.Core;
 
namespace EPiCode.Extensions
{
    public static partial class PageDataExtensions
    {
        public static string HtmlLink(this PageData page)
        {
            return HtmlLink(page, page.PageName, null);
        }
 
        public static string HtmlLink(this PageData page, string linkText)
        {
            return HtmlLink(page, linkText, null);
        }
 
        public static string HtmlLink(this PageData page, Func<PageData, string> linkText)
        {
            return HtmlLink(page, linkText(page), null);
        }
 
        public static string HtmlLink(this PageData page, object attributes)
        {
            return HtmlLink(page, page.PageName, new RouteValueDictionary(attributes));
        }
 
        public static string HtmlLink(this PageData page, string linkText, object attributes)
        {
            return HtmlLink(page, linkText, new RouteValueDictionary(attributes));
        }
 
        public static string HtmlLink(this PageData page, Func<PageData, string> linkText, object attributes)
        {
            return HtmlLink(page, linkText(page), new RouteValueDictionary(attributes));
        }
 
        private static string HtmlLink(PageData page, string linkText, IDictionary<string, object> attributes)
        {
            if (page.PageLink == null || page.PageLink.ID < 1)
            {
                return string.Empty;
            }
 
            return HtmlHelper.GenerateLink(page.LinkURL, linkText, attributes);
        }
    }
}

Usage

    // Method signatur
    public static string HtmlLink(this PageData page)
 
    // Usage
    CurrentPage.HtmlLink();
 
    // Renders
    <a href="/en/mypage/">My PageName</a>
    // Method signatur
    public static string HtmlLink(this PageData page, string linkText)
 
    // Usage
    CurrentPage.HtmlLink("Some text");
 
    // Renders
    <a href="/en/mypage/">Some text</a>
    // Method signatur
    public static string HtmlLink(this PageData page, Func<PageData, string> linkText)
 
    // Usage    
    CurrentPage.HtmlLink(p => p.GetProperty("Heading|PageName").Value.ToString());
 
    // Renders
    <a href="/en/mypage/">My Heading</a>
    // Method signatur
    public static string HtmlLink(this PageData page, object attributes)
 
    // Usage
    CurrentPage.HtmlLink(new { style = "color:red;" });
 
    // Renders
    <a href="/en/mypage/" style="color:red;">My PageName</a>
    // Method signatur
    public static string HtmlLink(this PageData page, string linkText, object attributes)
 
    // Usage
    CurrentPage.HtmlLink("Some text", new { target = "_blank", title = "A very cool link"});
 
    // Renders
    <a href="/en/mypage/" target="_blank" title="A very cool link">Some text</a>
    // Method signatur
    public static string HtmlLink(this PageData page, Func<PageData, string> linkText, object attributes)
 
    // Usage
    CurrentPage.HtmlLink(p => p.StartPublish.ToShortDateString(), new { style = "text-decoration: none;", @class = "myclass" });
 
    // Renders
    <a class="myclass" href="/en/mypage/" style="text-decoration: none;">11/3/2009</a>

This will of course be extra cool combined with the Page Type Builder project.

So what do you think? Cool? Spaghetti code? Don’t care? Comments are very much appreciated! :)

The SelectedTemplate and duplicate code

The SelectedTemplate is used in the MenuList and PageList EPiServer web controls. It is a template used for displaying selected items in navigation lists. This is a nice template to have, but sometimes it is an overkill to use it. Say when you only need to add a class of selected or active (which happened to me today).

The problem

<ul class="nav">
	<li>
		<a href="#">
			<span class="l"></span><span class="c">PageName</span><span class="r"></span>
		</a>
	</li>
	<li>
		<a href="#" class="active">
			<span class="l"></span><span class="c">PageName</span><span class="r"></span>
		</a>
	</li>
</ul>

This is a simple navigation list, but as you can see we have two span tags inside the anchors (this is a technique used when you need to use more than one background image). So we cannot use the EPiServer:Property control that we would use normally.

<EPiServer:Property PropertyName="PageLink" runat="server" />

The normal solution

Instead we’re using a combination of HTML and data binding syntax.

<ItemTemplate>
	<li>
		<a href="<%# Container.CurrentPage.LinkURL %>">
			<span class="l"></span><span class="c"><%# Container.CurrentPage.Property["PageName"].ToWebString() %></span><span class="r"></span>
		</a>
	</li>
</ItemTemplate>
<SelectedTemplate>
	<li>
		<a href="<%# Container.CurrentPage.LinkURL %>" class="active">
			<span class="l"></span><span class="c"><%# Container.CurrentPage.Property["PageName"].ToWebString() %></span><span class="r"></span>
		</a>
	</li>
</SelectedTemplate>

This will work fine, but is not good practice, since we now have duplicated the same code in both templates, only adding class=”active” to the SelectedTemplate.

Solution

We’re now going to update the code to only use the ItemTemplate, and add a little logic for checking if the item should be selected or not.

<ItemTemplate>
	<li>
		<a href="<%# Container.CurrentPage.LinkURL %>" <%# SelectedCssClass(Container.CurrentPage, "active") %>>
			<span class="l"></span><span class="c"><%# Container.CurrentPage.Property["PageName"].ToWebString() %></span><span class="r"></span>
		</a>
	</li>
    </ItemTemplate>

The SelectedCssClass method lives in our code-behind file and looks like this:

protected string SelectedCssClass(PageData page, string cssClass)
{
	var result = string.Empty;
	if (page == null || page.PageLink.ID < 1)
	{
		return result;
	}
 
	if (page.IsSelected(CurrentPage))
	{
		result = string.Format("class=\"{0}\"", cssClass);
	}
 
	return result;
}

As you can see I’m using an extension method (from the EPiCode.Extensions project) in my if statement. This method simply takes the CurrentPage and checks if it, or any of its parents, match the page that is being data binded (same thing as the SelectedTemplate does).

By adding this logic to our code-behind (or a helper class), instead of using the SelectedTemplate just for this little thing, we make it much easier for us or (even more important) the next developer to change and update the navigation list. We’ve eliminated a code smell :) .

© Copyright Frederik Vig. Based on Fluid Blue theme