Unit testing an EPiServer ContentArea

Background

Consider the following simple method that returns the names of the items of a content area:

public class ContentAreaHelper
{
    public static IEnumerable<string> GetItemNames(ContentArea contentArea)
    {
        return contentArea.Items.Select(item => item.GetContent().Name);
    }
}

The method is made up to be as simple as possible to illustrate the how unit testing against a ContentArea can be done, which turns out to be non-trivial.

You might often have more complex logic that really needs to be unit tested, but I’d argue that even simple methods like these are entitled to a few unit tests. Rather than just describe a finished solution, this post describes how to do this step by step and also includes some error messages you’re likely to encounter. The idea is to make it easier to find the post when googling for the subject matter or problems you might have. (For the record, this code has been tested with EPiServer 7.19, for other versions some adjustments may be required.)

To get started, let’s assume that we want to create a simple test, something like this:

[Test]
public void GetNames_WithContentAreaItem_ShouldReturnTheName()
{
    // Arrange
    var contentReference = new ContentReference(1);
    var content = new BasicContent { Name = "a" };

    // TODO: Associate GetContent calls to content

    var contentArea = new ContentArea();
    contentArea.Items.Add(new ContentAreaItem {ContentLink = contentReference});

    // Act
    var names = ContentAreaHelper.GetItemNames(contentArea);

    // Assert
    Assert.That(names.Count(), Is.EqualTo(1));
    Assert.That(names.First(), Is.EqualTo("a"));
}

However, this is not a finished test since we don’t connect the content variable to be returned from the call to item.GetContent() in the ContentAreaHelper.GetItemNames() method. So how do we do that?

Well it’s not immediately obvious but if you dig into the GetContent() method you’ll find that it’s an extension method that retrieves an instance of IContentRepository from the ServiceLocator and then calls an overloaded extension method that takes an IContentRepository as parameter. That repository’s TryGet method is then called, so that’s where we need to hook up our content.

So first we need a IContentRepository that returns our content when queried. The easiest way to do that is by using a mocking framework, in this example I’m using FakeItEasy.

var contentRepository = A.Fake<IContentRepository>();
IContent outContent;
A.CallTo(() => contentRepository.TryGet(contentReference,
        A<ILanguageSelector>.Ignored, out outContent))
    .Returns(true)
    .AssignsOutAndRefParameters(content);

This basically tells FakeItEasy that we need a IContentRepository instance that returns our content when queried for the given content reference. EPiServer also passes a ILanguageSelector object but we’re not interested in its value so we ignore that parameter. The code is further complicated by the fact that TryGet is a method with an output parameter.

We’re not finished yet, but if you’re tempted and try to run the test right now, you’ll probably get an exception such as this:

EPiServer.ServiceLocation.ActivationException : Activation error occurred while trying to get instance of type ISecuredFragmentMarkupGeneratorFactory, key ""
  ----> StructureMap.StructureMapException : StructureMap Exception Code:  202
No Default Instance defined for PluginFamily EPiServer.Core.Html.StringParsing.ISecuredFragmentMarkupGeneratorFactory, EPiServer, Version=7.19.2.0, Culture=neutral, PublicKeyToken=8fe83dea738b45b7

This might seem very cryptic but basically the problem is that EPiServer’s service locator is not set up which is needed when adding items to a content area, for some obscure reason. So we now have two options, either we do just that, or we take a short cut. I like short cuts, so let’s try that first.

A shortcut – faking a ContentArea

As I mentioned earlier the GetContent() extension method has an overload that takes a IContentRepository repository as parameter. We could use that instead of GetContent and our test should work. So we rewrite the class under test like this:

public class ContentAreaHelper
{
    public static IEnumerable<string> GetItemNames(ContentArea contentArea)
    {
        var rep = ServiceLocator.Current.GetInstance<IContentRepository>();
        return GetItemNames(contentArea, rep);
    }

    public static IEnumerable<string> GetItemNames(ContentArea contentArea,
        IContentRepository rep)
    {
        return contentArea.Items.Select(item => item.GetContent(rep).Name);
    }
}

And then we can change our test to call the second overload, passing in our fake IContentRepository. However, if we run the test now, which feels it should work, it still gives the ActivationException mentioned above. It occurs when adding items to the ContentArea as EPiServer apparently needs a live datasource for this to work. This is utterly confusing of course, and it might seem that the short cut is doomed. Not so!

