Tag Archives: episerver

Error in UI-path when upgrading from EPiServer 5 to 6

The other day we were upgrading a site for a customer from EPiServer 5 to EPiServer 6. In the upgrade process an exception was thrown telling us:

At C:\Program Files (x86)\EPiServer\CMS\6.0.530.0\Upgrade\System Scripts\Upgrade Site (SqlServer).ps1:361 char:29

+                  $newUiUrl = $uiUrl.Replace <<<< ($uiPath, $uiPath+”/CMS”)

System.Management.Automation.ParentContainsErrorRecordException: Cannot convert argument “1″, with value: “/CMS”, for “Replace” to type “System.Char”: “Cannot convert value “/CMS” to type “System.Char”. Error: “Strängen måste vara exakt ett tecken lång.”"

After some research we realized that the uiUrl in episerver.config was set to https://www.somedomain.com/ui/ and the upgrade script didn’t like it and most likely expected the value to be ~/ui/.

The solution was to change it to ~/ui/ during upgrade and then change it back.

Match EPiServer properties and Page Type Builder properties (Updated)

Updated: 2011-09-21, Lee Crowe has updated this plugin. Please check out his blog post: Introducing Page Type Builder UI

Updated: This can now be found on GitHub: https://github.com/eriknordin/PTB-Helpers

Updated: 2010-11-10 16:23, see more at the end of this post!

Using PageTypeBuilder when creating EPiServer web sites?

Then you’re probably aware of when removing properties in code, they won’t change in EPiServer. Same thing when changing a property type in PTB, it won’t change in EPiServer.

In larger projects with a lot of inheritance between page types this can be really annoying, going through all page types and remove/change properties. So I created a plugin that displays miss matches between EPiServer and PTB-properties. In the plugin you can also delete unwanted properties, but for now you can’t convert them to another property type.

The plugin will appear in admin-mode:

And looks something like this.

Don’t forget to put the plugin in a secured folder (or remove it in production environment).

This plugin is tested with EPiServer CMS 6 and Page Type Builder 1.3.

Download the plugin at: http://world.episerver.com/Code/Erik-Nordin/Match-EPiServer-and-Pgae-Type-Builder-properties/

Update

Fixed a bug reported at the code section and also added a link to the page type, and also added a link to edit the property if there was a mismatch.

Make your PropertyNumber a bit wider

The default style for PropertyNumber in EPiServer is often a bit short if you have number larger than 999 and it also aligns the text to left. An easy way around this is to use EPiServer PropertyControlClassFactory.

Just create a “PropertyNumberWideControl” that inherits PropertyNumberControl and override CreateEditControls to modify the style as you feel like.

namespace Some.Web.SpecializedProperties.Controls
{
public class PropertyNumberWideControl : PropertyNumberControl
{
public override void CreateEditControls()
{
base.CreateEditControls();

base.EditControl.Style.Add("width", "100px");
base.EditControl.Style.Add("text-align", "right");
}
}
}

There are now two ways to make this control override the default PropertyNumberControl.

1.
In Web.Config, find <episerver.baseLibrary><classFactories>. In that node you might find this <add type=”EPiServer.Core.PropertyControlClassFactory, EPiServer” id=”PropertyControlFactory”>, if not add it. Then you have to register your new control and that it should override the old one: <register type=”EPiServer.Core.PropertyNumber, EPiServer” mappedType=”Some.Web.SpecializedProperties.Controls.PropertyNumberWideControl, Some.Web” />.

<episerver.baseLibrary>

<classFactories>
.....
<add type="EPiServer.Core.PropertyControlClassFactory, EPiServer" id="PropertyControlFactory">
<register type="EPiServer.Core.PropertyNumber, EPiServer" mappedType="Some.Web.SpecializedProperties.Controls.PropertyNumberWideControl, Some.Web" />
</add>
</classFactories>
</episerver.baseLibrary>

2. You can also override the control with code. To do that, take a look at this post from Ted Nyberg.

Send mail in development environment

Just realized that in web.config you can specify a directory to “send” mail to instead of using a smtp-server, pretty neat. Just change to the following where you specify the smtp settings and you won’t have any troubles with smtp-servers. Just don’t forget to change this when you really need to send a mail.