Here comes the next trick. We don’t really need a “real” content area for the test, all we need is an object that looks like a ContentArea and behaves like it. If it looks like a duck, and all that. 🙂

So what we can do is to fake a ContentArea object and define ourselves what the Items collection contains:

//var contentArea = new ContentArea();
//contentArea.Items.Add(new ContentAreaItem {ContentLink = contentReference});
var contentArea = A.Fake<ContentArea>();
A.CallTo(() => contentArea.Items).Returns(new List<ContentAreaItem> {contentAreaItem});

If we run the test now, we get a new error:

EPiServer.BaseLibrary.ClassFactoryException : ClassFactory not initialized

Most people will now give up on the $@& EPiServer framework deeming unit testing impossible, but since we’re not quitters we add this to our test:

// Avoid "EPiServer.BaseLibrary.ClassFactoryException : ClassFactory not 
// initialized"
EPiServer.BaseLibrary.ClassFactory.Instance =
    new EPiServer.Implementation.DefaultBaseLibraryFactory(string.Empty);
EPiServer.BaseLibrary.ClassFactory.RegisterClass(
    typeof(EPiServer.BaseLibrary.IRuntimeCache),
    typeof(EPiServer.Implementation.DefaultRuntimeCache));
EPiServer.Globalization.ContentLanguage.PreferredCulture =
    new CultureInfo("en");

And finally, our test is green! This is what the final short cut version of the test looks like:

private IContentRepository _contentRepository;

[SetUp]
public void SetUp()
{
    _contentRepository = A.Fake<IContentRepository>();

    // Avoid "EPiServer.BaseLibrary.ClassFactoryException : ClassFactory not
    // initialized"
    ClassFactory.Instance = new DefaultBaseLibraryFactory(string.Empty);
    ClassFactory.RegisterClass(typeof(IRuntimeCache),
        typeof(DefaultRuntimeCache));
    ContentLanguage.PreferredCulture = new CultureInfo("en");
}



[Test]
public void GetNames_WithContentAreaItem_ShouldReturnTheName()
{
    // Arrange
    var contentReference = new ContentReference(1);
    var content = new BasicContent { Name = "a" };

    // Create fake IContentRepository that returns our content
    IContent outContent;
    A.CallTo(() => _contentRepository.TryGet(contentReference,
            A<ILanguageSelector>.Ignored, out outContent))
        .Returns(true)
        .AssignsOutAndRefParameters(content);

    // Create fake ContentArea with a ContentAreaItem
    var contentAreaItem = new ContentAreaItem {
        ContentLink = contentReference
    };
    var contentArea = A.Fake<ContentArea>();
    A.CallTo(() => contentArea.Items)
        .Returns(new List<ContentAreaItem> { contentAreaItem });

    // Act
    var names = ContentAreaHelper.GetItemNames(contentArea, _contentRepository);

    // Assert
    Assert.That(names.Count(), Is.EqualTo(1));
    Assert.That(names.First(), Is.EqualTo("a"));
}

I moved parts of the code into a SetUp method that NUnit executes prior to each test to make the actual test method a little more clean, but it still isn’t very pretty. Extracting some of the setup into some helper methods is probably a good idea, but for brevity we’ll leave it like it is.

Ok, that was the shortcut version with a fake ContentArea, but what if we don’t want to rewrite our method to take a IContentRepository parameter? Or perhaps we’re writing tests against other methods that don’t have these handy overloads? Well, then we need to setup up a basic service locator registry and initialize the EPiServer framework’s ServiceLocator prior to the test.

Running the test with a configured ServiceLocator

Ok, time to go back to our original method under test:

public class ContentAreaHelper
{
    public static IEnumerable<string> GetItemNames(ContentArea contentArea)
    {
        return contentArea.Items.Select(item => item.GetContent().Name);
    }
}

And for the test, remember that we had created a IContentRepository fake that we want EPiServer to use. This is how we create a StructureMap object factory and tell EPiServer to use it for its ServiceLocator:

// Clear the StructureMap registry and reinitialize
ObjectFactory.Initialize(expr => { });
ObjectFactory.Configure(expr => expr.For<IContentRepository>()
    .Use(contentRepository));
ObjectFactory.Configure(expr => 
    expr.For<ISecuredFragmentMarkupGeneratorFactory>()
        .Use(A.Fake<ISecuredFragmentMarkupGeneratorFactory>()));
ObjectFactory.Configure(expr => expr.For<IContentTypeRepository>()
    .Use(A.Fake<IContentTypeRepository>()));
ObjectFactory.Configure(expr => expr.For<IPublishedStateAssessor>()
    .Use(A.Fake<IPublishedStateAssessor>()));

// Set up the EPiServer service locator with our fakes
ServiceLocator.SetLocator(
    new StructureMapServiceLocator(ObjectFactory.Container));

The fakes for ISecuredFragmentMarkupGeneratorFactory, IContentTypeRepository and IPublishedStateAssessor were added because StructureMap complained that it did not know where to find instances for those interfaces when running the tests.

We still get the “ClassFactory not initialized” exception as above so we must apply the same fix again. After that, the test works.

After some refactoring, this is what the test looks like:

private IContentRepository _contentRepository;

[SetUp]
public void SetUp()
{
    _contentRepository = A.Fake<IContentRepository>();

    // Clear the StructureMap registry and reinitialize
    ObjectFactory.Initialize(expr => { });
    ObjectFactory.Configure(expr => expr.For<IContentRepository>()
        .Use(_contentRepository));
    ObjectFactory.Configure(expr => 
        expr.For<ISecuredFragmentMarkupGeneratorFactory>()
            .Use(A.Fake<ISecuredFragmentMarkupGeneratorFactory>()));
    ObjectFactory.Configure(expr => expr.For<IContentTypeRepository>()
        .Use(A.Fake<IContentTypeRepository>()));
    ObjectFactory.Configure(expr => expr.For<IPublishedStateAssessor>()
        .Use(A.Fake<IPublishedStateAssessor>()));

    // Set up the EPiServer service locator with our fakes
    ServiceLocator.SetLocator(
        new StructureMapServiceLocator(ObjectFactory.Container));

    // Avoid "EPiServer.BaseLibrary.ClassFactoryException : ClassFactory not
    // initialized"
    ClassFactory.Instance = new DefaultBaseLibraryFactory(string.Empty);
    ClassFactory.RegisterClass(typeof(IRuntimeCache),
        typeof(DefaultRuntimeCache));
    ContentLanguage.PreferredCulture = new CultureInfo("en");
}


[Test]
public void GetNames_WithContentAreaItem_ShouldReturnTheName()
{
    // Arrange
    var contentReference = new ContentReference(1);
    var content = new BasicContent { Name = "a" };

    // Associate GetContent calls to 'content'
    IContent outContent;
    A.CallTo(() => _contentRepository.TryGet(contentReference,
            A<ILanguageSelector>.Ignored, out outContent))
        .Returns(true)
        .AssignsOutAndRefParameters(content);

    var contentArea = new ContentArea();
    contentArea.Items.Add(new ContentAreaItem {ContentLink = contentReference});

    // Act
    var names = ContentAreaHelper.GetItemNames(contentArea);

    // Assert
    Assert.That(names.Count(), Is.EqualTo(1));
    Assert.That(names.First(), Is.EqualTo("a"));
} 

As before we do general initialization in the SetUp method and only do test-specific stuff in the actual test. This is so we can reuse as much setup as possible for the next test.

Final thoughts

So there you go, two ways of writing unit tests against an EPiServer ContentArea. Use the one most suitable for you. I tend to like the “faked ContentArea” version since you don’t have to get quite as messy with EPiServer internals, but sometimes it is not enough and I then use the other one. It’s useful to have both in your toolbox, and now you do as well. 🙂

There are probably other ways of accomplishing the same task, so feel free to comment below if you have opinions!

Cheers,

Emil

Get the Url to the EPiServer start page incl. language branch

This is how to retrieve the address to the startpage including the currently active language branch (e.g. “/sv/” or “/en/”):

PageData pagedata = Global.EPDataFactory.GetPage(Global.EPConfig.StartPage);
string url = pagedata.DetermineAutomaticURL(LanguageContext.Current.CurrentLanguageBranch);

This code looks simple but it actually took me an hour or so to get it right (I haven’t worked with globalization before) so I thought it’d make a good blog post…

/Emil

Databinding with a Repeater

This is simple stuff, but I wanted to store these code snippets somewhere for easy re-use…