<system.net>  
   <mailSettings>  
      <smtp deliveryMethod="SpecifiedPickupDirectory">  
         <specifiedPickupDirectory 
             pickupDirectoryLocation="c:\directory\to\emails\" />  
      </smtp>  
   </mailSettings>  
</system.net>

Quick way to create checkboxlist / dropdownlist properties

In EPiServer there is a easy way to create a checkbox list property by extending some existing classes.

In this example I will fetch the children for the start page and display them. In a future blog post I will show you how to do the same with a dropdown list control, and also show you have to extend this with Settings for properties to make the properties much more dynamic and useful.

Check box list / multiple choice property

1. Create a new class and make that class extend EPiServer.Core.PropertyMultiValue. This class should also have the attribute PageDefinitionPlugIn to be recognized as a property.

[PageDefinitionTypePlugIn(DisplayName="Custom CheckBox list")]
public class PropertyCustomCheckBoxList : PropertyMultipleValue
{
public override EPiServer.Core.IPropertyControl CreatePropertyControl()
{
return new PropertyCustomCheckBoxListControl();
}
}

2. Create the property control and extend EPiServer.Web.PropertyControls.PropertySelectMultipleControlBase

public class PropertyCustomCheckBoxListControl : PropertySelectMultipleControlBase
{
}

3. Now we need to populate the property with some data. In the control class, override the method SetupEditControls and do some magic

protected override void SetupEditControls()
{
// Get children to start page
foreach (PageData page in DataFactory.Instance.GetChildren(PageReference.StartPage))
{
// Create list item
ListItem li = new ListItem(page.PageName, page.PageLink.ID.ToString());
// check if list item is selected
li.Selected = ((PropertyMultipleValue)PropertyData).IsValueActive(li.Value);
// add item to checkbox list
this.EditControl.Items.Add(li);
}
}

4. That’s it. Everything else is handled by the classes you extend. By the way, the value of the property is saved as a comma separated string.

Creating classes for PageTypeBuilder in an existing project

Update: This can now be found on GitHub: https://github.com/eriknordin/PTB-Helpers

While everyone else is creating cool gadgets for the new site center I was appointed to update an “old” site with some new functionality. And since PageTypeBuilder was introduced in my EPiServer life, and don’t feel like working without it in any project. If this would’ve been a small project I would probably just created the PTB classes by hand, but after looking into the page type list I was freaked out. Therefore I spent some time creating a “plugin” (it’s not a  real plugin, just “some” code) that creates PageTypes classes from all the page types and properties in the current project.

Step 1
The first step is to download the source code, it’s a zip-file containing a .aspx/.designer/.cs
Download it here

Step 2
Include the files in your project.

Step 3
Open you web browser and surf to the page.

Step 4
There are a few values that yo can change before doing the import/export (it’s up to you to define what it is :)).
You can add a prefix before and after the class name, change the base class that the classes should extend, enter a namespace (required) and finally decide where to put the files.
ptb-classes1

You can also exclude page types that you don’t want to include.
ptb-classes2

And finally you can decide which namespaces that should be included by default.
ptb-classes3

Step 5
When clicking “Create classes” you will see a log of classes created plus if something is excluded.
An example is that every propertyname with a “-” in it will be excluded because you can’t have “-” in a property name in C#.
When the files are created you just have to include them in your project and you should be good to go. You have to remember to include a reference to PageTypeBuilder, and you also need to change so all PageTypes .aspx.cs files inherits from the right class.

One other thing that should be mentioned is that PageTypes names like “[Something] Page Type Name” will end up like [yout catalog]\Something\PageTypeName.cs (if you don’t have any prefix).

Update – 091103 10:23
1. Discovered a bug and updated the source files.
2. Before using this, backup you database, this code is used without any warranty.
3. If you want to extend the functionality, please feel free to do it.

Update – 100128
DefaultValueType was not set which lead to some problems. Fixed.

PageTypeBuilder – makes developing with EPiServer funny

As you may have noticed over the last month, Joel Abrahamsson has created a module to EPiServer called PageTypeBuilder. In a short explanation PageTypeBuilder brings joy into developing with EPiServer! No more need for ranting around in admin mode, no more need of synchronizing page types between dev – test- stage – live! You get stronged typed access to all properties defined, you can inherit page types, you can also very easy create your own package with page types and reuse it in another project. Anyway, Joel explains it all on his own blog in four different blog posts.

So why am I writing this post when Joel explains it all?

First of all, I want to spread the PageTypeBuilder – I can guarantee that you will enjoy working with EPiServer much much more with this module.

Just a small thing like this code makes me happy.


public T1 GetDefaultPageData<T1>(PageReference parent) where T1 : TypedPageData
{
int? id = PageTypeResolver.Instance.GetPageTypeID(typeof(T1));
if (!id.HasValue)
{
throw new Exception("Could not find PageTypeID for class " + typeof(T1).ToString());
}
return (T1)DataFactory.Instance.GetDefaultPageData(parent, id.Value);
}

With this code you can create a new page of any page type you have defined with the PageTypeBuilder without having to store the id or the name of the page type in some settings page/web.config. You just need to use this nice line:


MyPageType myPage = GetDefaultPageData<MyPageType>(pageRefParent);

Code snippets

Another reason for writing this post is to say that I’ve updated the code snippets I’ve blogged about earlier.

I’ve added two snippets:

  • pt – which is the attribute for the class
  • ptppage – page reference property

I’ve also updated all the old snippets to include EditCaption and HelpText, so it’s a bit more user friendly now.

You can download the new zip-package here

Unzip the files into “My Documents\Visual Studio 2008\Code Snippets\Visual C#\My Code Snippets”.

Update: Code Snippets to PageTypeBuilder

UPDATE: The code snippets are updated, read more in this blog post.

Since the way of including properties in PageTypeBuilder has been changed, so has the snippets.

This ZIP-package includes nine different snippets:

  • ptpbool – Selected/Not selected
  • ptpdate – Date
  • ptpimage – URL to image
  • ptpnumber- Integer
  • ptpobject – You decide.. :)
  • ptpstring – Short string
  • ptpurl – URL
  • ptpxhtmlstring – XHTML with properties
  • ptplongstring – XHTML string with no properties

Click here to download the snippets, unzip the files into “My Documents\Visual Studio 2008\Code Snippets\Visual C#\My Code Snippets”

By the way, I found a better tool for making snippets, even though it’s called VB Snippet Editor, it handles C# snippets aswell :) You can find it here: http://billmccarthy.com/Projects/Snippet_Editor/

Code Snippets to PageTypeBuilder

UPDATE: These snippets are out of date, download from this post instead

For you who have developed with the open source CMS N2 CMS, I guess you fell in love in how you are in control over the page type properties. And as a few of you have might notice the newly announced EMVP Joel Abrahamsson has found a really nice way to achieve this with EPiServer.

To create a property there are a few lines of code, and sometimes you might be to lazy to write these lines.. And as you may know there is a great thing in Visual Studio called Snippets that can help you out. A snippet is a XML-based file, and if you are lazy as I am, you probably want some help when you create your own snippets. I can recommend using a program called Snippy.

Here is a step by step how to create your own snippet. In this example I will create a snippet for a “Short string property” to the PageTypeBuilder earlier mentioned. (if you just want to download the snippets, check at the bottom of this post)

  1. Download and start Snippy
  2. Start by entering some information about the snippet.
    snippet_1
    The shortcut field is what you have to write in Visual studion to use the snippet.
  3. In the Code-area, change language to csharp and paste the code that you would like to make a snippet of. In my case I will use the code to create a definition for a Short string.
    [PageTypeProperty(SortOrder = 100, UniqueValuePerLanguage = true, Searchable=true, Type = typeof(PropertyString))]
    public string Headline
    {
    get
    {
    return GetPropertyValue<StartPageType, string>(page => page.Headline);
    }
    
    set
    {
    SetPropertyValue<StartPageType, string>(page => page.Headline, value);
    }
    }
    

    snippet_2

  4. If we save the snippet now, we would actually have a functional snippet, but there a few things that we would like to change..
    In this snippet I would like to change SortOrder, UniqueValuePerLangugae, Searchable, Headline(PropertyName) and the StartPageType(which pagetype this property should be saved/read to/from)
    In “Literal & Objects” we can define so these things mentioned above could be changed by just tabbing around when we are using our snippet.
  5. Let’s start with SortOrder. Press the “Add…”-button.
    • ID: the “variable”-name that we will refer to in the code-area
    • Tooltip: a little help-text when you are using the snippet
    • Default value: when using the snippet and you ignore this part you get the default value
    • Function: There are a few predefined functions you can use, we will use one later to retrive the class name of the page type. You can read more about the functions here: http://msdn.microsoft.com/en-us/library/ms242312(VS.80).aspx
    • Declaration type: Yo can read about the difference here: http://msdn.microsoft.com/en-us/library/ms165396(VS.80).aspx. We will use Literals.
    • Editable: Everything except the PageType should be editable by the user

    This is how the SortOrder should look like.
    snippet_4

    And when we refer to it in the code area we use the ID surronded with $-signs, like $SortOrder$.
    snippet_5

  6. Continue with the others, the only special one is the PageType. For this one we need to use a function called ClassName() and the Editable-box should not be checked.
    snippet_6
  7. This is how it should look like when you are done:
    snippet_7

    snippet_8
    As yo can see the PropertyName is used several times, but you will only need to enter it once.

  8. Now save your snippet. I think the right directory will choosen, if not it should be saved in “My Documents\Visual Studio [2005/2008]\Code Snippets\Visual C#\My Code Snippets”
  9. Open up visual studio, and in a class start typing the shorcut name given, and it will be shown in the intellisene.
    snippet_9
  10. Press Tab, Tab and you can now use your snippet.
    snippet_10