This is how to do databinding with a Repeater control in ASP.NET.

In the ASPX file:

<asp :Repeater runat="server" ID="rptPuffar">
   <itemtemplate>
          <h1>< %# GetTitle(Container) %></h1>
          <p>< %# Eval("XYZ") %></p>
   </itemtemplate>
</asp>

In the code-behind file:

protected override void Page_Load(object sender, EventArgs e)
{
   if (!IsPostBack)
   {
      PageDataCollection puffar = GetChildren(this.PuffContainer);
      rptPuffar.DataSource = puffar;
      rptPuffar.DataBind();
   }
}



protected string GetTitle(RepeaterItem item)
{
   PageData page = (PageData)item.DataItem;
   return page.PageName;
}

In Page_Load(), we connect the repeater to a datasource (in this case a collection of pages from EPiServer).

GetTitle() is a function that is called by the ItemTemplate in the repeater for extracting the string to include in the page (in this case the name of the page). Eval() can also be used directly in the ASPX file to display the value of a property.

As I said, easy stuff, but now I don’t have to write the code again the next time I need it…

How to detect if an EPiServer page is presented in DOPE mode

In some cases it may be useful to detect when an EPiServer page is displayed in DOPE (Direct On-Page Editing) mode rather than the “normal” View mode. This is how to do it:

string dopemode = Request.Params["DopeMode"];
if (!String.IsNullOrEmpty(dopemode) && dopemode.ToLower() == "enable")
{
   // DOPE mode detected!
}

This is the only way I have found to do this, but it feels like there should be a DOPE flag somewhere in the EPiServer API. If anyone has found it, please leave a comment 🙂

Resizing the Action Window panel in an EPiServer plugin

Have you ever written en EPiServer plugin for the Action Window? If so, you have probably noticed how irritatingly narrow it is. Luckily, the width can easily be adjusted by your plugin using this code:

<script>
  if (window.parent!=null && window.parent.parent!=null &&
    window.parent.parent.document.all['epCustomDIV']!=null)
  {
    window.parent.parent.document.all['epCustomDIV'].parentElement.style.pixelWidth = 500;
  }
</script>

This is the same code that the built-in EPiServer File Manager uses, so I think we can regard it as well tested. It has worked well for me, hope it helps you as well.

How to refer to an EPiServer page

Often you have to refer to a given page in a site. For example, on each page you may want to have a footer with a link to a page that describes the site’s usage of cookies. Note that this is different than linking to pages in the navigation menus since those links are created by traversing all non-hidden pages automatically. It’s also different from links created by the editors in edit mode, since they use the link tool to select the individual pages they want to link to.

The problem we have is instead how to identity a given page in code that we want to create a link to, and the question is what the best way to do that is. As always, the answer depends on the requirements. There are several alternatives, which I will now describe.

Hard-coding the page Url
The easiest way is of course to just hard-code the page’s address (we’re using EPiServer’s friendly Url function here):

<a href="/AboutCookies/">About cookies</a>

That works well, as long as we don’t move the page from the site’s root. If we move it, we will have to adjust all links to that page:

<a href="/InfoPages/AboutCookies/">About cookies</a>

That is obviously not all that great, especially since the page can be moved by a web site editor without thought of the consequences. You can also get into similar problems if you rename the page.

If you don’t use friendly Url’s you won’t have these problems since the page Url in that case will identify the page by its Id. In this case, this solution may be enough for you.

Referring to pages using page properties
The next alternative, and perhaps the most common, is to use page properties to refer to the page in question. In our example we could create a page property called “CookiePage” of the “Page” property type so that the web site editor could select the page which stores information about the cookie policies of the site.

On the page we then use code similar to this:

<episerver:property runat="server" PropertyName="CookiePage"></episerver:property>

Now we can move or rename the page without breaking the link. As an added bonus, EPiServer will now keep track of the reference to the page so if we try to delete it, EPiServer will warn us that the page is referenced.

Referring to pages using dynamic properties
Nothing is perfect though, and one problem with the above approach is that if the page is to be referenced from more than one page (remember, we want the link on all pages) we would need to put the page property on all pages, which of course would be ridiculous. To get around that we use EPiServer’s “dynamic property” functionality. A dynamic property works just like a page property, except that it’s not associated with a page type, but can be set on any page.