I’ve only created three snippets so far. You can download them here! (Unzip in “My Documents\Visual Studio [2005/2008]\Code Snippets\Visual C#\My Code Snippets”)

Feel free to contribute with your own snippets to the PageTypeBuilder, I will probably update this blog post as a create new ones.

My Documents\Visual Studio [2005/2008]\Code Snippets\Visual C#\My Code Snippets

Scheduled tasks – tips

Here are a few tips about scheduled tasks that may spare you some debugging and angry moments.

First of all, if you are interested in how you create a simple scheduled job, please check out Ted Nybergs post.

Several developers / Load balancing environment

If the same site is up’n'running on several computers/servers but with a shared database, the scheduled job might run at the “wrong” machine. There is a setting in web.config which controls if the scheduler should be run by this instance or not. It’s an attribute to <siteSettings> called “enableScheduler”, eg. <siteSettings enableScheduler=”false” …. /> if you don’t want the scheduler to run in this instance/machine.

Another way, not to tell if the job should be executed or not, but if you want to know which computer that executed the job, is to return the computer name with the return message. This can save you a lot of frustration when are about to pull you hair of cause the changes you make in to code doesn’t affect to job. :)

return "[Computer: " + System.Environment.MachineName + "] " + returnMessage;

Object reference not set to an instance…
Sometimes when you work with scheduled jobs, you can get this error, even though the only thing your job does is to return a “hellow world”. I’ve experienced this a few times, but never put much effort in to find out what causes this.
However, you can easily go around this by deleteing your job and create a new one with a slightly different class name.

Impersonate
In some cases you might need to run to job as a certain user.
Specially when you want to use FindPagesWithCriteria in EPiServer CMS 5 R2. It ignores the AccessControlList and only fetches pages that the current user has access rights to read. In R2 SP1 there is a new method called FindAllPagesWithCriteria which is supposed to find all pages despite access rights.
Well, this is how you login:

[ScheduledPlugIn(Description = "Test job with impersonated user", DisplayName = "Test job")]
public class TestJob
{

public static string Execute()
{
string returnMessage;

if (EnterImpersonatedState("erik.nordin", "password"))
{
returnMessage = "Job executed with user " + PrincipalInfo.CurrentPrincipal.Identity.Name;
LeaveImpersonatedState();
}
else
{
returnMessage = "Failed to login";
}
return "[Computer: " + System.Environment.MachineName + "] " + returnMessage;
}

private static IPrincipal prevPrincipal;
private static bool EnterImpersonatedState(string userName, string password)
{
IPrincipal impersonatedUser = null;

// If you don't want to validate the user, you can use skip the if-statement:
if (Membership.ValidateUser(userName, password))
{
impersonatedUser = PrincipalInfo.CreatePrincipal(userName);
}

if (impersonatedUser == null)
{
return false;
}

prevPrincipal = PrincipalInfo.CurrentPrincipal;
PrincipalInfo.CurrentPrincipal = impersonatedUser;

return true;
}

private static void LeaveImpersonatedState()
{
PrincipalInfo.CurrentPrincipal = prevPrincipal;
}
}