So instead of creating a page property called “CookiePage” we create a dynamic property “CookiePage” and set it’s value on the start page of our site. We can then use the same code as before in the ASPX page:

<episerver:property runat="server" PropertyName="CookiePage"></episerver:property>

Now, this works well but we risk having to create a lot of dynamic properties for different settings (there are probably more pages we need to reference than the “cookie page”). We therefore risk having a lot of dynamic properties which can be bewildering for web site editors. It can also be unclear which page these properties should be set on. Furthermore, the values of dynamic properties can normally only be edited by administrators, not by editors. If that is not wanted, we have to choose another solution.

This leads us to the next alternative…

Referring to pages using a settings page
Instead of using a lot of dynamic properties in our web site, we can create a special settings page (with its own page type). On this page we collect all our site-wide settings, such as a reference to our cookie page (i.e. we create a page property called “CookiePage” on the settings page). We then create a dynamic property called “SettingsPage” and set it’s value on the start page for our site so that it points to our settings page.

Finally, we modify our ASPX page so that it now reads

<episerver:property runat="server" PropertyName="CookiePage" PageLinkProperty="SettingsPage"></episerver:property>

This will still read the value of the property “CookiePage”, but now the value will come from the page referenced by the dynamic property “SettingsPage”. This can be seen as a form of property redirection. It’s a minimal code modification and we have gained

  • a clean separation of site settings from normal properties (page and dynamic ones)
  • web site editors can now modifiy the values (this can of course be denied using EPiServer security settings)

In many cases, this is probably the best solution as it’s scalable and gives clean page code. However, code in the code-behind files becomes a little more complicated if you want to retrieve settings from the settings page. Essentially you first have to retrieve the value of the “SettingsPage” property, then open the page it references and then finally read the property value from the loaded page.

If the settings stored in the settings page are mainly page references that are farily static (such as our cookie page) there is one more alternative.

Simple adresses
Each page in EPiServer has, in addition to the “normal” page address (friendly Url or normal), a shortcut address. This is editable on the “Advanced information” tab when editing a page:

cookiepage_property.gif

If you set this property on the cookie page to for example “cookiepage”, this page is accessible as “http://host/cookiepage”. This fact can be used in our page footer by creating a link like this:

<a href="/cookiepage">About cookies</a>

This looks a lot like our first, simple example, but now we can move or rename the page without problems. And in code-behind files we now don’t even have to read property values, we know beforehand what the page address is:

Response.Redirect("/cookiepage");

Very simple and very efficient code. Just what I like 🙂

This alternative is also useful if you have several pages that should be visited in sequence, for example when the user is ordering an item in a web shop. If you set the simple address on each form page, you always know what the address to the next page in the sequence is. If you select one of the other alternatives, it will be a lot of administration before you get all page properties right.

This post got longer than I thought when I started it, the subject may be more complicated than first expected. Maybe you guys out there have opinions on this matter? Please add comment to this post if that is the case 🙂

Cheers,

Emil

Using Web User Controls for EPiServer custom page property types

All content in EPiServer pages are stored in page properties which can be of different types such as short string, XHTML string, date, etc. It is also possible tocreate custom property data types, which can be very useful in many circumstances such as when integrating with other systems or creating content which is not easily representable only in page types.

A custom page property type is created by inheriting from an existing property type such as EPiServer.Core.PropertyLongString and overriding the CreateChildControls() function, and a skeleton looks like this:

[EPiServer.PlugIn.PageDefinitionTypePlugIn(DisplayName = "Stränglista")]
public class StringList : EPiServer.Core.PropertyLongString
{
    public override void CreateChildControls(string RenderType, System.Web.UI.Control Container)
    {
        switch (RenderType.ToLower()) 
        {
            case "edit":  // Edit mode, display controls to let the user edit the value
                ...
            case "dope":  // Direct on-page editing
                ...
            case "default":  // Show the content in view mode
                ...
            default:
                base.CreateChildControls(RenderType, Container);
                break;
        }
    }
}

So far, all of the above is documented in the book Developing Solutions with EPiServer together with a simple example of creating a BgColour type for choosing a color. However, for more complex properties, the techniques described there (creating control instances and calling Container.Controls.Add()) quickly becomes complicated. It’s then better to create a Web User Control and load that in the CreateChildControls() function. Here’s how to do that:

StringListEdit edit = (StringListEdit)Container.Page.LoadControl(
    "~/templates/PropertyDataTypes/StringListEdit.ascx");
edit.ID = Name;

// Initialize the user control with watever value it takes. In this case we happen
// to use a list of strings stored in this.Strings
edit.Strings = this.Strings;

CopyWebAttributes(Container, edit);
Container.Controls.Add(edit);

In the user control we don’t have to know anything about loading or saving the property value. Initializing is done explicitly in the code above, but how is saving accomplished?

If we only use the code above, the user control will be correctly initialized but no change will ever be saved. What’s missing is a code snippet something like this, just after the code above:

edit.Controls.Add(CreateParseValidator(edit.ValueText));

The ValueText property is a hidden TextBox property of our user control that always holds the string representation of the edited value (we’re using a string to store the value since we’re inheriting from PropertyLongString). The CreateParseValidator() method creates a custom validator that takes care of the saving for us.

NOTE: The validator must be created inside the user control, not inside the container!

This is actually the only way I have found to update the property value, and it’s not exacly apparent from the API or the documentation that we need to create an extra control in the user control with the complete value representation and connect a validator to it. 😉

The solution outlined here has worked well for me, but if anyone has other solutions for how to best use user controls with custom property types, please feel free to leave a comment!

/Emil

Why do I get “Registry access not allowed” error message?

Struggling with this error that occurs the first time the site is viewed after an IIS restart?

epi_reg_error.gif

This problem can be caused by the EPiServer Scheduler service not being installed.

Try this:

C:\Inetpub\wwwroot\bin>C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\InstallUtil.exe EPiServer.SchedulerSvc.exe

(From the EPiServer FAQ: http://www.episerver.com/en/EPiServer_Knowledge_Center/Support/FAQ_EPiServer_4/905/923/)

Retrieve the Html code for a Web User Control

Here’s how to extract the Html code for a web control:

public static string GetHtmlForControl(Control control)
{
    StringWriter textwriter = new StringWriter();
    HtmlTextWriter writer = new HtmlTextWriter(textwriter);
			
    control.DataBind();
    control.RenderControl(writer);
    string html = textwriter.GetStringBuilder().ToString();

    return html;
}

Tip: If you’re having problems with the generated Html being incomplete, then maybe you’re calling the function above in the wrong time? I’ve been having some problems with databound EPiServer controls until we discovered that we were doing this too early. When we started doing it in the PreRenderComplete event of the page, then it started working:

protected void Page_PreRenderComplete(object sender, EventArgs e)
{
    string html = FormHelper.GetHtmlForControl(Butikshuvud);
}

Open an EPiServer page

Here are a few ways to retrieve data for a given page (expressed in a PageReference instance) in EPiServer:

PageReference pageref = ...;
PageData pagedata;

// In a page (which is a sub-class of PageBase, e.g. TemplatePage, EditPage, SimplePage)
pagedata = this.Getpage(pageref);

// In a user control (which is a sub-class of UserControlBase)
pagedata = this.Getpage(pageref);

// Anywhere
pagedata = Global.EPDataFactory.GetPage(pageref);

Global.EPDataFactory also has some other useful functions:

// Open a page from a given FriendlyUrl rather than a PageReference
// (which requires knowing the Page ID)
pagedata = Global.EPDataFactory.GetPageByURL("/Bokningsbara-kurser/");

BTW, it’s also possible to initialize a PageReference with a Url (although NOT a Friendly Url):

pageref = PageReference.ParseUrl("http://localhost:8889/shop/Puff.aspx?id=130");

UPDATE (2007-06-04):

If you have a so called “simple address” such as “/foo”, then none of the above will work. In that case you have to use code such as this:

PropertyCriteriaCollection critcol = new PropertyCriteriaCollection();

PropertyCriteria crit = new PropertyCriteria();
crit.Condition = EPiServer.Filters.CompareCondition.Equal;
crit.Name = "PageExternalURL";
crit.Type = PropertyDataType.String;
crit.Value = simple_address.Trim(new char[] { '/' }); // Remove initial "/"
critcol.Add(crit);

PageDataCollection pagecol = Global.EPDataFactory.FindPagesWithCriteria(Global.EPConfig.RootPage, critcol);
if (pagecol.Count > 0)
{
   return pagecol[0].LinkURL;
}